Blame view

drivers/hwmon/adm1021.c 14.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
      adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
3
  		monitoring
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
      Philip Edelbrock <phil@netroedge.com>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
26
  #include <linux/hwmon.h>
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
27
  #include <linux/hwmon-sysfs.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
28
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
29
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
  
  
  /* Addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
33
34
  static const unsigned short normal_i2c[] = {
  	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

e5e9f44c2   Jean Delvare   i2c: Drop I2C_CLI...
36
37
  enum chips {
  	adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
  
  /* adm1021 constants specified below */
  
  /* The adm1021 registers */
  /* Read-only */
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
43
44
  /* For nr in 0-1 */
  #define ADM1021_REG_TEMP(nr)		(nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #define ADM1021_REG_STATUS		0x02
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
46
47
48
49
  /* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
  #define ADM1021_REG_MAN_ID		0xFE
  /* ADM1021 = 0x0X, ADM1023 = 0x3X */
  #define ADM1021_REG_DEV_ID		0xFF
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
  /* These use different addresses for reading/writing */
  #define ADM1021_REG_CONFIG_R		0x03
  #define ADM1021_REG_CONFIG_W		0x09
  #define ADM1021_REG_CONV_RATE_R		0x04
  #define ADM1021_REG_CONV_RATE_W		0x0A
  /* These are for the ADM1023's additional precision on the remote temp sensor */
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
56
57
58
59
60
  #define ADM1023_REG_REM_TEMP_PREC	0x10
  #define ADM1023_REG_REM_OFFSET		0x11
  #define ADM1023_REG_REM_OFFSET_PREC	0x12
  #define ADM1023_REG_REM_TOS_PREC	0x13
  #define ADM1023_REG_REM_THYST_PREC	0x14
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  /* limits */
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
62
63
64
65
66
  /* For nr in 0-1 */
  #define ADM1021_REG_TOS_R(nr)		(0x05 + 2 * (nr))
  #define ADM1021_REG_TOS_W(nr)		(0x0B + 2 * (nr))
  #define ADM1021_REG_THYST_R(nr)		(0x06 + 2 * (nr))
  #define ADM1021_REG_THYST_W(nr)		(0x0C + 2 * (nr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  /* write-only */
  #define ADM1021_REG_ONESHOT		0x0F
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  /* Initial values */
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
70
71
72
  /* Note: Even though I left the low and high limits named os and hyst,
  they don't quite work like a thermostat the way the LM75 does.  I.e.,
  a lower temp than THYST actually triggers an alarm instead of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
  clearing it.  Weird, ey?   --Phil  */
  
  /* Each client has this additional data */
  struct adm1021_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
77
  	struct device *hwmon_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  	enum chips type;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
79
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  	char valid;		/* !=0 if following fields are valid */
905ffdc35   Michael Abbott   drivers/hwmon/adm...
81
  	char low_power;		/* !=0 if device in low power mode */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  	unsigned long last_updated;	/* In jiffies */
f26688951   Michael Abbott   drivers/hwmon/adm...
83
84
85
  	int temp_max[2];		/* Register values */
  	int temp_min[2];
  	int temp[2];
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
86
87
  	u8 alarms;
  	/* Special values for ADM1023 only */
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
88
89
  	u8 remote_temp_offset;
  	u8 remote_temp_offset_prec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  };
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
91
92
  static int adm1021_probe(struct i2c_client *client,
  			 const struct i2c_device_id *id);
