Blame view

drivers/hwmon/asb100.c 27.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  /*
      asb100.c - Part of lm_sensors, Linux kernel modules for hardware
  	        monitoring
  
      Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
  
  	(derived from w83781d.c)
  
      Copyright (C) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
      Philip Edelbrock <phil@netroedge.com>, and
      Mark Studebaker <mdsxyz123@yahoo.com>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  
  /*
      This driver supports the hardware sensor chips: Asus ASB100 and
      ASB100-A "BACH".
  
      ASB100-A supports pwm1, while plain ASB100 does not.  There is no known
      way for the driver to tell which one is there.
  
      Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
      asb100	7	3	1	4	0x31	0x0694	yes	no
  */
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
38
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
42
  #include <linux/hwmon.h>
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
43
  #include <linux/hwmon-sysfs.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
44
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
45
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #include <linux/init.h>
ff3240946   Dominik Hackl   [PATCH] I2C: incl...
47
  #include <linux/jiffies.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
48
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #include "lm75.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  /* I2C addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
51
  static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

3aed198c3   Jean Delvare   hwmon: Don't over...
53
54
55
  static unsigned short force_subclients[4];
  module_param_array(force_subclients, short, NULL, 0);
  MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  	"{bus, clientaddr, subclientaddr1, subclientaddr2}");
  
  /* Voltage IN registers 0-6 */
  #define ASB100_REG_IN(nr)	(0x20 + (nr))
  #define ASB100_REG_IN_MAX(nr)	(0x2b + (nr * 2))
  #define ASB100_REG_IN_MIN(nr)	(0x2c + (nr * 2))
  
  /* FAN IN registers 1-3 */
  #define ASB100_REG_FAN(nr)	(0x28 + (nr))
  #define ASB100_REG_FAN_MIN(nr)	(0x3b + (nr))
  
  /* TEMPERATURE registers 1-4 */
  static const u16 asb100_reg_temp[]	= {0, 0x27, 0x150, 0x250, 0x17};
  static const u16 asb100_reg_temp_max[]	= {0, 0x39, 0x155, 0x255, 0x18};
  static const u16 asb100_reg_temp_hyst[]	= {0, 0x3a, 0x153, 0x253, 0x19};
  
  #define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr])
  #define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr])
  #define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr])
  
  #define ASB100_REG_TEMP2_CONFIG	0x0152
  #define ASB100_REG_TEMP3_CONFIG	0x0252
  
  
  #define ASB100_REG_CONFIG	0x40
  #define ASB100_REG_ALARM1	0x41
  #define ASB100_REG_ALARM2	0x42
  #define ASB100_REG_SMIM1	0x43
  #define ASB100_REG_SMIM2	0x44
  #define ASB100_REG_VID_FANDIV	0x47
  #define ASB100_REG_I2C_ADDR	0x48
  #define ASB100_REG_CHIPID	0x49
  #define ASB100_REG_I2C_SUBADDR	0x4a
  #define ASB100_REG_PIN		0x4b
  #define ASB100_REG_IRQ		0x4c
  #define ASB100_REG_BANK		0x4e
  #define ASB100_REG_CHIPMAN	0x4f
  
  #define ASB100_REG_WCHIPID	0x58
  
  /* bit 7 -> enable, bits 0-3 -> duty cycle */
  #define ASB100_REG_PWM1		0x59
  
  /* CONVERSIONS
     Rounding and limit checking is only done on the TO_REG variants. */
  
  /* These constants are a guess, consistent w/ w83781d */
  #define ASB100_IN_MIN (   0)
  #define ASB100_IN_MAX (4080)
  
  /* IN: 1/1000 V (0V to 4.08V)
     REG: 16mV/bit */
  static u8 IN_TO_REG(unsigned val)
  {
  	unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
  	return (nval + 8) / 16;
  }
  
  static unsigned IN_FROM_REG(u8 reg)
  {
  	return reg * 16;
  }
  
  static u8 FAN_TO_REG(long rpm, int div)
  {
  	if (rpm == -1)
  		return 0;
  	if (rpm == 0)
  		return 255;
  	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
  	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
  }
  
  static int FAN_FROM_REG(u8 val, int div)
  {
  	return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
  }
  
  /* These constants are a guess, consistent w/ w83781d */
  #define ASB100_TEMP_MIN (-128000)
  #define ASB100_TEMP_MAX ( 127000)
  
  /* TEMP: 0.001C/bit (-128C to +127C)
     REG: 1C/bit, two's complement */
