blob: 96338ddd74a7a961390bc2dd89622e994305a78e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
Jean Delvare7666c132007-05-08 17:22:02 +02005 Philip Edelbrock <phil@netroedge.com>,
6 and Mark Studebaker <mdsxyz123@yahoo.com>
7 Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
25 Supports following chips:
26
27 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
28 as99127f 7 3 0 3 0x31 0x12c3 yes no
29 as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
30 w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
31 w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
33 w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35*/
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/module.h>
38#include <linux/init.h>
39#include <linux/slab.h>
40#include <linux/jiffies.h>
41#include <linux/i2c.h>
Jean Delvare7666c132007-05-08 17:22:02 +020042#include <linux/platform_device.h>
43#include <linux/ioport.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040044#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020045#include <linux/hwmon-vid.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020046#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010048#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/io.h>
50#include "lm75.h"
51
Jean Delvare7666c132007-05-08 17:22:02 +020052/* ISA device, if found */
53static struct platform_device *pdev;
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055/* Addresses to scan */
56static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
57 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
58 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
Jean Delvare2d8672c2005-07-19 23:56:35 +020059static unsigned short isa_address = 0x290;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61/* Insmod parameters */
Jean Delvaref4b50262005-07-31 21:49:03 +020062I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
64 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
65
Jean Delvarefabddcd2006-02-05 23:26:51 +010066static int reset;
67module_param(reset, bool, 0);
68MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static int init = 1;
71module_param(init, bool, 0);
72MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
73
74/* Constants specified below */
75
76/* Length of ISA address segment */
77#define W83781D_EXTENT 8
78
79/* Where are the ISA address/data registers relative to the base address */
80#define W83781D_ADDR_REG_OFFSET 5
81#define W83781D_DATA_REG_OFFSET 6
82
83/* The W83781D registers */
84/* The W83782D registers for nr=7,8 are in bank 5 */
85#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
86 (0x554 + (((nr) - 7) * 2)))
87#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
88 (0x555 + (((nr) - 7) * 2)))
89#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
90 (0x550 + (nr) - 7))
91
92#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
93#define W83781D_REG_FAN(nr) (0x27 + (nr))
94
95#define W83781D_REG_BANK 0x4E
96#define W83781D_REG_TEMP2_CONFIG 0x152
97#define W83781D_REG_TEMP3_CONFIG 0x252
98#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
99 ((nr == 2) ? (0x0150) : \
100 (0x27)))
101#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
102 ((nr == 2) ? (0x153) : \
103 (0x3A)))
104#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
105 ((nr == 2) ? (0x155) : \
106 (0x39)))
107
108#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100109
110/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define W83781D_REG_ALARM1 0x41
112#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100114/* Real-time status (W83782D, W83783S, W83627HF) */
115#define W83782D_REG_ALARM1 0x459
116#define W83782D_REG_ALARM2 0x45A
117#define W83782D_REG_ALARM3 0x45B
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#define W83781D_REG_BEEP_CONFIG 0x4D
120#define W83781D_REG_BEEP_INTS1 0x56
121#define W83781D_REG_BEEP_INTS2 0x57
122#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
123
124#define W83781D_REG_VID_FANDIV 0x47
125
126#define W83781D_REG_CHIPID 0x49
127#define W83781D_REG_WCHIPID 0x58
128#define W83781D_REG_CHIPMAN 0x4F
129#define W83781D_REG_PIN 0x4B
130
131/* 782D/783S only */
132#define W83781D_REG_VBAT 0x5D
133
134/* PWM 782D (1-4) and 783S (1-2) only */
135#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */
136 /* on which is which; */
137#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */
138 /* However 782d is probably wrong. */
139#define W83781D_REG_PWM3 0x5E
140#define W83781D_REG_PWM4 0x5F
141#define W83781D_REG_PWMCLK12 0x5C
142#define W83781D_REG_PWMCLK34 0x45C
143static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2,
144 W83781D_REG_PWM3, W83781D_REG_PWM4
145};
146
147#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1])
148
149#define W83781D_REG_I2C_ADDR 0x48
150#define W83781D_REG_I2C_SUBADDR 0x4A
151
152/* The following are undocumented in the data sheets however we
153 received the information in an email from Winbond tech support */
154/* Sensor selection - not on 781d */
155#define W83781D_REG_SCFG1 0x5D
156static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
157
158#define W83781D_REG_SCFG2 0x59
159static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
160
161#define W83781D_DEFAULT_BETA 3435
162
163/* RT Table registers */
164#define W83781D_REG_RT_IDX 0x50
165#define W83781D_REG_RT_VAL 0x51
166
167/* Conversions. Rounding and limit checking is only done on the TO_REG
168 variants. Note that you should be a bit careful with which arguments
169 these macros are called: arguments may be evaluated more than once.
170 Fixing this is just not worth it. */
171#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
172#define IN_FROM_REG(val) (((val) * 16) / 10)
173
174static inline u8
175FAN_TO_REG(long rpm, int div)
176{
177 if (rpm == 0)
178 return 255;
179 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
180 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
181}
182
183#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
184 ((val) == 255 ? 0 : \
185 1350000 / ((val) * (div))))
186
187#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
188 : (val)) / 1000, 0, 0xff))
189#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191#define PWM_FROM_REG(val) (val)
192#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
193#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
194 (val) ^ 0x7fff : (val))
195#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
196 (~(val)) & 0x7fff : (val) & 0xffffff)
197
198#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0)
199#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0)
200
201#define DIV_FROM_REG(val) (1 << (val))
202
203static inline u8
204DIV_TO_REG(long val, enum chips type)
205{
206 int i;
207 val = SENSORS_LIMIT(val, 1,
208 ((type == w83781d
209 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000210 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 if (val == 0)
212 break;
213 val >>= 1;
214 }
215 return ((u8) i);
216}
217
218/* There are some complications in a module like this. First off, W83781D chips
219 may be both present on the SMBus and the ISA bus, and we have to handle
220 those cases separately at some places. Second, there might be several
221 W83781D chips available (well, actually, that is probably never done; but
222 it is a clean illustration of how to handle a case like that). Finally,
223 a specific chip may be attached to *both* ISA and SMBus, and we would
224 not like to detect it double. Fortunately, in the case of the W83781D at
225 least, a register tells us what SMBus address we are on, so that helps
226 a bit - except if there could be more than one SMBus. Groan. No solution
227 for this yet. */
228
Jean Delvare7666c132007-05-08 17:22:02 +0200229/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
230 the driver field to differentiate between I2C and ISA chips. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231struct w83781d_data {
232 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400233 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100234 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 enum chips type;
236
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100237 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 char valid; /* !=0 if following fields are valid */
239 unsigned long last_updated; /* In jiffies */
240
241 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
242 /* array of 2 pointers to subclients */
243
244 u8 in[9]; /* Register value - 8 & 9 for 782D only */
245 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
246 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
247 u8 fan[3]; /* Register value */
248 u8 fan_min[3]; /* Register value */
249 u8 temp;
250 u8 temp_max; /* Register value */
251 u8 temp_max_hyst; /* Register value */
252 u16 temp_add[2]; /* Register value */
253 u16 temp_max_add[2]; /* Register value */
254 u16 temp_max_hyst_add[2]; /* Register value */
255 u8 fan_div[3]; /* Register encoding, shifted right */
256 u8 vid; /* Register encoding, combined */
257 u32 alarms; /* Register encoding, combined */
258 u32 beep_mask; /* Register encoding, combined */
259 u8 beep_enable; /* Boolean */
260 u8 pwm[4]; /* Register value */
261 u8 pwmenable[4]; /* Boolean */
262 u16 sens[3]; /* 782D/783S only.
263 1 = pentium diode; 2 = 3904 diode;
264 3000-5000 = thermistor beta.
265 Default = 3435.
266 Other Betas unimplemented */
267 u8 vrm;
268};
269
270static int w83781d_attach_adapter(struct i2c_adapter *adapter);
271static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
272static int w83781d_detach_client(struct i2c_client *client);
273
Jean Delvare7666c132007-05-08 17:22:02 +0200274static int __devinit w83781d_isa_probe(struct platform_device *pdev);
275static int __devexit w83781d_isa_remove(struct platform_device *pdev);
276
Darren Jenkinsf6c27fc2006-02-27 23:14:58 +0100277static int w83781d_read_value(struct i2c_client *client, u16 reg);
278static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200280static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282static struct i2c_driver w83781d_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100283 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100284 .name = "w83781d",
285 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 .id = I2C_DRIVERID_W83781D,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 .attach_adapter = w83781d_attach_adapter,
288 .detach_client = w83781d_detach_client,
289};
290
Jean Delvare7666c132007-05-08 17:22:02 +0200291static struct platform_driver w83781d_isa_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100292 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200293 .owner = THIS_MODULE,
Jean Delvare7666c132007-05-08 17:22:02 +0200294 .name = "w83781d",
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100295 },
Jean Delvare7666c132007-05-08 17:22:02 +0200296 .probe = w83781d_isa_probe,
297 .remove = w83781d_isa_remove,
Jean Delvarefde09502005-07-19 23:51:07 +0200298};
299
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301/* following are the sysfs callback functions */
302#define show_in_reg(reg) \
303static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
304{ \
305 struct w83781d_data *data = w83781d_update_device(dev); \
306 return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \
307}
308show_in_reg(in);
309show_in_reg(in_min);
310show_in_reg(in_max);
311
312#define store_in_reg(REG, reg) \
313static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
314{ \
Jean Delvare7666c132007-05-08 17:22:02 +0200315 struct w83781d_data *data = dev_get_drvdata(dev); \
316 struct i2c_client *client = &data->client; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 u32 val; \
318 \
319 val = simple_strtoul(buf, NULL, 10) / 10; \
320 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100321 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 data->in_##reg[nr] = IN_TO_REG(val); \
323 w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
324 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100325 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 return count; \
327}
328store_in_reg(MIN, min);
329store_in_reg(MAX, max);
330
331#define sysfs_in_offset(offset) \
332static ssize_t \
Yani Ioannoue404e272005-05-17 06:42:58 -0400333show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{ \
335 return show_in(dev, buf, offset); \
336} \
337static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
338
339#define sysfs_in_reg_offset(reg, offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400340static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{ \
342 return show_in_##reg (dev, buf, offset); \
343} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400344static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{ \
346 return store_in_##reg (dev, buf, count, offset); \
347} \
348static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
349
350#define sysfs_in_offsets(offset) \
351sysfs_in_offset(offset); \
352sysfs_in_reg_offset(min, offset); \
353sysfs_in_reg_offset(max, offset);
354
355sysfs_in_offsets(0);
356sysfs_in_offsets(1);
357sysfs_in_offsets(2);
358sysfs_in_offsets(3);
359sysfs_in_offsets(4);
360sysfs_in_offsets(5);
361sysfs_in_offsets(6);
362sysfs_in_offsets(7);
363sysfs_in_offsets(8);
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365#define show_fan_reg(reg) \
366static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
367{ \
368 struct w83781d_data *data = w83781d_update_device(dev); \
369 return sprintf(buf,"%ld\n", \
370 FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
371}
372show_fan_reg(fan);
373show_fan_reg(fan_min);
374
375static ssize_t
376store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
377{
Jean Delvare7666c132007-05-08 17:22:02 +0200378 struct w83781d_data *data = dev_get_drvdata(dev);
379 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 u32 val;
381
382 val = simple_strtoul(buf, NULL, 10);
383
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100384 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 data->fan_min[nr - 1] =
386 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
387 w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
388 data->fan_min[nr - 1]);
389
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100390 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return count;
392}
393
394#define sysfs_fan_offset(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400395static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{ \
397 return show_fan(dev, buf, offset); \
398} \
399static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
400
401#define sysfs_fan_min_offset(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400402static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{ \
404 return show_fan_min(dev, buf, offset); \
405} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400406static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{ \
408 return store_fan_min(dev, buf, count, offset); \
409} \
410static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
411
412sysfs_fan_offset(1);
413sysfs_fan_min_offset(1);
414sysfs_fan_offset(2);
415sysfs_fan_min_offset(2);
416sysfs_fan_offset(3);
417sysfs_fan_min_offset(3);
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419#define show_temp_reg(reg) \
420static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
421{ \
422 struct w83781d_data *data = w83781d_update_device(dev); \
423 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
424 return sprintf(buf,"%d\n", \
425 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
426 } else { /* TEMP1 */ \
427 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
428 } \
429}
430show_temp_reg(temp);
431show_temp_reg(temp_max);
432show_temp_reg(temp_max_hyst);
433
434#define store_temp_reg(REG, reg) \
435static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
436{ \
Jean Delvare7666c132007-05-08 17:22:02 +0200437 struct w83781d_data *data = dev_get_drvdata(dev); \
438 struct i2c_client *client = &data->client; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 s32 val; \
440 \
441 val = simple_strtol(buf, NULL, 10); \
442 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100443 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 \
445 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
446 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
447 w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
448 data->temp_##reg##_add[nr-2]); \
449 } else { /* TEMP1 */ \
450 data->temp_##reg = TEMP_TO_REG(val); \
451 w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
452 data->temp_##reg); \
453 } \
454 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100455 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return count; \
457}
458store_temp_reg(OVER, max);
459store_temp_reg(HYST, max_hyst);
460
461#define sysfs_temp_offset(offset) \
462static ssize_t \
Yani Ioannoue404e272005-05-17 06:42:58 -0400463show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{ \
465 return show_temp(dev, buf, offset); \
466} \
467static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
468
469#define sysfs_temp_reg_offset(reg, offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400470static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{ \
472 return show_temp_##reg (dev, buf, offset); \
473} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400474static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{ \
476 return store_temp_##reg (dev, buf, count, offset); \
477} \
478static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
479
480#define sysfs_temp_offsets(offset) \
481sysfs_temp_offset(offset); \
482sysfs_temp_reg_offset(max, offset); \
483sysfs_temp_reg_offset(max_hyst, offset);
484
485sysfs_temp_offsets(1);
486sysfs_temp_offsets(2);
487sysfs_temp_offsets(3);
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400490show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 struct w83781d_data *data = w83781d_update_device(dev);
493 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
494}
495
Jim Cromie311ce2e2006-09-24 21:22:52 +0200496static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400499show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct w83781d_data *data = w83781d_update_device(dev);
502 return sprintf(buf, "%ld\n", (long) data->vrm);
503}
504
505static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400506store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Jean Delvare7666c132007-05-08 17:22:02 +0200508 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 u32 val;
510
511 val = simple_strtoul(buf, NULL, 10);
512 data->vrm = val;
513
514 return count;
515}
516
Jim Cromie311ce2e2006-09-24 21:22:52 +0200517static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400520show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200523 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
Jim Cromie311ce2e2006-09-24 21:22:52 +0200526static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
527
Yani Ioannoue404e272005-05-17 06:42:58 -0400528static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
530 struct w83781d_data *data = w83781d_update_device(dev);
531 return sprintf(buf, "%ld\n",
532 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
533}
Yani Ioannoue404e272005-05-17 06:42:58 -0400534static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 struct w83781d_data *data = w83781d_update_device(dev);
537 return sprintf(buf, "%ld\n",
538 (long)BEEP_ENABLE_FROM_REG(data->beep_enable));
539}
540
541#define BEEP_ENABLE 0 /* Store beep_enable */
542#define BEEP_MASK 1 /* Store beep_mask */
543
544static ssize_t
545store_beep_reg(struct device *dev, const char *buf, size_t count,
546 int update_mask)
547{
Jean Delvare7666c132007-05-08 17:22:02 +0200548 struct w83781d_data *data = dev_get_drvdata(dev);
549 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 u32 val, val2;
551
552 val = simple_strtoul(buf, NULL, 10);
553
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100554 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
557 data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
558 w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
559 data->beep_mask & 0xff);
560
561 if ((data->type != w83781d) && (data->type != as99127f)) {
562 w83781d_write_value(client, W83781D_REG_BEEP_INTS3,
563 ((data->beep_mask) >> 16) & 0xff);
564 }
565
566 val2 = (data->beep_mask >> 8) & 0x7f;
567 } else { /* We are storing beep_enable */
568 val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
569 data->beep_enable = BEEP_ENABLE_TO_REG(val);
570 }
571
572 w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
573 val2 | data->beep_enable << 7);
574
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100575 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return count;
577}
578
579#define sysfs_beep(REG, reg) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400580static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{ \
Yani Ioannoue404e272005-05-17 06:42:58 -0400582 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400584static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{ \
586 return store_beep_reg(dev, buf, count, BEEP_##REG); \
587} \
588static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
589
590sysfs_beep(ENABLE, enable);
591sysfs_beep(MASK, mask);
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593static ssize_t
594show_fan_div_reg(struct device *dev, char *buf, int nr)
595{
596 struct w83781d_data *data = w83781d_update_device(dev);
597 return sprintf(buf, "%ld\n",
598 (long) DIV_FROM_REG(data->fan_div[nr - 1]));
599}
600
601/* Note: we save and restore the fan minimum here, because its value is
602 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200603 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 because the divisor changed. */
605static ssize_t
606store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
607{
Jean Delvare7666c132007-05-08 17:22:02 +0200608 struct w83781d_data *data = dev_get_drvdata(dev);
609 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 unsigned long min;
611 u8 reg;
612 unsigned long val = simple_strtoul(buf, NULL, 10);
613
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100614 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 /* Save fan_min */
617 min = FAN_FROM_REG(data->fan_min[nr],
618 DIV_FROM_REG(data->fan_div[nr]));
619
620 data->fan_div[nr] = DIV_TO_REG(val, data->type);
621
622 reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
623 & (nr==0 ? 0xcf : 0x3f))
624 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
625 w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
626
627 /* w83781d and as99127f don't have extended divisor bits */
628 if (data->type != w83781d && data->type != as99127f) {
629 reg = (w83781d_read_value(client, W83781D_REG_VBAT)
630 & ~(1 << (5 + nr)))
631 | ((data->fan_div[nr] & 0x04) << (3 + nr));
632 w83781d_write_value(client, W83781D_REG_VBAT, reg);
633 }
634
635 /* Restore fan_min */
636 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
637 w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
638
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100639 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return count;
641}
642
643#define sysfs_fan_div(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400644static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{ \
646 return show_fan_div_reg(dev, buf, offset); \
647} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400648static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{ \
650 return store_fan_div_reg(dev, buf, count, offset - 1); \
651} \
652static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
653
654sysfs_fan_div(1);
655sysfs_fan_div(2);
656sysfs_fan_div(3);
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658static ssize_t
659show_pwm_reg(struct device *dev, char *buf, int nr)
660{
661 struct w83781d_data *data = w83781d_update_device(dev);
662 return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1]));
663}
664
665static ssize_t
666show_pwmenable_reg(struct device *dev, char *buf, int nr)
667{
668 struct w83781d_data *data = w83781d_update_device(dev);
669 return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]);
670}
671
672static ssize_t
673store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
674{
Jean Delvare7666c132007-05-08 17:22:02 +0200675 struct w83781d_data *data = dev_get_drvdata(dev);
676 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 u32 val;
678
679 val = simple_strtoul(buf, NULL, 10);
680
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100681 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 data->pwm[nr - 1] = PWM_TO_REG(val);
683 w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100684 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return count;
686}
687
688static ssize_t
689store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
690{
Jean Delvare7666c132007-05-08 17:22:02 +0200691 struct w83781d_data *data = dev_get_drvdata(dev);
692 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 u32 val, reg;
694
695 val = simple_strtoul(buf, NULL, 10);
696
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 switch (val) {
700 case 0:
701 case 1:
702 reg = w83781d_read_value(client, W83781D_REG_PWMCLK12);
703 w83781d_write_value(client, W83781D_REG_PWMCLK12,
704 (reg & 0xf7) | (val << 3));
705
706 reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
707 w83781d_write_value(client, W83781D_REG_BEEP_CONFIG,
708 (reg & 0xef) | (!val << 4));
709
710 data->pwmenable[nr - 1] = val;
711 break;
712
713 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100714 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return -EINVAL;
716 }
717
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100718 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return count;
720}
721
722#define sysfs_pwm(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400723static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{ \
725 return show_pwm_reg(dev, buf, offset); \
726} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400727static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 const char *buf, size_t count) \
729{ \
730 return store_pwm_reg(dev, buf, count, offset); \
731} \
732static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
733 show_regs_pwm_##offset, store_regs_pwm_##offset);
734
735#define sysfs_pwmenable(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400736static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{ \
738 return show_pwmenable_reg(dev, buf, offset); \
739} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400740static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 const char *buf, size_t count) \
742{ \
743 return store_pwmenable_reg(dev, buf, count, offset); \
744} \
745static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
746 show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
747
748sysfs_pwm(1);
749sysfs_pwm(2);
750sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
751sysfs_pwm(3);
752sysfs_pwm(4);
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754static ssize_t
755show_sensor_reg(struct device *dev, char *buf, int nr)
756{
757 struct w83781d_data *data = w83781d_update_device(dev);
758 return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
759}
760
761static ssize_t
762store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
763{
Jean Delvare7666c132007-05-08 17:22:02 +0200764 struct w83781d_data *data = dev_get_drvdata(dev);
765 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 u32 val, tmp;
767
768 val = simple_strtoul(buf, NULL, 10);
769
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100770 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 switch (val) {
773 case 1: /* PII/Celeron diode */
774 tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
775 w83781d_write_value(client, W83781D_REG_SCFG1,
776 tmp | BIT_SCFG1[nr - 1]);
777 tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
778 w83781d_write_value(client, W83781D_REG_SCFG2,
779 tmp | BIT_SCFG2[nr - 1]);
780 data->sens[nr - 1] = val;
781 break;
782 case 2: /* 3904 */
783 tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
784 w83781d_write_value(client, W83781D_REG_SCFG1,
785 tmp | BIT_SCFG1[nr - 1]);
786 tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
787 w83781d_write_value(client, W83781D_REG_SCFG2,
788 tmp & ~BIT_SCFG2[nr - 1]);
789 data->sens[nr - 1] = val;
790 break;
791 case W83781D_DEFAULT_BETA: /* thermistor */
792 tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
793 w83781d_write_value(client, W83781D_REG_SCFG1,
794 tmp & ~BIT_SCFG1[nr - 1]);
795 data->sens[nr - 1] = val;
796 break;
797 default:
798 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
799 (long) val, W83781D_DEFAULT_BETA);
800 break;
801 }
802
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100803 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return count;
805}
806
807#define sysfs_sensor(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400808static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{ \
810 return show_sensor_reg(dev, buf, offset); \
811} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400812static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{ \
814 return store_sensor_reg(dev, buf, count, offset); \
815} \
816static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
817
818sysfs_sensor(1);
819sysfs_sensor(2);
820sysfs_sensor(3);
821
Jean Delvare7666c132007-05-08 17:22:02 +0200822/* I2C devices get this name attribute automatically, but for ISA devices
823 we must create it by ourselves. */
824static ssize_t
825show_name(struct device *dev, struct device_attribute *devattr, char *buf)
826{
827 struct w83781d_data *data = dev_get_drvdata(dev);
828 return sprintf(buf, "%s\n", data->client.name);
829}
830static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832/* This function is called when:
833 * w83781d_driver is inserted (when this module is loaded), for each
834 available adapter
835 * when a new adapter is inserted (and w83781d_driver is still present) */
836static int
837w83781d_attach_adapter(struct i2c_adapter *adapter)
838{
839 if (!(adapter->class & I2C_CLASS_HWMON))
840 return 0;
Jean Delvare2ed2dc32005-07-31 21:42:02 +0200841 return i2c_probe(adapter, &addr_data, w83781d_detect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
844/* Assumes that adapter is of I2C, not ISA variety.
845 * OTHERWISE DON'T CALL THIS
846 */
847static int
848w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
849 struct i2c_client *new_client)
850{
851 int i, val1 = 0, id;
852 int err;
853 const char *client_name = "";
854 struct w83781d_data *data = i2c_get_clientdata(new_client);
855
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200856 data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (!(data->lm75[0])) {
858 err = -ENOMEM;
859 goto ERROR_SC_0;
860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
862 id = i2c_adapter_id(adapter);
863
864 if (force_subclients[0] == id && force_subclients[1] == address) {
865 for (i = 2; i <= 3; i++) {
866 if (force_subclients[i] < 0x48 ||
867 force_subclients[i] > 0x4f) {
868 dev_err(&new_client->dev, "Invalid subclient "
869 "address %d; must be 0x48-0x4f\n",
870 force_subclients[i]);
871 err = -EINVAL;
872 goto ERROR_SC_1;
873 }
874 }
875 w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR,
876 (force_subclients[2] & 0x07) |
877 ((force_subclients[3] & 0x07) << 4));
878 data->lm75[0]->addr = force_subclients[2];
879 } else {
880 val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR);
881 data->lm75[0]->addr = 0x48 + (val1 & 0x07);
882 }
883
884 if (kind != w83783s) {
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200885 data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (!(data->lm75[1])) {
887 err = -ENOMEM;
888 goto ERROR_SC_1;
889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 if (force_subclients[0] == id &&
892 force_subclients[1] == address) {
893 data->lm75[1]->addr = force_subclients[3];
894 } else {
895 data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07);
896 }
897 if (data->lm75[0]->addr == data->lm75[1]->addr) {
898 dev_err(&new_client->dev,
899 "Duplicate addresses 0x%x for subclients.\n",
900 data->lm75[0]->addr);
901 err = -EBUSY;
902 goto ERROR_SC_2;
903 }
904 }
905
906 if (kind == w83781d)
907 client_name = "w83781d subclient";
908 else if (kind == w83782d)
909 client_name = "w83782d subclient";
910 else if (kind == w83783s)
911 client_name = "w83783s subclient";
912 else if (kind == w83627hf)
913 client_name = "w83627hf subclient";
914 else if (kind == as99127f)
915 client_name = "as99127f subclient";
916
917 for (i = 0; i <= 1; i++) {
918 /* store all data in w83781d */
919 i2c_set_clientdata(data->lm75[i], NULL);
920 data->lm75[i]->adapter = adapter;
921 data->lm75[i]->driver = &w83781d_driver;
922 data->lm75[i]->flags = 0;
923 strlcpy(data->lm75[i]->name, client_name,
924 I2C_NAME_SIZE);
925 if ((err = i2c_attach_client(data->lm75[i]))) {
926 dev_err(&new_client->dev, "Subclient %d "
927 "registration at address 0x%x "
928 "failed.\n", i, data->lm75[i]->addr);
929 if (i == 1)
930 goto ERROR_SC_3;
931 goto ERROR_SC_2;
932 }
933 if (kind == w83783s)
934 break;
935 }
936
937 return 0;
938
939/* Undo inits in case of errors */
940ERROR_SC_3:
941 i2c_detach_client(data->lm75[0]);
942ERROR_SC_2:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800943 kfree(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944ERROR_SC_1:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800945 kfree(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946ERROR_SC_0:
947 return err;
948}
949
Jim Cromie311ce2e2006-09-24 21:22:52 +0200950#define IN_UNIT_ATTRS(X) \
951 &dev_attr_in##X##_input.attr, \
952 &dev_attr_in##X##_min.attr, \
953 &dev_attr_in##X##_max.attr
954
955#define FAN_UNIT_ATTRS(X) \
956 &dev_attr_fan##X##_input.attr, \
957 &dev_attr_fan##X##_min.attr, \
958 &dev_attr_fan##X##_div.attr
959
960#define TEMP_UNIT_ATTRS(X) \
961 &dev_attr_temp##X##_input.attr, \
962 &dev_attr_temp##X##_max.attr, \
963 &dev_attr_temp##X##_max_hyst.attr
964
965static struct attribute* w83781d_attributes[] = {
966 IN_UNIT_ATTRS(0),
967 IN_UNIT_ATTRS(2),
968 IN_UNIT_ATTRS(3),
969 IN_UNIT_ATTRS(4),
970 IN_UNIT_ATTRS(5),
971 IN_UNIT_ATTRS(6),
972 FAN_UNIT_ATTRS(1),
973 FAN_UNIT_ATTRS(2),
974 FAN_UNIT_ATTRS(3),
975 TEMP_UNIT_ATTRS(1),
976 TEMP_UNIT_ATTRS(2),
977 &dev_attr_cpu0_vid.attr,
978 &dev_attr_vrm.attr,
979 &dev_attr_alarms.attr,
980 &dev_attr_beep_mask.attr,
981 &dev_attr_beep_enable.attr,
982 NULL
983};
984static const struct attribute_group w83781d_group = {
985 .attrs = w83781d_attributes,
986};
987
988static struct attribute *w83781d_attributes_opt[] = {
989 IN_UNIT_ATTRS(1),
990 IN_UNIT_ATTRS(7),
991 IN_UNIT_ATTRS(8),
992 TEMP_UNIT_ATTRS(3),
993 &dev_attr_pwm1.attr,
994 &dev_attr_pwm2.attr,
995 &dev_attr_pwm2_enable.attr,
996 &dev_attr_pwm3.attr,
997 &dev_attr_pwm4.attr,
998 &dev_attr_temp1_type.attr,
999 &dev_attr_temp2_type.attr,
1000 &dev_attr_temp3_type.attr,
1001 NULL
1002};
1003static const struct attribute_group w83781d_group_opt = {
1004 .attrs = w83781d_attributes_opt,
1005};
1006
Jean Delvare7666c132007-05-08 17:22:02 +02001007/* No clean up is done on error, it's up to the caller */
1008static int
1009w83781d_create_files(struct device *dev, int kind, int is_isa)
1010{
1011 int err;
1012
1013 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
1014 return err;
1015
1016 if (kind != w83783s) {
1017 if ((err = device_create_file(dev, &dev_attr_in1_input))
1018 || (err = device_create_file(dev, &dev_attr_in1_min))
1019 || (err = device_create_file(dev, &dev_attr_in1_max)))
1020 return err;
1021 }
1022 if (kind != as99127f && kind != w83781d && kind != w83783s) {
1023 if ((err = device_create_file(dev, &dev_attr_in7_input))
1024 || (err = device_create_file(dev, &dev_attr_in7_min))
1025 || (err = device_create_file(dev, &dev_attr_in7_max))
1026 || (err = device_create_file(dev, &dev_attr_in8_input))
1027 || (err = device_create_file(dev, &dev_attr_in8_min))
1028 || (err = device_create_file(dev, &dev_attr_in8_max)))
1029 return err;
1030 }
1031 if (kind != w83783s) {
1032 if ((err = device_create_file(dev, &dev_attr_temp3_input))
1033 || (err = device_create_file(dev, &dev_attr_temp3_max))
1034 || (err = device_create_file(dev,
1035 &dev_attr_temp3_max_hyst)))
1036 return err;
1037 }
1038
1039 if (kind != w83781d && kind != as99127f) {
1040 if ((err = device_create_file(dev, &dev_attr_pwm1))
1041 || (err = device_create_file(dev, &dev_attr_pwm2))
1042 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1043 return err;
1044 }
1045 if (kind == w83782d && !is_isa) {
1046 if ((err = device_create_file(dev, &dev_attr_pwm3))
1047 || (err = device_create_file(dev, &dev_attr_pwm4)))
1048 return err;
1049 }
1050
1051 if (kind != as99127f && kind != w83781d) {
1052 if ((err = device_create_file(dev, &dev_attr_temp1_type))
1053 || (err = device_create_file(dev,
1054 &dev_attr_temp2_type)))
1055 return err;
1056 if (kind != w83783s) {
1057 if ((err = device_create_file(dev,
1058 &dev_attr_temp3_type)))
1059 return err;
1060 }
1061 }
1062
1063 if (is_isa) {
1064 err = device_create_file(&pdev->dev, &dev_attr_name);
1065 if (err)
1066 return err;
1067 }
1068
1069 return 0;
1070}
1071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072static int
1073w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
1074{
Jean Delvare7666c132007-05-08 17:22:02 +02001075 int val1 = 0, val2;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001076 struct i2c_client *client;
1077 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct w83781d_data *data;
1079 int err;
1080 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 enum vendor { winbond, asus } vendid;
1082
Jean Delvare7666c132007-05-08 17:22:02 +02001083 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 err = -EINVAL;
Jean Delvare7666c132007-05-08 17:22:02 +02001085 goto ERROR1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
1087
1088 /* OK. For now, we presume we have a valid client. We now create the
1089 client structure, even though we cannot fill it completely yet.
1090 But it allows us to access w83781d_{read,write}_value. */
1091
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001092 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 err = -ENOMEM;
1094 goto ERROR1;
1095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Jim Cromie311ce2e2006-09-24 21:22:52 +02001097 client = &data->client;
1098 i2c_set_clientdata(client, data);
1099 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001100 mutex_init(&data->lock);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001101 client->adapter = adapter;
Jean Delvare7666c132007-05-08 17:22:02 +02001102 client->driver = &w83781d_driver;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001103 dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 /* Now, we do the remaining detection. */
1106
1107 /* The w8378?d may be stuck in some other bank than bank 0. This may
1108 make reading other information impossible. Specify a force=... or
1109 force_*=... parameter, and the Winbond will be reset to the right
1110 bank. */
1111 if (kind < 0) {
Jim Cromie311ce2e2006-09-24 21:22:52 +02001112 if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001113 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1114 "failed at step 3\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 err = -ENODEV;
1116 goto ERROR2;
1117 }
Jim Cromie311ce2e2006-09-24 21:22:52 +02001118 val1 = w83781d_read_value(client, W83781D_REG_BANK);
1119 val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 /* Check for Winbond or Asus ID if in bank 0 */
1121 if ((!(val1 & 0x07)) &&
1122 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1123 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001124 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1125 "failed at step 4\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 err = -ENODEV;
1127 goto ERROR2;
1128 }
1129 /* If Winbond SMBus, check address at 0x48.
1130 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001131 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1132 ((val1 & 0x80) && (val2 == 0x5c))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (w83781d_read_value
Jim Cromie311ce2e2006-09-24 21:22:52 +02001134 (client, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001135 dev_dbg(&adapter->dev, "Detection of w83781d "
1136 "chip failed at step 5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 err = -ENODEV;
1138 goto ERROR2;
1139 }
1140 }
1141 }
1142
1143 /* We have either had a force parameter, or we have already detected the
1144 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001145 w83781d_write_value(client, W83781D_REG_BANK,
1146 (w83781d_read_value(client, W83781D_REG_BANK)
1147 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 /* Determine the chip type. */
1150 if (kind <= 0) {
1151 /* get vendor ID */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001152 val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (val2 == 0x5c)
1154 vendid = winbond;
1155 else if (val2 == 0x12)
1156 vendid = asus;
1157 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001158 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1159 "neither Winbond nor Asus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 err = -ENODEV;
1161 goto ERROR2;
1162 }
1163
Jim Cromie311ce2e2006-09-24 21:22:52 +02001164 val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1166 kind = w83781d;
1167 else if (val1 == 0x30 && vendid == winbond)
1168 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001169 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 kind = w83783s;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001171 else if (val1 == 0x21 && vendid == winbond)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 kind = w83627hf;
Jean Delvare7666c132007-05-08 17:22:02 +02001173 else if (val1 == 0x31 && address >= 0x28)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 else {
1176 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001177 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001179 "address 0x%02x\n", address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 err = -EINVAL;
1181 goto ERROR2;
1182 }
1183 }
1184
1185 if (kind == w83781d) {
1186 client_name = "w83781d";
1187 } else if (kind == w83782d) {
1188 client_name = "w83782d";
1189 } else if (kind == w83783s) {
1190 client_name = "w83783s";
1191 } else if (kind == w83627hf) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001192 client_name = "w83627hf";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 } else if (kind == as99127f) {
1194 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 }
1196
1197 /* Fill in the remaining client fields and put into the global list */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001198 strlcpy(client->name, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 data->type = kind;
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 /* Tell the I2C layer a new client has arrived */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001202 if ((err = i2c_attach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 goto ERROR2;
1204
1205 /* attach secondary i2c lm75-like clients */
Jean Delvare7666c132007-05-08 17:22:02 +02001206 if ((err = w83781d_detect_subclients(adapter, address,
1207 kind, client)))
1208 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001211 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 /* Register sysfs hooks */
Jean Delvare7666c132007-05-08 17:22:02 +02001214 err = w83781d_create_files(dev, kind, 0);
1215 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001216 goto ERROR4;
1217
Jim Cromie311ce2e2006-09-24 21:22:52 +02001218 data->class_dev = hwmon_device_register(dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001219 if (IS_ERR(data->class_dev)) {
1220 err = PTR_ERR(data->class_dev);
1221 goto ERROR4;
1222 }
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return 0;
1225
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001226ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001227 sysfs_remove_group(&dev->kobj, &w83781d_group);
1228 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1229
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001230 if (data->lm75[1]) {
1231 i2c_detach_client(data->lm75[1]);
1232 kfree(data->lm75[1]);
1233 }
1234 if (data->lm75[0]) {
1235 i2c_detach_client(data->lm75[0]);
1236 kfree(data->lm75[0]);
1237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238ERROR3:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001239 i2c_detach_client(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240ERROR2:
1241 kfree(data);
1242ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 return err;
1244}
1245
1246static int
1247w83781d_detach_client(struct i2c_client *client)
1248{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001249 struct w83781d_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 int err;
1251
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001252 /* main client */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001253 if (data) {
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001254 hwmon_device_unregister(data->class_dev);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001255 sysfs_remove_group(&client->dev.kobj, &w83781d_group);
1256 sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
1257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Jean Delvare7bef5592005-07-27 22:14:49 +02001259 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001262 /* main client */
1263 if (data)
1264 kfree(data);
1265
1266 /* subclient */
1267 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 kfree(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 return 0;
1271}
1272
Jean Delvare7666c132007-05-08 17:22:02 +02001273static int __devinit
1274w83781d_isa_probe(struct platform_device *pdev)
1275{
1276 int err, reg;
1277 struct w83781d_data *data;
1278 struct resource *res;
1279 const char *name;
1280
1281 /* Reserve the ISA region */
1282 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1283 if (!request_region(res->start, W83781D_EXTENT, "w83781d")) {
1284 err = -EBUSY;
1285 goto exit;
1286 }
1287
1288 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
1289 err = -ENOMEM;
1290 goto exit_release_region;
1291 }
1292 mutex_init(&data->lock);
1293 data->client.addr = res->start;
1294 i2c_set_clientdata(&data->client, data);
1295 platform_set_drvdata(pdev, data);
1296
1297 reg = w83781d_read_value(&data->client, W83781D_REG_WCHIPID);
1298 switch (reg) {
1299 case 0x21:
1300 data->type = w83627hf;
1301 name = "w83627hf";
1302 break;
1303 case 0x30:
1304 data->type = w83782d;
1305 name = "w83782d";
1306 break;
1307 default:
1308 data->type = w83781d;
1309 name = "w83781d";
1310 }
1311 strlcpy(data->client.name, name, I2C_NAME_SIZE);
1312
1313 /* Initialize the W83781D chip */
1314 w83781d_init_device(&pdev->dev);
1315
1316 /* Register sysfs hooks */
1317 err = w83781d_create_files(&pdev->dev, data->type, 1);
1318 if (err)
1319 goto exit_remove_files;
1320
1321 data->class_dev = hwmon_device_register(&pdev->dev);
1322 if (IS_ERR(data->class_dev)) {
1323 err = PTR_ERR(data->class_dev);
1324 goto exit_remove_files;
1325 }
1326
1327 return 0;
1328
1329 exit_remove_files:
1330 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1331 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1332 device_remove_file(&pdev->dev, &dev_attr_name);
1333 kfree(data);
1334 exit_release_region:
1335 release_region(res->start, W83781D_EXTENT);
1336 exit:
1337 return err;
1338}
1339
1340static int __devexit
1341w83781d_isa_remove(struct platform_device *pdev)
1342{
1343 struct w83781d_data *data = platform_get_drvdata(pdev);
1344
1345 hwmon_device_unregister(data->class_dev);
1346 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1347 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1348 device_remove_file(&pdev->dev, &dev_attr_name);
1349 release_region(data->client.addr, W83781D_EXTENT);
1350 kfree(data);
1351
1352 return 0;
1353}
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355/* The SMBus locks itself, usually, but nothing may access the Winbond between
1356 bank switches. ISA access must always be locked explicitly!
1357 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1358 would slow down the W83781D access and should not be necessary.
1359 There are some ugly typecasts here, but the good news is - they should
1360 nowhere else be necessary! */
1361static int
1362w83781d_read_value(struct i2c_client *client, u16 reg)
1363{
1364 struct w83781d_data *data = i2c_get_clientdata(client);
1365 int res, word_sized, bank;
1366 struct i2c_client *cl;
1367
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001368 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001369 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 word_sized = (((reg & 0xff00) == 0x100)
1371 || ((reg & 0xff00) == 0x200))
1372 && (((reg & 0x00ff) == 0x50)
1373 || ((reg & 0x00ff) == 0x53)
1374 || ((reg & 0x00ff) == 0x55));
1375 if (reg & 0xff00) {
1376 outb_p(W83781D_REG_BANK,
1377 client->addr + W83781D_ADDR_REG_OFFSET);
1378 outb_p(reg >> 8,
1379 client->addr + W83781D_DATA_REG_OFFSET);
1380 }
1381 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1382 res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
1383 if (word_sized) {
1384 outb_p((reg & 0xff) + 1,
1385 client->addr + W83781D_ADDR_REG_OFFSET);
1386 res =
1387 (res << 8) + inb_p(client->addr +
1388 W83781D_DATA_REG_OFFSET);
1389 }
1390 if (reg & 0xff00) {
1391 outb_p(W83781D_REG_BANK,
1392 client->addr + W83781D_ADDR_REG_OFFSET);
1393 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1394 }
1395 } else {
1396 bank = (reg >> 8) & 0x0f;
1397 if (bank > 2)
1398 /* switch banks */
1399 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1400 bank);
1401 if (bank == 0 || bank > 2) {
1402 res = i2c_smbus_read_byte_data(client, reg & 0xff);
1403 } else {
1404 /* switch to subclient */
1405 cl = data->lm75[bank - 1];
1406 /* convert from ISA to LM75 I2C addresses */
1407 switch (reg & 0xff) {
1408 case 0x50: /* TEMP */
1409 res = swab16(i2c_smbus_read_word_data(cl, 0));
1410 break;
1411 case 0x52: /* CONFIG */
1412 res = i2c_smbus_read_byte_data(cl, 1);
1413 break;
1414 case 0x53: /* HYST */
1415 res = swab16(i2c_smbus_read_word_data(cl, 2));
1416 break;
1417 case 0x55: /* OVER */
1418 default:
1419 res = swab16(i2c_smbus_read_word_data(cl, 3));
1420 break;
1421 }
1422 }
1423 if (bank > 2)
1424 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1425 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001426 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 return res;
1428}
1429
1430static int
1431w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
1432{
1433 struct w83781d_data *data = i2c_get_clientdata(client);
1434 int word_sized, bank;
1435 struct i2c_client *cl;
1436
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001437 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001438 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 word_sized = (((reg & 0xff00) == 0x100)
1440 || ((reg & 0xff00) == 0x200))
1441 && (((reg & 0x00ff) == 0x53)
1442 || ((reg & 0x00ff) == 0x55));
1443 if (reg & 0xff00) {
1444 outb_p(W83781D_REG_BANK,
1445 client->addr + W83781D_ADDR_REG_OFFSET);
1446 outb_p(reg >> 8,
1447 client->addr + W83781D_DATA_REG_OFFSET);
1448 }
1449 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1450 if (word_sized) {
1451 outb_p(value >> 8,
1452 client->addr + W83781D_DATA_REG_OFFSET);
1453 outb_p((reg & 0xff) + 1,
1454 client->addr + W83781D_ADDR_REG_OFFSET);
1455 }
1456 outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
1457 if (reg & 0xff00) {
1458 outb_p(W83781D_REG_BANK,
1459 client->addr + W83781D_ADDR_REG_OFFSET);
1460 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1461 }
1462 } else {
1463 bank = (reg >> 8) & 0x0f;
1464 if (bank > 2)
1465 /* switch banks */
1466 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1467 bank);
1468 if (bank == 0 || bank > 2) {
1469 i2c_smbus_write_byte_data(client, reg & 0xff,
1470 value & 0xff);
1471 } else {
1472 /* switch to subclient */
1473 cl = data->lm75[bank - 1];
1474 /* convert from ISA to LM75 I2C addresses */
1475 switch (reg & 0xff) {
1476 case 0x52: /* CONFIG */
1477 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1478 break;
1479 case 0x53: /* HYST */
1480 i2c_smbus_write_word_data(cl, 2, swab16(value));
1481 break;
1482 case 0x55: /* OVER */
1483 i2c_smbus_write_word_data(cl, 3, swab16(value));
1484 break;
1485 }
1486 }
1487 if (bank > 2)
1488 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1489 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001490 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 return 0;
1492}
1493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494static void
Jean Delvare7666c132007-05-08 17:22:02 +02001495w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496{
Jean Delvare7666c132007-05-08 17:22:02 +02001497 struct w83781d_data *data = dev_get_drvdata(dev);
1498 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 int i, p;
1500 int type = data->type;
1501 u8 tmp;
1502
Jean Delvarefabddcd2006-02-05 23:26:51 +01001503 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001505 /* Resetting the chip has been the default for a long time,
1506 but it causes the BIOS initializations (fan clock dividers,
1507 thermal sensor types...) to be lost, so it is now optional.
1508 It might even go away if nobody reports it as being useful,
1509 as I see very little reason why this would be needed at
1510 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001511 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001512 "having, please report!\n");
1513
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 /* save these registers */
1515 i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
1516 p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
1517 /* Reset all except Watchdog values and last conversion values
1518 This sets fan-divs to 2, among others */
1519 w83781d_write_value(client, W83781D_REG_CONFIG, 0x80);
1520 /* Restore the registers and disable power-on abnormal beep.
1521 This saves FAN 1/2/3 input/output values set by BIOS. */
1522 w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
1523 w83781d_write_value(client, W83781D_REG_PWMCLK12, p);
1524 /* Disable master beep-enable (reset turns it on).
1525 Individual beep_mask should be reset to off but for some reason
1526 disabling this bit helps some people not get beeped */
1527 w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
1528 }
1529
Jean Delvarefabddcd2006-02-05 23:26:51 +01001530 /* Disable power-on abnormal beep, as advised by the datasheet.
1531 Already done if reset=1. */
1532 if (init && !reset && type != as99127f) {
1533 i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
1534 w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
1535 }
1536
Jean Delvare303760b2005-07-31 21:52:01 +02001537 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539 if ((type != w83781d) && (type != as99127f)) {
1540 tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
1541 for (i = 1; i <= 3; i++) {
1542 if (!(tmp & BIT_SCFG1[i - 1])) {
1543 data->sens[i - 1] = W83781D_DEFAULT_BETA;
1544 } else {
1545 if (w83781d_read_value
1546 (client,
1547 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1548 data->sens[i - 1] = 1;
1549 else
1550 data->sens[i - 1] = 2;
1551 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001552 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 break;
1554 }
1555 }
1556
1557 if (init && type != as99127f) {
1558 /* Enable temp2 */
1559 tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG);
1560 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001561 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 "might not make sense\n");
1563 w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG,
1564 tmp & 0xfe);
1565 }
1566
1567 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001568 if (type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 tmp = w83781d_read_value(client,
1570 W83781D_REG_TEMP3_CONFIG);
1571 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001572 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 "readings might not make sense\n");
1574 w83781d_write_value(client,
1575 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1576 }
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 }
1579
1580 /* Start monitoring */
1581 w83781d_write_value(client, W83781D_REG_CONFIG,
1582 (w83781d_read_value(client,
1583 W83781D_REG_CONFIG) & 0xf7)
1584 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001585
1586 /* A few vars need to be filled upon startup */
1587 for (i = 1; i <= 3; i++) {
1588 data->fan_min[i - 1] = w83781d_read_value(client,
1589 W83781D_REG_FAN_MIN(i));
1590 }
1591 if (type != w83781d && type != as99127f)
1592 for (i = 0; i < 4; i++)
1593 data->pwmenable[i] = 1;
1594
1595 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596}
1597
1598static struct w83781d_data *w83781d_update_device(struct device *dev)
1599{
Jean Delvare7666c132007-05-08 17:22:02 +02001600 struct w83781d_data *data = dev_get_drvdata(dev);
1601 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 int i;
1603
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001604 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1607 || !data->valid) {
1608 dev_dbg(dev, "Starting device update\n");
1609
1610 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001611 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 continue; /* 783S has no in1 */
1613 data->in[i] =
1614 w83781d_read_value(client, W83781D_REG_IN(i));
1615 data->in_min[i] =
1616 w83781d_read_value(client, W83781D_REG_IN_MIN(i));
1617 data->in_max[i] =
1618 w83781d_read_value(client, W83781D_REG_IN_MAX(i));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001619 if ((data->type != w83782d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 && (data->type != w83627hf) && (i == 6))
1621 break;
1622 }
1623 for (i = 1; i <= 3; i++) {
1624 data->fan[i - 1] =
1625 w83781d_read_value(client, W83781D_REG_FAN(i));
1626 data->fan_min[i - 1] =
1627 w83781d_read_value(client, W83781D_REG_FAN_MIN(i));
1628 }
1629 if (data->type != w83781d && data->type != as99127f) {
1630 for (i = 1; i <= 4; i++) {
1631 data->pwm[i - 1] =
1632 w83781d_read_value(client,
1633 W83781D_REG_PWM(i));
Jean Delvare7666c132007-05-08 17:22:02 +02001634 if ((data->type != w83782d || !client->driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 && i == 2)
1636 break;
1637 }
1638 /* Only PWM2 can be disabled */
1639 data->pwmenable[1] = (w83781d_read_value(client,
1640 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1641 }
1642
1643 data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));
1644 data->temp_max =
1645 w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
1646 data->temp_max_hyst =
1647 w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));
1648 data->temp_add[0] =
1649 w83781d_read_value(client, W83781D_REG_TEMP(2));
1650 data->temp_max_add[0] =
1651 w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
1652 data->temp_max_hyst_add[0] =
1653 w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001654 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 data->temp_add[1] =
1656 w83781d_read_value(client, W83781D_REG_TEMP(3));
1657 data->temp_max_add[1] =
1658 w83781d_read_value(client,
1659 W83781D_REG_TEMP_OVER(3));
1660 data->temp_max_hyst_add[1] =
1661 w83781d_read_value(client,
1662 W83781D_REG_TEMP_HYST(3));
1663 }
1664 i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001665 data->vid = i & 0x0f;
1666 data->vid |= (w83781d_read_value(client,
1667 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 data->fan_div[0] = (i >> 4) & 0x03;
1669 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001670 data->fan_div[2] = (w83781d_read_value(client,
1671 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if ((data->type != w83781d) && (data->type != as99127f)) {
1673 i = w83781d_read_value(client, W83781D_REG_VBAT);
1674 data->fan_div[0] |= (i >> 3) & 0x04;
1675 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001676 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 if ((data->type == w83782d) || (data->type == w83627hf)) {
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001679 data->alarms = w83781d_read_value(client,
1680 W83782D_REG_ALARM1)
1681 | (w83781d_read_value(client,
1682 W83782D_REG_ALARM2) << 8)
1683 | (w83781d_read_value(client,
1684 W83782D_REG_ALARM3) << 16);
1685 } else if (data->type == w83783s) {
1686 data->alarms = w83781d_read_value(client,
1687 W83782D_REG_ALARM1)
1688 | (w83781d_read_value(client,
1689 W83782D_REG_ALARM2) << 8);
1690 } else {
1691 /* No real-time status registers, fall back to
1692 interrupt status registers */
1693 data->alarms = w83781d_read_value(client,
1694 W83781D_REG_ALARM1)
1695 | (w83781d_read_value(client,
1696 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 }
1698 i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
1699 data->beep_enable = i >> 7;
1700 data->beep_mask = ((i & 0x7f) << 8) +
1701 w83781d_read_value(client, W83781D_REG_BEEP_INTS1);
1702 if ((data->type != w83781d) && (data->type != as99127f)) {
1703 data->beep_mask |=
1704 w83781d_read_value(client,
1705 W83781D_REG_BEEP_INTS3) << 16;
1706 }
1707 data->last_updated = jiffies;
1708 data->valid = 1;
1709 }
1710
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001711 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 return data;
1714}
1715
Jean Delvare7666c132007-05-08 17:22:02 +02001716/* return 1 if a supported chip is found, 0 otherwise */
1717static int __init
1718w83781d_isa_found(unsigned short address)
1719{
1720 int val, save, found = 0;
1721
1722 if (!request_region(address, W83781D_EXTENT, "w83781d"))
1723 return 0;
1724
1725#define REALLY_SLOW_IO
1726 /* We need the timeouts for at least some W83781D-like
1727 chips. But only if we read 'undefined' registers. */
1728 val = inb_p(address + 1);
1729 if (inb_p(address + 2) != val
1730 || inb_p(address + 3) != val
1731 || inb_p(address + 7) != val) {
1732 pr_debug("w83781d: Detection failed at step 1\n");
1733 goto release;
1734 }
1735#undef REALLY_SLOW_IO
1736
1737 /* We should be able to change the 7 LSB of the address port. The
1738 MSB (busy flag) should be clear initially, set after the write. */
1739 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1740 if (save & 0x80) {
1741 pr_debug("w83781d: Detection failed at step 2\n");
1742 goto release;
1743 }
1744 val = ~save & 0x7f;
1745 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1746 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1747 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1748 pr_debug("w83781d: Detection failed at step 3\n");
1749 goto release;
1750 }
1751
1752 /* We found a device, now see if it could be a W83781D */
1753 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1754 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1755 if (val & 0x80) {
1756 pr_debug("w83781d: Detection failed at step 4\n");
1757 goto release;
1758 }
1759 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1760 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1761 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1762 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1763 if ((!(save & 0x80) && (val != 0xa3))
1764 || ((save & 0x80) && (val != 0x5c))) {
1765 pr_debug("w83781d: Detection failed at step 5\n");
1766 goto release;
1767 }
1768 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1769 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1770 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1771 pr_debug("w83781d: Detection failed at step 6\n");
1772 goto release;
1773 }
1774
1775 /* The busy flag should be clear again */
1776 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1777 pr_debug("w83781d: Detection failed at step 7\n");
1778 goto release;
1779 }
1780
1781 /* Determine the chip type */
1782 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1783 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1784 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1785 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1786 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1787 if ((val & 0xfe) == 0x10 /* W83781D */
1788 || val == 0x30 /* W83782D */
1789 || val == 0x21) /* W83627HF */
1790 found = 1;
1791
1792 if (found)
1793 pr_info("w83781d: Found a %s chip at %#x\n",
1794 val == 0x21 ? "W83627HF" :
1795 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1796
1797 release:
1798 release_region(address, W83781D_EXTENT);
1799 return found;
1800}
1801
1802static int __init
1803w83781d_isa_device_add(unsigned short address)
1804{
1805 struct resource res = {
1806 .start = address,
1807 .end = address + W83781D_EXTENT,
1808 .name = "w83781d",
1809 .flags = IORESOURCE_IO,
1810 };
1811 int err;
1812
1813 pdev = platform_device_alloc("w83781d", address);
1814 if (!pdev) {
1815 err = -ENOMEM;
1816 printk(KERN_ERR "w83781d: Device allocation failed\n");
1817 goto exit;
1818 }
1819
1820 err = platform_device_add_resources(pdev, &res, 1);
1821 if (err) {
1822 printk(KERN_ERR "w83781d: Device resource addition failed "
1823 "(%d)\n", err);
1824 goto exit_device_put;
1825 }
1826
1827 err = platform_device_add(pdev);
1828 if (err) {
1829 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1830 err);
1831 goto exit_device_put;
1832 }
1833
1834 return 0;
1835
1836 exit_device_put:
1837 platform_device_put(pdev);
1838 exit:
1839 pdev = NULL;
1840 return err;
1841}
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843static int __init
1844sensors_w83781d_init(void)
1845{
Jean Delvarefde09502005-07-19 23:51:07 +02001846 int res;
1847
1848 res = i2c_add_driver(&w83781d_driver);
1849 if (res)
Jean Delvare7666c132007-05-08 17:22:02 +02001850 goto exit;
Jean Delvarefde09502005-07-19 23:51:07 +02001851
Jean Delvare7666c132007-05-08 17:22:02 +02001852 if (w83781d_isa_found(isa_address)) {
1853 res = platform_driver_register(&w83781d_isa_driver);
1854 if (res)
1855 goto exit_unreg_i2c_driver;
1856
1857 /* Sets global pdev as a side effect */
1858 res = w83781d_isa_device_add(isa_address);
1859 if (res)
1860 goto exit_unreg_isa_driver;
1861 }
Jean Delvarefde09502005-07-19 23:51:07 +02001862
1863 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02001864
1865 exit_unreg_isa_driver:
1866 platform_driver_unregister(&w83781d_isa_driver);
1867 exit_unreg_i2c_driver:
1868 i2c_del_driver(&w83781d_driver);
1869 exit:
1870 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871}
1872
1873static void __exit
1874sensors_w83781d_exit(void)
1875{
Jean Delvare7666c132007-05-08 17:22:02 +02001876 if (pdev) {
1877 platform_device_unregister(pdev);
1878 platform_driver_unregister(&w83781d_isa_driver);
1879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 i2c_del_driver(&w83781d_driver);
1881}
1882
1883MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1884 "Philip Edelbrock <phil@netroedge.com>, "
1885 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1886MODULE_DESCRIPTION("W83781D driver");
1887MODULE_LICENSE("GPL");
1888
1889module_init(sensors_w83781d_init);
1890module_exit(sensors_w83781d_exit);