Blame view

drivers/hwmon/lm87.c 29.1 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
  /*
   * lm87.c
   *
   * Copyright (C) 2000       Frodo Looijaard <frodol@dds.nl>
   *                          Philip Edelbrock <phil@netroedge.com>
   *                          Stephen Rousset <stephen.rousset@rocketlogix.com>
   *                          Dan Eaton <dan.eaton@rocketlogix.com>
7c81c60f3   Jean Delvare   Update Jean Delva...
9
   * Copyright (C) 2004-2008  Jean Delvare <jdelvare@suse.de>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * Original port to Linux 2.6 by Jeff Oliver.
   *
   * The LM87 is a sensor chip made by National Semiconductor. It monitors up
   * to 8 voltages (including its own power source), up to three temperatures
   * (its own plus up to two external ones) and up to two fans. The default
   * configuration is 6 voltages, two temperatures and two fans (see below).
   * Voltages are scaled internally with ratios such that the nominal value of
   * each voltage correspond to a register value of 192 (which means a
   * resolution of about 0.5% of the nominal value). Temperature values are
   * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete
   * datasheet can be obtained from National's website at:
   *   http://www.national.com/pf/LM/LM87.html
   *
   * Some functions share pins, so not all functions are available at the same
47064d645   Ben Hutchings   hwmon: (lm87) Add...
25
26
27
28
   * time. Which are depends on the hardware setup. This driver normally
   * assumes that firmware configured the chip correctly. Where this is not
   * the case, platform code must set the I2C client's platform_data to point
   * to a u8 value to be written to the channel register.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
   * For reference, here is the list of exclusive functions:
   *  - in0+in5 (default) or temp3
   *  - fan1 (default) or in6
   *  - fan2 (default) or in7
   *  - VID lines (default) or IRQ lines (not handled by this driver)
   *
   * The LM87 additionally features an analog output, supposedly usable to
   * control the speed of a fan. All new chips use pulse width modulation
   * instead. The LM87 is the only hardware monitoring chipset I know of
   * which uses amplitude modulation. Be careful when using this feature.
   *
c7fa37379   Jean Delvare   hwmon: (lm87) Add...
40
41
42
   * This driver also supports the ADM1024, a sensor chip made by Analog
   * Devices. That chip is fully compatible with the LM87. Complete
   * datasheet can be obtained from Analog's website at:
ad736c1a4   Alexander A. Klimov   hwmon: Replace HT...
43
   *   https://www.analog.com/en/prod/0,2877,ADM1024,00.html
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
  #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...
50
  #include <linux/hwmon.h>
c2803b985   Jean Delvare   hwmon: (lm87) Add...
51
  #include <linux/hwmon-sysfs.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
52
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
53
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
54
  #include <linux/mutex.h>
67043d185   Mahoda Ratnayaka   hwmon: (lm87) All...
55
  #include <linux/regulator/consumer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
  
  /*
   * Addresses to scan
   * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e.
   */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
61
  static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  /*
   * The LM87 registers
   */
  
  /* nr in 0..5 */
  #define LM87_REG_IN(nr)			(0x20 + (nr))
  #define LM87_REG_IN_MAX(nr)		(0x2B + (nr) * 2)
  #define LM87_REG_IN_MIN(nr)		(0x2C + (nr) * 2)
  /* nr in 0..1 */
  #define LM87_REG_AIN(nr)		(0x28 + (nr))
  #define LM87_REG_AIN_MIN(nr)		(0x1A + (nr))
  #define LM87_REG_AIN_MAX(nr)		(0x3B + (nr))
  
  static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 };
  static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B };
  static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
  
  #define LM87_REG_TEMP_HW_INT_LOCK	0x13
  #define LM87_REG_TEMP_HW_EXT_LOCK	0x14
  #define LM87_REG_TEMP_HW_INT		0x17
  #define LM87_REG_TEMP_HW_EXT		0x18
  
  /* nr in 0..1 */
  #define LM87_REG_FAN(nr)		(0x28 + (nr))
  #define LM87_REG_FAN_MIN(nr)		(0x3B + (nr))
  #define LM87_REG_AOUT			0x19
  
  #define LM87_REG_CONFIG			0x40
  #define LM87_REG_CHANNEL_MODE		0x16
  #define LM87_REG_VID_FAN_DIV		0x47
  #define LM87_REG_VID4			0x49
  
  #define LM87_REG_ALARMS1		0x41
  #define LM87_REG_ALARMS2		0x42
  
  #define LM87_REG_COMPANY_ID		0x3E
  #define LM87_REG_REVISION		0x3F
  
  /*
   * Conversions and various macros
   * The LM87 uses signed 8-bit values for temperatures.
   */
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
105
106
  #define IN_FROM_REG(reg, scale)	(((reg) * (scale) + 96) / 192)
  #define IN_TO_REG(val, scale)	((val) <= 0 ? 0 : \
