xref: /openbmc/linux/drivers/hwmon/thmc50.c (revision ccf37488322429bf8709f2227f3d48466add2b6b)
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 */
3525e9c86dSMark M. Hoffman static const 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 
555910a9b2STobias Klauser static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
565910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
575910a9b2STobias Klauser static const 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 {
631beeffe4STony Jones 	struct device *hwmon_dev;
64add77c64SKrzysztof Helt 
65add77c64SKrzysztof Helt 	struct mutex update_lock;
66add77c64SKrzysztof Helt 	enum chips type;
67add77c64SKrzysztof Helt 	unsigned long last_updated;	/* In jiffies */
68add77c64SKrzysztof Helt 	char has_temp3;		/* !=0 if it is ADM1022 in temp3 mode */
69add77c64SKrzysztof Helt 	char valid;		/* !=0 if following fields are valid */
70add77c64SKrzysztof Helt 
71add77c64SKrzysztof Helt 	/* Register values */
72add77c64SKrzysztof Helt 	s8 temp_input[3];
73add77c64SKrzysztof Helt 	s8 temp_max[3];
74add77c64SKrzysztof Helt 	s8 temp_min[3];
75add77c64SKrzysztof Helt 	u8 analog_out;
76dcf3b5fbSKrzysztof Helt 	u8 alarms;
77add77c64SKrzysztof Helt };
78add77c64SKrzysztof Helt 
79*ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind,
80*ccf37488SJean Delvare 			 struct i2c_board_info *info);
81*ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client,
82*ccf37488SJean Delvare 			const struct i2c_device_id *id);
83*ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client);
84add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client);
85add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev);
86add77c64SKrzysztof Helt 
87*ccf37488SJean Delvare static const struct i2c_device_id thmc50_id[] = {
88*ccf37488SJean Delvare 	{ "adm1022", adm1022 },
89*ccf37488SJean Delvare 	{ "thmc50", thmc50 },
90*ccf37488SJean Delvare 	{ }
91*ccf37488SJean Delvare };
92*ccf37488SJean Delvare MODULE_DEVICE_TABLE(i2c, thmc50_id);
93*ccf37488SJean Delvare 
94add77c64SKrzysztof Helt static struct i2c_driver thmc50_driver = {
95*ccf37488SJean Delvare 	.class = I2C_CLASS_HWMON,
96add77c64SKrzysztof Helt 	.driver = {
97add77c64SKrzysztof Helt 		.name = "thmc50",
98add77c64SKrzysztof Helt 	},
99*ccf37488SJean Delvare 	.probe = thmc50_probe,
100*ccf37488SJean Delvare 	.remove = thmc50_remove,
101*ccf37488SJean Delvare 	.id_table = thmc50_id,
102*ccf37488SJean Delvare 	.detect = thmc50_detect,
103*ccf37488SJean Delvare 	.address_data = &addr_data,
104add77c64SKrzysztof Helt };
105add77c64SKrzysztof Helt 
106add77c64SKrzysztof Helt static ssize_t show_analog_out(struct device *dev,
107add77c64SKrzysztof Helt 			       struct device_attribute *attr, char *buf)
108add77c64SKrzysztof Helt {
109add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
110add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->analog_out);
111add77c64SKrzysztof Helt }
112add77c64SKrzysztof Helt 
113add77c64SKrzysztof Helt static ssize_t set_analog_out(struct device *dev,
114add77c64SKrzysztof Helt 			      struct device_attribute *attr,
115add77c64SKrzysztof Helt 			      const char *buf, size_t count)
116add77c64SKrzysztof Helt {
117add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
118add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
119add77c64SKrzysztof Helt 	int tmp = simple_strtoul(buf, NULL, 10);
120add77c64SKrzysztof Helt 	int config;
121add77c64SKrzysztof Helt 
122add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
123add77c64SKrzysztof Helt 	data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
124add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
125add77c64SKrzysztof Helt 				  data->analog_out);
126add77c64SKrzysztof Helt 
127add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
128add77c64SKrzysztof Helt 	if (data->analog_out == 0)
129add77c64SKrzysztof Helt 		config &= ~THMC50_REG_CONF_nFANOFF;
130add77c64SKrzysztof Helt 	else
131add77c64SKrzysztof Helt 		config |= THMC50_REG_CONF_nFANOFF;
132add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
133add77c64SKrzysztof Helt 
134add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
135add77c64SKrzysztof Helt 	return count;
136add77c64SKrzysztof Helt }
137add77c64SKrzysztof Helt 
138add77c64SKrzysztof Helt /* There is only one PWM mode = DC */
139add77c64SKrzysztof Helt static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
140add77c64SKrzysztof Helt 			     char *buf)
141add77c64SKrzysztof Helt {
142add77c64SKrzysztof Helt 	return sprintf(buf, "0\n");
143add77c64SKrzysztof Helt }
144add77c64SKrzysztof Helt 
145add77c64SKrzysztof Helt /* Temperatures */
146add77c64SKrzysztof Helt static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
147add77c64SKrzysztof Helt 			 char *buf)
148add77c64SKrzysztof Helt {
149add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
150add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
151add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
152add77c64SKrzysztof Helt }
153add77c64SKrzysztof Helt 
154add77c64SKrzysztof Helt static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
155add77c64SKrzysztof Helt 			     char *buf)
156add77c64SKrzysztof Helt {
157add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
158add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
159add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
160add77c64SKrzysztof Helt }
161add77c64SKrzysztof Helt 
162add77c64SKrzysztof Helt static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
163add77c64SKrzysztof Helt 			    const char *buf, size_t count)
164add77c64SKrzysztof Helt {
165add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
166add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
167add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
168add77c64SKrzysztof Helt 	int val = simple_strtol(buf, NULL, 10);
169add77c64SKrzysztof Helt 
170add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
171add77c64SKrzysztof Helt 	data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
172add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
173add77c64SKrzysztof Helt 				  data->temp_min[nr]);
174add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
175add77c64SKrzysztof Helt 	return count;
176add77c64SKrzysztof Helt }
177add77c64SKrzysztof Helt 
178add77c64SKrzysztof Helt static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
179add77c64SKrzysztof Helt 			     char *buf)
180add77c64SKrzysztof Helt {
181add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
182add77c64SKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
183add77c64SKrzysztof Helt 	return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
184add77c64SKrzysztof Helt }
185add77c64SKrzysztof Helt 
186add77c64SKrzysztof Helt static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
187add77c64SKrzysztof Helt 			    const char *buf, size_t count)
188add77c64SKrzysztof Helt {
189add77c64SKrzysztof Helt 	int nr = to_sensor_dev_attr(attr)->index;
190add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
191add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
192add77c64SKrzysztof Helt 	int val = simple_strtol(buf, NULL, 10);
193add77c64SKrzysztof Helt 
194add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
195add77c64SKrzysztof Helt 	data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
196add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
197add77c64SKrzysztof Helt 				  data->temp_max[nr]);
198add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
199add77c64SKrzysztof Helt 	return count;
200add77c64SKrzysztof Helt }
201add77c64SKrzysztof Helt 
202dcf3b5fbSKrzysztof Helt static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
203dcf3b5fbSKrzysztof Helt 			  char *buf)
204dcf3b5fbSKrzysztof Helt {
205dcf3b5fbSKrzysztof Helt 	int index = to_sensor_dev_attr(attr)->index;
206dcf3b5fbSKrzysztof Helt 	struct thmc50_data *data = thmc50_update_device(dev);
207dcf3b5fbSKrzysztof Helt 
208dcf3b5fbSKrzysztof Helt 	return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
209dcf3b5fbSKrzysztof Helt }
210dcf3b5fbSKrzysztof Helt 
211add77c64SKrzysztof Helt #define temp_reg(offset)						\
212add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,	\
213add77c64SKrzysztof Helt 			NULL, offset - 1);				\
214add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
215add77c64SKrzysztof Helt 			show_temp_min, set_temp_min, offset - 1);	\
216add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
217add77c64SKrzysztof Helt 			show_temp_max, set_temp_max, offset - 1);
218add77c64SKrzysztof Helt 
219add77c64SKrzysztof Helt temp_reg(1);
220add77c64SKrzysztof Helt temp_reg(2);
221add77c64SKrzysztof Helt temp_reg(3);
222add77c64SKrzysztof Helt 
223dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
224dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
225dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
226dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
227dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
228dcf3b5fbSKrzysztof Helt 
229add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
230add77c64SKrzysztof Helt 			  set_analog_out, 0);
231add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
232add77c64SKrzysztof Helt 
233add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = {
234add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_max.dev_attr.attr,
235add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_min.dev_attr.attr,
236add77c64SKrzysztof Helt 	&sensor_dev_attr_temp1_input.dev_attr.attr,
237dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
238add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_max.dev_attr.attr,
239add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_min.dev_attr.attr,
240add77c64SKrzysztof Helt 	&sensor_dev_attr_temp2_input.dev_attr.attr,
241dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
242dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp2_fault.dev_attr.attr,
243add77c64SKrzysztof Helt 	&sensor_dev_attr_pwm1.dev_attr.attr,
244add77c64SKrzysztof Helt 	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
245add77c64SKrzysztof Helt 	NULL
246add77c64SKrzysztof Helt };
247add77c64SKrzysztof Helt 
248add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = {
249add77c64SKrzysztof Helt 	.attrs = thmc50_attributes,
250add77c64SKrzysztof Helt };
251add77c64SKrzysztof Helt 
252add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */
253894c00cfSJean Delvare static struct attribute *temp3_attributes[] = {
254add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_max.dev_attr.attr,
255add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_min.dev_attr.attr,
256add77c64SKrzysztof Helt 	&sensor_dev_attr_temp3_input.dev_attr.attr,
257dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
258dcf3b5fbSKrzysztof Helt 	&sensor_dev_attr_temp3_fault.dev_attr.attr,
259add77c64SKrzysztof Helt 	NULL
260add77c64SKrzysztof Helt };
261add77c64SKrzysztof Helt 
262894c00cfSJean Delvare static const struct attribute_group temp3_group = {
263894c00cfSJean Delvare 	.attrs = temp3_attributes,
264add77c64SKrzysztof Helt };
265add77c64SKrzysztof Helt 
266*ccf37488SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
267*ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind,
268*ccf37488SJean Delvare 			 struct i2c_board_info *info)
269add77c64SKrzysztof Helt {
270add77c64SKrzysztof Helt 	unsigned company;
271add77c64SKrzysztof Helt 	unsigned revision;
272add77c64SKrzysztof Helt 	unsigned config;
273*ccf37488SJean Delvare 	struct i2c_adapter *adapter = client->adapter;
274add77c64SKrzysztof Helt 	int err = 0;
275cc28a610SJean Delvare 	const char *type_name;
276add77c64SKrzysztof Helt 
277add77c64SKrzysztof Helt 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
278add77c64SKrzysztof Helt 		pr_debug("thmc50: detect failed, "
279add77c64SKrzysztof Helt 			 "smbus byte data not supported!\n");
280*ccf37488SJean Delvare 		return -ENODEV;
281add77c64SKrzysztof Helt 	}
282add77c64SKrzysztof Helt 
283add77c64SKrzysztof Helt 	pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
284add77c64SKrzysztof Helt 		 client->addr, i2c_adapter_id(client->adapter));
285add77c64SKrzysztof Helt 
286add77c64SKrzysztof Helt 	/* Now, we do the remaining detection. */
287add77c64SKrzysztof Helt 	company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
288add77c64SKrzysztof Helt 	revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
289add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
290add77c64SKrzysztof Helt 
291add77c64SKrzysztof Helt 	if (kind == 0)
292add77c64SKrzysztof Helt 		kind = thmc50;
293add77c64SKrzysztof Helt 	else if (kind < 0) {
294add77c64SKrzysztof Helt 		err = -ENODEV;
295add77c64SKrzysztof Helt 		if (revision >= 0xc0 && ((config & 0x10) == 0)) {
296add77c64SKrzysztof Helt 			if (company == 0x49) {
297add77c64SKrzysztof Helt 				kind = thmc50;
298add77c64SKrzysztof Helt 				err = 0;
299add77c64SKrzysztof Helt 			} else if (company == 0x41) {
300add77c64SKrzysztof Helt 				kind = adm1022;
301add77c64SKrzysztof Helt 				err = 0;
302add77c64SKrzysztof Helt 			}
303add77c64SKrzysztof Helt 		}
304add77c64SKrzysztof Helt 	}
305add77c64SKrzysztof Helt 	if (err == -ENODEV) {
306add77c64SKrzysztof Helt 		pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
307*ccf37488SJean Delvare 		return err;
308add77c64SKrzysztof Helt 	}
309add77c64SKrzysztof Helt 
310cc28a610SJean Delvare 	if (kind == adm1022) {
311add77c64SKrzysztof Helt 		int id = i2c_adapter_id(client->adapter);
312add77c64SKrzysztof Helt 		int i;
313add77c64SKrzysztof Helt 
314add77c64SKrzysztof Helt 		type_name = "adm1022";
315add77c64SKrzysztof Helt 		for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
316add77c64SKrzysztof Helt 			if (adm1022_temp3[i] == id &&
317*ccf37488SJean Delvare 			    adm1022_temp3[i + 1] == client->addr) {
318add77c64SKrzysztof Helt 				/* enable 2nd remote temp */
319*ccf37488SJean Delvare 				config |= (1 << 7);
320*ccf37488SJean Delvare 				i2c_smbus_write_byte_data(client,
321*ccf37488SJean Delvare 							  THMC50_REG_CONF,
322*ccf37488SJean Delvare 							  config);
323add77c64SKrzysztof Helt 				break;
324add77c64SKrzysztof Helt 			}
325cc28a610SJean Delvare 	} else {
326cc28a610SJean Delvare 		type_name = "thmc50";
327add77c64SKrzysztof Helt 	}
328cc28a610SJean Delvare 	pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
329cc28a610SJean Delvare 		 type_name, (revision >> 4) - 0xc, revision & 0xf);
330add77c64SKrzysztof Helt 
331*ccf37488SJean Delvare 	strlcpy(info->type, type_name, I2C_NAME_SIZE);
332add77c64SKrzysztof Helt 
333*ccf37488SJean Delvare 	return 0;
334*ccf37488SJean Delvare }
335*ccf37488SJean Delvare 
336*ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client,
337*ccf37488SJean Delvare 			const struct i2c_device_id *id)
338*ccf37488SJean Delvare {
339*ccf37488SJean Delvare 	struct thmc50_data *data;
340*ccf37488SJean Delvare 	int err;
341*ccf37488SJean Delvare 
342*ccf37488SJean Delvare 	data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL);
343*ccf37488SJean Delvare 	if (!data) {
344*ccf37488SJean Delvare 		pr_debug("thmc50: detect failed, kzalloc failed!\n");
345*ccf37488SJean Delvare 		err = -ENOMEM;
346*ccf37488SJean Delvare 		goto exit;
347*ccf37488SJean Delvare 	}
348*ccf37488SJean Delvare 
349*ccf37488SJean Delvare 	i2c_set_clientdata(client, data);
350*ccf37488SJean Delvare 	data->type = id->driver_data;
351*ccf37488SJean Delvare 	mutex_init(&data->update_lock);
352add77c64SKrzysztof Helt 
353add77c64SKrzysztof Helt 	thmc50_init_client(client);
354add77c64SKrzysztof Helt 
355add77c64SKrzysztof Helt 	/* Register sysfs hooks */
356add77c64SKrzysztof Helt 	if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
357*ccf37488SJean Delvare 		goto exit_free;
358add77c64SKrzysztof Helt 
359add77c64SKrzysztof Helt 	/* Register ADM1022 sysfs hooks */
360894c00cfSJean Delvare 	if (data->has_temp3)
361add77c64SKrzysztof Helt 		if ((err = sysfs_create_group(&client->dev.kobj,
362894c00cfSJean Delvare 					      &temp3_group)))
363add77c64SKrzysztof Helt 			goto exit_remove_sysfs_thmc50;
364add77c64SKrzysztof Helt 
365add77c64SKrzysztof Helt 	/* Register a new directory entry with module sensors */
3661beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&client->dev);
3671beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
3681beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
369add77c64SKrzysztof Helt 		goto exit_remove_sysfs;
370add77c64SKrzysztof Helt 	}
371add77c64SKrzysztof Helt 
372add77c64SKrzysztof Helt 	return 0;
373add77c64SKrzysztof Helt 
374add77c64SKrzysztof Helt exit_remove_sysfs:
375894c00cfSJean Delvare 	if (data->has_temp3)
376894c00cfSJean Delvare 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
377add77c64SKrzysztof Helt exit_remove_sysfs_thmc50:
378add77c64SKrzysztof Helt 	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
379add77c64SKrzysztof Helt exit_free:
380add77c64SKrzysztof Helt 	kfree(data);
381add77c64SKrzysztof Helt exit:
382add77c64SKrzysztof Helt 	return err;
383add77c64SKrzysztof Helt }
384add77c64SKrzysztof Helt 
385*ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client)
386add77c64SKrzysztof Helt {
387add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
388add77c64SKrzysztof Helt 
3891beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
390add77c64SKrzysztof Helt 	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
391894c00cfSJean Delvare 	if (data->has_temp3)
392894c00cfSJean Delvare 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
393add77c64SKrzysztof Helt 
394add77c64SKrzysztof Helt 	kfree(data);
395add77c64SKrzysztof Helt 
396add77c64SKrzysztof Helt 	return 0;
397add77c64SKrzysztof Helt }
398add77c64SKrzysztof Helt 
399add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client)
400add77c64SKrzysztof Helt {
401add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
402add77c64SKrzysztof Helt 	int config;
403add77c64SKrzysztof Helt 
404add77c64SKrzysztof Helt 	data->analog_out = i2c_smbus_read_byte_data(client,
405add77c64SKrzysztof Helt 						    THMC50_REG_ANALOG_OUT);
406add77c64SKrzysztof Helt 	/* set up to at least 1 */
407add77c64SKrzysztof Helt 	if (data->analog_out == 0) {
408add77c64SKrzysztof Helt 		data->analog_out = 1;
409add77c64SKrzysztof Helt 		i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
410add77c64SKrzysztof Helt 					  data->analog_out);
411add77c64SKrzysztof Helt 	}
412add77c64SKrzysztof Helt 	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
413add77c64SKrzysztof Helt 	config |= 0x1;	/* start the chip if it is in standby mode */
414*ccf37488SJean Delvare 	if (data->type == adm1022 && (config & (1 << 7)))
415*ccf37488SJean Delvare 		data->has_temp3 = 1;
416add77c64SKrzysztof Helt 	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
417add77c64SKrzysztof Helt }
418add77c64SKrzysztof Helt 
419add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev)
420add77c64SKrzysztof Helt {
421add77c64SKrzysztof Helt 	struct i2c_client *client = to_i2c_client(dev);
422add77c64SKrzysztof Helt 	struct thmc50_data *data = i2c_get_clientdata(client);
423add77c64SKrzysztof Helt 	int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
424add77c64SKrzysztof Helt 
425add77c64SKrzysztof Helt 	mutex_lock(&data->update_lock);
426add77c64SKrzysztof Helt 
427add77c64SKrzysztof Helt 	if (time_after(jiffies, data->last_updated + timeout)
428add77c64SKrzysztof Helt 	    || !data->valid) {
429add77c64SKrzysztof Helt 
430add77c64SKrzysztof Helt 		int temps = data->has_temp3 ? 3 : 2;
431add77c64SKrzysztof Helt 		int i;
432add77c64SKrzysztof Helt 		for (i = 0; i < temps; i++) {
433add77c64SKrzysztof Helt 			data->temp_input[i] = i2c_smbus_read_byte_data(client,
434add77c64SKrzysztof Helt 						THMC50_REG_TEMP[i]);
435add77c64SKrzysztof Helt 			data->temp_max[i] = i2c_smbus_read_byte_data(client,
436add77c64SKrzysztof Helt 						THMC50_REG_TEMP_MAX[i]);
437add77c64SKrzysztof Helt 			data->temp_min[i] = i2c_smbus_read_byte_data(client,
438add77c64SKrzysztof Helt 						THMC50_REG_TEMP_MIN[i]);
439add77c64SKrzysztof Helt 		}
440add77c64SKrzysztof Helt 		data->analog_out =
441add77c64SKrzysztof Helt 		    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
442dcf3b5fbSKrzysztof Helt 		data->alarms =
443bba891c2SKrzysztof Helt 		    i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
444add77c64SKrzysztof Helt 		data->last_updated = jiffies;
445add77c64SKrzysztof Helt 		data->valid = 1;
446add77c64SKrzysztof Helt 	}
447add77c64SKrzysztof Helt 
448add77c64SKrzysztof Helt 	mutex_unlock(&data->update_lock);
449add77c64SKrzysztof Helt 
450add77c64SKrzysztof Helt 	return data;
451add77c64SKrzysztof Helt }
452add77c64SKrzysztof Helt 
453add77c64SKrzysztof Helt static int __init sm_thmc50_init(void)
454add77c64SKrzysztof Helt {
455add77c64SKrzysztof Helt 	return i2c_add_driver(&thmc50_driver);
456add77c64SKrzysztof Helt }
457add77c64SKrzysztof Helt 
458add77c64SKrzysztof Helt static void __exit sm_thmc50_exit(void)
459add77c64SKrzysztof Helt {
460add77c64SKrzysztof Helt 	i2c_del_driver(&thmc50_driver);
461add77c64SKrzysztof Helt }
462add77c64SKrzysztof Helt 
463add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
464add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver");
465add77c64SKrzysztof Helt 
466add77c64SKrzysztof Helt module_init(sm_thmc50_init);
467add77c64SKrzysztof Helt module_exit(sm_thmc50_exit);
468