5bfedac04   Christian Hohnstaedt   hwmon: Allow writ...
140
  static u8 TEMP_TO_REG(long temp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  {
  	int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
  	ntemp += (ntemp<0 ? -500 : 500);
  	return (u8)(ntemp / 1000);
  }
  
  static int TEMP_FROM_REG(u8 reg)
  {
  	return (s8)reg * 1000;
  }
  
  /* PWM: 0 - 255 per sensors documentation
     REG: (6.25% duty cycle per bit) */
  static u8 ASB100_PWM_TO_REG(int pwm)
  {
  	pwm = SENSORS_LIMIT(pwm, 0, 255);
  	return (u8)(pwm / 16);
  }
  
  static int ASB100_PWM_FROM_REG(u8 reg)
  {
  	return reg * 16;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
169
170
171
172
173
174
175
176
  #define DIV_FROM_REG(val) (1 << (val))
  
  /* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
     REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
  static u8 DIV_TO_REG(long val)
  {
  	return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
  }
  
  /* For each registered client, we need to keep some data in memory. That
     data is pointed to by client->data. The structure itself is
     dynamically allocated, at the same time the client itself is allocated. */
  struct asb100_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
177
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
178
  	struct mutex lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
180
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	unsigned long last_updated;	/* In jiffies */
  
  	/* array of 2 pointers to subclients */
  	struct i2c_client *lm75[2];
  
  	char valid;		/* !=0 if following fields are valid */
  	u8 in[7];		/* Register value */
  	u8 in_max[7];		/* Register value */
  	u8 in_min[7];		/* Register value */
  	u8 fan[3];		/* Register value */
  	u8 fan_min[3];		/* Register value */
  	u16 temp[4];		/* Register value (0 and 3 are u8 only) */
  	u16 temp_max[4];	/* Register value (0 and 3 are u8 only) */
  	u16 temp_hyst[4];	/* Register value (0 and 3 are u8 only) */
  	u8 fan_div[3];		/* Register encoding, right justified */
  	u8 pwm;			/* Register encoding */
  	u8 vid;			/* Register encoding, combined */
  	u32 alarms;		/* Register encoding, combined */
  	u8 vrm;
  };
  
  static int asb100_read_value(struct i2c_client *client, u16 reg);
  static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
063675b15   Jean Delvare   hwmon: (asb100) C...
204
205
  static int asb100_probe(struct i2c_client *client,
  			const struct i2c_device_id *id);
310ec7921   Jean Delvare   i2c: Drop the kin...
206
  static int asb100_detect(struct i2c_client *client,
063675b15   Jean Delvare   hwmon: (asb100) C...
207
208
  			 struct i2c_board_info *info);
  static int asb100_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  static struct asb100_data *asb100_update_device(struct device *dev);
  static void asb100_init_client(struct i2c_client *client);
063675b15   Jean Delvare   hwmon: (asb100) C...
211
  static const struct i2c_device_id asb100_id[] = {
1f86df49d   Jean Delvare   i2c: Drop I2C_CLI...
212
  	{ "asb100", 0 },
063675b15   Jean Delvare   hwmon: (asb100) C...
213
214
215
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, asb100_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  static struct i2c_driver asb100_driver = {
063675b15   Jean Delvare   hwmon: (asb100) C...
217
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
218
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
219
220
  		.name	= "asb100",
  	},
063675b15   Jean Delvare   hwmon: (asb100) C...
221
222
223
224
  	.probe		= asb100_probe,
  	.remove		= asb100_remove,
  	.id_table	= asb100_id,
  	.detect		= asb100_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
225
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  };
  
  /* 7 Voltages */
  #define show_in_reg(reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
230
231
  static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
  		char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
233
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
238
239
240
241
242
243
  	struct asb100_data *data = asb100_update_device(dev); \
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->reg[nr])); \
  }
  
  show_in_reg(in)
  show_in_reg(in_min)
  show_in_reg(in_max)
  
  #define set_in_reg(REG, reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