12fa55ccc   Guenter Roeck   hwmon: (lm87) Fix...
107
  				 (val) >= (scale) * 255 / 192 ? 255 : \
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
108
  				 ((val) * 192 + (scale) / 2) / (scale))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
  
  #define TEMP_FROM_REG(reg)	((reg) * 1000)
  #define TEMP_TO_REG(val)	((val) <= -127500 ? -128 : \
  				 (val) >= 126500 ? 127 : \
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
113
114
  				 (((val) < 0 ? (val) - 500 : \
  				   (val) + 500) / 1000))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
116
117
118
119
  #define FAN_FROM_REG(reg, div)	((reg) == 255 || (reg) == 0 ? 0 : \
  				 (1350000 + (reg)*(div) / 2) / ((reg) * (div)))
  #define FAN_TO_REG(val, div)	((val) * (div) * 255 <= 1350000 ? 255 : \
  				 (1350000 + (val)*(div) / 2) / ((val) * (div)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
127
128
129
130
131
132
  
  #define FAN_DIV_FROM_REG(reg)	(1 << (reg))
  
  /* analog out is 9.80mV/LSB */
  #define AOUT_FROM_REG(reg)	(((reg) * 98 + 5) / 10)
  #define AOUT_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 2500 ? 255 : \
  				 ((val) * 10 + 49) / 98)
  
  /* nr in 0..1 */
  #define CHAN_NO_FAN(nr)		(1 << (nr))
  #define CHAN_TEMP3		(1 << 2)
  #define CHAN_VCC_5V		(1 << 3)