310ec7921   Jean Delvare   i2c: Drop the kin...
93
  static int adm1021_detect(struct i2c_client *client,
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
94
  			  struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  static void adm1021_init_client(struct i2c_client *client);
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
96
  static int adm1021_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  static struct adm1021_data *adm1021_update_device(struct device *dev);
  
  /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
90ab5ee94   Rusty Russell   module_param: mak...
100
  static bool read_only;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

65817ed8d   Jean Delvare   hwmon: (adm1021) ...
102
103
104
105
106
107
108
109
110
111
112
113
  static const struct i2c_device_id adm1021_id[] = {
  	{ "adm1021", adm1021 },
  	{ "adm1023", adm1023 },
  	{ "max1617", max1617 },
  	{ "max1617a", max1617a },
  	{ "thmc10", thmc10 },
  	{ "lm84", lm84 },
  	{ "gl523sm", gl523sm },
  	{ "mc1066", mc1066 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, adm1021_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  /* This is the driver that will be inserted */
  static struct i2c_driver adm1021_driver = {
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
116
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
117
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
118
119
  		.name	= "adm1021",
  	},
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
120
121
122
123
  	.probe		= adm1021_probe,
  	.remove		= adm1021_remove,
  	.id_table	= adm1021_id,
  	.detect		= adm1021_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
124
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  };
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
126
127
128
129
130
  static ssize_t show_temp(struct device *dev,
  			 struct device_attribute *devattr, char *buf)
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct adm1021_data *data = adm1021_update_device(dev);
f26688951   Michael Abbott   drivers/hwmon/adm...
131
132
  	return sprintf(buf, "%d
  ", data->temp[index]);
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
133
134
135
136
137
138
139
  }
  
  static ssize_t show_temp_max(struct device *dev,
  			     struct device_attribute *devattr, char *buf)
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct adm1021_data *data = adm1021_update_device(dev);
f26688951   Michael Abbott   drivers/hwmon/adm...
140
141
  	return sprintf(buf, "%d
  ", data->temp_max[index]);
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
142
143
144
145
146
147
148
  }
  
  static ssize_t show_temp_min(struct device *dev,
  			     struct device_attribute *devattr, char *buf)
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct adm1021_data *data = adm1021_update_device(dev);
f26688951   Michael Abbott   drivers/hwmon/adm...
149
150
  	return sprintf(buf, "%d
  ", data->temp_min[index]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

739ba2486   Krzysztof Helt   hwmon: (adm1021) ...
153
154
155
156
157
158
159
160
  static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
  			  char *buf)
  {
  	int index = to_sensor_dev_attr(attr)->index;
  	struct adm1021_data *data = adm1021_update_device(dev);
  	return sprintf(buf, "%u
  ", (data->alarms >> index) & 1);
  }
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
161
162
163
164
165
166
167
  static ssize_t show_alarms(struct device *dev,
  			   struct device_attribute *attr,
  			   char *buf)
  {
  	struct adm1021_data *data = adm1021_update_device(dev);
  	return sprintf(buf, "%u
  ", data->alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  }
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
169

a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  static ssize_t set_temp_max(struct device *dev,
  			    struct device_attribute *devattr,
  			    const char *buf, size_t count)
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct i2c_client *client = to_i2c_client(dev);
  	struct adm1021_data *data = i2c_get_clientdata(client);
  	long temp = simple_strtol(buf, NULL, 10) / 1000;
  
  	mutex_lock(&data->update_lock);
  	data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
  	if (!read_only)
  		i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
  					  data->temp_max[index]);
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
  
  static ssize_t set_temp_min(struct device *dev,
  			    struct device_attribute *devattr,
  			    const char *buf, size_t count)
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct i2c_client *client = to_i2c_client(dev);
  	struct adm1021_data *data = i2c_get_clientdata(client);
  	long temp = simple_strtol(buf, NULL, 10) / 1000;
  
  	mutex_lock(&data->update_lock);
  	data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
  	if (!read_only)
  		i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
  					  data->temp_min[index]);
  	mutex_unlock(&data->update_lock);
  
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

905ffdc35   Michael Abbott   drivers/hwmon/adm...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  static ssize_t show_low_power(struct device *dev,
  			      struct device_attribute *devattr, char *buf)
  {
  	struct adm1021_data *data = adm1021_update_device(dev);
  	return sprintf(buf, "%d
  ", data->low_power);
  }
  
  static ssize_t set_low_power(struct device *dev,
  			     struct device_attribute *devattr,
  			     const char *buf, size_t count)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct adm1021_data *data = i2c_get_clientdata(client);
  	int low_power = simple_strtol(buf, NULL, 10) != 0;
  
  	mutex_lock(&data->update_lock);
  	if (low_power != data->low_power) {
  		int config = i2c_smbus_read_byte_data(
  			client, ADM1021_REG_CONFIG_R);
  		data->low_power = low_power;
  		i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
  			(config & 0xBF) | (low_power << 6));
  	}
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
236
237
238
239
240
241
242
243
244
245
  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
  			  set_temp_max, 0);
  static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
  			  set_temp_min, 0);
  static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
  static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
  			  set_temp_max, 1);
  static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
  			  set_temp_min, 1);
