blob: ba0c28015f6af57dc17a3c30ba02edbe0e874cdf [file] [log] [blame]
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001/*
2 w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (C) 2004, 2005 Winbond Electronics Corp.
5 Chunhao Huang <DZShen@Winbond.com.tw>,
6 Rudolf Marek <r.marek@sh.cvut.cz>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 Note:
23 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver.
24 2. This driver is only for Winbond W83792D C version device, there
25 are also some motherboards with B version W83792D device. The
26 calculation method to in6-in7(measured value, limits) is a little
27 different between C and B version. C or B version can be identified
28 by CR[0x49h].
29*/
30
31/*
32 Supports following chips:
33
34 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
35 w83792d 9 7 7 3 0x7a 0x5ca3 yes no
36*/
37
38#include <linux/config.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/slab.h>
42#include <linux/i2c.h>
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +000043#include <linux/hwmon.h>
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +000044#include <linux/hwmon-sysfs.h>
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +000045#include <linux/err.h>
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +000046
47/* Addresses to scan */
48static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
49
50/* Insmod parameters */
Jean Delvaref4b50262005-07-31 21:49:03 +020051I2C_CLIENT_INSMOD_1(w83792d);
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +000052I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
53 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
54
55static int init;
56module_param(init, bool, 0);
57MODULE_PARM_DESC(init, "Set to one to force chip initialization");
58
59/* The W83792D registers */
60static const u8 W83792D_REG_IN[9] = {
61 0x20, /* Vcore A in DataSheet */
62 0x21, /* Vcore B in DataSheet */
63 0x22, /* VIN0 in DataSheet */
64 0x23, /* VIN1 in DataSheet */
65 0x24, /* VIN2 in DataSheet */
66 0x25, /* VIN3 in DataSheet */
67 0x26, /* 5VCC in DataSheet */
68 0xB0, /* 5VSB in DataSheet */
69 0xB1 /* VBAT in DataSheet */
70};
71#define W83792D_REG_LOW_BITS1 0x3E /* Low Bits I in DataSheet */
72#define W83792D_REG_LOW_BITS2 0x3F /* Low Bits II in DataSheet */
73static const u8 W83792D_REG_IN_MAX[9] = {
74 0x2B, /* Vcore A High Limit in DataSheet */
75 0x2D, /* Vcore B High Limit in DataSheet */
76 0x2F, /* VIN0 High Limit in DataSheet */
77 0x31, /* VIN1 High Limit in DataSheet */
78 0x33, /* VIN2 High Limit in DataSheet */
79 0x35, /* VIN3 High Limit in DataSheet */
80 0x37, /* 5VCC High Limit in DataSheet */
81 0xB4, /* 5VSB High Limit in DataSheet */
82 0xB6 /* VBAT High Limit in DataSheet */
83};
84static const u8 W83792D_REG_IN_MIN[9] = {
85 0x2C, /* Vcore A Low Limit in DataSheet */
86 0x2E, /* Vcore B Low Limit in DataSheet */
87 0x30, /* VIN0 Low Limit in DataSheet */
88 0x32, /* VIN1 Low Limit in DataSheet */
89 0x34, /* VIN2 Low Limit in DataSheet */
90 0x36, /* VIN3 Low Limit in DataSheet */
91 0x38, /* 5VCC Low Limit in DataSheet */
92 0xB5, /* 5VSB Low Limit in DataSheet */
93 0xB7 /* VBAT Low Limit in DataSheet */
94};
95static const u8 W83792D_REG_FAN[7] = {
96 0x28, /* FAN 1 Count in DataSheet */
97 0x29, /* FAN 2 Count in DataSheet */
98 0x2A, /* FAN 3 Count in DataSheet */
99 0xB8, /* FAN 4 Count in DataSheet */
100 0xB9, /* FAN 5 Count in DataSheet */
101 0xBA, /* FAN 6 Count in DataSheet */
102 0xBE /* FAN 7 Count in DataSheet */
103};
104static const u8 W83792D_REG_FAN_MIN[7] = {
105 0x3B, /* FAN 1 Count Low Limit in DataSheet */
106 0x3C, /* FAN 2 Count Low Limit in DataSheet */
107 0x3D, /* FAN 3 Count Low Limit in DataSheet */
108 0xBB, /* FAN 4 Count Low Limit in DataSheet */
109 0xBC, /* FAN 5 Count Low Limit in DataSheet */
110 0xBD, /* FAN 6 Count Low Limit in DataSheet */
111 0xBF /* FAN 7 Count Low Limit in DataSheet */
112};
113#define W83792D_REG_FAN_CFG 0x84 /* FAN Configuration in DataSheet */
114static const u8 W83792D_REG_FAN_DIV[4] = {
115 0x47, /* contains FAN2 and FAN1 Divisor */
116 0x5B, /* contains FAN4 and FAN3 Divisor */
117 0x5C, /* contains FAN6 and FAN5 Divisor */
118 0x9E /* contains FAN7 Divisor. */
119};
120static const u8 W83792D_REG_PWM[7] = {
121 0x81, /* FAN 1 Duty Cycle, be used to control */
122 0x83, /* FAN 2 Duty Cycle, be used to control */
123 0x94, /* FAN 3 Duty Cycle, be used to control */
124 0xA3, /* FAN 4 Duty Cycle, be used to control */
125 0xA4, /* FAN 5 Duty Cycle, be used to control */
126 0xA5, /* FAN 6 Duty Cycle, be used to control */
127 0xA6 /* FAN 7 Duty Cycle, be used to control */
128};
129#define W83792D_REG_BANK 0x4E
130#define W83792D_REG_TEMP2_CONFIG 0xC2
131#define W83792D_REG_TEMP3_CONFIG 0xCA
132
133static const u8 W83792D_REG_TEMP1[3] = {
134 0x27, /* TEMP 1 in DataSheet */
135 0x39, /* TEMP 1 Over in DataSheet */
136 0x3A, /* TEMP 1 Hyst in DataSheet */
137};
138
139static const u8 W83792D_REG_TEMP_ADD[2][6] = {
140 { 0xC0, /* TEMP 2 in DataSheet */
141 0xC1, /* TEMP 2(0.5 deg) in DataSheet */
142 0xC5, /* TEMP 2 Over High part in DataSheet */
143 0xC6, /* TEMP 2 Over Low part in DataSheet */
144 0xC3, /* TEMP 2 Thyst High part in DataSheet */
145 0xC4 }, /* TEMP 2 Thyst Low part in DataSheet */
146 { 0xC8, /* TEMP 3 in DataSheet */
147 0xC9, /* TEMP 3(0.5 deg) in DataSheet */
148 0xCD, /* TEMP 3 Over High part in DataSheet */
149 0xCE, /* TEMP 3 Over Low part in DataSheet */
150 0xCB, /* TEMP 3 Thyst High part in DataSheet */
151 0xCC } /* TEMP 3 Thyst Low part in DataSheet */
152};
153
154static const u8 W83792D_REG_THERMAL[3] = {
155 0x85, /* SmartFanI: Fan1 target value */
156 0x86, /* SmartFanI: Fan2 target value */
157 0x96 /* SmartFanI: Fan3 target value */
158};
159
160static const u8 W83792D_REG_TOLERANCE[3] = {
161 0x87, /* (bit3-0)SmartFan Fan1 tolerance */
162 0x87, /* (bit7-4)SmartFan Fan2 tolerance */
163 0x97 /* (bit3-0)SmartFan Fan3 tolerance */
164};
165
166static const u8 W83792D_REG_POINTS[3][4] = {
167 { 0x85, /* SmartFanII: Fan1 temp point 1 */
168 0xE3, /* SmartFanII: Fan1 temp point 2 */
169 0xE4, /* SmartFanII: Fan1 temp point 3 */
170 0xE5 }, /* SmartFanII: Fan1 temp point 4 */
171 { 0x86, /* SmartFanII: Fan2 temp point 1 */
172 0xE6, /* SmartFanII: Fan2 temp point 2 */
173 0xE7, /* SmartFanII: Fan2 temp point 3 */
174 0xE8 }, /* SmartFanII: Fan2 temp point 4 */
175 { 0x96, /* SmartFanII: Fan3 temp point 1 */
176 0xE9, /* SmartFanII: Fan3 temp point 2 */
177 0xEA, /* SmartFanII: Fan3 temp point 3 */
178 0xEB } /* SmartFanII: Fan3 temp point 4 */
179};
180
181static const u8 W83792D_REG_LEVELS[3][4] = {
182 { 0x88, /* (bit3-0) SmartFanII: Fan1 Non-Stop */
183 0x88, /* (bit7-4) SmartFanII: Fan1 Level 1 */
184 0xE0, /* (bit7-4) SmartFanII: Fan1 Level 2 */
185 0xE0 }, /* (bit3-0) SmartFanII: Fan1 Level 3 */
186 { 0x89, /* (bit3-0) SmartFanII: Fan2 Non-Stop */
187 0x89, /* (bit7-4) SmartFanII: Fan2 Level 1 */
188 0xE1, /* (bit7-4) SmartFanII: Fan2 Level 2 */
189 0xE1 }, /* (bit3-0) SmartFanII: Fan2 Level 3 */
190 { 0x98, /* (bit3-0) SmartFanII: Fan3 Non-Stop */
191 0x98, /* (bit7-4) SmartFanII: Fan3 Level 1 */
192 0xE2, /* (bit7-4) SmartFanII: Fan3 Level 2 */
193 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */
194};
195
196#define W83792D_REG_CONFIG 0x40
197#define W83792D_REG_VID_FANDIV 0x47
198#define W83792D_REG_CHIPID 0x49
199#define W83792D_REG_WCHIPID 0x58
200#define W83792D_REG_CHIPMAN 0x4F
201#define W83792D_REG_PIN 0x4B
202#define W83792D_REG_I2C_SUBADDR 0x4A
203
204#define W83792D_REG_ALARM1 0xA9 /* realtime status register1 */
205#define W83792D_REG_ALARM2 0xAA /* realtime status register2 */
206#define W83792D_REG_ALARM3 0xAB /* realtime status register3 */
207#define W83792D_REG_CHASSIS 0x42 /* Bit 5: Case Open status bit */
208#define W83792D_REG_CHASSIS_CLR 0x44 /* Bit 7: Case Open CLR_CHS/Reset bit */
209
210/* control in0/in1 's limit modifiability */
211#define W83792D_REG_VID_IN_B 0x17
212
213#define W83792D_REG_VBAT 0x5D
214#define W83792D_REG_I2C_ADDR 0x48
215
216/* Conversions. Rounding and limit checking is only done on the TO_REG
217 variants. Note that you should be a bit careful with which arguments
218 these macros are called: arguments may be evaluated more than once.
219 Fixing this is just not worth it. */
220#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \
221 ((((nr)==6)||((nr)==7))?(val*6):(val*4)))
222#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \
223 ((((nr)==6)||((nr)==7))?(val/6):(val/4)))
224
225static inline u8
226FAN_TO_REG(long rpm, int div)
227{
228 if (rpm == 0)
229 return 255;
230 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
231 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
232}
233
234#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
235 ((val) == 255 ? 0 : \
236 1350000 / ((val) * (div))))
237
238/* for temp1 */
239#define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
240 : (val)) / 1000, 0, 0xff))
241#define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
242/* for temp2 and temp3, because they need addtional resolution */
243#define TEMP_ADD_FROM_REG(val1, val2) \
244 ((((val1) & 0x80 ? (val1)-0x100 \
245 : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
246#define TEMP_ADD_TO_REG_HIGH(val) \
247 (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
248 : (val)) / 1000, 0, 0xff))
249#define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00)
250
251#define PWM_FROM_REG(val) (val)
252#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
253#define DIV_FROM_REG(val) (1 << (val))
254
255static inline u8
256DIV_TO_REG(long val)
257{
258 int i;
259 val = SENSORS_LIMIT(val, 1, 128) >> 1;
260 for (i = 0; i < 6; i++) {
261 if (val == 0)
262 break;
263 val >>= 1;
264 }
265 return ((u8) i);
266}
267
268struct w83792d_data {
269 struct i2c_client client;
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +0000270 struct class_device *class_dev;
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +0000271 struct semaphore lock;
272 enum chips type;
273
274 struct semaphore update_lock;
275 char valid; /* !=0 if following fields are valid */
276 unsigned long last_updated; /* In jiffies */
277
278 /* array of 2 pointers to subclients */
279 struct i2c_client *lm75[2];
280
281 u8 in[9]; /* Register value */
282 u8 in_max[9]; /* Register value */
283 u8 in_min[9]; /* Register value */
284 u8 low_bits[2]; /* Additional resolution to voltage in0-6 */
285 u8 fan[7]; /* Register value */
286 u8 fan_min[7]; /* Register value */
287 u8 temp1[3]; /* current, over, thyst */
288 u8 temp_add[2][6]; /* Register value */
289 u8 fan_div[7]; /* Register encoding, shifted right */
290 u8 pwm[7]; /* We only consider the first 3 set of pwm,
291 although 792 chip has 7 set of pwm. */
292 u8 pwmenable[3];
293 u8 pwm_mode[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */
294 u32 alarms; /* realtime status register encoding,combined */
295 u8 chassis; /* Chassis status */
296 u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */
297 u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */
298 u8 tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */
299 u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */
300 u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
301};
302
303static int w83792d_attach_adapter(struct i2c_adapter *adapter);
304static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
305static int w83792d_detach_client(struct i2c_client *client);
306
307static int w83792d_read_value(struct i2c_client *client, u8 register);
308static int w83792d_write_value(struct i2c_client *client, u8 register,
309 u8 value);
310static struct w83792d_data *w83792d_update_device(struct device *dev);
311
312#ifdef DEBUG
313static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
314#endif
315
316static void w83792d_init_client(struct i2c_client *client);
317
318static struct i2c_driver w83792d_driver = {
319 .owner = THIS_MODULE,
320 .name = "w83792d",
321 .flags = I2C_DF_NOTIFY,
322 .attach_adapter = w83792d_attach_adapter,
323 .detach_client = w83792d_detach_client,
324};
325
326static long in_count_from_reg(int nr, struct w83792d_data *data)
327{
328 u16 vol_count = data->in[nr];
329 u16 low_bits = 0;
330 vol_count = (vol_count << 2);
331 switch (nr)
332 {
333 case 0: /* vin0 */
334 low_bits = (data->low_bits[0]) & 0x03;
335 break;
336 case 1: /* vin1 */
337 low_bits = ((data->low_bits[0]) & 0x0c) >> 2;
338 break;
339 case 2: /* vin2 */
340 low_bits = ((data->low_bits[0]) & 0x30) >> 4;
341 break;
342 case 3: /* vin3 */
343 low_bits = ((data->low_bits[0]) & 0xc0) >> 6;
344 break;
345 case 4: /* vin4 */
346 low_bits = (data->low_bits[1]) & 0x03;
347 break;
348 case 5: /* vin5 */
349 low_bits = ((data->low_bits[1]) & 0x0c) >> 2;
350 break;
351 case 6: /* vin6 */
352 low_bits = ((data->low_bits[1]) & 0x30) >> 4;
353 default:
354 break;
355 }
356 vol_count = vol_count | low_bits;
357 return vol_count;
358}
359
360/* following are the sysfs callback functions */
361static ssize_t show_in(struct device *dev, struct device_attribute *attr,
362 char *buf)
363{
364 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
365 int nr = sensor_attr->index;
366 struct w83792d_data *data = w83792d_update_device(dev);
367 return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data))));
368}
369
370#define show_in_reg(reg) \
371static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
372 char *buf) \
373{ \
374 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
375 int nr = sensor_attr->index; \
376 struct w83792d_data *data = w83792d_update_device(dev); \
377 return sprintf(buf,"%ld\n", (long)(IN_FROM_REG(nr, (data->reg[nr])*4))); \
378}
379
380show_in_reg(in_min);
381show_in_reg(in_max);
382
383#define store_in_reg(REG, reg) \
384static ssize_t store_in_##reg (struct device *dev, \
385 struct device_attribute *attr, \
386 const char *buf, size_t count) \
387{ \
388 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
389 int nr = sensor_attr->index; \
390 struct i2c_client *client = to_i2c_client(dev); \
391 struct w83792d_data *data = i2c_get_clientdata(client); \
392 u32 val; \
393 \
394 val = simple_strtoul(buf, NULL, 10); \
395 data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \
396 w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \
397 \
398 return count; \
399}
400store_in_reg(MIN, min);
401store_in_reg(MAX, max);
402
403#define sysfs_in_reg(offset) \
404static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \
405 NULL, offset); \
406static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
407 show_in_min, store_in_min, offset); \
408static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
409 show_in_max, store_in_max, offset);
410
411sysfs_in_reg(0);
412sysfs_in_reg(1);
413sysfs_in_reg(2);
414sysfs_in_reg(3);
415sysfs_in_reg(4);
416sysfs_in_reg(5);
417sysfs_in_reg(6);
418sysfs_in_reg(7);
419sysfs_in_reg(8);
420
421#define device_create_file_in(client, offset) \
422do { \
423device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \
424device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \
425device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \
426} while (0)
427
428#define show_fan_reg(reg) \
429static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
430 char *buf) \
431{ \
432 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
433 int nr = sensor_attr->index - 1; \
434 struct w83792d_data *data = w83792d_update_device(dev); \
435 return sprintf(buf,"%d\n", \
436 FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
437}
438
439show_fan_reg(fan);
440show_fan_reg(fan_min);
441
442static ssize_t
443store_fan_min(struct device *dev, struct device_attribute *attr,
444 const char *buf, size_t count)
445{
446 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
447 int nr = sensor_attr->index - 1;
448 struct i2c_client *client = to_i2c_client(dev);
449 struct w83792d_data *data = i2c_get_clientdata(client);
450 u32 val;
451
452 val = simple_strtoul(buf, NULL, 10);
453 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
454 w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
455 data->fan_min[nr]);
456
457 return count;
458}
459
460static ssize_t
461show_fan_div(struct device *dev, struct device_attribute *attr,
462 char *buf)
463{
464 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
465 int nr = sensor_attr->index;
466 struct w83792d_data *data = w83792d_update_device(dev);
467 return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1]));
468}
469
470/* Note: we save and restore the fan minimum here, because its value is
471 determined in part by the fan divisor. This follows the principle of
472 least suprise; the user doesn't expect the fan minimum to change just
473 because the divisor changed. */
474static ssize_t
475store_fan_div(struct device *dev, struct device_attribute *attr,
476 const char *buf, size_t count)
477{
478 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
479 int nr = sensor_attr->index - 1;
480 struct i2c_client *client = to_i2c_client(dev);
481 struct w83792d_data *data = i2c_get_clientdata(client);
482 unsigned long min;
483 /*u8 reg;*/
484 u8 fan_div_reg = 0;
485 u8 tmp_fan_div;
486
487 /* Save fan_min */
488 min = FAN_FROM_REG(data->fan_min[nr],
489 DIV_FROM_REG(data->fan_div[nr]));
490
491 data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
492
493 fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]);
494 fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8;
495 tmp_fan_div = (nr & 0x01) ? (((data->fan_div[nr]) << 4) & 0x70)
496 : ((data->fan_div[nr]) & 0x07);
497 w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1],
498 fan_div_reg | tmp_fan_div);
499
500 /* Restore fan_min */
501 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
502 w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
503
504 return count;
505}
506
507#define sysfs_fan(offset) \
508static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
509 offset); \
510static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
511 show_fan_div, store_fan_div, offset); \
512static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
513 show_fan_min, store_fan_min, offset);
514
515sysfs_fan(1);
516sysfs_fan(2);
517sysfs_fan(3);
518sysfs_fan(4);
519sysfs_fan(5);
520sysfs_fan(6);
521sysfs_fan(7);
522
523#define device_create_file_fan(client, offset) \
524do { \
525device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \
526device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \
527device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \
528} while (0)
529
530
531/* read/write the temperature1, includes measured value and limits */
532
533static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
534 char *buf)
535{
536 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
537 int nr = sensor_attr->index;
538 struct w83792d_data *data = w83792d_update_device(dev);
539 return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[nr]));
540}
541
542static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
543 const char *buf, size_t count)
544{
545 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
546 int nr = sensor_attr->index;
547 struct i2c_client *client = to_i2c_client(dev);
548 struct w83792d_data *data = i2c_get_clientdata(client);
549 s32 val;
550
551 val = simple_strtol(buf, NULL, 10);
552
553 data->temp1[nr] = TEMP1_TO_REG(val);
554 w83792d_write_value(client, W83792D_REG_TEMP1[nr],
555 data->temp1[nr]);
556
557 return count;
558}
559
560
561static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0);
562static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1,
563 store_temp1, 1);
564static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1,
565 store_temp1, 2);
566
567#define device_create_file_temp1(client) \
568do { \
569device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \
570device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \
571device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \
572} while (0)
573
574
575/* read/write the temperature2-3, includes measured value and limits */
576
577static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
578 char *buf)
579{
580 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
581 int nr = sensor_attr->nr;
582 int index = sensor_attr->index;
583 struct w83792d_data *data = w83792d_update_device(dev);
584 return sprintf(buf,"%ld\n",
585 (long)TEMP_ADD_FROM_REG(data->temp_add[nr][index],
586 data->temp_add[nr][index+1]));
587}
588
589static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
590 const char *buf, size_t count)
591{
592 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
593 int nr = sensor_attr->nr;
594 int index = sensor_attr->index;
595 struct i2c_client *client = to_i2c_client(dev);
596 struct w83792d_data *data = i2c_get_clientdata(client);
597 s32 val;
598
599 val = simple_strtol(buf, NULL, 10);
600
601 data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
602 data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
603 w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
604 data->temp_add[nr][index]);
605 w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
606 data->temp_add[nr][index+1]);
607
608 return count;
609}
610
611#define sysfs_temp23(name,idx) \
612static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \
613 idx, 0); \
614static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \
615 show_temp23, store_temp23, idx, 2); \
616static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \
617 show_temp23, store_temp23, idx, 4);
618
619sysfs_temp23(temp2,0)
620sysfs_temp23(temp3,1)
621
622#define device_create_file_temp_add(client, offset) \
623do { \
624device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \
625device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \
626device_create_file(&client->dev, \
627&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \
628} while (0)
629
630
631/* get reatime status of all sensors items: voltage, temp, fan */
632static ssize_t
633show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
634{
635 struct w83792d_data *data = w83792d_update_device(dev);
636 return sprintf(buf, "%d\n", data->alarms);
637}
638
639static
640DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
641#define device_create_file_alarms(client) \
642device_create_file(&client->dev, &dev_attr_alarms);
643
644
645
646static ssize_t
647show_pwm(struct device *dev, struct device_attribute *attr,
648 char *buf)
649{
650 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
651 int nr = sensor_attr->index;
652 struct w83792d_data *data = w83792d_update_device(dev);
653 return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1]));
654}
655
656static ssize_t
657show_pwmenable(struct device *dev, struct device_attribute *attr,
658 char *buf)
659{
660 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
661 int nr = sensor_attr->index - 1;
662 struct w83792d_data *data = w83792d_update_device(dev);
663 long pwm_enable_tmp = 1;
664
665 switch (data->pwmenable[nr]) {
666 case 0:
667 pwm_enable_tmp = 1; /* manual mode */
668 break;
669 case 1:
670 pwm_enable_tmp = 3; /*thermal cruise/Smart Fan I */
671 break;
672 case 2:
673 pwm_enable_tmp = 2; /* Smart Fan II */
674 break;
675 }
676
677 return sprintf(buf, "%ld\n", pwm_enable_tmp);
678}
679
680static ssize_t
681store_pwm(struct device *dev, struct device_attribute *attr,
682 const char *buf, size_t count)
683{
684 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
685 int nr = sensor_attr->index - 1;
686 struct i2c_client *client = to_i2c_client(dev);
687 struct w83792d_data *data = i2c_get_clientdata(client);
688 u32 val;
689
690 val = simple_strtoul(buf, NULL, 10);
691 data->pwm[nr] = PWM_TO_REG(val);
692 w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
693
694 return count;
695}
696
697static ssize_t
698store_pwmenable(struct device *dev, struct device_attribute *attr,
699 const char *buf, size_t count)
700{
701 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
702 int nr = sensor_attr->index - 1;
703 struct i2c_client *client = to_i2c_client(dev);
704 struct w83792d_data *data = i2c_get_clientdata(client);
705 u32 val;
706 u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
707
708 val = simple_strtoul(buf, NULL, 10);
709 switch (val) {
710 case 1:
711 data->pwmenable[nr] = 0; /* manual mode */
712 break;
713 case 2:
714 data->pwmenable[nr] = 2; /* Smart Fan II */
715 break;
716 case 3:
717 data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
718 break;
719 default:
720 return -EINVAL;
721 }
722 cfg1_tmp = data->pwmenable[0];
723 cfg2_tmp = (data->pwmenable[1]) << 2;
724 cfg3_tmp = (data->pwmenable[2]) << 4;
725 cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0;
726 fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
727 w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
728
729 return count;
730}
731
732#define sysfs_pwm(offset) \
733static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
734 show_pwm, store_pwm, offset); \
735static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
736 show_pwmenable, store_pwmenable, offset); \
737
738sysfs_pwm(1);
739sysfs_pwm(2);
740sysfs_pwm(3);
741
742
743#define device_create_file_pwm(client, offset) \
744do { \
745device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \
746} while (0)
747
748#define device_create_file_pwmenable(client, offset) \
749do { \
750device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \
751} while (0)
752
753
754static ssize_t
755show_pwm_mode(struct device *dev, struct device_attribute *attr,
756 char *buf)
757{
758 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
759 int nr = sensor_attr->index;
760 struct w83792d_data *data = w83792d_update_device(dev);
761 return sprintf(buf, "%d\n", data->pwm_mode[nr-1]);
762}
763
764static ssize_t
765store_pwm_mode(struct device *dev, struct device_attribute *attr,
766 const char *buf, size_t count)
767{
768 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
769 int nr = sensor_attr->index - 1;
770 struct i2c_client *client = to_i2c_client(dev);
771 struct w83792d_data *data = i2c_get_clientdata(client);
772 u32 val;
773 u8 pwm_mode_mask = 0;
774
775 val = simple_strtoul(buf, NULL, 10);
776 data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1);
777 pwm_mode_mask = w83792d_read_value(client,
778 W83792D_REG_PWM[nr]) & 0x7f;
779 w83792d_write_value(client, W83792D_REG_PWM[nr],
780 ((data->pwm_mode[nr]) << 7) | pwm_mode_mask);
781
782 return count;
783}
784
785#define sysfs_pwm_mode(offset) \
786static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \
787 show_pwm_mode, store_pwm_mode, offset);
788
789sysfs_pwm_mode(1);
790sysfs_pwm_mode(2);
791sysfs_pwm_mode(3);
792
793#define device_create_file_pwm_mode(client, offset) \
794do { \
795device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \
796} while (0)
797
798
799static ssize_t
800show_regs_chassis(struct device *dev, struct device_attribute *attr,
801 char *buf)
802{
803 struct w83792d_data *data = w83792d_update_device(dev);
804 return sprintf(buf, "%d\n", data->chassis);
805}
806
807static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
808
809#define device_create_file_chassis(client) \
810do { \
811device_create_file(&client->dev, &dev_attr_chassis); \
812} while (0)
813
814
815static ssize_t
816show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
817{
818 struct w83792d_data *data = w83792d_update_device(dev);
819 return sprintf(buf, "%d\n", data->chassis_clear);
820}
821
822static ssize_t
823store_chassis_clear(struct device *dev, struct device_attribute *attr,
824 const char *buf, size_t count)
825{
826 struct i2c_client *client = to_i2c_client(dev);
827 struct w83792d_data *data = i2c_get_clientdata(client);
828 u32 val;
829 u8 temp1 = 0, temp2 = 0;
830
831 val = simple_strtoul(buf, NULL, 10);
832
833 data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
834 temp1 = ((data->chassis_clear) << 7) & 0x80;
835 temp2 = w83792d_read_value(client,
836 W83792D_REG_CHASSIS_CLR) & 0x7f;
837 w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
838
839 return count;
840}
841
842static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
843 show_chassis_clear, store_chassis_clear);
844
845#define device_create_file_chassis_clear(client) \
846do { \
847device_create_file(&client->dev, &dev_attr_chassis_clear); \
848} while (0)
849
850
851
852/* For Smart Fan I / Thermal Cruise */
853static ssize_t
854show_thermal_cruise(struct device *dev, struct device_attribute *attr,
855 char *buf)
856{
857 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
858 int nr = sensor_attr->index;
859 struct w83792d_data *data = w83792d_update_device(dev);
860 return sprintf(buf, "%ld\n", (long)data->thermal_cruise[nr-1]);
861}
862
863static ssize_t
864store_thermal_cruise(struct device *dev, struct device_attribute *attr,
865 const char *buf, size_t count)
866{
867 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
868 int nr = sensor_attr->index - 1;
869 struct i2c_client *client = to_i2c_client(dev);
870 struct w83792d_data *data = i2c_get_clientdata(client);
871 u32 val;
872 u8 target_tmp=0, target_mask=0;
873
874 val = simple_strtoul(buf, NULL, 10);
875 target_tmp = val;
876 target_tmp = target_tmp & 0x7f;
877 target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80;
878 data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
879 w83792d_write_value(client, W83792D_REG_THERMAL[nr],
880 (data->thermal_cruise[nr]) | target_mask);
881
882 return count;
883}
884
885#define sysfs_thermal_cruise(offset) \
886static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \
887 show_thermal_cruise, store_thermal_cruise, offset);
888
889sysfs_thermal_cruise(1);
890sysfs_thermal_cruise(2);
891sysfs_thermal_cruise(3);
892
893#define device_create_file_thermal_cruise(client, offset) \
894do { \
895device_create_file(&client->dev, \
896&sensor_dev_attr_thermal_cruise##offset.dev_attr); \
897} while (0)
898
899
900/* For Smart Fan I/Thermal Cruise and Smart Fan II */
901static ssize_t
902show_tolerance(struct device *dev, struct device_attribute *attr,
903 char *buf)
904{
905 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
906 int nr = sensor_attr->index;
907 struct w83792d_data *data = w83792d_update_device(dev);
908 return sprintf(buf, "%ld\n", (long)data->tolerance[nr-1]);
909}
910
911static ssize_t
912store_tolerance(struct device *dev, struct device_attribute *attr,
913 const char *buf, size_t count)
914{
915 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
916 int nr = sensor_attr->index - 1;
917 struct i2c_client *client = to_i2c_client(dev);
918 struct w83792d_data *data = i2c_get_clientdata(client);
919 u32 val;
920 u8 tol_tmp, tol_mask;
921
922 val = simple_strtoul(buf, NULL, 10);
923 tol_mask = w83792d_read_value(client,
924 W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
925 tol_tmp = SENSORS_LIMIT(val, 0, 15);
926 tol_tmp &= 0x0f;
927 data->tolerance[nr] = tol_tmp;
928 if (nr == 1) {
929 tol_tmp <<= 4;
930 }
931 w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
932 tol_mask | tol_tmp);
933
934 return count;
935}
936
937#define sysfs_tolerance(offset) \
938static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \
939 show_tolerance, store_tolerance, offset);
940
941sysfs_tolerance(1);
942sysfs_tolerance(2);
943sysfs_tolerance(3);
944
945#define device_create_file_tolerance(client, offset) \
946do { \
947device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \
948} while (0)
949
950
951/* For Smart Fan II */
952static ssize_t
953show_sf2_point(struct device *dev, struct device_attribute *attr,
954 char *buf)
955{
956 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
957 int nr = sensor_attr->nr;
958 int index = sensor_attr->index;
959 struct w83792d_data *data = w83792d_update_device(dev);
960 return sprintf(buf, "%ld\n", (long)data->sf2_points[index-1][nr-1]);
961}
962
963static ssize_t
964store_sf2_point(struct device *dev, struct device_attribute *attr,
965 const char *buf, size_t count)
966{
967 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
968 int nr = sensor_attr->nr - 1;
969 int index = sensor_attr->index - 1;
970 struct i2c_client *client = to_i2c_client(dev);
971 struct w83792d_data *data = i2c_get_clientdata(client);
972 u32 val;
973 u8 mask_tmp = 0;
974
975 val = simple_strtoul(buf, NULL, 10);
976 data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
977 mask_tmp = w83792d_read_value(client,
978 W83792D_REG_POINTS[index][nr]) & 0x80;
979 w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
980 mask_tmp|data->sf2_points[index][nr]);
981
982 return count;
983}
984
985#define sysfs_sf2_point(offset, index) \
986static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \
987 show_sf2_point, store_sf2_point, offset, index);
988
989sysfs_sf2_point(1, 1); /* Fan1 */
990sysfs_sf2_point(2, 1); /* Fan1 */
991sysfs_sf2_point(3, 1); /* Fan1 */
992sysfs_sf2_point(4, 1); /* Fan1 */
993sysfs_sf2_point(1, 2); /* Fan2 */
994sysfs_sf2_point(2, 2); /* Fan2 */
995sysfs_sf2_point(3, 2); /* Fan2 */
996sysfs_sf2_point(4, 2); /* Fan2 */
997sysfs_sf2_point(1, 3); /* Fan3 */
998sysfs_sf2_point(2, 3); /* Fan3 */
999sysfs_sf2_point(3, 3); /* Fan3 */
1000sysfs_sf2_point(4, 3); /* Fan3 */
1001
1002#define device_create_file_sf2_point(client, offset, index) \
1003do { \
1004device_create_file(&client->dev, \
1005&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \
1006} while (0)
1007
1008
1009static ssize_t
1010show_sf2_level(struct device *dev, struct device_attribute *attr,
1011 char *buf)
1012{
1013 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
1014 int nr = sensor_attr->nr;
1015 int index = sensor_attr->index;
1016 struct w83792d_data *data = w83792d_update_device(dev);
1017 return sprintf(buf, "%d\n",
1018 (((data->sf2_levels[index-1][nr]) * 100) / 15));
1019}
1020
1021static ssize_t
1022store_sf2_level(struct device *dev, struct device_attribute *attr,
1023 const char *buf, size_t count)
1024{
1025 struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
1026 int nr = sensor_attr->nr;
1027 int index = sensor_attr->index - 1;
1028 struct i2c_client *client = to_i2c_client(dev);
1029 struct w83792d_data *data = i2c_get_clientdata(client);
1030 u32 val;
1031 u8 mask_tmp=0, level_tmp=0;
1032
1033 val = simple_strtoul(buf, NULL, 10);
1034 data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
1035 mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
1036 & ((nr==3) ? 0xf0 : 0x0f);
1037 if (nr==3) {
1038 level_tmp = data->sf2_levels[index][nr];
1039 } else {
1040 level_tmp = data->sf2_levels[index][nr] << 4;
1041 }
1042 w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
1043
1044 return count;
1045}
1046
1047#define sysfs_sf2_level(offset, index) \
1048static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \
1049 show_sf2_level, store_sf2_level, offset, index);
1050
1051sysfs_sf2_level(1, 1); /* Fan1 */
1052sysfs_sf2_level(2, 1); /* Fan1 */
1053sysfs_sf2_level(3, 1); /* Fan1 */
1054sysfs_sf2_level(1, 2); /* Fan2 */
1055sysfs_sf2_level(2, 2); /* Fan2 */
1056sysfs_sf2_level(3, 2); /* Fan2 */
1057sysfs_sf2_level(1, 3); /* Fan3 */
1058sysfs_sf2_level(2, 3); /* Fan3 */
1059sysfs_sf2_level(3, 3); /* Fan3 */
1060
1061#define device_create_file_sf2_level(client, offset, index) \
1062do { \
1063device_create_file(&client->dev, \
1064&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \
1065} while (0)
1066
1067
1068/* This function is called when:
1069 * w83792d_driver is inserted (when this module is loaded), for each
1070 available adapter
1071 * when a new adapter is inserted (and w83792d_driver is still present) */
1072static int
1073w83792d_attach_adapter(struct i2c_adapter *adapter)
1074{
1075 if (!(adapter->class & I2C_CLASS_HWMON))
1076 return 0;
Jean Delvare2ed2dc32005-07-31 21:42:02 +02001077 return i2c_probe(adapter, &addr_data, w83792d_detect);
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001078}
1079
1080
1081static int
1082w83792d_create_subclient(struct i2c_adapter *adapter,
1083 struct i2c_client *new_client, int addr,
1084 struct i2c_client **sub_cli)
1085{
1086 int err;
1087 struct i2c_client *sub_client;
1088
1089 (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
1090 if (!(sub_client)) {
1091 return -ENOMEM;
1092 }
1093 memset(sub_client, 0x00, sizeof(struct i2c_client));
1094 sub_client->addr = 0x48 + addr;
1095 i2c_set_clientdata(sub_client, NULL);
1096 sub_client->adapter = adapter;
1097 sub_client->driver = &w83792d_driver;
1098 sub_client->flags = 0;
1099 strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
1100 if ((err = i2c_attach_client(sub_client))) {
1101 dev_err(&new_client->dev, "subclient registration "
1102 "at address 0x%x failed\n", sub_client->addr);
1103 kfree(sub_client);
1104 return err;
1105 }
1106 return 0;
1107}
1108
1109
1110static int
1111w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
1112 struct i2c_client *new_client)
1113{
1114 int i, id, err;
1115 u8 val;
1116 struct w83792d_data *data = i2c_get_clientdata(new_client);
1117
1118 id = i2c_adapter_id(adapter);
1119 if (force_subclients[0] == id && force_subclients[1] == address) {
1120 for (i = 2; i <= 3; i++) {
1121 if (force_subclients[i] < 0x48 ||
1122 force_subclients[i] > 0x4f) {
1123 dev_err(&new_client->dev, "invalid subclient "
1124 "address %d; must be 0x48-0x4f\n",
1125 force_subclients[i]);
1126 err = -ENODEV;
1127 goto ERROR_SC_0;
1128 }
1129 }
1130 w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
1131 (force_subclients[2] & 0x07) |
1132 ((force_subclients[3] & 0x07) << 4));
1133 }
1134
1135 val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
1136 if (!(val & 0x08)) {
1137 err = w83792d_create_subclient(adapter, new_client, val & 0x7,
1138 &data->lm75[0]);
1139 if (err < 0)
1140 goto ERROR_SC_0;
1141 }
1142 if (!(val & 0x80)) {
1143 if ((data->lm75[0] != NULL) &&
1144 ((val & 0x7) == ((val >> 4) & 0x7))) {
1145 dev_err(&new_client->dev, "duplicate addresses 0x%x, "
1146 "use force_subclient\n", data->lm75[0]->addr);
1147 err = -ENODEV;
1148 goto ERROR_SC_1;
1149 }
1150 err = w83792d_create_subclient(adapter, new_client,
1151 (val >> 4) & 0x7, &data->lm75[1]);
1152 if (err < 0)
1153 goto ERROR_SC_1;
1154 }
1155
1156 return 0;
1157
1158/* Undo inits in case of errors */
1159
1160ERROR_SC_1:
1161 if (data->lm75[0] != NULL) {
1162 i2c_detach_client(data->lm75[0]);
1163 kfree(data->lm75[0]);
1164 }
1165ERROR_SC_0:
1166 return err;
1167}
1168
1169
1170static int
1171w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
1172{
1173 int i = 0, val1 = 0, val2;
1174 struct i2c_client *new_client;
1175 struct w83792d_data *data;
1176 int err = 0;
1177 const char *client_name = "";
1178
1179 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1180 goto ERROR0;
1181 }
1182
1183 /* OK. For now, we presume we have a valid client. We now create the
1184 client structure, even though we cannot fill it completely yet.
1185 But it allows us to access w83792d_{read,write}_value. */
1186
1187 if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
1188 err = -ENOMEM;
1189 goto ERROR0;
1190 }
1191 memset(data, 0, sizeof(struct w83792d_data));
1192
1193 new_client = &data->client;
1194 i2c_set_clientdata(new_client, data);
1195 new_client->addr = address;
1196 init_MUTEX(&data->lock);
1197 new_client->adapter = adapter;
1198 new_client->driver = &w83792d_driver;
1199 new_client->flags = 0;
1200
1201 /* Now, we do the remaining detection. */
1202
1203 /* The w83792d may be stuck in some other bank than bank 0. This may
1204 make reading other information impossible. Specify a force=... or
1205 force_*=... parameter, and the Winbond will be reset to the right
1206 bank. */
1207 if (kind < 0) {
1208 if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) {
1209 dev_warn(&new_client->dev, "Detection failed at step "
1210 "3\n");
1211 goto ERROR1;
1212 }
1213 val1 = w83792d_read_value(new_client, W83792D_REG_BANK);
1214 val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
1215 /* Check for Winbond ID if in bank 0 */
1216 if (!(val1 & 0x07)) { /* is Bank0 */
1217 if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
1218 ((val1 & 0x80) && (val2 != 0x5c))) {
1219 goto ERROR1;
1220 }
1221 }
1222 /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
1223 should match */
1224 if (w83792d_read_value(new_client,
1225 W83792D_REG_I2C_ADDR) != address) {
1226 dev_warn(&new_client->dev, "Detection failed "
1227 "at step 5\n");
1228 goto ERROR1;
1229 }
1230 }
1231
1232 /* We have either had a force parameter, or we have already detected the
1233 Winbond. Put it now into bank 0 and Vendor ID High Byte */
1234 w83792d_write_value(new_client,
1235 W83792D_REG_BANK,
1236 (w83792d_read_value(new_client,
1237 W83792D_REG_BANK) & 0x78) | 0x80);
1238
1239 /* Determine the chip type. */
1240 if (kind <= 0) {
1241 /* get vendor ID */
1242 val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
1243 if (val2 != 0x5c) { /* the vendor is NOT Winbond */
1244 goto ERROR1;
1245 }
1246 val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID);
1247 if (val1 == 0x7a && address >= 0x2c) {
1248 kind = w83792d;
1249 } else {
1250 if (kind == 0)
1251 dev_warn(&new_client->dev,
1252 "w83792d: Ignoring 'force' parameter for"
1253 " unknown chip at adapter %d, address"
1254 " 0x%02x\n", i2c_adapter_id(adapter),
1255 address);
1256 goto ERROR1;
1257 }
1258 }
1259
1260 if (kind == w83792d) {
1261 client_name = "w83792d";
1262 } else {
1263 dev_err(&new_client->dev, "w83792d: Internal error: unknown"
1264 " kind (%d)?!?", kind);
1265 goto ERROR1;
1266 }
1267
1268 /* Fill in the remaining client fields and put into the global list */
1269 strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
1270 data->type = kind;
1271
1272 data->valid = 0;
1273 init_MUTEX(&data->update_lock);
1274
1275 /* Tell the I2C layer a new client has arrived */
1276 if ((err = i2c_attach_client(new_client)))
1277 goto ERROR1;
1278
1279 if ((err = w83792d_detect_subclients(adapter, address,
1280 kind, new_client)))
1281 goto ERROR2;
1282
1283 /* Initialize the chip */
1284 w83792d_init_client(new_client);
1285
1286 /* A few vars need to be filled upon startup */
1287 for (i = 1; i <= 7; i++) {
1288 data->fan_min[i - 1] = w83792d_read_value(new_client,
1289 W83792D_REG_FAN_MIN[i]);
1290 }
1291
1292 /* Register sysfs hooks */
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +00001293 data->class_dev = hwmon_device_register(&new_client->dev);
1294 if (IS_ERR(data->class_dev)) {
1295 err = PTR_ERR(data->class_dev);
1296 goto ERROR3;
1297 }
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001298 device_create_file_in(new_client, 0);
1299 device_create_file_in(new_client, 1);
1300 device_create_file_in(new_client, 2);
1301 device_create_file_in(new_client, 3);
1302 device_create_file_in(new_client, 4);
1303 device_create_file_in(new_client, 5);
1304 device_create_file_in(new_client, 6);
1305 device_create_file_in(new_client, 7);
1306 device_create_file_in(new_client, 8);
1307
1308 device_create_file_fan(new_client, 1);
1309 device_create_file_fan(new_client, 2);
1310 device_create_file_fan(new_client, 3);
1311 device_create_file_fan(new_client, 4);
1312 device_create_file_fan(new_client, 5);
1313 device_create_file_fan(new_client, 6);
1314 device_create_file_fan(new_client, 7);
1315
1316 device_create_file_temp1(new_client); /* Temp1 */
1317 device_create_file_temp_add(new_client, 2); /* Temp2 */
1318 device_create_file_temp_add(new_client, 3); /* Temp3 */
1319
1320 device_create_file_alarms(new_client);
1321
1322 device_create_file_pwm(new_client, 1);
1323 device_create_file_pwm(new_client, 2);
1324 device_create_file_pwm(new_client, 3);
1325
1326 device_create_file_pwmenable(new_client, 1);
1327 device_create_file_pwmenable(new_client, 2);
1328 device_create_file_pwmenable(new_client, 3);
1329
1330 device_create_file_pwm_mode(new_client, 1);
1331 device_create_file_pwm_mode(new_client, 2);
1332 device_create_file_pwm_mode(new_client, 3);
1333
1334 device_create_file_chassis(new_client);
1335 device_create_file_chassis_clear(new_client);
1336
1337 device_create_file_thermal_cruise(new_client, 1);
1338 device_create_file_thermal_cruise(new_client, 2);
1339 device_create_file_thermal_cruise(new_client, 3);
1340
1341 device_create_file_tolerance(new_client, 1);
1342 device_create_file_tolerance(new_client, 2);
1343 device_create_file_tolerance(new_client, 3);
1344
1345 device_create_file_sf2_point(new_client, 1, 1); /* Fan1 */
1346 device_create_file_sf2_point(new_client, 2, 1); /* Fan1 */
1347 device_create_file_sf2_point(new_client, 3, 1); /* Fan1 */
1348 device_create_file_sf2_point(new_client, 4, 1); /* Fan1 */
1349 device_create_file_sf2_point(new_client, 1, 2); /* Fan2 */
1350 device_create_file_sf2_point(new_client, 2, 2); /* Fan2 */
1351 device_create_file_sf2_point(new_client, 3, 2); /* Fan2 */
1352 device_create_file_sf2_point(new_client, 4, 2); /* Fan2 */
1353 device_create_file_sf2_point(new_client, 1, 3); /* Fan3 */
1354 device_create_file_sf2_point(new_client, 2, 3); /* Fan3 */
1355 device_create_file_sf2_point(new_client, 3, 3); /* Fan3 */
1356 device_create_file_sf2_point(new_client, 4, 3); /* Fan3 */
1357
1358 device_create_file_sf2_level(new_client, 1, 1); /* Fan1 */
1359 device_create_file_sf2_level(new_client, 2, 1); /* Fan1 */
1360 device_create_file_sf2_level(new_client, 3, 1); /* Fan1 */
1361 device_create_file_sf2_level(new_client, 1, 2); /* Fan2 */
1362 device_create_file_sf2_level(new_client, 2, 2); /* Fan2 */
1363 device_create_file_sf2_level(new_client, 3, 2); /* Fan2 */
1364 device_create_file_sf2_level(new_client, 1, 3); /* Fan3 */
1365 device_create_file_sf2_level(new_client, 2, 3); /* Fan3 */
1366 device_create_file_sf2_level(new_client, 3, 3); /* Fan3 */
1367
1368 return 0;
1369
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +00001370ERROR3:
1371 if (data->lm75[0] != NULL) {
1372 i2c_detach_client(data->lm75[0]);
1373 kfree(data->lm75[0]);
1374 }
1375 if (data->lm75[1] != NULL) {
1376 i2c_detach_client(data->lm75[1]);
1377 kfree(data->lm75[1]);
1378 }
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001379ERROR2:
1380 i2c_detach_client(new_client);
1381ERROR1:
1382 kfree(data);
1383ERROR0:
1384 return err;
1385}
1386
1387static int
1388w83792d_detach_client(struct i2c_client *client)
1389{
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +00001390 struct w83792d_data *data = i2c_get_clientdata(client);
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001391 int err;
1392
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +00001393 /* main client */
1394 if (data)
1395 hwmon_device_unregister(data->class_dev);
1396
Jean Delvare7bef5592005-07-27 22:14:49 +02001397 if ((err = i2c_detach_client(client)))
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001398 return err;
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001399
R.Marek@sh.cvut.czce785ab2005-07-27 11:50:18 +00001400 /* main client */
1401 if (data)
1402 kfree(data);
1403 /* subclient */
1404 else
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001405 kfree(client);
R.Marek@sh.cvut.cz5563e272005-07-27 11:43:47 +00001406
1407 return 0;
1408}
1409
1410/* The SMBus locks itself, usually, but nothing may access the Winbond between
1411 bank switches. ISA access must always be locked explicitly!
1412 We ignore the W83792D BUSY flag at this moment - it could lead to deadlocks,
1413 would slow down the W83792D access and should not be necessary.
1414 There are some ugly typecasts here, but the good news is - they should
1415 nowhere else be necessary! */
1416static int
1417w83792d_read_value(struct i2c_client *client, u8 reg)
1418{
1419 int res=0;
1420 res = i2c_smbus_read_byte_data(client, reg);
1421
1422 return res;
1423}
1424
1425static int
1426w83792d_write_value(struct i2c_client *client, u8 reg, u8 value)
1427{
1428 i2c_smbus_write_byte_data(client, reg, value);
1429 return 0;
1430}
1431
1432/* Called when we have found a new W83792D. It should set limits, etc. */
1433static void
1434w83792d_init_client(struct i2c_client *client)
1435{
1436 u8 temp2_cfg, temp3_cfg, vid_in_b;
1437
1438 if (init) {
1439 w83792d_write_value(client, W83792D_REG_CONFIG, 0x80);
1440 }
1441 /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0):
1442 W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of
1443 vin0/vin1 can be modified by user;
1444 W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of
1445 vin0/vin1 auto-updated, can NOT be modified by user. */
1446 vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B);
1447 w83792d_write_value(client, W83792D_REG_VID_IN_B,
1448 vid_in_b & 0xbf);
1449
1450 temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP2_CONFIG);
1451 temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP3_CONFIG);
1452 w83792d_write_value(client, W83792D_REG_TEMP2_CONFIG,
1453 temp2_cfg & 0xe6);
1454 w83792d_write_value(client, W83792D_REG_TEMP3_CONFIG,
1455 temp3_cfg & 0xe6);
1456
1457 /* Start monitoring */
1458 w83792d_write_value(client, W83792D_REG_CONFIG,
1459 (w83792d_read_value(client,
1460 W83792D_REG_CONFIG) & 0xf7)
1461 | 0x01);
1462}
1463
1464static struct w83792d_data *w83792d_update_device(struct device *dev)
1465{
1466 struct i2c_client *client = to_i2c_client(dev);
1467 struct w83792d_data *data = i2c_get_clientdata(client);
1468 int i, j;
1469 u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
1470
1471 down(&data->update_lock);
1472
1473 if (time_after
1474 (jiffies - data->last_updated, (unsigned long) (HZ * 3))
1475 || time_before(jiffies, data->last_updated) || !data->valid) {
1476 dev_dbg(dev, "Starting device update\n");
1477
1478 /* Update the voltages measured value and limits */
1479 for (i = 0; i < 9; i++) {
1480 data->in[i] = w83792d_read_value(client,
1481 W83792D_REG_IN[i]);
1482 data->in_max[i] = w83792d_read_value(client,
1483 W83792D_REG_IN_MAX[i]);
1484 data->in_min[i] = w83792d_read_value(client,
1485 W83792D_REG_IN_MIN[i]);
1486 }
1487 data->low_bits[0] = w83792d_read_value(client,
1488 W83792D_REG_LOW_BITS1);
1489 data->low_bits[1] = w83792d_read_value(client,
1490 W83792D_REG_LOW_BITS2);
1491 for (i = 0; i < 7; i++) {
1492 /* Update the Fan measured value and limits */
1493 data->fan[i] = w83792d_read_value(client,
1494 W83792D_REG_FAN[i]);
1495 data->fan_min[i] = w83792d_read_value(client,
1496 W83792D_REG_FAN_MIN[i]);
1497 /* Update the PWM/DC Value and PWM/DC flag */
1498 pwm_array_tmp[i] = w83792d_read_value(client,
1499 W83792D_REG_PWM[i]);
1500 data->pwm[i] = pwm_array_tmp[i] & 0x0f;
1501 data->pwm_mode[i] = (pwm_array_tmp[i] >> 7) & 0x01;
1502 }
1503
1504 reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
1505 data->pwmenable[0] = reg_tmp & 0x03;
1506 data->pwmenable[1] = (reg_tmp>>2) & 0x03;
1507 data->pwmenable[2] = (reg_tmp>>4) & 0x03;
1508
1509 for (i = 0; i < 3; i++) {
1510 data->temp1[i] = w83792d_read_value(client,
1511 W83792D_REG_TEMP1[i]);
1512 }
1513 for (i = 0; i < 2; i++) {
1514 for (j = 0; j < 6; j++) {
1515 data->temp_add[i][j] = w83792d_read_value(
1516 client,W83792D_REG_TEMP_ADD[i][j]);
1517 }
1518 }
1519
1520 /* Update the Fan Divisor */
1521 for (i = 0; i < 4; i++) {
1522 reg_array_tmp[i] = w83792d_read_value(client,
1523 W83792D_REG_FAN_DIV[i]);
1524 }
1525 data->fan_div[0] = reg_array_tmp[0] & 0x07;
1526 data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07;
1527 data->fan_div[2] = reg_array_tmp[1] & 0x07;
1528 data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07;
1529 data->fan_div[4] = reg_array_tmp[2] & 0x07;
1530 data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07;
1531 data->fan_div[6] = reg_array_tmp[3] & 0x07;
1532
1533 /* Update the realtime status */
1534 data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) +
1535 (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) +
1536 (w83792d_read_value(client, W83792D_REG_ALARM3) << 16);
1537
1538 /* Update CaseOpen status and it's CLR_CHS. */
1539 data->chassis = (w83792d_read_value(client,
1540 W83792D_REG_CHASSIS) >> 5) & 0x01;
1541 data->chassis_clear = (w83792d_read_value(client,
1542 W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
1543
1544 /* Update Thermal Cruise/Smart Fan I target value */
1545 for (i = 0; i < 3; i++) {
1546 data->thermal_cruise[i] =
1547 w83792d_read_value(client,
1548 W83792D_REG_THERMAL[i]) & 0x7f;
1549 }
1550
1551 /* Update Smart Fan I/II tolerance */
1552 reg_tmp = w83792d_read_value(client, W83792D_REG_TOLERANCE[0]);
1553 data->tolerance[0] = reg_tmp & 0x0f;
1554 data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
1555 data->tolerance[2] = w83792d_read_value(client,
1556 W83792D_REG_TOLERANCE[2]) & 0x0f;
1557
1558 /* Update Smart Fan II temperature points */
1559 for (i = 0; i < 3; i++) {
1560 for (j = 0; j < 4; j++) {
1561 data->sf2_points[i][j] = w83792d_read_value(
1562 client,W83792D_REG_POINTS[i][j]) & 0x7f;
1563 }
1564 }
1565
1566 /* Update Smart Fan II duty cycle levels */
1567 for (i = 0; i < 3; i++) {
1568 reg_tmp = w83792d_read_value(client,
1569 W83792D_REG_LEVELS[i][0]);
1570 data->sf2_levels[i][0] = reg_tmp & 0x0f;
1571 data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f;
1572 reg_tmp = w83792d_read_value(client,
1573 W83792D_REG_LEVELS[i][2]);
1574 data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f;
1575 data->sf2_levels[i][3] = reg_tmp & 0x0f;
1576 }
1577
1578 data->last_updated = jiffies;
1579 data->valid = 1;
1580 }
1581
1582 up(&data->update_lock);
1583
1584#ifdef DEBUG
1585 w83792d_print_debug(data, dev);
1586#endif
1587
1588 return data;
1589}
1590
1591#ifdef DEBUG
1592static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
1593{
1594 int i=0, j=0;
1595 dev_dbg(dev, "==========The following is the debug message...========\n");
1596 dev_dbg(dev, "9 set of Voltages: =====>\n");
1597 for (i=0; i<9; i++) {
1598 dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]);
1599 dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]);
1600 dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]);
1601 }
1602 dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits[0]);
1603 dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits[1]);
1604 dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n");
1605 for (i=0; i<7; i++) {
1606 dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
1607 dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
1608 dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]);
1609 dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]);
1610 }
1611 dev_dbg(dev, "3 set of Temperatures: =====>\n");
1612 for (i=0; i<3; i++) {
1613 dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]);
1614 }
1615
1616 for (i=0; i<2; i++) {
1617 for (j=0; j<6; j++) {
1618 dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j,
1619 data->temp_add[i][j]);
1620 }
1621 }
1622
1623 for (i=0; i<7; i++) {
1624 dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]);
1625 }
1626 dev_dbg(dev, "==========End of the debug message...==================\n");
1627 dev_dbg(dev, "\n");
1628}
1629#endif
1630
1631static int __init
1632sensors_w83792d_init(void)
1633{
1634 return i2c_add_driver(&w83792d_driver);
1635}
1636
1637static void __exit
1638sensors_w83792d_exit(void)
1639{
1640 i2c_del_driver(&w83792d_driver);
1641}
1642
1643MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
1644MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
1645MODULE_LICENSE("GPL");
1646
1647module_init(sensors_w83792d_init);
1648module_exit(sensors_w83792d_exit);
1649