889af3d5d   Jean Delvare   hwmon: (lm87) Dis...
133
  #define CHAN_NO_VID		(1 << 7)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
   * Client data (each client gets its own)
   */
  
  struct lm87_data {
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
140
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
  	char valid; /* zero until following fields are valid */
  	unsigned long last_updated; /* In jiffies */
  
  	u8 channel;		/* register value */
d2cac802f   Ben Hutchings   hwmon: (lm87) Res...
145
  	u8 config;		/* original register value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  
  	u8 in[8];		/* register value */
  	u8 in_max[8];		/* register value */
  	u8 in_min[8];		/* register value */
  	u16 in_scale[8];
  
  	s8 temp[3];		/* register value */
  	s8 temp_high[3];	/* register value */
  	s8 temp_low[3];		/* register value */
  	s8 temp_crit_int;	/* min of two register values */
  	s8 temp_crit_ext;	/* min of two register values */
  
  	u8 fan[2];		/* register value */
  	u8 fan_min[2];		/* register value */
  	u8 fan_div[2];		/* register value, shifted right */
  	u8 aout;		/* register value */
  
  	u16 alarms;		/* register values, combined */
  	u8 vid;			/* register values, combined */
  	u8 vrm;
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
166
167
  
  	const struct attribute_group *attr_groups[6];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
  static inline int lm87_read_value(struct i2c_client *client, u8 reg)
  {
  	return i2c_smbus_read_byte_data(client, reg);
  }
  
  static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
  {
  	return i2c_smbus_write_byte_data(client, reg, value);
  }
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
178
179
  static struct lm87_data *lm87_update_device(struct device *dev)
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
180
  	struct i2c_client *client = dev_get_drvdata(dev);
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
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
206
207
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	struct lm87_data *data = i2c_get_clientdata(client);
  
  	mutex_lock(&data->update_lock);
  
  	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
  		int i, j;
  
  		dev_dbg(&client->dev, "Updating data.
  ");
  
  		i = (data->channel & CHAN_TEMP3) ? 1 : 0;
  		j = (data->channel & CHAN_TEMP3) ? 5 : 6;
  		for (; i < j; i++) {
  			data->in[i] = lm87_read_value(client,
  				      LM87_REG_IN(i));
  			data->in_min[i] = lm87_read_value(client,
  					  LM87_REG_IN_MIN(i));
  			data->in_max[i] = lm87_read_value(client,
  					  LM87_REG_IN_MAX(i));
  		}
  
  		for (i = 0; i < 2; i++) {
  			if (data->channel & CHAN_NO_FAN(i)) {
  				data->in[6+i] = lm87_read_value(client,
  						LM87_REG_AIN(i));
  				data->in_max[6+i] = lm87_read_value(client,
  						    LM87_REG_AIN_MAX(i));
  				data->in_min[6+i] = lm87_read_value(client,
  						    LM87_REG_AIN_MIN(i));
  
  			} else {
  				data->fan[i] = lm87_read_value(client,
  					       LM87_REG_FAN(i));
  				data->fan_min[i] = lm87_read_value(client,
  						   LM87_REG_FAN_MIN(i));
  			}
  		}
  
  		j = (data->channel & CHAN_TEMP3) ? 3 : 2;
  		for (i = 0 ; i < j; i++) {
  			data->temp[i] = lm87_read_value(client,
  					LM87_REG_TEMP[i]);
  			data->temp_high[i] = lm87_read_value(client,
  					     LM87_REG_TEMP_HIGH[i]);
  			data->temp_low[i] = lm87_read_value(client,
  					    LM87_REG_TEMP_LOW[i]);
  		}
  
  		i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK);
  		j = lm87_read_value(client, LM87_REG_TEMP_HW_INT);
  		data->temp_crit_int = min(i, j);
  
  		i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK);
  		j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT);
  		data->temp_crit_ext = min(i, j);
  
  		i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
  		data->fan_div[0] = (i >> 4) & 0x03;
  		data->fan_div[1] = (i >> 6) & 0x03;
  		data->vid = (i & 0x0F)
  			  | (lm87_read_value(client, LM87_REG_VID4) & 0x01)
  			     << 4;
  
  		data->alarms = lm87_read_value(client, LM87_REG_ALARMS1)
  			     | (lm87_read_value(client, LM87_REG_ALARMS2)
  				<< 8);
  		data->aout = lm87_read_value(client, LM87_REG_AOUT);
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
  
  	mutex_unlock(&data->update_lock);
  
  	return data;
  }
  
  /*
   * Sysfs stuff
   */
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
261
262
  static ssize_t in_input_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