739ba2486   Krzysztof Helt   hwmon: (adm1021) ...
246
247
248
249
250
  static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
  static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
  static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
  static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
251
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
905ffdc35   Michael Abbott   drivers/hwmon/adm...
252
  static DEVICE_ATTR(low_power, S_IWUSR | S_IRUGO, show_low_power, set_low_power);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
254
  static struct attribute *adm1021_attributes[] = {
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
255
256
257
258
259
260
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_min.dev_attr.attr,
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_min.dev_attr.attr,
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
739ba2486   Krzysztof Helt   hwmon: (adm1021) ...
261
262
263
264
265
  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
266
  	&dev_attr_alarms.attr,
905ffdc35   Michael Abbott   drivers/hwmon/adm...
267
  	&dev_attr_low_power.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
268
269
270
271
272
273
  	NULL
  };
  
  static const struct attribute_group adm1021_group = {
  	.attrs = adm1021_attributes,
  };
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
274
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
275
  static int adm1021_detect(struct i2c_client *client,
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
276
  			  struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  {
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
278
  	struct i2c_adapter *adapter = client->adapter;
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
279
280
  	const char *type_name;
  	int conv_rate, status, config, man_id, dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281

c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
282
283
284
285
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  		pr_debug("adm1021: detect failed, "
  			 "smbus byte data not supported!
  ");
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
286
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288

c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
289
290
291
292
  	status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
  	conv_rate = i2c_smbus_read_byte_data(client,
  					     ADM1021_REG_CONV_RATE_R);
  	config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293

8007ea35e   Jean Delvare   hwmon: (adm1021) ...
294
295
296
297
298
  	/* Check unused bits */
  	if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
  		pr_debug("adm1021: detect failed, chip not detected!
  ");
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
  	}
  
  	/* Determine the chip type. */
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
302
303
  	man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
  	dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

8007ea35e   Jean Delvare   hwmon: (adm1021) ...
305
  	if (man_id == 0x4d && dev_id == 0x01)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  		type_name = "max1617a";
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
307
308
309
310
311
312
  	else if (man_id == 0x41) {
  		if ((dev_id & 0xF0) == 0x30)
  			type_name = "adm1023";
  		else
  			type_name = "adm1021";
  	} else if (man_id == 0x49)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  		type_name = "thmc10";
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
314
  	else if (man_id == 0x23)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  		type_name = "gl523sm";
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
316
  	else if (man_id == 0x54)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  		type_name = "mc1066";
8007ea35e   Jean Delvare   hwmon: (adm1021) ...
318
319
320
321
322
323
324
  	/* LM84 Mfr ID in a different place, and it has more unused bits */
  	else if (conv_rate == 0x00
  		 && (config & 0x7F) == 0x00
  		 && (status & 0xAB) == 0x00)
  		type_name = "lm84";
  	else
  		type_name = "max1617";
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
325
326
  	pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.
  ",
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
327
328
  		 type_name, i2c_adapter_id(adapter), client->addr);
  	strlcpy(info->type, type_name, I2C_NAME_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

65817ed8d   Jean Delvare   hwmon: (adm1021) ...
330
331
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

65817ed8d   Jean Delvare   hwmon: (adm1021) ...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  static int adm1021_probe(struct i2c_client *client,
  			 const struct i2c_device_id *id)
  {
  	struct adm1021_data *data;
  	int err;
  
  	data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL);
  	if (!data) {
  		pr_debug("adm1021: detect failed, kzalloc failed!
  ");
  		err = -ENOMEM;
  		goto error0;
  	}
  
  	i2c_set_clientdata(client, data);
  	data->type = id->driver_data;
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
  
  	/* Initialize the ADM1021 chip */
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
352
  	if (data->type != lm84 && !read_only)
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
353
  		adm1021_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
  
  	/* Register sysfs hooks */
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
356
  	if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
357
  		goto error1;
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
358

1beeffe43   Tony Jones   hwmon: Convert fr...
359
360
361
  	data->hwmon_dev = hwmon_device_register(&client->dev);
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
362
  		goto error3;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
363
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	return 0;
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
365
  error3:
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
366
  	sysfs_remove_group(&client->dev.kobj, &adm1021_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
  error1:
  	kfree(data);
  error0:
  	return err;
  }
  
  static void adm1021_init_client(struct i2c_client *client)
  {
  	/* Enable ADC and disable suspend mode */
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
376
377
  	i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
  		i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  	/* Set Conversion rate to 1/sec (this can be tinkered with) */
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
379
  	i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  }
65817ed8d   Jean Delvare   hwmon: (adm1021) ...
381
  static int adm1021_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
383
  	struct adm1021_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384

1beeffe43   Tony Jones   hwmon: Convert fr...
385
  	hwmon_device_unregister(data->hwmon_dev);
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
386
  	sysfs_remove_group(&client->dev.kobj, &adm1021_group);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
387

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
388
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
  static struct adm1021_data *adm1021_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct adm1021_data *data = i2c_get_clientdata(client);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
395
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
  
  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
  	    || !data->valid) {
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
399
  		int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  		dev_dbg(&client->dev, "Starting adm1021 update
  ");
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
402
  		for (i = 0; i < 2; i++) {
f26688951   Michael Abbott   drivers/hwmon/adm...
403
404
405
406
407
408
409
410
411
  			data->temp[i] = 1000 *
  				(s8) i2c_smbus_read_byte_data(
  					client, ADM1021_REG_TEMP(i));
  			data->temp_max[i] = 1000 *
  				(s8) i2c_smbus_read_byte_data(
  					client, ADM1021_REG_TOS_R(i));
  			data->temp_min[i] = 1000 *
  				(s8) i2c_smbus_read_byte_data(
  					client, ADM1021_REG_THYST_R(i));
a8d6646e2   Krzysztof Helt   hwmon: (adm1021) ...
412
  		}
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
413
414
  		data->alarms = i2c_smbus_read_byte_data(client,
  						ADM1021_REG_STATUS) & 0x7c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  		if (data->type == adm1023) {
f26688951   Michael Abbott   drivers/hwmon/adm...
416
417
418
419
420
421
422
423
  			/* The ADM1023 provides 3 extra bits of precision for
  			 * the remote sensor in extra registers. */
  			data->temp[1] += 125 * (i2c_smbus_read_byte_data(
  				client, ADM1023_REG_REM_TEMP_PREC) >> 5);
  			data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
  				client, ADM1023_REG_REM_TOS_PREC) >> 5);
  			data->temp_min[1] += 125 * (i2c_smbus_read_byte_data(
  				client, ADM1023_REG_REM_THYST_PREC) >> 5);
c83c41e4e   Krzysztof Helt   hwmon: adm1021 cl...
424
425
426
427
428
429
  			data->remote_temp_offset =
  				i2c_smbus_read_byte_data(client,
  						ADM1023_REG_REM_OFFSET);
  			data->remote_temp_offset_prec =
  				i2c_smbus_read_byte_data(client,
  						ADM1023_REG_REM_OFFSET_PREC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
  		}
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
434
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  
  	return data;
  }
  
  static int __init sensors_adm1021_init(void)
  {
  	return i2c_add_driver(&adm1021_driver);
  }
  
  static void __exit sensors_adm1021_exit(void)
  {
  	i2c_del_driver(&adm1021_driver);
  }
  
  MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl> and "
  		"Philip Edelbrock <phil@netroedge.com>");
  MODULE_DESCRIPTION("adm1021 driver");
  MODULE_LICENSE("GPL");
  
  module_param(read_only, bool, 0);
  MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
  
  module_init(sensors_adm1021_init)
  module_exit(sensors_adm1021_exit)