Blame view

drivers/hwmon/asb100.c 27.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
8c103696f   Guenter Roeck   hwmon: (asb100): ...
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
   * 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.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  
  /*
8c103696f   Guenter Roeck   hwmon: (asb100): ...
29
30
31
32
33
34
   * 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.
   *
4101ece3a   Jean Delvare   hwmon: Fix chip f...
35
   * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
8c103696f   Guenter Roeck   hwmon: (asb100): ...
36
37
   * asb100	7	3	1	4	0x31	0x0694	yes	no
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

4d630e2ba   Joe Perches   hwmon: (asb1000) ...
39
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
43
  #include <linux/hwmon.h>
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
44
  #include <linux/hwmon-sysfs.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
45
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
46
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include <linux/init.h>
ff3240946   Dominik Hackl   [PATCH] I2C: incl...
48
  #include <linux/jiffies.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
49
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #include "lm75.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  /* I2C addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
52
  static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

3aed198c3   Jean Delvare   hwmon: Don't over...
54
55
  static unsigned short force_subclients[4];
  module_param_array(force_subclients, short, NULL, 0);
b55f37572   Guenter Roeck   hwmon: Fix checkp...
56
57
  MODULE_PARM_DESC(force_subclients,
  	"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  
  /* 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
8c103696f   Guenter Roeck   hwmon: (asb100): ...
99
100
101
102
  /*
   * CONVERSIONS
   * Rounding and limit checking is only done on the TO_REG variants.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  
  /* These constants are a guess, consistent w/ w83781d */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
105
106
  #define ASB100_IN_MIN		0
  #define ASB100_IN_MAX		4080
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

8c103696f   Guenter Roeck   hwmon: (asb100): ...
108
109
110
111
  /*
   * IN: 1/1000 V (0V to 4.08V)
   * REG: 16mV/bit
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  static u8 IN_TO_REG(unsigned val)
  {
2a844c148   Guenter Roeck   hwmon: Replace SE...
114
  	unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  	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;
2a844c148   Guenter Roeck   hwmon: Replace SE...
129
130
  	rpm = clamp_val(rpm, 1, 1000000);
  	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
  }
  
  static int FAN_FROM_REG(u8 val, int div)
  {
8c103696f   Guenter Roeck   hwmon: (asb100): ...
135
  	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
  }
  
  /* These constants are a guess, consistent w/ w83781d */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
139
140
  #define ASB100_TEMP_MIN		-128000
  #define ASB100_TEMP_MAX		127000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

8c103696f   Guenter Roeck   hwmon: (asb100): ...
142
143
144
145
  /*
   * TEMP: 0.001C/bit (-128C to +127C)
   * REG: 1C/bit, two's complement
   */
5bfedac04   Christian Hohnstaedt   hwmon: Allow writ...
146
  static u8 TEMP_TO_REG(long temp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  {
2a844c148   Guenter Roeck   hwmon: Replace SE...
148
  	int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
149
  	ntemp += (ntemp < 0 ? -500 : 500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
  	return (u8)(ntemp / 1000);
  }
  
  static int TEMP_FROM_REG(u8 reg)
  {
  	return (s8)reg * 1000;
  }
8c103696f   Guenter Roeck   hwmon: (asb100): ...
157
158
159
160
  /*
   * PWM: 0 - 255 per sensors documentation
   * REG: (6.25% duty cycle per bit)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  static u8 ASB100_PWM_TO_REG(int pwm)
  {
2a844c148   Guenter Roeck   hwmon: Replace SE...
163
  	pwm = clamp_val(pwm, 0, 255);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
169
170
  	return (u8)(pwm / 16);
  }
  
  static int ASB100_PWM_FROM_REG(u8 reg)
  {
  	return reg * 16;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  #define DIV_FROM_REG(val) (1 << (val))
8c103696f   Guenter Roeck   hwmon: (asb100): ...
172
173
174
175
  /*
   * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
   * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  static u8 DIV_TO_REG(long val)
  {
8c103696f   Guenter Roeck   hwmon: (asb100): ...
178
  	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  }
8c103696f   Guenter Roeck   hwmon: (asb100): ...
180
181
182
183
184
  /*
   * 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.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  struct asb100_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
186
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
187
  	struct mutex lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
189
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  	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...
213
214
  static int asb100_probe(struct i2c_client *client,
  			const struct i2c_device_id *id);
310ec7921   Jean Delvare   i2c: Drop the kin...
215
  static int asb100_detect(struct i2c_client *client,
063675b15   Jean Delvare   hwmon: (asb100) C...
216
217
  			 struct i2c_board_info *info);
  static int asb100_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  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...
220
  static const struct i2c_device_id asb100_id[] = {
1f86df49d   Jean Delvare   i2c: Drop I2C_CLI...
221
  	{ "asb100", 0 },
063675b15   Jean Delvare   hwmon: (asb100) C...
222
223
224
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, asb100_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  static struct i2c_driver asb100_driver = {
063675b15   Jean Delvare   hwmon: (asb100) C...
226
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
227
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
228
229
  		.name	= "asb100",
  	},
063675b15   Jean Delvare   hwmon: (asb100) C...
230
231
232
233
  	.probe		= asb100_probe,
  	.remove		= asb100_remove,
  	.id_table	= asb100_id,
  	.detect		= asb100_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
234
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
  };
  
  /* 7 Voltages */
  #define show_in_reg(reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
239
240
  static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
  		char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
242
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
251
252
  	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...
253
254
  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
255
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
256
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct asb100_data *data = i2c_get_clientdata(client); \
8c103696f   Guenter Roeck   hwmon: (asb100): ...
259
260
261
262
  	unsigned long val; \
  	int err = kstrtoul(buf, 10, &val); \
  	if (err) \
  		return err; \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
263
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
  	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...
267
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
  	return count; \
  }
  
  set_in_reg(MIN, min)
  set_in_reg(MAX, max)
  
  #define sysfs_in(offset) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
275
276
277
278
279
280
  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
281
282
283
284
285
286
287
288
  
  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
289
  /* 3 Fans */
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
290
291
  static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
293
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
  	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...
299
300
  static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
302
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
  	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...
308
309
  static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
311
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
  	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...
316
317
  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
318
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
319
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
322
323
324
325
326
327
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
329
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
  	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...
332
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  	return count;
  }
