Blame view

drivers/hwmon/adm9240.c 23.8 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
40b5cda28   Grant Coady   [PATCH] I2C: add ...
2
3
  /*
   * adm9240.c	Part of lm_sensors, Linux kernel modules for hardware
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
4
   *		monitoring
40b5cda28   Grant Coady   [PATCH] I2C: add ...
5
6
7
8
   *
   * Copyright (C) 1999	Frodo Looijaard <frodol@dds.nl>
   *			Philip Edelbrock <phil@netroedge.com>
   * Copyright (C) 2003	Michiel Rook <michiel@grendelproject.nl>
2ca7b961c   Grant Coady   adm9240: Update G...
9
   * Copyright (C) 2005	Grant Coady <gcoady.lk@gmail.com> with valuable
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
10
   *				guidance from Jean Delvare
40b5cda28   Grant Coady   [PATCH] I2C: add ...
11
12
13
14
15
16
17
18
19
20
21
22
23
   *
   * Driver supports	Analog Devices		ADM9240
   *			Dallas Semiconductor	DS1780
   *			National Semiconductor	LM81
   *
   * ADM9240 is the reference, DS1780 and LM81 are register compatibles
   *
   * Voltage	Six inputs are scaled by chip, VID also reported
   * Temperature	Chip temperature to 0.5'C, maximum and max_hysteris
   * Fans		2 fans, low speed alarm, automatic fan clock divider
   * Alarms	16-bit map of active alarms
   * Analog Out	0..1250 mV output
   *
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
24
   * Chassis Intrusion: clear CI latch with 'echo 0 > intrusion0_alarm'
40b5cda28   Grant Coady   [PATCH] I2C: add ...
25
26
27
28
   *
   * Test hardware: Intel SE440BX-2 desktop motherboard --Grant
   *
   * LM81 extended temp reading not implemented
40b5cda28   Grant Coady   [PATCH] I2C: add ...
29
30
31
32
33
34
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/i2c.h>
c7461a665   Grant Coady   [PATCH] hwmon: ad...
35
  #include <linux/hwmon-sysfs.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
36
  #include <linux/hwmon.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
37
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
38
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
39
  #include <linux/mutex.h>
dcd8f3923   Jean Delvare   hwmon: Add missin...
40
  #include <linux/jiffies.h>
df885d912   Chris Packham   hwmon: (adm9240) ...
41
  #include <linux/regmap.h>
40b5cda28   Grant Coady   [PATCH] I2C: add ...
42
43
  
  /* Addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
44
  static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
40b5cda28   Grant Coady   [PATCH] I2C: add ...
45
  					I2C_CLIENT_END };
e5e9f44c2   Jean Delvare   i2c: Drop I2C_CLI...
46
  enum chips { adm9240, ds1780, lm81 };
40b5cda28   Grant Coady   [PATCH] I2C: add ...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  
  /* ADM9240 registers */
  #define ADM9240_REG_MAN_ID		0x3e
  #define ADM9240_REG_DIE_REV		0x3f
  #define ADM9240_REG_CONFIG		0x40
  
  #define ADM9240_REG_IN(nr)		(0x20 + (nr))   /* 0..5 */
  #define ADM9240_REG_IN_MAX(nr)		(0x2b + (nr) * 2)
  #define ADM9240_REG_IN_MIN(nr)		(0x2c + (nr) * 2)
  #define ADM9240_REG_FAN(nr)		(0x28 + (nr))   /* 0..1 */
  #define ADM9240_REG_FAN_MIN(nr)		(0x3b + (nr))
  #define ADM9240_REG_INT(nr)		(0x41 + (nr))
  #define ADM9240_REG_INT_MASK(nr)	(0x43 + (nr))
  #define ADM9240_REG_TEMP		0x27
c7461a665   Grant Coady   [PATCH] hwmon: ad...
61
  #define ADM9240_REG_TEMP_MAX(nr)	(0x39 + (nr)) /* 0, 1 = high, hyst */