263
264
265
266
267
268
269
270
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%u
  ", IN_FROM_REG(data->in[nr],
  		       data->in_scale[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
271
272
  static ssize_t in_min_show(struct device *dev, struct device_attribute *attr,
  			   char *buf)
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
273
274
275
276
277
278
279
280
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%u
  ", IN_FROM_REG(data->in_min[nr],
  		       data->in_scale[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
281
282
  static ssize_t in_max_show(struct device *dev, struct device_attribute *attr,
  			   char *buf)
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
283
284
285
286
287
288
289
290
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%u
  ", IN_FROM_REG(data->in_max[nr],
  		       data->in_scale[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
291
292
  static ssize_t in_min_store(struct device *dev, struct device_attribute *attr,
  			    const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
294
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
296
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
297
298
299
300
301
302
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
304
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  	data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
306
307
  	lm87_write_value(client, nr < 6 ? LM87_REG_IN_MIN(nr) :
  			 LM87_REG_AIN_MIN(nr - 6), data->in_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
308
  	mutex_unlock(&data->update_lock);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
309
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
311
312
  static ssize_t in_max_store(struct device *dev, struct device_attribute *attr,
  			    const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
314
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
316
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
317
318
319
320
321
322
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
324
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
326
327
  	lm87_write_value(client, nr < 6 ? LM87_REG_IN_MAX(nr) :
  			 LM87_REG_AIN_MAX(nr - 6), data->in_max[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
328
  	mutex_unlock(&data->update_lock);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
329
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  static SENSOR_DEVICE_ATTR_RO(in0_input, in_input, 0);
  static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
  static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
  static SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 1);
  static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
  static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
  static SENSOR_DEVICE_ATTR_RO(in2_input, in_input, 2);
  static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
  static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
  static SENSOR_DEVICE_ATTR_RO(in3_input, in_input, 3);
  static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
  static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
  static SENSOR_DEVICE_ATTR_RO(in4_input, in_input, 4);
  static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
  static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
  static SENSOR_DEVICE_ATTR_RO(in5_input, in_input, 5);
  static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5);
  static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5);
  static SENSOR_DEVICE_ATTR_RO(in6_input, in_input, 6);
  static SENSOR_DEVICE_ATTR_RW(in6_min, in_min, 6);
  static SENSOR_DEVICE_ATTR_RW(in6_max, in_max, 6);
  static SENSOR_DEVICE_ATTR_RO(in7_input, in_input, 7);
  static SENSOR_DEVICE_ATTR_RW(in7_min, in_min, 7);
  static SENSOR_DEVICE_ATTR_RW(in7_max, in_max, 7);
  
  static ssize_t temp_input_show(struct device *dev,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
357
358
359
360
361
362
363
364
  			       struct device_attribute *attr, char *buf)
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
365
  static ssize_t temp_low_show(struct device *dev,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
366
367
368
369
370
371
372
373
374
  			     struct device_attribute *attr, char *buf)
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ",
  		       TEMP_FROM_REG(data->temp_low[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
375
  static ssize_t temp_high_show(struct device *dev,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
376
377
378
379
380
381
382
383
384
  			      struct device_attribute *attr, char *buf)
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ",
  		       TEMP_FROM_REG(data->temp_high[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
385
386
387
  static ssize_t temp_low_store(struct device *dev,
  			      struct device_attribute *attr, const char *buf,
  			      size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
389
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
391
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
392
393
394
395
396
397
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
399
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  	data->temp_low[nr] = TEMP_TO_REG(val);
  	lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
402
  	mutex_unlock(&data->update_lock);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
403
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
405
406
407
  static ssize_t temp_high_store(struct device *dev,
  			       struct device_attribute *attr, const char *buf,
  			       size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
409
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
411
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
412
413
414
415
416
417
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
419
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	data->temp_high[nr] = TEMP_TO_REG(val);
  	lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
422
  	mutex_unlock(&data->update_lock);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
423
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
425
426
427
428
429
430
431
432
433
  static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
  static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_low, 0);
  static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_high, 0);
  static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_input, 1);
  static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_low, 1);
  static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_high, 1);
  static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_input, 2);
  static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_low, 2);
  static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_high, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434

07a366cc5   Julia Lawall   hwmon: (lm87) use...
435
436
  static ssize_t temp1_crit_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_crit_int));
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
442
443
  static ssize_t temp2_crit_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_crit_ext));
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
449
450
  static DEVICE_ATTR_RO(temp1_crit);
  static DEVICE_ATTR_RO(temp2_crit);
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
451
  static DEVICE_ATTR(temp3_crit, 0444, temp2_crit_show, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452

f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
453
  static ssize_t fan_input_show(struct device *dev,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
454
455
456
457
458
459
460
461
462
  			      struct device_attribute *attr, char *buf)
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[nr],
  		       FAN_DIV_FROM_REG(data->fan_div[nr])));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
463
464
  static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
  			    char *buf)
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
465
466
467
468
469
470
471
472
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan_min[nr],
  		       FAN_DIV_FROM_REG(data->fan_div[nr])));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
