Blame view

drivers/hwmon/asb100.c 27.1 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
8c103696f   Guenter Roeck   hwmon: (asb100): ...
3
4
5
6
7
8
9
10
11
12
   * 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>
8c103696f   Guenter Roeck   hwmon: (asb100): ...
13
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  
  /*
8c103696f   Guenter Roeck   hwmon: (asb100): ...
16
17
18
19
20
21
   * 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...
22
   * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
8c103696f   Guenter Roeck   hwmon: (asb100): ...
23
24
   * asb100	7	3	1	4	0x31	0x0694	yes	no
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

4d630e2ba   Joe Perches   hwmon: (asb1000) ...
26
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
30
  #include <linux/hwmon.h>
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
31
  #include <linux/hwmon-sysfs.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
32
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
33
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/init.h>
ff3240946   Dominik Hackl   [PATCH] I2C: incl...
35
  #include <linux/jiffies.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
36
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  #include "lm75.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  /* I2C addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
39
  static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

3aed198c3   Jean Delvare   hwmon: Don't over...
41
42
  static unsigned short force_subclients[4];
  module_param_array(force_subclients, short, NULL, 0);
b55f37572   Guenter Roeck   hwmon: Fix checkp...
43
44
  MODULE_PARM_DESC(force_subclients,
  	"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
53
54
55
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
  
  /* 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): ...
86
87
88
89
  /*
   * CONVERSIONS
   * Rounding and limit checking is only done on the TO_REG variants.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
  
  /* These constants are a guess, consistent w/ w83781d */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
92
93
  #define ASB100_IN_MIN		0
  #define ASB100_IN_MAX		4080
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

8c103696f   Guenter Roeck   hwmon: (asb100): ...
95
96
97
98
  /*
   * IN: 1/1000 V (0V to 4.08V)
   * REG: 16mV/bit
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
  static u8 IN_TO_REG(unsigned val)
  {
2a844c148   Guenter Roeck   hwmon: Replace SE...
101
  	unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  	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...
116
117
  	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
118
119
120
121
  }
  
  static int FAN_FROM_REG(u8 val, int div)
  {
8c103696f   Guenter Roeck   hwmon: (asb100): ...
122
  	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
  }
  
  /* These constants are a guess, consistent w/ w83781d */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
126
127
  #define ASB100_TEMP_MIN		-128000
  #define ASB100_TEMP_MAX		127000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

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

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

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
315
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  	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...
318
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	return count;
  }