40b5cda28   Grant Coady   [PATCH] I2C: add ...
62
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
  #define ADM9240_REG_ANALOG_OUT		0x19
  #define ADM9240_REG_CHASSIS_CLEAR	0x46
  #define ADM9240_REG_VID_FAN_DIV		0x47
  #define ADM9240_REG_I2C_ADDR		0x48
  #define ADM9240_REG_VID4		0x49
  #define ADM9240_REG_TEMP_CONF		0x4b
  
  /* generalised scaling with integer rounding */
  static inline int SCALE(long val, int mul, int div)
  {
  	if (val < 0)
  		return (val * mul - div / 2) / div;
  	else
  		return (val * mul + div / 2) / div;
  }
  
  /* adm9240 internally scales voltage measurements */
  static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
  
  static inline unsigned int IN_FROM_REG(u8 reg, int n)
  {
  	return SCALE(reg, nom_mv[n], 192);
  }
  
  static inline u8 IN_TO_REG(unsigned long val, int n)
  {
0fb620c43   Guenter Roeck   hwmon: (adm9240) ...
88
89
  	val = clamp_val(val, 0, nom_mv[n] * 255 / 192);
  	return SCALE(val, 192, nom_mv[n]);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
90
91
92
93
94
  }
  
  /* temperature range: -40..125, 127 disables temperature alarm */
  static inline s8 TEMP_TO_REG(long val)
  {
0fb620c43   Guenter Roeck   hwmon: (adm9240) ...
95
96
  	val = clamp_val(val, -40000, 127000);
  	return SCALE(val, 1, 1000);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  }
  
  /* two fans, each with low fan speed limit */
  static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
  {
  	if (!reg) /* error */
  		return -1;
  
  	if (reg == 255)
  		return 0;
  
  	return SCALE(1350000, 1, reg * div);
  }
  
  /* analog out 0..1250mV */
  static inline u8 AOUT_TO_REG(unsigned long val)
  {
0fb620c43   Guenter Roeck   hwmon: (adm9240) ...
114
115
  	val = clamp_val(val, 0, 1250);
  	return SCALE(val, 255, 1250);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
116
117
118
119
120
121
  }
  
  static inline unsigned int AOUT_FROM_REG(u8 reg)
  {
  	return SCALE(reg, 1250, 255);
  }
40b5cda28   Grant Coady   [PATCH] I2C: add ...
122
123
  /* per client data */
  struct adm9240_data {
715f69bef   Axel Lin   hwmon: (adm9240) ...
124
  	struct i2c_client *client;
df885d912   Chris Packham   hwmon: (adm9240) ...
125
  	struct regmap *regmap;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
126
  	struct mutex update_lock;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
127
128
129
130
131
132
133
134
135
136
137
  	char valid;
  	unsigned long last_updated_measure;
  	unsigned long last_updated_config;
  
  	u8 in[6];		/* ro	in0_input */
  	u8 in_max[6];		/* rw	in0_max */
  	u8 in_min[6];		/* rw	in0_min */
  	u8 fan[2];		/* ro	fan1_input */
  	u8 fan_min[2];		/* rw	fan1_min */
  	u8 fan_div[2];		/* rw	fan1_div, read-only accessor */
  	s16 temp;		/* ro	temp1_input, 9-bit sign-extended */
c7461a665   Grant Coady   [PATCH] hwmon: ad...
138
  	s8 temp_max[2];		/* rw	0 -> temp_max, 1 -> temp_max_hyst */
40b5cda28   Grant Coady   [PATCH] I2C: add ...
139
  	u16 alarms;		/* ro	alarms */
8e8f9289c   Grant Coady   [PATCH] I2C: adm9...
140
  	u8 aout;		/* rw	aout_output */
40b5cda28   Grant Coady   [PATCH] I2C: add ...
141
142
143
  	u8 vid;			/* ro	vid */
  	u8 vrm;			/* --	vrm set on startup, no accessor */
  };
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
144
  /* write new fan div, callers must hold data->update_lock */
df885d912   Chris Packham   hwmon: (adm9240) ...
145
  static int adm9240_write_fan_div(struct adm9240_data *data, int nr,
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
146
147
  		u8 fan_div)
  {
df885d912   Chris Packham   hwmon: (adm9240) ...
148
149
  	unsigned int reg, old, shift = (nr + 2) * 2;
  	int err;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
150

df885d912   Chris Packham   hwmon: (adm9240) ...
151
152
153
  	err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &reg);
  	if (err < 0)
  		return err;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
154
155
156
  	old = (reg >> shift) & 3;
  	reg &= ~(3 << shift);
  	reg |= (fan_div << shift);
df885d912   Chris Packham   hwmon: (adm9240) ...
157
158
159
160
  	err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg);
  	if (err < 0)
  		return err;
  	dev_dbg(&data->client->dev,
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
161
162
163
  		"fan%d clock divider changed from %u to %u
  ",
  		nr + 1, 1 << old, 1 << fan_div);
df885d912   Chris Packham   hwmon: (adm9240) ...
164
165
  
  	return 0;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
166
  }
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
167
168
  static int adm9240_update_measure(struct adm9240_data *data)
  {
df885d912   Chris Packham   hwmon: (adm9240) ...
169
170
171
  	unsigned int val;
  	u8 regs[2];
  	int err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
172
  	int i;
df885d912   Chris Packham   hwmon: (adm9240) ...
173
174
175
176
177
178
179
180
  	err = regmap_bulk_read(data->regmap, ADM9240_REG_IN(0), &data->in[0], 6);
  	if (err < 0)
  		return err;
  	err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), &regs, 2);
  	if (err < 0)
  		return err;
  
  	data->alarms = regs[0] | regs[1] << 8;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