244
245
  static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \
  		const char *buf, size_t count) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
247
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct asb100_data *data = i2c_get_clientdata(client); \
  	unsigned long val = simple_strtoul(buf, NULL, 10); \
   \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
252
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
  	data->in_##reg[nr] = IN_TO_REG(val); \
  	asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
  		data->in_##reg[nr]); \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
256
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
  	return count; \
  }
  
  set_in_reg(MIN, min)
  set_in_reg(MAX, max)
  
  #define sysfs_in(offset) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
264
265
266
267
268
269
  static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
  		show_in, NULL, offset); \
  static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
  		show_in_min, set_in_min, offset); \
  static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
  		show_in_max, set_in_max, offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
  
  sysfs_in(0);
  sysfs_in(1);
  sysfs_in(2);
  sysfs_in(3);
  sysfs_in(4);
  sysfs_in(5);
  sysfs_in(6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  /* 3 Fans */
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
279
280
  static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
282
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[nr],
  		DIV_FROM_REG(data->fan_div[nr])));
  }
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
288
289
  static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
291
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan_min[nr],
  		DIV_FROM_REG(data->fan_div[nr])));
  }
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
297
298
  static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
300
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", DIV_FROM_REG(data->fan_div[nr]));
  }
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
305
306
  static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
  		const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
308
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	u32 val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
312
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
  	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
  	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
315
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
  	return count;
  }
  
  /* Note: we save and restore the fan minimum here, because its value is
     determined in part by the fan divisor.  This follows the principle of
d6e05edc5   Andreas Mohr   spelling fixes
321
     least surprise; the user doesn't expect the fan minimum to change just
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
     because the divisor changed. */
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
323
324
  static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
  		const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
326
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	unsigned long min;
  	unsigned long val = simple_strtoul(buf, NULL, 10);
  	int reg;
af2219315   Jean Delvare   hwmon: (asb100) V...
332

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
333
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
  
  	min = FAN_FROM_REG(data->fan_min[nr],
  			DIV_FROM_REG(data->fan_div[nr]));
  	data->fan_div[nr] = DIV_TO_REG(val);
af2219315   Jean Delvare   hwmon: (asb100) V...
338
  	switch (nr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  	case 0:	/* fan 1 */
  		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
  		reg = (reg & 0xcf) | (data->fan_div[0] << 4);
  		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
  		break;
  
  	case 1:	/* fan 2 */
  		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
  		reg = (reg & 0x3f) | (data->fan_div[1] << 6);
  		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
  		break;
  
  	case 2:	/* fan 3 */
  		reg = asb100_read_value(client, ASB100_REG_PIN);
  		reg = (reg & 0x3f) | (data->fan_div[2] << 6);
  		asb100_write_value(client, ASB100_REG_PIN, reg);
  		break;
  	}
  
  	data->fan_min[nr] =
  		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
  	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
361
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  
  	return count;
  }
  
  #define sysfs_fan(offset) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