8c103696f   Guenter Roeck   hwmon: (asb100): ...
321
322
323
324
325
326
  /*
   * 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...
327
328
  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
329
  {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
330
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
  	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
334
  	int reg;
8c103696f   Guenter Roeck   hwmon: (asb100): ...
335
336
337
338
339
340
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
af2219315   Jean Delvare   hwmon: (asb100) V...
341

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
342
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
  
  	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...
347
  	switch (nr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  	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...
370
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
  
  	return count;
  }
  
  #define sysfs_fan(offset) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
376
377
378
379
380
381
  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
382
383
384
385
  
  sysfs_fan(1);
  sysfs_fan(2);
  sysfs_fan(3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  /* 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...
403

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  #define show_temp_reg(reg) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
405
406
  static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
  		char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
408
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
416
417
  	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...
418
419
  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
420
  { \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
421
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct asb100_data *data = i2c_get_clientdata(client); \
8c103696f   Guenter Roeck   hwmon: (asb100): ...
424
425
426
427
  	long val; \
  	int err = kstrtol(buf, 10, &val); \
  	if (err) \
  		return err; \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
428
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
436
437
438
  	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...
439
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
443
444
445
446
  	return count; \
  }
  
  set_temp_reg(MAX, temp_max);
  set_temp_reg(HYST, temp_hyst);
  
  #define sysfs_temp(num) \
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
447
448
449
450
451
452
  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
453
454
455
456
457
458
459
  
  sysfs_temp(1);
  sysfs_temp(2);
  sysfs_temp(3);
  sysfs_temp(4);
  
  /* VID */
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
460
461
  static ssize_t cpu0_vid_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", vid_from_reg(data->vid, data->vrm));
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
467
  static DEVICE_ATTR_RO(cpu0_vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  
  /* VRM */
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
470
  static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
af2219315   Jean Delvare   hwmon: (asb100) V...
471
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  {
90d6619a9   Jean Delvare   hwmon: VRM is not...
473
  	struct asb100_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
  	return sprintf(buf, "%d
  ", data->vrm);
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
477
478
  static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
  			 const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  {
8f74efe81   Jean Delvare   hwmon: VRM is not...
480
  	struct asb100_data *data = dev_get_drvdata(dev);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
481
482
483
484
485
486
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
db59ac434   Axel Lin   hwmon: (asb100) F...
487
488
489
  
  	if (val > 255)
  		return -EINVAL;
8c103696f   Guenter Roeck   hwmon: (asb100): ...
490
  	data->vrm = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
  	return count;
  }
  
  /* Alarms */
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
495
  static DEVICE_ATTR_RW(vrm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

82e73f7f9   Julia Lawall   hwmon: (asb100) u...
497
  static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
af2219315   Jean Delvare   hwmon: (asb100) V...
498
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
  {
  	struct asb100_data *data = asb100_update_device(dev);
68188ba7d   Jean Delvare   [PATCH] I2C: Kill...
501
502
  	return sprintf(buf, "%u
  ", data->alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
504
  static DEVICE_ATTR_RO(alarms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505

636866b9f   Jean Delvare   hwmon: (asb100) A...
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  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
525
  /* 1 PWM */
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
526
  static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr,
af2219315   Jean Delvare   hwmon: (asb100) V...
527
  		char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", ASB100_PWM_FROM_REG(data->pwm & 0x0f));
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
533
534
  static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
538
539
540
541
542
543
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
545
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
  	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...
549
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
  	return count;
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
552
  static ssize_t pwm1_enable_show(struct device *dev,
af2219315   Jean Delvare   hwmon: (asb100) V...
553
  		struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
  {
  	struct asb100_data *data = asb100_update_device(dev);
  	return sprintf(buf, "%d
  ", (data->pwm & 0x80) ? 1 : 0);
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
559
560
561
  static ssize_t pwm1_enable_store(struct device *dev,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct asb100_data *data = i2c_get_clientdata(client);
8c103696f   Guenter Roeck   hwmon: (asb100): ...
565
566
567
568
569
570
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
572
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
  	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...
576
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  	return count;
  }
82e73f7f9   Julia Lawall   hwmon: (asb100) u...
579
580
  static DEVICE_ATTR_RW(pwm1);
  static DEVICE_ATTR_RW(pwm1_enable);
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
581
582
  
  static struct attribute *asb100_attributes[] = {
fad33c5fd   Jean Delvare   hwmon: (asb100) D...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
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
  	&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...
627

636866b9f   Jean Delvare   hwmon: (asb100) A...
628
629
630
631
632
633
634
635
636
637
638
  	&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...
639
640
641
642
643
644
645
646
647
648
649
650
  	&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
651

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
4d630e2ba   Joe Perches   hwmon: (asb1000) ...
727
728
  		pr_debug("detect failed, smbus byte data not supported!
  ");
063675b15   Jean Delvare   hwmon: (asb100) C...
729
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	}
52df6440a   Jean Delvare   hwmon: Clean up d...
731
732
  	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
733

52df6440a   Jean Delvare   hwmon: Clean up d...
734
735
736
737
738
739
  	/* 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) ...
740
741
  		pr_debug("detect failed, bad chip id 0x%02x!
  ", val2);
52df6440a   Jean Delvare   hwmon: Clean up d...
742
743
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744

52df6440a   Jean Delvare   hwmon: Clean up d...
745
  	/* Put it now into bank 0 and Vendor ID High Byte */
063675b15   Jean Delvare   hwmon: (asb100) C...
746
747
748
  	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
749
750
  
  	/* Determine the chip type. */
52df6440a   Jean Delvare   hwmon: Clean up d...
751
752
753
754
755
  	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
756

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

063675b15   Jean Delvare   hwmon: (asb100) C...
759
760
  	return 0;
  }
674870385   Stephen Kitt   hwmon: use simple...
761
  static int asb100_probe(struct i2c_client *client)
063675b15   Jean Delvare   hwmon: (asb100) C...
762
763
764
  {
  	int err;
  	struct asb100_data *data;
64adf3983   Guenter Roeck   hwmon: (asb100) C...
765
766
767
768
  	data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
  			    GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
063675b15   Jean Delvare   hwmon: (asb100) C...
769
770
771
772
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->lock);
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  
  	/* Attach secondary lm75 clients */
063675b15   Jean Delvare   hwmon: (asb100) C...
775
776
  	err = asb100_detect_subclients(client);
  	if (err)
64adf3983   Guenter Roeck   hwmon: (asb100) C...
777
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
  
  	/* Initialize the chip */
af2219315   Jean Delvare   hwmon: (asb100) V...
780
  	asb100_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
  
  	/* A few vars need to be filled upon startup */
af2219315   Jean Delvare   hwmon: (asb100) V...
783
784
785
  	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
786
787
  
  	/* Register sysfs hooks */
8c103696f   Guenter Roeck   hwmon: (asb100): ...
788
789
  	err = sysfs_create_group(&client->dev.kobj, &asb100_group);
  	if (err)
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
790
  		goto ERROR3;
af2219315   Jean Delvare   hwmon: (asb100) V...
791
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
792
793
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
794
  		goto ERROR4;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
795
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  	return 0;
c1685f61b   Mark M. Hoffman   hwmon: Fix unchec...
797
  ERROR4:
af2219315   Jean Delvare   hwmon: (asb100) V...
798
  	sysfs_remove_group(&client->dev.kobj, &asb100_group);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
799
  ERROR3:
063675b15   Jean Delvare   hwmon: (asb100) C...
800
801
  	i2c_unregister_device(data->lm75[1]);
  	i2c_unregister_device(data->lm75[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  	return err;
  }
063675b15   Jean Delvare   hwmon: (asb100) C...
804
  static int asb100_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
806
  	struct asb100_data *data = i2c_get_clientdata(client);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
807

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

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

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

303760b44   Jean Delvare   [PATCH] hwmon: hw...
904
  	data->vrm = vid_which_vrm();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
  
  	/* Start monitoring */
af2219315   Jean Delvare   hwmon: (asb100) V...
907
  	asb100_write_value(client, ASB100_REG_CONFIG,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
915
  		(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...
916
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  
  	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...
975
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
  
  	return data;
  }
f0967eea8   Axel Lin   hwmon: convert dr...
979
  module_i2c_driver(asb100_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
  
  MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
  MODULE_DESCRIPTION("ASB100 Bach driver");
  MODULE_LICENSE("GPL");