181
182
183
184
185
186
  
  	/*
  	 * read temperature: assume temperature changes less than
  	 * 0.5'C per two measurement cycles thus ignore possible
  	 * but unlikely aliasing error on lsb reading. --Grant
  	 */
df885d912   Chris Packham   hwmon: (adm9240) ...
187
188
189
190
191
192
193
194
  	err = regmap_read(data->regmap, ADM9240_REG_TEMP, &val);
  	if (err < 0)
  		return err;
  	data->temp = val << 8;
  	err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &val);
  	if (err < 0)
  		return err;
  	data->temp |= val;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
195

df885d912   Chris Packham   hwmon: (adm9240) ...
196
197
198
199
  	err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN(0),
  			       &data->fan[0], 2);
  	if (err < 0)
  		return err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
200

df885d912   Chris Packham   hwmon: (adm9240) ...
201
  	for (i = 0; i < 2; i++) { /* read fans */
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
202
203
204
  		/* adjust fan clock divider on overflow */
  		if (data->valid && data->fan[i] == 255 &&
  				data->fan_div[i] < 3) {
df885d912   Chris Packham   hwmon: (adm9240) ...
205
  			err = adm9240_write_fan_div(data, i,
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
206
  					++data->fan_div[i]);
df885d912   Chris Packham   hwmon: (adm9240) ...
207
208
  			if (err < 0)
  				return err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
209
210
211
212
213
214
215
216
217
218
219
220
  
  			/* adjust fan_min if active, but not to 0 */
  			if (data->fan_min[i] < 255 &&
  					data->fan_min[i] >= 2)
  				data->fan_min[i] /= 2;
  		}
  	}
  
  	return 0;
  }
  
  static int adm9240_update_config(struct adm9240_data *data)
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
221
  {
df885d912   Chris Packham   hwmon: (adm9240) ...
222
  	unsigned int val;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
223
  	int i;
df885d912   Chris Packham   hwmon: (adm9240) ...
224
  	int err;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
225

6a8cdd146   Chris Packham   hwmon: (adm9240) ...
226
  	for (i = 0; i < 6; i++) {
df885d912   Chris Packham   hwmon: (adm9240) ...
227
228
229
230
231
232
233
234
  		err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MIN(i),
  				      &data->in_min[i], 1);
  		if (err < 0)
  			return err;
  		err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MAX(i),
  				      &data->in_max[i], 1);
  		if (err < 0)
  			return err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
235
  	}
df885d912   Chris Packham   hwmon: (adm9240) ...
236
237
238
239
240
241
242
243
  	err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN_MIN(0),
  				      &data->fan_min[0], 2);
  	if (err < 0)
  		return err;
  	err = regmap_bulk_read(data->regmap, ADM9240_REG_TEMP_MAX(0),
  				      &data->temp_max[0], 2);
  	if (err < 0)
  		return err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
244
245
  
  	/* read fan divs and 5-bit VID */
df885d912   Chris Packham   hwmon: (adm9240) ...
246
247
248
249
250
251
252
253
254
255
  	err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &val);
  	if (err < 0)
  		return err;
  	data->fan_div[0] = (val >> 4) & 3;
  	data->fan_div[1] = (val >> 6) & 3;
  	data->vid = val & 0x0f;
  	err = regmap_read(data->regmap, ADM9240_REG_VID4, &val);
  	if (err < 0)
  		return err;
  	data->vid |= (val & 1) << 4;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
256
  	/* read analog out */
df885d912   Chris Packham   hwmon: (adm9240) ...
257
258
  	err = regmap_raw_read(data->regmap, ADM9240_REG_ANALOG_OUT,
  			      &data->aout, 1);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
259

df885d912   Chris Packham   hwmon: (adm9240) ...
260
  	return err;
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
261
262
263
264
265
266
  }
  
  static struct adm9240_data *adm9240_update_device(struct device *dev)
  {
  	struct adm9240_data *data = dev_get_drvdata(dev);
  	int err;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
267
268
269
270
271
  	mutex_lock(&data->update_lock);
  
  	/* minimum measurement cycle: 1.75 seconds */
  	if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
  			|| !data->valid) {
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
272
273
274
275
276
  		err = adm9240_update_measure(data);
  		if (err < 0) {
  			data->valid = 0;
  			mutex_unlock(&data->update_lock);
  			return ERR_PTR(err);
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
277
278
279
280
281
282
283
  		}
  		data->last_updated_measure = jiffies;
  	}
  
  	/* minimum config reading cycle: 300 seconds */
  	if (time_after(jiffies, data->last_updated_config + (HZ * 300))
  			|| !data->valid) {
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
284
285
286
287
288
  		err = adm9240_update_config(data);
  		if (err < 0) {
  			data->valid = 0;
  			mutex_unlock(&data->update_lock);
  			return ERR_PTR(err);
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
289
  		}
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
290
291
292
293
294
295
  		data->last_updated_config = jiffies;
  		data->valid = 1;
  	}
  	mutex_unlock(&data->update_lock);
  	return data;
  }