8c103696f   Guenter Roeck   hwmon: (asb100): ...
335
336
337
338
339
340
  /*
   * 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
   * least surprise; the user doesn't expect the fan minimum to change just
   * because the divisor changed.
   */
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
341
342
  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
343
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
344
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
  	unsigned long min;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	int reg;
8c103696f   Guenter Roeck   hwmon: (asb100): ...
349
350
351
352
353
354
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
af2219315   Jean Delvare   hwmon: (asb100) V...
355

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
356
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  
  	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...
361
  	switch (nr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	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...
384
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
  
  	return count;
  }
  
  #define sysfs_fan(offset) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
390
391
392
393
394
395
  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
396
397
398
399
  
  sysfs_fan(1);
  sysfs_fan(2);
  sysfs_fan(3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  /* 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...
417

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  #define show_temp_reg(reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
419
420
  static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
  		char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
422
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
  	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...
432
433
  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
434
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
435
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct asb100_data *data = i2c_get_clientdata(client); \
8c103696f   Guenter Roeck   hwmon: (asb100): ...
438
439
440
441
  	long val; \
  	int err = kstrtol(buf, 10, &val); \
  	if (err) \
  		return err; \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
442
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
446
447
448
449
450
451
452
  	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...
453
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
458
459
460
  	return count; \
  }
  
  set_temp_reg(MAX, temp_max);
  set_temp_reg(HYST, temp_hyst);
  
  #define sysfs_temp(num) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
461
462
463
464
465
466
  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
467
468
469
470
471
472
473
  
  sysfs_temp(1);
  sysfs_temp(2);
  sysfs_temp(3);
  sysfs_temp(4);
  
  /* VID */
af2219315   Jean Delvare   hwmon: (asb100) V...
474
475
  static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
481
482
  {
  	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
483
484
  
  /* VRM */
af2219315   Jean Delvare   hwmon: (asb100) V...
485
486
  static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  {
90d6619a9   Jean Delvare   hwmon: VRM is not...
488
  	struct asb100_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
  	return sprintf(buf, "%d
  ", data->vrm);
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
492
493
  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
494
  {
8f74efe81   Jean Delvare   hwmon: VRM is not...
495
  	struct asb100_data *data = dev_get_drvdata(dev);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
496
497
498
499
500
501
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
db59ac434   Axel Lin   hwmon: (asb100) F...
502
503
504
  
  	if (val > 255)
  		return -EINVAL;
8c103696f   Guenter Roeck   hwmon: (asb100): ...
505
  	data->vrm = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
  	return count;
  }
  
  /* Alarms */
  static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511

af2219315   Jean Delvare   hwmon: (asb100) V...
512
513
  static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
  {
  	struct asb100_data *data = asb100_update_device(dev);
68188ba7d   Jean Delvare   [PATCH] I2C: Kill...
516
517
  	return sprintf(buf, "%u
  ", data->alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
  }
  
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521

636866b9f   Jean Delvare   hwmon: (asb100) A...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  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
541
  /* 1 PWM */
af2219315   Jean Delvare   hwmon: (asb100) V...
542
543
  static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr,
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
  {
  	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...
549
550
  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
551
552
553
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
554
555
556
557
558
559
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
561
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  	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...
565
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
  	return count;
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
568
569
  static ssize_t show_pwm_enable1(struct device *dev,
  		struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", (data->pwm & 0x80) ? 1 : 0);
  }
af2219315   Jean Delvare   hwmon: (asb100) V...
575
576
  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
577
578
579
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
580
581
582
583
584
585
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
587
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
  	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...
591
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
  	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...
598
599
  
  static struct attribute *asb100_attributes[] = {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  	&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...
644

636866b9f   Jean Delvare   hwmon: (asb100) A...
645
646
647
648
649
650
651
652
653
654
655
  	&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...
656
657
658
659
660
661
662
663
664
665
666
667
  	&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
668

063675b15   Jean Delvare   hwmon: (asb100) C...
669
  static int asb100_detect_subclients(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
  {
  	int i, id, err;
063675b15   Jean Delvare   hwmon: (asb100) C...
672
673
  	int address = client->addr;
  	unsigned short sc_addr[2];
af2219315   Jean Delvare   hwmon: (asb100) V...
674
  	struct asb100_data *data = i2c_get_clientdata(client);
063675b15   Jean Delvare   hwmon: (asb100) C...
675
  	struct i2c_adapter *adapter = client->adapter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
680
681
682
  
  	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) {
b55f37572   Guenter Roeck   hwmon: Fix checkp...
683
684
685
  				dev_err(&client->dev,
  					"invalid subclient address %d; must be 0x48-0x4f
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
  					force_subclients[i]);
  				err = -ENODEV;
  				goto ERROR_SC_2;
  			}
  		}
af2219315   Jean Delvare   hwmon: (asb100) V...
691
  		asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  					(force_subclients[2] & 0x07) |
af2219315   Jean Delvare   hwmon: (asb100) V...
693
  					((force_subclients[3] & 0x07) << 4));
063675b15   Jean Delvare   hwmon: (asb100) C...
694
695
  		sc_addr[0] = force_subclients[2];
  		sc_addr[1] = force_subclients[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  	} else {
af2219315   Jean Delvare   hwmon: (asb100) V...
697
  		int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
063675b15   Jean Delvare   hwmon: (asb100) C...
698
699
  		sc_addr[0] = 0x48 + (val & 0x07);
  		sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
701
  	if (sc_addr[0] == sc_addr[1]) {
b55f37572   Guenter Roeck   hwmon: Fix checkp...
702
703
704
705
  		dev_err(&client->dev,
  			"duplicate addresses 0x%x for subclients
  ",
  			sc_addr[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
  		err = -ENODEV;
  		goto ERROR_SC_2;
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
709
710
  	data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
  	if (!data->lm75[0]) {
b55f37572   Guenter Roeck   hwmon: Fix checkp...
711
712
713
714
  		dev_err(&client->dev,
  			"subclient %d registration at address 0x%x failed.
  ",
  			1, sc_addr[0]);
063675b15   Jean Delvare   hwmon: (asb100) C...
715
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
  		goto ERROR_SC_2;
  	}
063675b15   Jean Delvare   hwmon: (asb100) C...
718
719
  	data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
  	if (!data->lm75[1]) {
b55f37572   Guenter Roeck   hwmon: Fix checkp...
720
721
722
723
  		dev_err(&client->dev,
  			"subclient %d registration at address 0x%x failed.
  ",
  			2, sc_addr[1]);
063675b15   Jean Delvare   hwmon: (asb100) C...
724
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
730
731
  		goto ERROR_SC_3;
  	}
  
  	return 0;
  
  /* Undo inits in case of errors */
  ERROR_SC_3:
063675b15   Jean Delvare   hwmon: (asb100) C...
732
  	i2c_unregister_device(data->lm75[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  ERROR_SC_2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  	return err;
  }
063675b15   Jean Delvare   hwmon: (asb100) C...
736
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
737
  static int asb100_detect(struct i2c_client *client,
063675b15   Jean Delvare   hwmon: (asb100) C...
738
  			 struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
  {
063675b15   Jean Delvare   hwmon: (asb100) C...
740
  	struct i2c_adapter *adapter = client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
741
  	int val1, val2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
744
745
  		pr_debug("detect failed, smbus byte data not supported!
  ");
063675b15   Jean Delvare   hwmon: (asb100) C...
746
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
748
749
  	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
750

52df6440a   Jean Delvare   hwmon: Clean up d...
751
752
753
754
755
756
  	/* 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) ...
757
758
  		pr_debug("detect failed, bad chip id 0x%02x!
  ", val2);
52df6440a   Jean Delvare   hwmon: Clean up d...
759
760
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761

52df6440a   Jean Delvare   hwmon: Clean up d...
762
  	/* Put it now into bank 0 and Vendor ID High Byte */
063675b15   Jean Delvare   hwmon: (asb100) C...
763
764
765
  	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
766
767
  
  	/* Determine the chip type. */
52df6440a   Jean Delvare   hwmon: Clean up d...
768
769
770
771
772
  	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
773

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

063675b15   Jean Delvare   hwmon: (asb100) C...
776
777
778
779
780
781
782
783
  	return 0;
  }
  
  static int asb100_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
  {
  	int err;
  	struct asb100_data *data;
64adf3983   Guenter Roeck   hwmon: (asb100) C...
784
785
786
787
  	data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
  			    GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
063675b15   Jean Delvare   hwmon: (asb100) C...
788
789
790
791
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->lock);
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
  
  	/* Attach secondary lm75 clients */
063675b15   Jean Delvare   hwmon: (asb100) C...
794
795
  	err = asb100_detect_subclients(client);
  	if (err)
64adf3983   Guenter Roeck   hwmon: (asb100) C...
796
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
  
  	/* Initialize the chip */
af2219315   Jean Delvare   hwmon: (asb100) V...
799
  	asb100_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
  
  	/* A few vars need to be filled upon startup */
af2219315   Jean Delvare   hwmon: (asb100) V...
802
803
804
  	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
805
806
  
  	/* Register sysfs hooks */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
807
808
  	err = sysfs_create_group(&client->dev.kobj, &asb100_group);
  	if (err)
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
809
  		goto ERROR3;
af2219315   Jean Delvare   hwmon: (asb100) V...
810
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
811
812
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
813
  		goto ERROR4;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
814
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  	return 0;
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
816
  ERROR4:
af2219315   Jean Delvare   hwmon: (asb100) V...
817
  	sysfs_remove_group(&client->dev.kobj, &asb100_group);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
818
  ERROR3:
063675b15   Jean Delvare   hwmon: (asb100) C...
819
820
  	i2c_unregister_device(data->lm75[1]);
  	i2c_unregister_device(data->lm75[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  	return err;
  }
063675b15   Jean Delvare   hwmon: (asb100) C...
823
  static int asb100_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
825
  	struct asb100_data *data = i2c_get_clientdata(client);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
826

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
  	return 0;
  }
8c103696f   Guenter Roeck   hwmon: (asb100): ...
835
836
837
838
  /*
   * The SMBus locks itself, usually, but nothing may access the chip between
   * bank switches.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
841
842
843
  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...
844
  	mutex_lock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  
  	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...
860
  			res = i2c_smbus_read_word_swapped(cl, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
865
  			break;
  		case 0x52: /* CONFIG */
  			res = i2c_smbus_read_byte_data(cl, 1);
  			break;
  		case 0x53: /* HYST */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
866
  			res = i2c_smbus_read_word_swapped(cl, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
  			break;
  		case 0x55: /* MAX */
  		default:
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
870
  			res = i2c_smbus_read_word_swapped(cl, 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
876
  			break;
  		}
  	}
  
  	if (bank > 2)
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
877
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
884
885
886
  
  	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...
887
  	mutex_lock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  
  	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...
906
  			i2c_smbus_write_word_swapped(cl, 2, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
  			break;
  		case 0x55: /* MAX */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
909
  			i2c_smbus_write_word_swapped(cl, 3, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
912
913
914
915
  			break;
  		}
  	}
  
  	if (bank > 2)
  		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
916
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
  }
  
  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
922

303760b44   Jean Delvare   [PATCH] hwmon: hw...
923
  	data->vrm = vid_which_vrm();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
  
  	/* Start monitoring */
af2219315   Jean Delvare   hwmon: (asb100) V...
926
  	asb100_write_value(client, ASB100_REG_CONFIG,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
933
934
  		(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...
935
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
  
  	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...
994
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
  
  	return data;
  }
f0967eea8   Axel Lin   hwmon: convert dr...
998
  module_i2c_driver(asb100_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
  
  MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
  MODULE_DESCRIPTION("ASB100 Bach driver");
  MODULE_LICENSE("GPL");