367
368
369
370
371
372
  static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
  		show_fan, NULL, offset - 1); \
  static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
  		show_fan_min, set_fan_min, offset - 1); \
  static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
  		show_fan_div, set_fan_div, offset - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
  
  sysfs_fan(1);
  sysfs_fan(2);
  sysfs_fan(3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  /* 4 Temp. Sensors */
  static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
  {
  	int ret = 0;
  
  	switch (nr) {
  	case 1: case 2:
  		ret = sprintf(buf, "%d
  ", LM75_TEMP_FROM_REG(reg));
  		break;
  	case 0: case 3: default:
  		ret = sprintf(buf, "%d
  ", TEMP_FROM_REG(reg));
  		break;
  	}
  	return ret;
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
394

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  #define show_temp_reg(reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
396
397
  static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
  		char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
399
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
  	struct asb100_data *data = asb100_update_device(dev); \
  	return sprintf_temp_from_reg(data->reg[nr], buf, nr); \
  }
  
  show_temp_reg(temp);
  show_temp_reg(temp_max);
  show_temp_reg(temp_hyst);
  
  #define set_temp_reg(REG, reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
409
410
  static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \
  		const char *buf, size_t count) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
412
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct asb100_data *data = i2c_get_clientdata(client); \
5bfedac04   Christian Hohnstaedt   hwmon: Allow writ...
415
  	long val = simple_strtol(buf, NULL, 10); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
   \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
417
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
424
425
426
427
  	switch (nr) { \
  	case 1: case 2: \
  		data->reg[nr] = LM75_TEMP_TO_REG(val); \
  		break; \
  	case 0: case 3: default: \
  		data->reg[nr] = TEMP_TO_REG(val); \
  		break; \
  	} \
  	asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \
  			data->reg[nr]); \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
428
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
  	return count; \
  }
  
  set_temp_reg(MAX, temp_max);
  set_temp_reg(HYST, temp_hyst);
  
  #define sysfs_temp(num) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
436
437
438
439
440
441
  static SENSOR_DEVICE_ATTR(temp##num##_input, S_IRUGO, \
  		show_temp, NULL, num - 1); \
  static SENSOR_DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
  		show_temp_max, set_temp_max, num - 1); \
  static SENSOR_DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
  		show_temp_hyst, set_temp_hyst, num - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
  
  sysfs_temp(1);
  sysfs_temp(2);
  sysfs_temp(3);
  sysfs_temp(4);
  
  /* VID */
af2219315   Jean Delvare   hwmon: (asb100) V...
449
450
  static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", vid_from_reg(data->vid, data->vrm));
  }
  
  static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  
  /* VRM */