40b5cda28   Grant Coady   [PATCH] I2C: add ...
296
297
298
  /*** sysfs accessors ***/
  
  /* temperature */
b57511165   Julia Lawall   hwmon: (adm9240) ...
299
300
  static ssize_t temp1_input_show(struct device *dev,
  				struct device_attribute *dummy, char *buf)
c7461a665   Grant Coady   [PATCH] hwmon: ad...
301
302
  {
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
303
304
305
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
667f4bab8   Chris Packham   hwmon: (adm9240) ...
306
307
  	return sprintf(buf, "%d
  ", data->temp / 128 * 500); /* 9-bit value */
c7461a665   Grant Coady   [PATCH] hwmon: ad...
308
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
309
310
  static ssize_t max_show(struct device *dev, struct device_attribute *devattr,
  			char *buf)
c7461a665   Grant Coady   [PATCH] hwmon: ad...
311
312
313
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
314
315
316
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
317
318
319
  	return sprintf(buf, "%d
  ", data->temp_max[attr->index] * 1000);
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
320
321
  static ssize_t max_store(struct device *dev, struct device_attribute *devattr,
  			 const char *buf, size_t count)
c7461a665   Grant Coady   [PATCH] hwmon: ad...
322
323
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
715f69bef   Axel Lin   hwmon: (adm9240) ...
324
  	struct adm9240_data *data = dev_get_drvdata(dev);
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
325
326
327
328
329
330
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
c7461a665   Grant Coady   [PATCH] hwmon: ad...
331

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
332
  	mutex_lock(&data->update_lock);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
333
  	data->temp_max[attr->index] = TEMP_TO_REG(val);
df885d912   Chris Packham   hwmon: (adm9240) ...
334
335
  	err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(attr->index),
  			   data->temp_max[attr->index]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
336
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
337
  	return err < 0 ? err : count;
c7461a665   Grant Coady   [PATCH] hwmon: ad...
338
  }
b57511165   Julia Lawall   hwmon: (adm9240) ...
339
  static DEVICE_ATTR_RO(temp1_input);
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
340
341
  static SENSOR_DEVICE_ATTR_RW(temp1_max, max, 0);
  static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, max, 1);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
342
343
  
  /* voltage */
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
344
345
  static ssize_t in_show(struct device *dev, struct device_attribute *devattr,
  		       char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
346
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
347
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
348
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
349
350
351
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
352
353
354
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in[attr->index],
  				attr->index));
40b5cda28   Grant Coady   [PATCH] I2C: add ...
355
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
356
357
  static ssize_t in_min_show(struct device *dev,
  			   struct device_attribute *devattr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
358
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
359
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
360
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
361
362
363
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
364
365
366
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in_min[attr->index],
  				attr->index));
40b5cda28   Grant Coady   [PATCH] I2C: add ...
367
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
368
369
  static ssize_t in_max_show(struct device *dev,
  			   struct device_attribute *devattr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
370
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
371
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
372
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
373
374
375
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
376
377
378
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in_max[attr->index],
  				attr->index));
40b5cda28   Grant Coady   [PATCH] I2C: add ...
379
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
380
381
382
  static ssize_t in_min_store(struct device *dev,
  			    struct device_attribute *devattr, const char *buf,
  			    size_t count)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
383
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
384
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
715f69bef   Axel Lin   hwmon: (adm9240) ...
385
  	struct adm9240_data *data = dev_get_drvdata(dev);
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
386
387
388
389
390
391
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
392

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
393
  	mutex_lock(&data->update_lock);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
394
  	data->in_min[attr->index] = IN_TO_REG(val, attr->index);
df885d912   Chris Packham   hwmon: (adm9240) ...
395
396
  	err = regmap_write(data->regmap, ADM9240_REG_IN_MIN(attr->index),
  			   data->in_min[attr->index]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
397
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
398
  	return err < 0 ? err : count;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
399
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
400
401
402
  static ssize_t in_max_store(struct device *dev,
  			    struct device_attribute *devattr, const char *buf,
  			    size_t count)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
403
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
404
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
715f69bef   Axel Lin   hwmon: (adm9240) ...
405
  	struct adm9240_data *data = dev_get_drvdata(dev);
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
406
407
408
409
410
411
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
412

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
413
  	mutex_lock(&data->update_lock);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
414
  	data->in_max[attr->index] = IN_TO_REG(val, attr->index);
df885d912   Chris Packham   hwmon: (adm9240) ...
415
416
  	err = regmap_write(data->regmap, ADM9240_REG_IN_MAX(attr->index),
  			   data->in_max[attr->index]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
417
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
418
  	return err < 0 ? err : count;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
419
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  static SENSOR_DEVICE_ATTR_RO(in0_input, in, 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, 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, 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, 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, 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, 5);
  static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5);
  static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
438
439
  
  /* fans */
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
440
441
  static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
  			char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
442
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
443
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
444
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
445
446
447
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
448
449
450
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[attr->index],
  				1 << data->fan_div[attr->index]));