473
474
  static ssize_t fan_div_show(struct device *dev, struct device_attribute *attr,
  			    char *buf)
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
475
476
477
478
479
480
481
482
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int nr = to_sensor_dev_attr(attr)->index;
  
  	return sprintf(buf, "%d
  ",
  		       FAN_DIV_FROM_REG(data->fan_div[nr]));
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
483
484
485
  static ssize_t fan_min_store(struct device *dev,
  			     struct device_attribute *attr, const char *buf,
  			     size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
487
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
489
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
490
491
492
493
494
495
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
497
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
  	data->fan_min[nr] = FAN_TO_REG(val,
  			    FAN_DIV_FROM_REG(data->fan_div[nr]));
  	lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
501
  	mutex_unlock(&data->update_lock);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
502
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  }
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
504
505
506
507
508
509
  /*
   * Note: we save and restore the fan minimum here, because its value is
   * determined in part by the fan clock divider.  This follows the principle
   * of least surprise; the user doesn't expect the fan minimum to change just
   * because the divider changed.
   */
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
510
511
512
  static ssize_t fan_div_store(struct device *dev,
  			     struct device_attribute *attr, const char *buf,
  			     size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
514
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	struct lm87_data *data = i2c_get_clientdata(client);
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
516
  	int nr = to_sensor_dev_attr(attr)->index;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
517
518
  	long val;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  	unsigned long min;
  	u8 reg;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
521
522
523
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
524
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
  	min = FAN_FROM_REG(data->fan_min[nr],
  			   FAN_DIV_FROM_REG(data->fan_div[nr]));
  
  	switch (val) {
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
529
530
531
532
533
534
535
536
537
538
539
540
  	case 1:
  		data->fan_div[nr] = 0;
  		break;
  	case 2:
  		data->fan_div[nr] = 1;
  		break;
  	case 4:
  		data->fan_div[nr] = 2;
  		break;
  	case 8:
  		data->fan_div[nr] = 3;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	default:
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
542
  		mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  		return -EINVAL;
  	}
  
  	reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
  	switch (nr) {
  	case 0:
  	    reg = (reg & 0xCF) | (data->fan_div[0] << 4);
  	    break;
  	case 1:
  	    reg = (reg & 0x3F) | (data->fan_div[1] << 6);
  	    break;
  	}
  	lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg);
  
  	data->fan_min[nr] = FAN_TO_REG(min, val);
  	lm87_write_value(client, LM87_REG_FAN_MIN(nr),
  			 data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
560
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
  
  	return count;
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
564
565
566
567
568
569
  static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0);
  static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
  static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
  static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1);
  static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
  static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

07a366cc5   Julia Lawall   hwmon: (lm87) use...
571
  static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