af2219315   Jean Delvare   hwmon: (asb100) V...
460
461
  static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  {
90d6619a9   Jean Delvare   hwmon: VRM is not...
463
  	struct asb100_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
  	return sprintf(buf, "%d
  ", data->vrm);
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
467
468
  static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
  		const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  {
8f74efe81   Jean Delvare   hwmon: VRM is not...
470
471
  	struct asb100_data *data = dev_get_drvdata(dev);
  	data->vrm = simple_strtoul(buf, NULL, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
  	return count;
  }
  
  /* Alarms */
  static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477

af2219315   Jean Delvare   hwmon: (asb100) V...
478
479
  static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
  {
  	struct asb100_data *data = asb100_update_device(dev);
68188ba7d   Jean Delvare   [PATCH] I2C: Kill...
482
483
  	return sprintf(buf, "%u
  ", data->alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
  }
  
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487

636866b9f   Jean Delvare   hwmon: (asb100) A...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
  		char *buf)
  {
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%u
  ", (data->alarms >> bitnr) & 1);
  }
  static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
  static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
  static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
  static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
  static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
  static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
  static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  /* 1 PWM */
af2219315   Jean Delvare   hwmon: (asb100) V...
508
509
  static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", ASB100_PWM_FROM_REG(data->pwm & 0x0f));
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
515
516
  static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr,
  		const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	unsigned long val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
521
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
  	data->pwm &= 0x80; /* keep the enable bit */
  	data->pwm |= (0x0f & ASB100_PWM_TO_REG(val));
  	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
525
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  	return count;
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
528
529
  static ssize_t show_pwm_enable1(struct device *dev,
  		struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
534
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", (data->pwm & 0x80) ? 1 : 0);
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
535
536
  static ssize_t set_pwm_enable1(struct device *dev,
  		struct device_attribute *attr, const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	unsigned long val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
541
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
  	data->pwm &= 0x0f; /* keep the duty cycle bits */
  	data->pwm |= (val ? 0x80 : 0x00);
  	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
545
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
551
  	return count;
  }
  
  static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
  static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
  		show_pwm_enable1, set_pwm_enable1);
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
552
553
  
  static struct attribute *asb100_attributes[] = {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
  	&sensor_dev_attr_in5_input.dev_attr.attr,
  	&sensor_dev_attr_in5_min.dev_attr.attr,
  	&sensor_dev_attr_in5_max.dev_attr.attr,
  	&sensor_dev_attr_in6_input.dev_attr.attr,
  	&sensor_dev_attr_in6_min.dev_attr.attr,
  	&sensor_dev_attr_in6_max.dev_attr.attr,
  
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
  	&sensor_dev_attr_fan3_input.dev_attr.attr,
  	&sensor_dev_attr_fan3_min.dev_attr.attr,
  	&sensor_dev_attr_fan3_div.dev_attr.attr,
  
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
  	&sensor_dev_attr_temp3_input.dev_attr.attr,
  	&sensor_dev_attr_temp3_max.dev_attr.attr,
  	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
  	&sensor_dev_attr_temp4_input.dev_attr.attr,
  	&sensor_dev_attr_temp4_max.dev_attr.attr,
  	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
598

636866b9f   Jean Delvare   hwmon: (asb100) A...
599
600
601
602
603
604
605
606
607
608
609
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
610
611
612
613
614
615
616
617
618
619
620
621
  	&dev_attr_cpu0_vid.attr,
  	&dev_attr_vrm.attr,
  	&dev_attr_alarms.attr,
  	&dev_attr_pwm1.attr,
  	&dev_attr_pwm1_enable.attr,
  
  	NULL
  };
  
  static const struct attribute_group asb100_group = {
  	.attrs = asb100_attributes,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622

063675b15   Jean Delvare   hwmon: (asb100) C...
623
  static int asb100_detect_subclients(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
  {
  	int i, id, err;
063675b15   Jean Delvare   hwmon: (asb100) C...
626
627
  	int address = client->addr;
  	unsigned short sc_addr[2];
af2219315   Jean Delvare   hwmon: (asb100) V...
628
  	struct asb100_data *data = i2c_get_clientdata(client);
063675b15   Jean Delvare   hwmon: (asb100) C...
629
  	struct i2c_adapter *adapter = client->adapter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
636
  
  	id = i2c_adapter_id(adapter);
  
  	if (force_subclients[0] == id && force_subclients[1] == address) {
  		for (i = 2; i <= 3; i++) {
  			if (force_subclients[i] < 0x48 ||
  			    force_subclients[i] > 0x4f) {
af2219315   Jean Delvare   hwmon: (asb100) V...
637
  				dev_err(&client->dev, "invalid subclient "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
644
  					"address %d; must be 0x48-0x4f
  ",
  					force_subclients[i]);
  				err = -ENODEV;
  				goto ERROR_SC_2;
  			}
  		}
af2219315   Jean Delvare   hwmon: (asb100) V...
645
  		asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  					(force_subclients[2] & 0x07) |
af2219315   Jean Delvare   hwmon: (asb100) V...
647
  					((force_subclients[3] & 0x07) << 4));
063675b15   Jean Delvare   hwmon: (asb100) C...
648
649
  		sc_addr[0] = force_subclients[2];
  		sc_addr[1] = force_subclients[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	} else {
af2219315   Jean Delvare   hwmon: (asb100) V...
651
  		int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
063675b15   Jean Delvare   hwmon: (asb100) C...
652
653
  		sc_addr[0] = 0x48 + (val & 0x07);
  		sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
655
  	if (sc_addr[0] == sc_addr[1]) {
af2219315   Jean Delvare   hwmon: (asb100) V...
656
  		dev_err(&client->dev, "duplicate addresses 0x%x "
063675b15   Jean Delvare   hwmon: (asb100) C...
657
658
  				"for subclients
  ", sc_addr[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
  		err = -ENODEV;
  		goto ERROR_SC_2;
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
662
663
  	data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
  	if (!data->lm75[0]) {
af2219315   Jean Delvare   hwmon: (asb100) V...
664
  		dev_err(&client->dev, "subclient %d registration "
063675b15   Jean Delvare   hwmon: (asb100) C...
665
666
667
  			"at address 0x%x failed.
  ", 1, sc_addr[0]);
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  		goto ERROR_SC_2;
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
670
671
  	data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
  	if (!data->lm75[1]) {
af2219315   Jean Delvare   hwmon: (asb100) V...
672
  		dev_err(&client->dev, "subclient %d registration "
063675b15   Jean Delvare   hwmon: (asb100) C...
673
674
675
  			"at address 0x%x failed.
  ", 2, sc_addr[1]);
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
680
681
682
  		goto ERROR_SC_3;
  	}
  
  	return 0;
  
  /* Undo inits in case of errors */
  ERROR_SC_3:
063675b15   Jean Delvare   hwmon: (asb100) C...
683
  	i2c_unregister_device(data->lm75[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  ERROR_SC_2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  	return err;
  }
063675b15   Jean Delvare   hwmon: (asb100) C...
687
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
688
  static int asb100_detect(struct i2c_client *client,
063675b15   Jean Delvare   hwmon: (asb100) C...
689
  			 struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  {
063675b15   Jean Delvare   hwmon: (asb100) C...
691
  	struct i2c_adapter *adapter = client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
692
  	int val1, val2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
695
696
  		pr_debug("detect failed, smbus byte data not supported!
  ");
063675b15   Jean Delvare   hwmon: (asb100) C...
697
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
699
700
  	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
  	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701

52df6440a   Jean Delvare   hwmon: Clean up d...
702
703
704
705
706
707
  	/* If we're in bank 0 */
  	if ((!(val1 & 0x07)) &&
  			/* Check for ASB100 ID (low byte) */
  			(((!(val1 & 0x80)) && (val2 != 0x94)) ||
  			/* Check for ASB100 ID (high byte ) */
  			((val1 & 0x80) && (val2 != 0x06)))) {
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
708
709
  		pr_debug("detect failed, bad chip id 0x%02x!
  ", val2);
52df6440a   Jean Delvare   hwmon: Clean up d...
710
711
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712

52df6440a   Jean Delvare   hwmon: Clean up d...
713
  	/* Put it now into bank 0 and Vendor ID High Byte */
063675b15   Jean Delvare   hwmon: (asb100) C...
714
715
716
  	i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
  		(i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
  		| 0x80);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
  
  	/* Determine the chip type. */
52df6440a   Jean Delvare   hwmon: Clean up d...
719
720
721
722
723
  	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
  	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
  
  	if (val1 != 0x31 || val2 != 0x06)
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724

063675b15   Jean Delvare   hwmon: (asb100) C...
725
  	strlcpy(info->type, "asb100", I2C_NAME_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726

063675b15   Jean Delvare   hwmon: (asb100) C...
727
728
729
730
731
732
733
734
735
736
737
  	return 0;
  }
  
  static int asb100_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
  {
  	int err;
  	struct asb100_data *data;
  
  	data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
  	if (!data) {
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
738
739
  		pr_debug("probe failed, kzalloc failed!
  ");
063675b15   Jean Delvare   hwmon: (asb100) C...
740
741
742
743
744
745
746
  		err = -ENOMEM;
  		goto ERROR0;
  	}
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->lock);
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  
  	/* Attach secondary lm75 clients */
063675b15   Jean Delvare   hwmon: (asb100) C...
749
750
751
  	err = asb100_detect_subclients(client);
  	if (err)
  		goto ERROR1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
  
  	/* Initialize the chip */
af2219315   Jean Delvare   hwmon: (asb100) V...
754
  	asb100_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  
  	/* A few vars need to be filled upon startup */
af2219315   Jean Delvare   hwmon: (asb100) V...
757
758
759
  	data->fan_min[0] = asb100_read_value(client, ASB100_REG_FAN_MIN(0));
  	data->fan_min[1] = asb100_read_value(client, ASB100_REG_FAN_MIN(1));
  	data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  
  	/* Register sysfs hooks */
af2219315   Jean Delvare   hwmon: (asb100) V...
762
  	if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group)))
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
763
  		goto ERROR3;
af2219315   Jean Delvare   hwmon: (asb100) V...
764
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
765
766
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
767
  		goto ERROR4;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
768
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  	return 0;
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
770
  ERROR4:
af2219315   Jean Delvare   hwmon: (asb100) V...
771
  	sysfs_remove_group(&client->dev.kobj, &asb100_group);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
772
  ERROR3:
063675b15   Jean Delvare   hwmon: (asb100) C...
773
774
  	i2c_unregister_device(data->lm75[1]);
  	i2c_unregister_device(data->lm75[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
  ERROR1:
  	kfree(data);
  ERROR0:
  	return err;
  }
063675b15   Jean Delvare   hwmon: (asb100) C...
780
  static int asb100_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
782
  	struct asb100_data *data = i2c_get_clientdata(client);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
783

063675b15   Jean Delvare   hwmon: (asb100) C...
784
785
  	hwmon_device_unregister(data->hwmon_dev);
  	sysfs_remove_group(&client->dev.kobj, &asb100_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786

063675b15   Jean Delvare   hwmon: (asb100) C...
787
788
  	i2c_unregister_device(data->lm75[1]);
  	i2c_unregister_device(data->lm75[0]);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
789

063675b15   Jean Delvare   hwmon: (asb100) C...
790
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
794
795
796
797
798
799
800
801
  
  	return 0;
  }
  
  /* The SMBus locks itself, usually, but nothing may access the chip between
     bank switches. */
  static int asb100_read_value(struct i2c_client *client, u16 reg)
  {
  	struct asb100_data *data = i2c_get_clientdata(client);
  	struct i2c_client *cl;
  	int res, bank;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
802
  	mutex_lock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
  
  	bank = (reg >> 8) & 0x0f;
  	if (bank > 2)
  		/* switch banks */
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
  
  	if (bank == 0 || bank > 2) {
  		res = i2c_smbus_read_byte_data(client, reg & 0xff);
  	} else {
  		/* switch to subclient */
  		cl = data->lm75[bank - 1];
  
  		/* convert from ISA to LM75 I2C addresses */
  		switch (reg & 0xff) {
  		case 0x50: /* TEMP */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
818
  			res = i2c_smbus_read_word_swapped(cl, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
  			break;
  		case 0x52: /* CONFIG */
  			res = i2c_smbus_read_byte_data(cl, 1);
  			break;
  		case 0x53: /* HYST */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
824
  			res = i2c_smbus_read_word_swapped(cl, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
  			break;
  		case 0x55: /* MAX */
  		default:
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
828
  			res = i2c_smbus_read_word_swapped(cl, 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
834
  			break;
  		}
  	}
  
  	if (bank > 2)
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
835
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
844
  
  	return res;
  }
  
  static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
  {
  	struct asb100_data *data = i2c_get_clientdata(client);
  	struct i2c_client *cl;
  	int bank;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
845
  	mutex_lock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
  
  	bank = (reg >> 8) & 0x0f;
  	if (bank > 2)
  		/* switch banks */
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
  
  	if (bank == 0 || bank > 2) {
  		i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff);
  	} else {
  		/* switch to subclient */
  		cl = data->lm75[bank - 1];
  
  		/* convert from ISA to LM75 I2C addresses */
  		switch (reg & 0xff) {
  		case 0x52: /* CONFIG */
  			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
  			break;
  		case 0x53: /* HYST */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
864
  			i2c_smbus_write_word_swapped(cl, 2, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  			break;
  		case 0x55: /* MAX */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
867
  			i2c_smbus_write_word_swapped(cl, 3, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
871
872
873
  			break;
  		}
  	}
  
  	if (bank > 2)
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
874
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
878
879
  }
  
  static void asb100_init_client(struct i2c_client *client)
  {
  	struct asb100_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880

303760b44   Jean Delvare   [PATCH] hwmon: hw...
881
  	data->vrm = vid_which_vrm();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  
  	/* Start monitoring */
af2219315   Jean Delvare   hwmon: (asb100) V...
884
  	asb100_write_value(client, ASB100_REG_CONFIG,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
892
  		(asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01);
  }
  
  static struct asb100_data *asb100_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	int i;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
893
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
  
  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
  		|| !data->valid) {
  
  		dev_dbg(&client->dev, "starting device update...
  ");
  
  		/* 7 voltage inputs */
  		for (i = 0; i < 7; i++) {
  			data->in[i] = asb100_read_value(client,
  				ASB100_REG_IN(i));
  			data->in_min[i] = asb100_read_value(client,
  				ASB100_REG_IN_MIN(i));
  			data->in_max[i] = asb100_read_value(client,
  				ASB100_REG_IN_MAX(i));
  		}
  
  		/* 3 fan inputs */
  		for (i = 0; i < 3; i++) {
  			data->fan[i] = asb100_read_value(client,
  					ASB100_REG_FAN(i));
  			data->fan_min[i] = asb100_read_value(client,
  					ASB100_REG_FAN_MIN(i));
  		}
  
  		/* 4 temperature inputs */
  		for (i = 1; i <= 4; i++) {
  			data->temp[i-1] = asb100_read_value(client,
  					ASB100_REG_TEMP(i));
  			data->temp_max[i-1] = asb100_read_value(client,
  					ASB100_REG_TEMP_MAX(i));
  			data->temp_hyst[i-1] = asb100_read_value(client,
  					ASB100_REG_TEMP_HYST(i));
  		}
  
  		/* VID and fan divisors */
  		i = asb100_read_value(client, ASB100_REG_VID_FANDIV);
  		data->vid = i & 0x0f;
  		data->vid |= (asb100_read_value(client,
  				ASB100_REG_CHIPID) & 0x01) << 4;
  		data->fan_div[0] = (i >> 4) & 0x03;
  		data->fan_div[1] = (i >> 6) & 0x03;
  		data->fan_div[2] = (asb100_read_value(client,
  				ASB100_REG_PIN) >> 6) & 0x03;
  
  		/* PWM */
  		data->pwm = asb100_read_value(client, ASB100_REG_PWM1);
  
  		/* alarms */
  		data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) +
  			(asb100_read_value(client, ASB100_REG_ALARM2) << 8);
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  
  		dev_dbg(&client->dev, "... device update complete
  ");
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
952
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  
  	return data;
  }
  
  static int __init asb100_init(void)
  {
  	return i2c_add_driver(&asb100_driver);
  }
  
  static void __exit asb100_exit(void)
  {
  	i2c_del_driver(&asb100_driver);
  }
  
  MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
  MODULE_DESCRIPTION("ASB100 Bach driver");
  MODULE_LICENSE("GPL");
  
  module_init(asb100_init);
  module_exit(asb100_exit);