xref: /openbmc/linux/drivers/hwmon/thmc50.c (revision cc28a610d4fcce1831d26f2099e23fbb3eb7260c)
1add77c64SKrzysztof Helt /*
2add77c64SKrzysztof Helt     thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
3add77c64SKrzysztof Helt              monitoring
4add77c64SKrzysztof Helt     Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
5add77c64SKrzysztof Helt     Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and
6add77c64SKrzysztof Helt     Philip Edelbrock <phil@netroedge.com>
7add77c64SKrzysztof Helt 
8add77c64SKrzysztof Helt     This program is free software; you can redistribute it and/or modify
9add77c64SKrzysztof Helt     it under the terms of the GNU General Public License as published by
10add77c64SKrzysztof Helt     the Free Software Foundation; either version 2 of the License, or
11add77c64SKrzysztof Helt     (at your option) any later version.
12add77c64SKrzysztof Helt 
13add77c64SKrzysztof Helt     This program is distributed in the hope that it will be useful,
14add77c64SKrzysztof Helt     but WITHOUT ANY WARRANTY; without even the implied warranty of
15add77c64SKrzysztof Helt     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16add77c64SKrzysztof Helt     GNU General Public License for more details.
17add77c64SKrzysztof Helt 
18add77c64SKrzysztof Helt     You should have received a copy of the GNU General Public License
19add77c64SKrzysztof Helt     along with this program; if not, write to the Free Software
20add77c64SKrzysztof Helt     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21add77c64SKrzysztof Helt */
22add77c64SKrzysztof Helt 
23add77c64SKrzysztof Helt #include <linux/module.h>
24add77c64SKrzysztof Helt #include <linux/init.h>
25add77c64SKrzysztof Helt #include <linux/slab.h>
26add77c64SKrzysztof Helt #include <linux/i2c.h>
27add77c64SKrzysztof Helt #include <linux/hwmon.h>
28add77c64SKrzysztof Helt #include <linux/hwmon-sysfs.h>
29add77c64SKrzysztof Helt #include <linux/err.h>
30add77c64SKrzysztof Helt #include <linux/mutex.h>
31add77c64SKrzysztof Helt 
32add77c64SKrzysztof Helt MODULE_LICENSE("GPL");
33add77c64SKrzysztof Helt 
34add77c64SKrzysztof Helt /* Addresses to scan */
35add77c64SKrzysztof Helt static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
36add77c64SKrzysztof Helt 
37add77c64SKrzysztof Helt /* Insmod parameters */
38add77c64SKrzysztof Helt I2C_CLIENT_INSMOD_2(thmc50, adm1022);
39add77c64SKrzysztof Helt I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
40add77c64SKrzysztof Helt 			"to enable 3rd temperature (ADM1022 only)");
41add77c64SKrzysztof Helt 
42add77c64SKrzysztof Helt /* Many THMC50 constants specified below */
43add77c64SKrzysztof Helt 
44add77c64SKrzysztof Helt /* The THMC50 registers */
45add77c64SKrzysztof Helt #define THMC50_REG_CONF				0x40
46add77c64SKrzysztof Helt #define THMC50_REG_COMPANY_ID			0x3E
47add77c64SKrzysztof Helt #define THMC50_REG_DIE_CODE			0x3F
48add77c64SKrzysztof Helt #define THMC50_REG_ANALOG_OUT			0x19
49dcf3b5fbSKrzysztof Helt /*
50bba891c2SKrzysztof Helt  * The mirror status register cannot be used as
51bba891c2SKrzysztof Helt  * reading it does not clear alarms.
52dcf3b5fbSKrzysztof Helt  */
53bba891c2SKrzysztof Helt #define THMC50_REG_INTR				0x41
54add77c64SKrzysztof Helt 
55add77c64SKrzysztof Helt const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
56add77c64SKrzysztof Helt const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
57add77c64SKrzysztof Helt const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
58add77c64SKrzysztof Helt 
59add77c64SKrzysztof Helt #define THMC50_REG_CONF_nFANOFF			0x20
60add77c64SKrzysztof Helt 
61add77c64SKrzysztof Helt /* Each client has this additional data */
62add77c64SKrzysztof Helt struct thmc50_data {
63add77c64SKrzysztof Helt 	struct i2c_client client;
641beeffe4STony Jones 	struct device *hwmon_dev;
65add77c64SKrzysztof Helt 
66add77c64SKrzysztof Helt 	struct mutex update_lock;
67add77c64SKrzysztof Helt 	enum chips type;
68add77c64SKrzysztof Helt 	unsigned long last_updated;	/* In jiffies */
69add77c64SKrzysztof Helt 	char has_temp3;		/* !=0 if it is ADM1022 in temp3 mode */
70add77c64SKrzysztof Helt 	char valid;		/* !=0 if following fields are valid */
71add77c64SKrzysztof Helt 
72add77c64SKrzysztof Helt 	/* Register values */
73add77c64SKrzysztof Helt 	s8 temp_input[3];
74add77c64SKrzysztof Helt 	s8 temp_max[3];
75add77c64SKrzysztof Helt 	s8 temp_min[3];
76add77c64SKrzysztof Helt 	u8 analog_out;
77dcf3b5fbSKrzysztof Helt 	u8 alarms;
78add77c64SKrzysztof Helt };
79add77c64SKrzysztof Helt 
80add77c64SKrzysztof Helt static int thmc50_attach_adapter(struct i2c_adapter *adapter);
81add77c64SKrzysztof Helt static int thmc50_detach_client(struct i2c_client *client);
82add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client);
83add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev);
84add77c64SKrzysztof Helt 
85add77c64SKrzysztof Helt static struct i2c_driver thmc50_driver = {
86add77c64SKrzysztof Helt 	.driver = {
87add77c64SKrzysztof Helt 		.name = "thmc50",
88add77c64SKrzysztof Helt 	},
89add77c64SKrzysztof Helt 	.attach_adapter = thmc50_attach_adapter,
90add77c64SKrzysztof Helt 	.detach_client = thmc50_detach_client,
91add77c64SKrzysztof Helt };
92add77c64SKrzysztof Helt 
93add77c64SKrzysztof Helt static ssize_t show_analog_out(struct device *dev,
94add77c64SKrzysztof Helt 			       struct device_attribute *attr, char *buf)
95add77c64SKrzysztof Helt {
96add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
97add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->analog_out);
98add77c64SKrzysztof Helt }
99add77c64SKrzysztof Helt 
100add77c64SKrzysztof Helt static ssize_t set_analog_out(struct device *dev,
101add77c64SKrzysztof Helt 			      struct device_attribute *attr,
102add77c64SKrzysztof Helt 			      const char *buf, size_t count)
103add77c64SKrzysztof Helt {
104add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
105add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
106add77c64SKrzysztof Helt 	int tmp = simple_strtoul(buf, NULL, 10);
107add77c64SKrzysztof Helt 	int config;
108add77c64SKrzysztof Helt 
109add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
110add77c64SKrzysztof Helt 	data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
111add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
112add77c64SKrzysztof Helt 				  data->analog_out);
113add77c64SKrzysztof Helt 
114add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
115add77c64SKrzysztof Helt 	if (data->analog_out == 0)
116add77c64SKrzysztof Helt 		config &= ~THMC50_REG_CONF_nFANOFF;
117add77c64SKrzysztof Helt 	else
118add77c64SKrzysztof Helt 		config |= THMC50_REG_CONF_nFANOFF;
119add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
120add77c64SKrzysztof Helt 
121add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
122add77c64SKrzysztof Helt 	return count;
123add77c64SKrzysztof Helt }
124add77c64SKrzysztof Helt 
125add77c64SKrzysztof Helt /* There is only one PWM mode = DC */
126add77c64SKrzysztof Helt static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
127add77c64SKrzysztof Helt 			     char *buf)
128add77c64SKrzysztof Helt {
129add77c64SKrzysztof Helt 	return sprintf(buf, "0\n");
130add77c64SKrzysztof Helt }
131add77c64SKrzysztof Helt 
132add77c64SKrzysztof Helt /* Temperatures */
133add77c64SKrzysztof Helt static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
134add77c64SKrzysztof Helt 			 char *buf)
135add77c64SKrzysztof Helt {
136add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
137add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
138add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
139add77c64SKrzysztof Helt }
140add77c64SKrzysztof Helt 
141add77c64SKrzysztof Helt static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
142add77c64SKrzysztof Helt 			     char *buf)
143add77c64SKrzysztof Helt {
144add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
145add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
146add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
147add77c64SKrzysztof Helt }
148add77c64SKrzysztof Helt 
149add77c64SKrzysztof Helt static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
150add77c64SKrzysztof Helt 			    const char *buf, size_t count)
151add77c64SKrzysztof Helt {
152add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
153add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
154add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
155add77c64SKrzysztof Helt 	int val = simple_strtol(buf, NULL, 10);
156add77c64SKrzysztof Helt 
157add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
158add77c64SKrzysztof Helt 	data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
159add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
160add77c64SKrzysztof Helt 				  data->temp_min[nr]);
161add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
162add77c64SKrzysztof Helt 	return count;
163add77c64SKrzysztof Helt }
164add77c64SKrzysztof Helt 
165add77c64SKrzysztof Helt static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
166add77c64SKrzysztof Helt 			     char *buf)
167add77c64SKrzysztof Helt {
168add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
169add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
170add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
171add77c64SKrzysztof Helt }
172add77c64SKrzysztof Helt 
173add77c64SKrzysztof Helt static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
174add77c64SKrzysztof Helt 			    const char *buf, size_t count)
175add77c64SKrzysztof Helt {
176add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
177add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
178add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
179add77c64SKrzysztof Helt 	int val = simple_strtol(buf, NULL, 10);
180add77c64SKrzysztof Helt 
181add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
182add77c64SKrzysztof Helt 	data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
183add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
184add77c64SKrzysztof Helt 				  data->temp_max[nr]);
185add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
186add77c64SKrzysztof Helt 	return count;
187add77c64SKrzysztof Helt }
188add77c64SKrzysztof Helt 
189dcf3b5fbSKrzysztof Helt static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
190dcf3b5fbSKrzysztof Helt 			  char *buf)
191dcf3b5fbSKrzysztof Helt {
192dcf3b5fbSKrzysztof Helt 	int index = to_sensor_dev_attr(attr)->index;
193dcf3b5fbSKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
194dcf3b5fbSKrzysztof Helt 
195dcf3b5fbSKrzysztof Helt 	return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
196dcf3b5fbSKrzysztof Helt }
197dcf3b5fbSKrzysztof Helt 
198add77c64SKrzysztof Helt #define temp_reg(offset)						\
199add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,	\
200add77c64SKrzysztof Helt 			NULL, offset - 1);				\
201add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
202add77c64SKrzysztof Helt 			show_temp_min, set_temp_min, offset - 1);	\
203add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
204add77c64SKrzysztof Helt 			show_temp_max, set_temp_max, offset - 1);
205add77c64SKrzysztof Helt 
206add77c64SKrzysztof Helt temp_reg(1);
207add77c64SKrzysztof Helt temp_reg(2);
208add77c64SKrzysztof Helt temp_reg(3);
209add77c64SKrzysztof Helt 
210dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
211dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
212dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
213dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
214dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
215dcf3b5fbSKrzysztof Helt 
216add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
217add77c64SKrzysztof Helt 			  set_analog_out, 0);
218add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
219add77c64SKrzysztof Helt 
220add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = {
221add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_max.dev_attr.attr,
222add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_min.dev_attr.attr,
223add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_input.dev_attr.attr,
224dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
225add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_max.dev_attr.attr,
226add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_min.dev_attr.attr,
227add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_input.dev_attr.attr,
228dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
229dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp2_fault.dev_attr.attr,
230add77c64SKrzysztof Helt 	&sensor_dev_attr_pwm1.dev_attr.attr,
231add77c64SKrzysztof Helt 	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
232add77c64SKrzysztof Helt 	NULL
233add77c64SKrzysztof Helt };
234add77c64SKrzysztof Helt 
235add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = {
236add77c64SKrzysztof Helt 	.attrs = thmc50_attributes,
237add77c64SKrzysztof Helt };
238add77c64SKrzysztof Helt 
239add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */
240894c00cfSJean Delvare static struct attribute *temp3_attributes[] = {
241add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_max.dev_attr.attr,
242add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_min.dev_attr.attr,
243add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_input.dev_attr.attr,
244dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
245dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp3_fault.dev_attr.attr,
246add77c64SKrzysztof Helt 	NULL
247add77c64SKrzysztof Helt };
248add77c64SKrzysztof Helt 
249894c00cfSJean Delvare static const struct attribute_group temp3_group = {
250894c00cfSJean Delvare 	.attrs = temp3_attributes,
251add77c64SKrzysztof Helt };
252add77c64SKrzysztof Helt 
253add77c64SKrzysztof Helt static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
254add77c64SKrzysztof Helt {
255add77c64SKrzysztof Helt 	unsigned company;
256add77c64SKrzysztof Helt 	unsigned revision;
257add77c64SKrzysztof Helt 	unsigned config;
258add77c64SKrzysztof Helt 	struct i2c_client *client;
259add77c64SKrzysztof Helt 	struct thmc50_data *data;
260add77c64SKrzysztof Helt 	struct device *dev;
261add77c64SKrzysztof Helt 	int err = 0;
262*cc28a610SJean Delvare 	const char *type_name;
263add77c64SKrzysztof Helt 
264add77c64SKrzysztof Helt 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
265add77c64SKrzysztof Helt 		pr_debug("thmc50: detect failed, "
266add77c64SKrzysztof Helt 			 "smbus byte data not supported!\n");
267add77c64SKrzysztof Helt 		goto exit;
268add77c64SKrzysztof Helt 	}
269add77c64SKrzysztof Helt 
270add77c64SKrzysztof Helt 	/* OK. For now, we presume we have a valid client. We now create the
271add77c64SKrzysztof Helt 	   client structure, even though we cannot fill it completely yet.
272add77c64SKrzysztof Helt 	   But it allows us to access thmc50 registers. */
273add77c64SKrzysztof Helt 	if (!(data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
274add77c64SKrzysztof Helt 		pr_debug("thmc50: detect failed, kzalloc failed!\n");
275add77c64SKrzysztof Helt 		err = -ENOMEM;
276add77c64SKrzysztof Helt 		goto exit;
277add77c64SKrzysztof Helt 	}
278add77c64SKrzysztof Helt 
279add77c64SKrzysztof Helt 	client = &data->client;
280add77c64SKrzysztof Helt 	i2c_set_clientdata(client, data);
281add77c64SKrzysztof Helt 	client->addr = address;
282add77c64SKrzysztof Helt 	client->adapter = adapter;
283add77c64SKrzysztof Helt 	client->driver = &thmc50_driver;
284add77c64SKrzysztof Helt 	dev = &client->dev;
285add77c64SKrzysztof Helt 
286add77c64SKrzysztof Helt 	pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
287add77c64SKrzysztof Helt 		 client->addr, i2c_adapter_id(client->adapter));
288add77c64SKrzysztof Helt 
289add77c64SKrzysztof Helt 	/* Now, we do the remaining detection. */
290add77c64SKrzysztof Helt 	company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
291add77c64SKrzysztof Helt 	revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
292add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
293add77c64SKrzysztof Helt 
294add77c64SKrzysztof Helt 	if (kind == 0)
295add77c64SKrzysztof Helt 		kind = thmc50;
296add77c64SKrzysztof Helt 	else if (kind < 0) {
297add77c64SKrzysztof Helt 		err = -ENODEV;
298add77c64SKrzysztof Helt 		if (revision >= 0xc0 && ((config & 0x10) == 0)) {
299add77c64SKrzysztof Helt 			if (company == 0x49) {
300add77c64SKrzysztof Helt 				kind = thmc50;
301add77c64SKrzysztof Helt 				err = 0;
302add77c64SKrzysztof Helt 			} else if (company == 0x41) {
303add77c64SKrzysztof Helt 				kind = adm1022;
304add77c64SKrzysztof Helt 				err = 0;
305add77c64SKrzysztof Helt 			}
306add77c64SKrzysztof Helt 		}
307add77c64SKrzysztof Helt 	}
308add77c64SKrzysztof Helt 	if (err == -ENODEV) {
309add77c64SKrzysztof Helt 		pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
310add77c64SKrzysztof Helt 		goto exit_free;
311add77c64SKrzysztof Helt 	}
312add77c64SKrzysztof Helt 	data->type = kind;
313add77c64SKrzysztof Helt 
314*cc28a610SJean Delvare 	if (kind == adm1022) {
315add77c64SKrzysztof Helt 		int id = i2c_adapter_id(client->adapter);
316add77c64SKrzysztof Helt 		int i;
317add77c64SKrzysztof Helt 
318add77c64SKrzysztof Helt 		type_name = "adm1022";
319add77c64SKrzysztof Helt 		data->has_temp3 = (config >> 7) & 1;	/* config MSB */
320add77c64SKrzysztof Helt 		for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
321add77c64SKrzysztof Helt 			if (adm1022_temp3[i] == id &&
322add77c64SKrzysztof Helt 			    adm1022_temp3[i + 1] == address) {
323add77c64SKrzysztof Helt 				/* enable 2nd remote temp */
324add77c64SKrzysztof Helt 				data->has_temp3 = 1;
325add77c64SKrzysztof Helt 				break;
326add77c64SKrzysztof Helt 			}
327*cc28a610SJean Delvare 	} else {
328*cc28a610SJean Delvare 		type_name = "thmc50";
329add77c64SKrzysztof Helt 	}
330*cc28a610SJean Delvare 	pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
331*cc28a610SJean Delvare 		 type_name, (revision >> 4) - 0xc, revision & 0xf);
332add77c64SKrzysztof Helt 
333add77c64SKrzysztof Helt 	/* Fill in the remaining client fields & put it into the global list */
334add77c64SKrzysztof Helt 	strlcpy(client->name, type_name, I2C_NAME_SIZE);
335add77c64SKrzysztof Helt 	mutex_init(&data->update_lock);
336add77c64SKrzysztof Helt 
337add77c64SKrzysztof Helt 	/* Tell the I2C layer a new client has arrived */
338add77c64SKrzysztof Helt 	if ((err = i2c_attach_client(client)))
339add77c64SKrzysztof Helt 		goto exit_free;
340add77c64SKrzysztof Helt 
341add77c64SKrzysztof Helt 	thmc50_init_client(client);
342add77c64SKrzysztof Helt 
343add77c64SKrzysztof Helt 	/* Register sysfs hooks */
344add77c64SKrzysztof Helt 	if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
345add77c64SKrzysztof Helt 		goto exit_detach;
346add77c64SKrzysztof Helt 
347add77c64SKrzysztof Helt 	/* Register ADM1022 sysfs hooks */
348894c00cfSJean Delvare 	if (data->has_temp3)
349add77c64SKrzysztof Helt 		if ((err = sysfs_create_group(&client->dev.kobj,
350894c00cfSJean Delvare 					      &temp3_group)))
351add77c64SKrzysztof Helt 			goto exit_remove_sysfs_thmc50;
352add77c64SKrzysztof Helt 
353add77c64SKrzysztof Helt 	/* Register a new directory entry with module sensors */
3541beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&client->dev);
3551beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
3561beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
357add77c64SKrzysztof Helt 		goto exit_remove_sysfs;
358add77c64SKrzysztof Helt 	}
359add77c64SKrzysztof Helt 
360add77c64SKrzysztof Helt 	return 0;
361add77c64SKrzysztof Helt 
362add77c64SKrzysztof Helt exit_remove_sysfs:
363894c00cfSJean Delvare 	if (data->has_temp3)
364894c00cfSJean Delvare 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
365add77c64SKrzysztof Helt exit_remove_sysfs_thmc50:
366add77c64SKrzysztof Helt 	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
367add77c64SKrzysztof Helt exit_detach:
368add77c64SKrzysztof Helt 	i2c_detach_client(client);
369add77c64SKrzysztof Helt exit_free:
370add77c64SKrzysztof Helt 	kfree(data);
371add77c64SKrzysztof Helt exit:
372add77c64SKrzysztof Helt 	return err;
373add77c64SKrzysztof Helt }
374add77c64SKrzysztof Helt 
375add77c64SKrzysztof Helt static int thmc50_attach_adapter(struct i2c_adapter *adapter)
376add77c64SKrzysztof Helt {
377add77c64SKrzysztof Helt 	if (!(adapter->class & I2C_CLASS_HWMON))
378add77c64SKrzysztof Helt 		return 0;
379add77c64SKrzysztof Helt 	return i2c_probe(adapter, &addr_data, thmc50_detect);
380add77c64SKrzysztof Helt }
381add77c64SKrzysztof Helt 
382add77c64SKrzysztof Helt static int thmc50_detach_client(struct i2c_client *client)
383add77c64SKrzysztof Helt {
384add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
385add77c64SKrzysztof Helt 	int err;
386add77c64SKrzysztof Helt 
3871beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
388add77c64SKrzysztof Helt 	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
389894c00cfSJean Delvare 	if (data->has_temp3)
390894c00cfSJean Delvare 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
391add77c64SKrzysztof Helt 
392add77c64SKrzysztof Helt 	if ((err = i2c_detach_client(client)))
393add77c64SKrzysztof Helt 		return err;
394add77c64SKrzysztof Helt 
395add77c64SKrzysztof Helt 	kfree(data);
396add77c64SKrzysztof Helt 
397add77c64SKrzysztof Helt 	return 0;
398add77c64SKrzysztof Helt }
399add77c64SKrzysztof Helt 
400add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client)
401add77c64SKrzysztof Helt {
402add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
403add77c64SKrzysztof Helt 	int config;
404add77c64SKrzysztof Helt 
405add77c64SKrzysztof Helt 	data->analog_out = i2c_smbus_read_byte_data(client,
406add77c64SKrzysztof Helt 						    THMC50_REG_ANALOG_OUT);
407add77c64SKrzysztof Helt 	/* set up to at least 1 */
408add77c64SKrzysztof Helt 	if (data->analog_out == 0) {
409add77c64SKrzysztof Helt 		data->analog_out = 1;
410add77c64SKrzysztof Helt 		i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
411add77c64SKrzysztof Helt 					  data->analog_out);
412add77c64SKrzysztof Helt 	}
413add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
414add77c64SKrzysztof Helt 	config |= 0x1;	/* start the chip if it is in standby mode */
415add77c64SKrzysztof Helt 	if (data->has_temp3)
416add77c64SKrzysztof Helt 		config |= 0x80;		/* enable 2nd remote temp */
417add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
418add77c64SKrzysztof Helt }
419add77c64SKrzysztof Helt 
420add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev)
421add77c64SKrzysztof Helt {
422add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
423add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
424add77c64SKrzysztof Helt 	int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
425add77c64SKrzysztof Helt 
426add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
427add77c64SKrzysztof Helt 
428add77c64SKrzysztof Helt 	if (time_after(jiffies, data->last_updated + timeout)
429add77c64SKrzysztof Helt 	    || !data->valid) {
430add77c64SKrzysztof Helt 
431add77c64SKrzysztof Helt 		int temps = data->has_temp3 ? 3 : 2;
432add77c64SKrzysztof Helt 		int i;
433add77c64SKrzysztof Helt 		for (i = 0; i < temps; i++) {
434add77c64SKrzysztof Helt 			data->temp_input[i] = i2c_smbus_read_byte_data(client,
435add77c64SKrzysztof Helt 						THMC50_REG_TEMP[i]);
436add77c64SKrzysztof Helt 			data->temp_max[i] = i2c_smbus_read_byte_data(client,
437add77c64SKrzysztof Helt 						THMC50_REG_TEMP_MAX[i]);
438add77c64SKrzysztof Helt 			data->temp_min[i] = i2c_smbus_read_byte_data(client,
439add77c64SKrzysztof Helt 						THMC50_REG_TEMP_MIN[i]);
440add77c64SKrzysztof Helt 		}
441add77c64SKrzysztof Helt 		data->analog_out =
442add77c64SKrzysztof Helt 		    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
443dcf3b5fbSKrzysztof Helt 		data->alarms =
444bba891c2SKrzysztof Helt 		    i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
445add77c64SKrzysztof Helt 		data->last_updated = jiffies;
446add77c64SKrzysztof Helt 		data->valid = 1;
447add77c64SKrzysztof Helt 	}
448add77c64SKrzysztof Helt 
449add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
450add77c64SKrzysztof Helt 
451add77c64SKrzysztof Helt 	return data;
452add77c64SKrzysztof Helt }
453add77c64SKrzysztof Helt 
454add77c64SKrzysztof Helt static int __init sm_thmc50_init(void)
455add77c64SKrzysztof Helt {
456add77c64SKrzysztof Helt 	return i2c_add_driver(&thmc50_driver);
457add77c64SKrzysztof Helt }
458add77c64SKrzysztof Helt 
459add77c64SKrzysztof Helt static void __exit sm_thmc50_exit(void)
460add77c64SKrzysztof Helt {
461add77c64SKrzysztof Helt 	i2c_del_driver(&thmc50_driver);
462add77c64SKrzysztof Helt }
463add77c64SKrzysztof Helt 
464add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
465add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver");
466add77c64SKrzysztof Helt 
467add77c64SKrzysztof Helt module_init(sm_thmc50_init);
468add77c64SKrzysztof Helt module_exit(sm_thmc50_exit);
469