40b5cda28   Grant Coady   [PATCH] I2C: add ...
451
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
452
453
  static ssize_t fan_min_show(struct device *dev,
  			    struct device_attribute *devattr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
454
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
455
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
456
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
457
458
459
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
460
461
462
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan_min[attr->index],
  				1 << data->fan_div[attr->index]));
40b5cda28   Grant Coady   [PATCH] I2C: add ...
463
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
464
465
  static ssize_t fan_div_show(struct device *dev,
  			    struct device_attribute *devattr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
466
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
467
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
468
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
469
470
471
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
c7461a665   Grant Coady   [PATCH] hwmon: ad...
472
473
  	return sprintf(buf, "%d
  ", 1 << data->fan_div[attr->index]);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
474
  }
e415e48b6   Jean Delvare   [PATCH] hwmon: ad...
475
  /*
40b5cda28   Grant Coady   [PATCH] I2C: add ...
476
477
478
479
480
481
482
483
484
485
   * set fan speed low limit:
   *
   * - value is zero: disable fan speed low limit alarm
   *
   * - value is below fan speed measurement range: enable fan speed low
   *   limit alarm to be asserted while fan speed too slow to measure
   *
   * - otherwise: select fan clock divider to suit fan speed low limit,
   *   measurement code may adjust registers to ensure fan speed reading
   */
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
486
487
488
  static ssize_t fan_min_store(struct device *dev,
  			     struct device_attribute *devattr,
  			     const char *buf, size_t count)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
489
  {
c7461a665   Grant Coady   [PATCH] hwmon: ad...
490
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
715f69bef   Axel Lin   hwmon: (adm9240) ...
491
492
  	struct adm9240_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
c7461a665   Grant Coady   [PATCH] hwmon: ad...
493
  	int nr = attr->index;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
494
  	u8 new_div;
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
495
496
497
498
499
500
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
501

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
502
  	mutex_lock(&data->update_lock);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  
  	if (!val) {
  		data->fan_min[nr] = 255;
  		new_div = data->fan_div[nr];
  
  		dev_dbg(&client->dev, "fan%u low limit set disabled
  ",
  				nr + 1);
  
  	} else if (val < 1350000 / (8 * 254)) {
  		new_div = 3;
  		data->fan_min[nr] = 254;
  
  		dev_dbg(&client->dev, "fan%u low limit set minimum %u
  ",
  				nr + 1, FAN_FROM_REG(254, 1 << new_div));
  
  	} else {
  		unsigned int new_min = 1350000 / val;
  
  		new_div = 0;
  		while (new_min > 192 && new_div < 3) {
  			new_div++;
  			new_min /= 2;
  		}
  		if (!new_min) /* keep > 0 */
  			new_min++;
  
  		data->fan_min[nr] = new_min;
  
  		dev_dbg(&client->dev, "fan%u low limit set fan speed %u
  ",
  				nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
  	}
  
  	if (new_div != data->fan_div[nr]) {
  		data->fan_div[nr] = new_div;
df885d912   Chris Packham   hwmon: (adm9240) ...
540
  		adm9240_write_fan_div(data, nr, new_div);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
541
  	}
df885d912   Chris Packham   hwmon: (adm9240) ...
542
543
  	err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(nr),
  			   data->fan_min[nr]);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
544

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
545
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
546
  	return err < 0 ? err : count;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
547
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
548
549
550
551
552
553
  static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
  static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
  static SENSOR_DEVICE_ATTR_RO(fan1_div, fan_div, 0);
  static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
  static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
  static SENSOR_DEVICE_ATTR_RO(fan2_div, fan_div, 1);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
554
555
  
  /* alarms */
b57511165   Julia Lawall   hwmon: (adm9240) ...
556
  static ssize_t alarms_show(struct device *dev,
e415e48b6   Jean Delvare   [PATCH] hwmon: ad...
557
  		struct device_attribute *attr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
558
559
  {
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
560
561
562
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
563
564
565
  	return sprintf(buf, "%u
  ", data->alarms);
  }
b57511165   Julia Lawall   hwmon: (adm9240) ...
566
  static DEVICE_ATTR_RO(alarms);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
567

7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
568
569
  static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
  			  char *buf)
360f9452d   Jean Delvare   hwmon: (adm9240) ...
570
571
572
  {
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
573
574
575
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
360f9452d   Jean Delvare   hwmon: (adm9240) ...
576
577
578
  	return sprintf(buf, "%u
  ", (data->alarms >> bitnr) & 1);
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
579
580
581
582
583
584
585
586
587
  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(temp1_alarm, alarm, 4);
  static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
  static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
360f9452d   Jean Delvare   hwmon: (adm9240) ...
588

40b5cda28   Grant Coady   [PATCH] I2C: add ...
589
  /* vid */
b57511165   Julia Lawall   hwmon: (adm9240) ...
590
591
  static ssize_t cpu0_vid_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
592
593
  {
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
594
595
596
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
597
598
599
  	return sprintf(buf, "%d
  ", vid_from_reg(data->vid, data->vrm));
  }
b57511165   Julia Lawall   hwmon: (adm9240) ...
600
  static DEVICE_ATTR_RO(cpu0_vid);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
601
602
  
  /* analog output */
b57511165   Julia Lawall   hwmon: (adm9240) ...
603
604
  static ssize_t aout_output_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
605
606
  {
  	struct adm9240_data *data = adm9240_update_device(dev);
6a8cdd146   Chris Packham   hwmon: (adm9240) ...
607
608
609
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
610
611
612
  	return sprintf(buf, "%d
  ", AOUT_FROM_REG(data->aout));
  }
b57511165   Julia Lawall   hwmon: (adm9240) ...
613
614
615
  static ssize_t aout_output_store(struct device *dev,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
616
  {
715f69bef   Axel Lin   hwmon: (adm9240) ...
617
  	struct adm9240_data *data = dev_get_drvdata(dev);
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
618
619
620
621
622
623
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
624

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
625
  	mutex_lock(&data->update_lock);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
626
  	data->aout = AOUT_TO_REG(val);
df885d912   Chris Packham   hwmon: (adm9240) ...
627
  	err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, data->aout);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
628
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
629
  	return err < 0 ? err : count;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
630
  }
b57511165   Julia Lawall   hwmon: (adm9240) ...
631
  static DEVICE_ATTR_RW(aout_output);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
632

7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
633
634
  static ssize_t alarm_store(struct device *dev, struct device_attribute *attr,
  			   const char *buf, size_t count)
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
635
  {
715f69bef   Axel Lin   hwmon: (adm9240) ...
636
  	struct adm9240_data *data = dev_get_drvdata(dev);
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
637
  	unsigned long val;
df885d912   Chris Packham   hwmon: (adm9240) ...
638
  	int err;
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
639

179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
640
  	if (kstrtoul(buf, 10, &val) || val != 0)
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
641
642
643
  		return -EINVAL;
  
  	mutex_lock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
644
  	err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80);
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
645
646
  	data->valid = 0;		/* Force cache refresh */
  	mutex_unlock(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
647
648
649
650
  	if (err < 0)
  		return err;
  	dev_dbg(&data->client->dev, "chassis intrusion latch cleared
  ");
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
651
652
653
  
  	return count;
  }
7352ae8d0   Guenter Roeck   hwmon: (adm9240) ...
654
  static SENSOR_DEVICE_ATTR_RW(intrusion0_alarm, alarm, 12);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
655

715f69bef   Axel Lin   hwmon: (adm9240) ...
656
  static struct attribute *adm9240_attrs[] = {
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
657
658
659
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
660
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
661
662
663
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
664
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
665
666
667
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
668
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
669
670
671
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
672
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
673
674
675
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
676
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
677
678
679
  	&sensor_dev_attr_in5_input.dev_attr.attr,
  	&sensor_dev_attr_in5_min.dev_attr.attr,
  	&sensor_dev_attr_in5_max.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
680
  	&sensor_dev_attr_in5_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
681
682
683
  	&dev_attr_temp1_input.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
684
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
685
686
687
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
688
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
689
690
691
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
360f9452d   Jean Delvare   hwmon: (adm9240) ...
692
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
693
694
  	&dev_attr_alarms.attr,
  	&dev_attr_aout_output.attr,
0de2b2448   Jean Delvare   hwmon: (adm9240) ...
695
  	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
696
697
698
  	&dev_attr_cpu0_vid.attr,
  	NULL
  };
715f69bef   Axel Lin   hwmon: (adm9240) ...
699
  ATTRIBUTE_GROUPS(adm9240);
681c6f7a6   Mark M. Hoffman   hwmon: Fix unchec...
700

40b5cda28   Grant Coady   [PATCH] I2C: add ...
701
  /*** sensor chip detect and driver install ***/
7fae82831   Jean Delvare   hwmon: (adm9240) ...
702
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
703
  static int adm9240_detect(struct i2c_client *new_client,
7fae82831   Jean Delvare   hwmon: (adm9240) ...
704
  			  struct i2c_board_info *info)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
705
  {
7fae82831   Jean Delvare   hwmon: (adm9240) ...
706
  	struct i2c_adapter *adapter = new_client->adapter;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
707
  	const char *name = "";
7fae82831   Jean Delvare   hwmon: (adm9240) ...
708
  	int address = new_client->addr;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
709
710
711
  	u8 man_id, die_rev;
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
7fae82831   Jean Delvare   hwmon: (adm9240) ...
712
  		return -ENODEV;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
713

52df6440a   Jean Delvare   hwmon: Clean up d...
714
715
716
717
718
719
720
  	/* verify chip: reg address should match i2c address */
  	if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR)
  			!= address) {
  		dev_err(&adapter->dev, "detect fail: address match, 0x%02x
  ",
  			address);
  		return -ENODEV;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
721
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
722
723
724
  	/* check known chip manufacturer */
  	man_id = i2c_smbus_read_byte_data(new_client, ADM9240_REG_MAN_ID);
  	if (man_id == 0x23) {
40b5cda28   Grant Coady   [PATCH] I2C: add ...
725
  		name = "adm9240";
52df6440a   Jean Delvare   hwmon: Clean up d...
726
  	} else if (man_id == 0xda) {
40b5cda28   Grant Coady   [PATCH] I2C: add ...
727
  		name = "ds1780";
52df6440a   Jean Delvare   hwmon: Clean up d...
728
  	} else if (man_id == 0x01) {
40b5cda28   Grant Coady   [PATCH] I2C: add ...
729
  		name = "lm81";
52df6440a   Jean Delvare   hwmon: Clean up d...
730
731
732
733
734
  	} else {
  		dev_err(&adapter->dev, "detect fail: unknown manuf, 0x%02x
  ",
  			man_id);
  		return -ENODEV;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
735
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
736
737
738
739
740
741
742
  
  	/* successful detect, print chip info */
  	die_rev = i2c_smbus_read_byte_data(new_client, ADM9240_REG_DIE_REV);
  	dev_info(&adapter->dev, "found %s revision %u
  ",
  		 man_id == 0x23 ? "ADM9240" :
  		 man_id == 0xda ? "DS1780" : "LM81", die_rev);
7fae82831   Jean Delvare   hwmon: (adm9240) ...
743
  	strlcpy(info->type, name, I2C_NAME_SIZE);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
744

7fae82831   Jean Delvare   hwmon: (adm9240) ...
745
746
  	return 0;
  }
40b5cda28   Grant Coady   [PATCH] I2C: add ...
747

df885d912   Chris Packham   hwmon: (adm9240) ...
748
  static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *data)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
749
  {
df885d912   Chris Packham   hwmon: (adm9240) ...
750
751
752
753
754
755
756
757
758
759
  	u8 conf, mode;
  	int err;
  
  	err = regmap_raw_read(data->regmap, ADM9240_REG_CONFIG, &conf, 1);
  	if (err < 0)
  		return err;
  	err = regmap_raw_read(data->regmap, ADM9240_REG_TEMP_CONF, &mode, 1);
  	if (err < 0)
  		return err;
  	mode &= 3;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
760

303760b44   Jean Delvare   [PATCH] hwmon: hw...
761
  	data->vrm = vid_which_vrm(); /* need this to report vid as mV */
40b5cda28   Grant Coady   [PATCH] I2C: add ...
762

8e8f9289c   Grant Coady   [PATCH] I2C: adm9...
763
764
765
  	dev_info(&client->dev, "Using VRM: %d.%d
  ", data->vrm / 10,
  			data->vrm % 10);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
766
767
768
769
770
771
772
773
  	if (conf & 1) { /* measurement cycle running: report state */
  
  		dev_info(&client->dev, "status: config 0x%02x mode %u
  ",
  				conf, mode);
  
  	} else { /* cold start: open limits before starting chip */
  		int i;
c387e4eb2   Guenter Roeck   hwmon: (adm9240) ...
774
  		for (i = 0; i < 6; i++) {
df885d912   Chris Packham   hwmon: (adm9240) ...
775
776
777
778
779
780
781
782
  			err = regmap_write(data->regmap,
  					   ADM9240_REG_IN_MIN(i), 0);
  			if (err < 0)
  				return err;
  			err = regmap_write(data->regmap,
  					   ADM9240_REG_IN_MAX(i), 255);
  			if (err < 0)
  				return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
783
  		}
10d097737   Chris Packham   hwmon: (adm9240) ...
784
  		for (i = 0; i < 2; i++) {
df885d912   Chris Packham   hwmon: (adm9240) ...
785
  			err = regmap_write(data->regmap,
10d097737   Chris Packham   hwmon: (adm9240) ...
786
  					ADM9240_REG_FAN_MIN(i), 255);
df885d912   Chris Packham   hwmon: (adm9240) ...
787
788
  			if (err < 0)
  				return err;
10d097737   Chris Packham   hwmon: (adm9240) ...
789
790
  		}
  		for (i = 0; i < 2; i++) {
df885d912   Chris Packham   hwmon: (adm9240) ...
791
  			err = regmap_write(data->regmap,
10d097737   Chris Packham   hwmon: (adm9240) ...
792
  					ADM9240_REG_TEMP_MAX(i), 127);
df885d912   Chris Packham   hwmon: (adm9240) ...
793
794
  			if (err < 0)
  				return err;
10d097737   Chris Packham   hwmon: (adm9240) ...
795
  		}
40b5cda28   Grant Coady   [PATCH] I2C: add ...
796
797
  
  		/* start measurement cycle */
df885d912   Chris Packham   hwmon: (adm9240) ...
798
799
800
  		err = regmap_write(data->regmap, ADM9240_REG_CONFIG, 1);
  		if (err < 0)
  			return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
801

b55f37572   Guenter Roeck   hwmon: Fix checkp...
802
803
804
  		dev_info(&client->dev,
  			 "cold start: config was 0x%02x mode %u
  ", conf, mode);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
805
  	}
df885d912   Chris Packham   hwmon: (adm9240) ...
806
807
  
  	return 0;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
808
  }
df885d912   Chris Packham   hwmon: (adm9240) ...
809
810
811
812
813
814
  static const struct regmap_config adm9240_regmap_config = {
  	.reg_bits = 8,
  	.val_bits = 8,
  	.use_single_read = true,
  	.use_single_write = true,
  };
674870385   Stephen Kitt   hwmon: use simple...
815
  static int adm9240_probe(struct i2c_client *new_client)
40b5cda28   Grant Coady   [PATCH] I2C: add ...
816
  {
715f69bef   Axel Lin   hwmon: (adm9240) ...
817
818
  	struct device *dev = &new_client->dev;
  	struct device *hwmon_dev;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
819
  	struct adm9240_data *data;
df885d912   Chris Packham   hwmon: (adm9240) ...
820
  	int err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
821

715f69bef   Axel Lin   hwmon: (adm9240) ...
822
  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
823
824
  	if (!data)
  		return -ENOMEM;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
825

715f69bef   Axel Lin   hwmon: (adm9240) ...
826
  	data->client = new_client;
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
827
  	mutex_init(&data->update_lock);
df885d912   Chris Packham   hwmon: (adm9240) ...
828
829
830
  	data->regmap = devm_regmap_init_i2c(new_client, &adm9240_regmap_config);
  	if (IS_ERR(data->regmap))
  		return PTR_ERR(data->regmap);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
831

df885d912   Chris Packham   hwmon: (adm9240) ...
832
833
834
  	err = adm9240_init_client(new_client, data);
  	if (err < 0)
  		return err;
40b5cda28   Grant Coady   [PATCH] I2C: add ...
835

715f69bef   Axel Lin   hwmon: (adm9240) ...
836
837
838
839
840
  	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
  							   new_client->name,
  							   data,
  							   adm9240_groups);
  	return PTR_ERR_OR_ZERO(hwmon_dev);
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
841
  }
40b5cda28   Grant Coady   [PATCH] I2C: add ...
842

4341fc3f3   Axel Lin   hwmon: (adm9240) ...
843
844
845
846
847
848
849
  static const struct i2c_device_id adm9240_id[] = {
  	{ "adm9240", adm9240 },
  	{ "ds1780", ds1780 },
  	{ "lm81", lm81 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, adm9240_id);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
850

4341fc3f3   Axel Lin   hwmon: (adm9240) ...
851
852
853
854
855
  static struct i2c_driver adm9240_driver = {
  	.class		= I2C_CLASS_HWMON,
  	.driver = {
  		.name	= "adm9240",
  	},
674870385   Stephen Kitt   hwmon: use simple...
856
  	.probe_new	= adm9240_probe,
4341fc3f3   Axel Lin   hwmon: (adm9240) ...
857
858
859
860
  	.id_table	= adm9240_id,
  	.detect		= adm9240_detect,
  	.address_list	= normal_i2c,
  };
40b5cda28   Grant Coady   [PATCH] I2C: add ...
861

f0967eea8   Axel Lin   hwmon: convert dr...
862
  module_i2c_driver(adm9240_driver);
40b5cda28   Grant Coady   [PATCH] I2C: add ...
863
864
  
  MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
2ca7b961c   Grant Coady   adm9240: Update G...
865
  		"Grant Coady <gcoady.lk@gmail.com> and others");
40b5cda28   Grant Coady   [PATCH] I2C: add ...
866
867
  MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
  MODULE_LICENSE("GPL");