[go: nahoru, domu]

1ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/*
2ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Windfarm PowerMac thermal control.  MAX6690 sensor.
3ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt *
4ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
5ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt *
6ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Use and redistribute under the terms of the GNU GPL v2.
7ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt */
8ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/types.h>
9ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/errno.h>
10ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/kernel.h>
11ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/init.h>
12ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/slab.h>
13ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/i2c.h>
14ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/prom.h>
15ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/pmac_low_i2c.h>
16ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
17ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include "windfarm.h"
18ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
1922b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt#define VERSION "1.0"
20ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
21ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* This currently only exports the external temperature sensor,
22ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt   since that's all the control loops need. */
23ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
24ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* Some MAX6690 register numbers */
25ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define MAX6690_INTERNAL_TEMP	0
26ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define MAX6690_EXTERNAL_TEMP	1
27ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
28ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstruct wf_6690_sensor {
29351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	struct i2c_client	*i2c;
30ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	struct wf_sensor	sens;
31ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt};
32ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
33ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define wf_to_6690(x)	container_of((x), struct wf_6690_sensor, sens)
34ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
35ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic int wf_max6690_get(struct wf_sensor *sr, s32 *value)
36ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{
37ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	struct wf_6690_sensor *max = wf_to_6690(sr);
38ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	s32 data;
39ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
40351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	if (max->i2c == NULL)
41ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt		return -ENODEV;
42ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
43ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	/* chip gets initialized by firmware */
44351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP);
45ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	if (data < 0)
46ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt		return data;
47ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	*value = data << 16;
48ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	return 0;
49ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}
50ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
51ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic void wf_max6690_release(struct wf_sensor *sr)
52ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{
53ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	struct wf_6690_sensor *max = wf_to_6690(sr);
54ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
55ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	kfree(max);
56ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}
57ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
58ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic struct wf_sensor_ops wf_max6690_ops = {
59ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	.get_value	= wf_max6690_get,
60ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	.release	= wf_max6690_release,
61ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	.owner		= THIS_MODULE,
62ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt};
63ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
64351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_max6690_probe(struct i2c_client *client,
65351ca3e31197929535418f5affc761cd9fb07428Jean Delvare			    const struct i2c_device_id *id)
66ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{
6722b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	const char *name, *loc;
68ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	struct wf_6690_sensor *max;
69351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	int rc;
70ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
7122b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
7222b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	if (!loc) {
7322b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
7422b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		return -ENXIO;
7522b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	}
7622b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt
77d839ba2ab2f3270fe4f067e082a7233ba06bcf9cBenjamin Herrenschmidt	/*
78d839ba2ab2f3270fe4f067e082a7233ba06bcf9cBenjamin Herrenschmidt	 * We only expose the external temperature register for
79d839ba2ab2f3270fe4f067e082a7233ba06bcf9cBenjamin Herrenschmidt	 * now as this is all we need for our control loops
80d839ba2ab2f3270fe4f067e082a7233ba06bcf9cBenjamin Herrenschmidt	 */
81d839ba2ab2f3270fe4f067e082a7233ba06bcf9cBenjamin Herrenschmidt	if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
8222b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		name = "backside-temp";
8322b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	else if (!strcmp(loc, "NB Ambient"))
8422b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		name = "north-bridge-temp";
8522b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	else if (!strcmp(loc, "GPU Ambient"))
8622b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		name = "gpu-temp";
8722b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	else
8822b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt		return -ENXIO;
8922b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt
90ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
91ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	if (max == NULL) {
92351ca3e31197929535418f5affc761cd9fb07428Jean Delvare		printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
93351ca3e31197929535418f5affc761cd9fb07428Jean Delvare		       "no memory\n");
94351ca3e31197929535418f5affc761cd9fb07428Jean Delvare		return -ENOMEM;
95351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	}
96351ca3e31197929535418f5affc761cd9fb07428Jean Delvare
97351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	max->i2c = client;
988bb61fe1d03123a625265d599a22fb12af79e1aeGeert Uytterhoeven	max->sens.name = name;
99351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	max->sens.ops = &wf_max6690_ops;
100351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	i2c_set_clientdata(client, max);
101351ca3e31197929535418f5affc761cd9fb07428Jean Delvare
102351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	rc = wf_register_sensor(&max->sens);
10322b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	if (rc)
104351ca3e31197929535418f5affc761cd9fb07428Jean Delvare		kfree(max);
105351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	return rc;
106351ca3e31197929535418f5affc761cd9fb07428Jean Delvare}
107351ca3e31197929535418f5affc761cd9fb07428Jean Delvare
108351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_max6690_remove(struct i2c_client *client)
109ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{
110351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	struct wf_6690_sensor *max = i2c_get_clientdata(client);
111ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
112351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	max->i2c = NULL;
113ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	wf_unregister_sensor(&max->sens);
114ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
115ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt	return 0;
116ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}
117ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
118351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic const struct i2c_device_id wf_max6690_id[] = {
11922b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin Herrenschmidt	{ "MAC,max6690", 0 },
120351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	{ }
121351ca3e31197929535418f5affc761cd9fb07428Jean Delvare};
12222b6d2ea355449fc2a9a4dc5c346615af86b876eBenjamin HerrenschmidtMODULE_DEVICE_TABLE(i2c, wf_max6690_id);
123351ca3e31197929535418f5affc761cd9fb07428Jean Delvare
124351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic struct i2c_driver wf_max6690_driver = {
125351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	.driver = {
126351ca3e31197929535418f5affc761cd9fb07428Jean Delvare		.name		= "wf_max6690",
127351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	},
128351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	.probe		= wf_max6690_probe,
129351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	.remove		= wf_max6690_remove,
130351ca3e31197929535418f5affc761cd9fb07428Jean Delvare	.id_table	= wf_max6690_id,
131351ca3e31197929535418f5affc761cd9fb07428Jean Delvare};
132351ca3e31197929535418f5affc761cd9fb07428Jean Delvare
133f7fb862b843269d02a2fa75e4bbb49603f801b88Wei Yongjunmodule_i2c_driver(wf_max6690_driver);
134ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt
135ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
136ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control");
137ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_LICENSE("GPL");
138