572
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
577
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	return sprintf(buf, "%d
  ", data->alarms);
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
578
  static DEVICE_ATTR_RO(alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

07a366cc5   Julia Lawall   hwmon: (lm87) use...
580
581
  static ssize_t cpu0_vid_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	return sprintf(buf, "%d
  ", vid_from_reg(data->vid, data->vrm));
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
587
  static DEVICE_ATTR_RO(cpu0_vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588

07a366cc5   Julia Lawall   hwmon: (lm87) use...
589
  static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
590
  			char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  {
90d6619a9   Jean Delvare   hwmon: VRM is not...
592
  	struct lm87_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  	return sprintf(buf, "%d
  ", data->vrm);
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
596
597
  static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
  			 const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  {
8f74efe81   Jean Delvare   hwmon: VRM is not...
599
  	struct lm87_data *data = dev_get_drvdata(dev);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
600
601
602
603
604
605
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
fa642d9d6   Axel Lin   hwmon: (lm87) Fix...
606
607
608
  
  	if (val > 255)
  		return -EINVAL;
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
609
  	data->vrm = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
  	return count;
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
612
  static DEVICE_ATTR_RW(vrm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613

07a366cc5   Julia Lawall   hwmon: (lm87) use...
614
615
  static ssize_t aout_output_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
620
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	return sprintf(buf, "%d
  ", AOUT_FROM_REG(data->aout));
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
621
622
623
  static ssize_t aout_output_store(struct device *dev,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
625
  	struct i2c_client *client = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  	struct lm87_data *data = i2c_get_clientdata(client);
c6370dbe4   Guenter Roeck   hwmon: (lm87) Fix...
627
628
629
630
631
632
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
634
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
  	data->aout = AOUT_TO_REG(val);
  	lm87_write_value(client, LM87_REG_AOUT, data->aout);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
637
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
  	return count;
  }
07a366cc5   Julia Lawall   hwmon: (lm87) use...
640
  static DEVICE_ATTR_RW(aout_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641

f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
642
  static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
643
644
645
646
647
648
649
  			  char *buf)
  {
  	struct lm87_data *data = lm87_update_device(dev);
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	return sprintf(buf, "%u
  ", (data->alarms >> bitnr) & 1);
  }
f6c93aeb0   Guenter Roeck   hwmon: (lm87) Use...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
  static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
  static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
  static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
  static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
  static SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 9);
  static SENSOR_DEVICE_ATTR_RO(in6_alarm, alarm, 6);
  static SENSOR_DEVICE_ATTR_RO(in7_alarm, alarm, 7);
  static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
  static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5);
  static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 5);
  static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
  static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
  static SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 14);
  static SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 15);
c2803b985   Jean Delvare   hwmon: (lm87) Add...
665

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
668
  /*
   * Real code
   */
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
669
  static struct attribute *lm87_attributes[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
670
671
672
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
673
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
674
675
676
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
677
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
678
679
680
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
681
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
682
683
684
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
685
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
686

0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
687
688
689
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_min.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
690
  	&dev_attr_temp1_crit.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
691
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
692
693
694
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_min.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
695
  	&dev_attr_temp2_crit.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
696
697
  	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
698
699
700
701
702
703
704
705
706
707
  
  	&dev_attr_alarms.attr,
  	&dev_attr_aout_output.attr,
  
  	NULL
  };
  
  static const struct attribute_group lm87_group = {
  	.attrs = lm87_attributes,
  };
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
708
  static struct attribute *lm87_attributes_in6[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
709
710
711
  	&sensor_dev_attr_in6_input.dev_attr.attr,
  	&sensor_dev_attr_in6_min.dev_attr.attr,
  	&sensor_dev_attr_in6_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
712
  	&sensor_dev_attr_in6_alarm.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
713
714
715
716
717
718
  	NULL
  };
  
  static const struct attribute_group lm87_group_in6 = {
  	.attrs = lm87_attributes_in6,
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
719

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
720
  static struct attribute *lm87_attributes_fan1[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
721
722
723
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
724
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
725
726
727
728
729
730
  	NULL
  };
  
  static const struct attribute_group lm87_group_fan1 = {
  	.attrs = lm87_attributes_fan1,
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
731

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
732
  static struct attribute *lm87_attributes_in7[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
733
734
735
  	&sensor_dev_attr_in7_input.dev_attr.attr,
  	&sensor_dev_attr_in7_min.dev_attr.attr,
  	&sensor_dev_attr_in7_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
736
  	&sensor_dev_attr_in7_alarm.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
737
738
  	NULL
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
739

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
740
741
742
743
744
  static const struct attribute_group lm87_group_in7 = {
  	.attrs = lm87_attributes_in7,
  };
  
  static struct attribute *lm87_attributes_fan2[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
745
746
747
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
748
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
749
750
  	NULL
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
751

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
752
753
754
755
756
  static const struct attribute_group lm87_group_fan2 = {
  	.attrs = lm87_attributes_fan2,
  };
  
  static struct attribute *lm87_attributes_temp3[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
757
758
759
  	&sensor_dev_attr_temp3_input.dev_attr.attr,
  	&sensor_dev_attr_temp3_max.dev_attr.attr,
  	&sensor_dev_attr_temp3_min.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
760
  	&dev_attr_temp3_crit.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
761
762
  	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp3_fault.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
763
764
  	NULL
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
765

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
766
767
768
769
770
  static const struct attribute_group lm87_group_temp3 = {
  	.attrs = lm87_attributes_temp3,
  };
  
  static struct attribute *lm87_attributes_in0_5[] = {
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
771
772
773
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
774
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
0e190b7fa   Jean Delvare   hwmon: (lm87) Get...
775
776
777
  	&sensor_dev_attr_in5_input.dev_attr.attr,
  	&sensor_dev_attr_in5_min.dev_attr.attr,
  	&sensor_dev_attr_in5_max.dev_attr.attr,
c2803b985   Jean Delvare   hwmon: (lm87) Add...
778
  	&sensor_dev_attr_in5_alarm.dev_attr.attr,
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
779
780
781
782
783
784
  	NULL
  };
  
  static const struct attribute_group lm87_group_in0_5 = {
  	.attrs = lm87_attributes_in0_5,
  };
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
785

073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
786
  static struct attribute *lm87_attributes_vid[] = {
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
787
788
  	&dev_attr_cpu0_vid.attr,
  	&dev_attr_vrm.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
789
790
  	NULL
  };
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
791
792
  static const struct attribute_group lm87_group_vid = {
  	.attrs = lm87_attributes_vid,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
793
  };
a888420af   Jean Delvare   hwmon: (lm87) Con...
794
  /* Return 0 if detection is successful, -ENODEV otherwise */
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
795
  static int lm87_detect(struct i2c_client *client, struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  {
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
797
  	struct i2c_adapter *adapter = client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
798
799
  	const char *name;
  	u8 cid, rev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
a888420af   Jean Delvare   hwmon: (lm87) Con...
802
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803

8652a2642   Jean Delvare   hwmon: (lm87) Reo...
804
  	if (lm87_read_value(client, LM87_REG_CONFIG) & 0x80)
52df6440a   Jean Delvare   hwmon: Clean up d...
805
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
  
  	/* Now, we do the remaining detection. */
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
808
809
  	cid = lm87_read_value(client, LM87_REG_COMPANY_ID);
  	rev = lm87_read_value(client, LM87_REG_REVISION);
52df6440a   Jean Delvare   hwmon: Clean up d...
810
811
812
813
814
815
816
817
818
819
  
  	if (cid == 0x02			/* National Semiconductor */
  	 && (rev >= 0x01 && rev <= 0x08))
  		name = "lm87";
  	else if (cid == 0x41		/* Analog Devices */
  	      && (rev & 0xf0) == 0x10)
  		name = "adm1024";
  	else {
  		dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x
  ",
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
820
  			client->addr);
52df6440a   Jean Delvare   hwmon: Clean up d...
821
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
823
  	strlcpy(info->type, name, I2C_NAME_SIZE);
a888420af   Jean Delvare   hwmon: (lm87) Con...
824
825
826
  
  	return 0;
  }
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
827
  static void lm87_restore_config(void *arg)
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
828
  {
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
829
830
831
832
  	struct i2c_client *client = arg;
  	struct lm87_data *data = i2c_get_clientdata(client);
  
  	lm87_write_value(client, LM87_REG_CONFIG, data->config);
073f1e6c8   Guenter Roeck   hwmon: (lm87) Fix...
833
  }
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
834
  static int lm87_init_client(struct i2c_client *client)
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
835
836
  {
  	struct lm87_data *data = i2c_get_clientdata(client);
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
837
  	int rc;
67043d185   Mahoda Ratnayaka   hwmon: (lm87) All...
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  	struct device_node *of_node = client->dev.of_node;
  	u8 val = 0;
  	struct regulator *vcc = NULL;
  
  	if (of_node) {
  		if (of_property_read_bool(of_node, "has-temp3"))
  			val |= CHAN_TEMP3;
  		if (of_property_read_bool(of_node, "has-in6"))
  			val |= CHAN_NO_FAN(0);
  		if (of_property_read_bool(of_node, "has-in7"))
  			val |= CHAN_NO_FAN(1);
  		vcc = devm_regulator_get_optional(&client->dev, "vcc");
  		if (!IS_ERR(vcc)) {
  			if (regulator_get_voltage(vcc) == 5000000)
  				val |= CHAN_VCC_5V;
  		}
  		data->channel = val;
  		lm87_write_value(client,
  				LM87_REG_CHANNEL_MODE, data->channel);
  	} else if (dev_get_platdata(&client->dev)) {
a8b3a3a53   Jingoo Han   hwmon: use dev_ge...
858
  		data->channel = *(u8 *)dev_get_platdata(&client->dev);
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
859
860
861
862
863
864
  		lm87_write_value(client,
  				 LM87_REG_CHANNEL_MODE, data->channel);
  	} else {
  		data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
  	}
  	data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F;
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
865
866
867
  	rc = devm_add_action(&client->dev, lm87_restore_config, client);
  	if (rc)
  		return rc;
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  	if (!(data->config & 0x01)) {
  		int i;
  
  		/* Limits are left uninitialized after power-up */
  		for (i = 1; i < 6; i++) {
  			lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00);
  			lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF);
  		}
  		for (i = 0; i < 2; i++) {
  			lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F);
  			lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00);
  			lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00);
  			lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF);
  		}
  		if (data->channel & CHAN_TEMP3) {
  			lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F);
  			lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00);
  		} else {
  			lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00);
  			lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF);
  		}
  	}
  
  	/* Make sure Start is set and INT#_Clear is clear */
  	if ((data->config & 0x09) != 0x01)
  		lm87_write_value(client, LM87_REG_CONFIG,
  				 (data->config & 0x77) | 0x01);
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
895
  	return 0;
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
896
  }
673afe466   Stephen Kitt   hwmon: use simple...
897
  static int lm87_probe(struct i2c_client *client)
a888420af   Jean Delvare   hwmon: (lm87) Con...
898
899
  {
  	struct lm87_data *data;
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
900
  	struct device *hwmon_dev;
a888420af   Jean Delvare   hwmon: (lm87) Con...
901
  	int err;
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
902
  	unsigned int group_tail = 0;
a888420af   Jean Delvare   hwmon: (lm87) Con...
903

5ff512b45   Guenter Roeck   hwmon: (lm87) Con...
904
905
906
  	data = devm_kzalloc(&client->dev, sizeof(struct lm87_data), GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
a888420af   Jean Delvare   hwmon: (lm87) Con...
907

8652a2642   Jean Delvare   hwmon: (lm87) Reo...
908
  	i2c_set_clientdata(client, data);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
909
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	/* Initialize the LM87 chip */
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
912
913
914
  	err = lm87_init_client(client);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
917
918
919
920
921
922
923
  
  	data->in_scale[0] = 2500;
  	data->in_scale[1] = 2700;
  	data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300;
  	data->in_scale[3] = 5000;
  	data->in_scale[4] = 12000;
  	data->in_scale[5] = 2700;
  	data->in_scale[6] = 1875;
  	data->in_scale[7] = 1875;
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  	/*
  	 * Construct the list of attributes, the list depends on the
  	 * configuration of the chip
  	 */
  	data->attr_groups[group_tail++] = &lm87_group;
  	if (data->channel & CHAN_NO_FAN(0))
  		data->attr_groups[group_tail++] = &lm87_group_in6;
  	else
  		data->attr_groups[group_tail++] = &lm87_group_fan1;
  
  	if (data->channel & CHAN_NO_FAN(1))
  		data->attr_groups[group_tail++] = &lm87_group_in7;
  	else
  		data->attr_groups[group_tail++] = &lm87_group_fan2;
  
  	if (data->channel & CHAN_TEMP3)
  		data->attr_groups[group_tail++] = &lm87_group_temp3;
  	else
  		data->attr_groups[group_tail++] = &lm87_group_in0_5;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
  
  	if (!(data->channel & CHAN_NO_VID)) {
8a665a055   Jean Delvare   hwmon: Only call ...
945
  		data->vrm = vid_which_vrm();
00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
946
  		data->attr_groups[group_tail++] = &lm87_group_vid;
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
947
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948

00a0c905a   Jason Gunthorpe   hwmon: (lm87) Use...
949
950
951
  	hwmon_dev = devm_hwmon_device_register_with_groups(
  	    &client->dev, client->name, client, data->attr_groups);
  	return PTR_ERR_OR_ZERO(hwmon_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  }
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
953
954
955
  /*
   * Driver data (common to all clients)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956

8652a2642   Jean Delvare   hwmon: (lm87) Reo...
957
  static const struct i2c_device_id lm87_id[] = {
0439bf71c   Javier Martinez Canillas   hwmon: (lm87) Rem...
958
959
  	{ "lm87", 0 },
  	{ "adm1024", 0 },
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
960
961
962
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, lm87_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963

a02c24a32   Javier Martinez Canillas   hwmon: (lm87) Add...
964
965
966
967
968
969
  static const struct of_device_id lm87_of_match[] = {
  	{ .compatible = "ti,lm87" },
  	{ .compatible = "adi,adm1024" },
  	{ },
  };
  MODULE_DEVICE_TABLE(of, lm87_of_match);
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
970
971
972
973
  static struct i2c_driver lm87_driver = {
  	.class		= I2C_CLASS_HWMON,
  	.driver = {
  		.name	= "lm87",
a02c24a32   Javier Martinez Canillas   hwmon: (lm87) Add...
974
  		.of_match_table = lm87_of_match,
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
975
  	},
673afe466   Stephen Kitt   hwmon: use simple...
976
  	.probe_new	= lm87_probe,
8652a2642   Jean Delvare   hwmon: (lm87) Reo...
977
978
979
980
  	.id_table	= lm87_id,
  	.detect		= lm87_detect,
  	.address_list	= normal_i2c,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981

f0967eea8   Axel Lin   hwmon: convert dr...
982
  module_i2c_driver(lm87_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983

7c81c60f3   Jean Delvare   Update Jean Delva...
984
  MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de> and others");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
  MODULE_DESCRIPTION("LM87 driver");
  MODULE_LICENSE("GPL");