blob: 136bec3fd64542f952e7325c17805ac306249e3a [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
32 w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34*/
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/module.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/jiffies.h>
40#include <linux/i2c.h>
Jean Delvare7666c132007-05-08 17:22:02 +020041#include <linux/platform_device.h>
42#include <linux/ioport.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040043#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020044#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020045#include <linux/hwmon-sysfs.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 */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050056static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
57 0x2e, 0x2f, I2C_CLIENT_END };
Jean Delvare2d8672c2005-07-19 23:56:35 +020058static unsigned short isa_address = 0x290;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/* Insmod parameters */
Jean Delvare05663362007-11-30 23:51:24 +010061I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
63 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
64
Jean Delvarefabddcd2006-02-05 23:26:51 +010065static int reset;
66module_param(reset, bool, 0);
67MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static int init = 1;
70module_param(init, bool, 0);
71MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
72
73/* Constants specified below */
74
75/* Length of ISA address segment */
76#define W83781D_EXTENT 8
77
78/* Where are the ISA address/data registers relative to the base address */
79#define W83781D_ADDR_REG_OFFSET 5
80#define W83781D_DATA_REG_OFFSET 6
81
Jean Delvare34875332007-05-08 17:22:03 +020082/* The device registers */
83/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
85 (0x554 + (((nr) - 7) * 2)))
86#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
87 (0x555 + (((nr) - 7) * 2)))
88#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
89 (0x550 + (nr) - 7))
90
Jean Delvare34875332007-05-08 17:22:03 +020091/* fan nr from 0 to 2 */
92#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
93#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95#define W83781D_REG_BANK 0x4E
96#define W83781D_REG_TEMP2_CONFIG 0x152
97#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +020098/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
100 ((nr == 2) ? (0x0150) : \
101 (0x27)))
102#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
103 ((nr == 2) ? (0x153) : \
104 (0x3A)))
105#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
106 ((nr == 2) ? (0x155) : \
107 (0x39)))
108
109#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100110
111/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define W83781D_REG_ALARM1 0x41
113#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Jean Delvare05663362007-11-30 23:51:24 +0100115/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100116#define W83782D_REG_ALARM1 0x459
117#define W83782D_REG_ALARM2 0x45A
118#define W83782D_REG_ALARM3 0x45B
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define W83781D_REG_BEEP_CONFIG 0x4D
121#define W83781D_REG_BEEP_INTS1 0x56
122#define W83781D_REG_BEEP_INTS2 0x57
123#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
124
125#define W83781D_REG_VID_FANDIV 0x47
126
127#define W83781D_REG_CHIPID 0x49
128#define W83781D_REG_WCHIPID 0x58
129#define W83781D_REG_CHIPMAN 0x4F
130#define W83781D_REG_PIN 0x4B
131
132/* 782D/783S only */
133#define W83781D_REG_VBAT 0x5D
134
135/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200136static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137#define W83781D_REG_PWMCLK12 0x5C
138#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140#define W83781D_REG_I2C_ADDR 0x48
141#define W83781D_REG_I2C_SUBADDR 0x4A
142
143/* The following are undocumented in the data sheets however we
144 received the information in an email from Winbond tech support */
145/* Sensor selection - not on 781d */
146#define W83781D_REG_SCFG1 0x5D
147static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
148
149#define W83781D_REG_SCFG2 0x59
150static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
151
152#define W83781D_DEFAULT_BETA 3435
153
Jean Delvare474d00a2007-05-08 17:22:03 +0200154/* Conversions */
155#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
156#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158static inline u8
159FAN_TO_REG(long rpm, int div)
160{
161 if (rpm == 0)
162 return 255;
163 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
164 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
165}
166
Jean Delvare474d00a2007-05-08 17:22:03 +0200167static inline long
168FAN_FROM_REG(u8 val, int div)
169{
170 if (val == 0)
171 return -1;
172 if (val == 255)
173 return 0;
174 return 1350000 / (val * div);
175}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Jean Delvare474d00a2007-05-08 17:22:03 +0200177#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
178#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200181 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200183 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#define DIV_FROM_REG(val) (1 << (val))
186
187static inline u8
188DIV_TO_REG(long val, enum chips type)
189{
190 int i;
191 val = SENSORS_LIMIT(val, 1,
192 ((type == w83781d
193 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000194 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 if (val == 0)
196 break;
197 val >>= 1;
198 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200199 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}
201
202/* There are some complications in a module like this. First off, W83781D chips
203 may be both present on the SMBus and the ISA bus, and we have to handle
204 those cases separately at some places. Second, there might be several
205 W83781D chips available (well, actually, that is probably never done; but
206 it is a clean illustration of how to handle a case like that). Finally,
207 a specific chip may be attached to *both* ISA and SMBus, and we would
208 not like to detect it double. Fortunately, in the case of the W83781D at
209 least, a register tells us what SMBus address we are on, so that helps
210 a bit - except if there could be more than one SMBus. Groan. No solution
211 for this yet. */
212
Jean Delvare7666c132007-05-08 17:22:02 +0200213/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
214 the driver field to differentiate between I2C and ISA chips. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215struct w83781d_data {
216 struct i2c_client client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700217 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100218 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 enum chips type;
220
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100221 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 char valid; /* !=0 if following fields are valid */
223 unsigned long last_updated; /* In jiffies */
224
225 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
226 /* array of 2 pointers to subclients */
227
228 u8 in[9]; /* Register value - 8 & 9 for 782D only */
229 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
230 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
231 u8 fan[3]; /* Register value */
232 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200233 s8 temp; /* Register value */
234 s8 temp_max; /* Register value */
235 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 u16 temp_add[2]; /* Register value */
237 u16 temp_max_add[2]; /* Register value */
238 u16 temp_max_hyst_add[2]; /* Register value */
239 u8 fan_div[3]; /* Register encoding, shifted right */
240 u8 vid; /* Register encoding, combined */
241 u32 alarms; /* Register encoding, combined */
242 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200244 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 u16 sens[3]; /* 782D/783S only.
246 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200247 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 u8 vrm;
249};
250
251static int w83781d_attach_adapter(struct i2c_adapter *adapter);
252static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
253static int w83781d_detach_client(struct i2c_client *client);
254
Jean Delvare7666c132007-05-08 17:22:02 +0200255static int __devinit w83781d_isa_probe(struct platform_device *pdev);
256static int __devexit w83781d_isa_remove(struct platform_device *pdev);
257
Jean Delvare31b8dc42007-05-08 17:22:03 +0200258static int w83781d_read_value(struct w83781d_data *data, u16 reg);
259static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200261static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263static struct i2c_driver w83781d_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100264 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100265 .name = "w83781d",
266 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .attach_adapter = w83781d_attach_adapter,
268 .detach_client = w83781d_detach_client,
269};
270
Jean Delvare7666c132007-05-08 17:22:02 +0200271static struct platform_driver w83781d_isa_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100272 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200273 .owner = THIS_MODULE,
Jean Delvare7666c132007-05-08 17:22:02 +0200274 .name = "w83781d",
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100275 },
Jean Delvare7666c132007-05-08 17:22:02 +0200276 .probe = w83781d_isa_probe,
277 .remove = w83781d_isa_remove,
Jean Delvarefde09502005-07-19 23:51:07 +0200278};
279
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281/* following are the sysfs callback functions */
282#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200283static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
284 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{ \
Jean Delvare34875332007-05-08 17:22:03 +0200286 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200288 return sprintf(buf, "%ld\n", \
289 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290}
291show_in_reg(in);
292show_in_reg(in_min);
293show_in_reg(in_max);
294
295#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200296static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
297 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{ \
Jean Delvare34875332007-05-08 17:22:03 +0200299 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200300 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200301 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 u32 val; \
303 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200304 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100306 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200308 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100310 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return count; \
312}
313store_in_reg(MIN, min);
314store_in_reg(MAX, max);
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200317static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
318 show_in, NULL, offset); \
319static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
320 show_in_min, store_in_min, offset); \
321static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
322 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324sysfs_in_offsets(0);
325sysfs_in_offsets(1);
326sysfs_in_offsets(2);
327sysfs_in_offsets(3);
328sysfs_in_offsets(4);
329sysfs_in_offsets(5);
330sysfs_in_offsets(6);
331sysfs_in_offsets(7);
332sysfs_in_offsets(8);
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200335static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
336 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{ \
Jean Delvare34875332007-05-08 17:22:03 +0200338 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 struct w83781d_data *data = w83781d_update_device(dev); \
340 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200341 FAN_FROM_REG(data->reg[attr->index], \
342 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343}
344show_fan_reg(fan);
345show_fan_reg(fan_min);
346
347static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200348store_fan_min(struct device *dev, struct device_attribute *da,
349 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Jean Delvare34875332007-05-08 17:22:03 +0200351 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200352 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200353 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 u32 val;
355
356 val = simple_strtoul(buf, NULL, 10);
357
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100358 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200359 data->fan_min[nr] =
360 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200361 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200362 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100364 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 return count;
366}
367
Jean Delvare34875332007-05-08 17:22:03 +0200368static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
369static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
370 show_fan_min, store_fan_min, 0);
371static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
372static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
373 show_fan_min, store_fan_min, 1);
374static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
375static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
376 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200379static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
380 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{ \
Jean Delvare34875332007-05-08 17:22:03 +0200382 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200384 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
386 return sprintf(buf,"%d\n", \
387 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
388 } else { /* TEMP1 */ \
389 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
390 } \
391}
392show_temp_reg(temp);
393show_temp_reg(temp_max);
394show_temp_reg(temp_max_hyst);
395
396#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200397static ssize_t store_temp_##reg (struct device *dev, \
398 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{ \
Jean Delvare34875332007-05-08 17:22:03 +0200400 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200401 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200402 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200403 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 \
405 val = simple_strtol(buf, NULL, 10); \
406 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100407 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 \
409 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
410 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200411 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 data->temp_##reg##_add[nr-2]); \
413 } else { /* TEMP1 */ \
414 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200415 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 data->temp_##reg); \
417 } \
418 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100419 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return count; \
421}
422store_temp_reg(OVER, max);
423store_temp_reg(HYST, max_hyst);
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200426static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
427 show_temp, NULL, offset); \
428static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
429 show_temp_max, store_temp_max, offset); \
430static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
431 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433sysfs_temp_offsets(1);
434sysfs_temp_offsets(2);
435sysfs_temp_offsets(3);
436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400438show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct w83781d_data *data = w83781d_update_device(dev);
441 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
442}
443
Jim Cromie311ce2e2006-09-24 21:22:52 +0200444static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400447show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Jean Delvare90d66192007-10-08 18:24:35 +0200449 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return sprintf(buf, "%ld\n", (long) data->vrm);
451}
452
453static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400454store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
Jean Delvare7666c132007-05-08 17:22:02 +0200456 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 u32 val;
458
459 val = simple_strtoul(buf, NULL, 10);
460 data->vrm = val;
461
462 return count;
463}
464
Jim Cromie311ce2e2006-09-24 21:22:52 +0200465static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400468show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200471 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
Jim Cromie311ce2e2006-09-24 21:22:52 +0200474static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
475
Jean Delvare7d4a1372007-10-08 18:29:43 +0200476static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
477 char *buf)
478{
479 struct w83781d_data *data = w83781d_update_device(dev);
480 int bitnr = to_sensor_dev_attr(attr)->index;
481 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
482}
483
484/* The W83781D has a single alarm bit for temp2 and temp3 */
485static ssize_t show_temp3_alarm(struct device *dev,
486 struct device_attribute *attr, char *buf)
487{
488 struct w83781d_data *data = w83781d_update_device(dev);
489 int bitnr = (data->type == w83781d) ? 5 : 13;
490 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
491}
492
493static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
494static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
495static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
496static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
497static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
498static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
499static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
500static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
501static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
502static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
503static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
504static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
505static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
506static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
507static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
508
Yani Ioannoue404e272005-05-17 06:42:58 -0400509static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct w83781d_data *data = w83781d_update_device(dev);
512 return sprintf(buf, "%ld\n",
513 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
514}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200517store_beep_mask(struct device *dev, struct device_attribute *attr,
518 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
Jean Delvare7666c132007-05-08 17:22:02 +0200520 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200521 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 val = simple_strtoul(buf, NULL, 10);
524
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100525 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200526 data->beep_mask &= 0x8000; /* preserve beep enable */
527 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200528 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
529 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200530 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200531 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200532 if (data->type != w83781d && data->type != as99127f) {
533 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
534 ((data->beep_mask) >> 16) & 0xff);
535 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100536 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return count;
539}
540
Jean Delvare34875332007-05-08 17:22:03 +0200541static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
542 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Jean Delvare7d4a1372007-10-08 18:29:43 +0200544static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
545 char *buf)
546{
547 struct w83781d_data *data = w83781d_update_device(dev);
548 int bitnr = to_sensor_dev_attr(attr)->index;
549 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
550}
551
552static ssize_t
553store_beep(struct device *dev, struct device_attribute *attr,
554 const char *buf, size_t count)
555{
556 struct w83781d_data *data = dev_get_drvdata(dev);
557 int bitnr = to_sensor_dev_attr(attr)->index;
558 unsigned long bit;
559 u8 reg;
560
561 bit = simple_strtoul(buf, NULL, 10);
562 if (bit & ~1)
563 return -EINVAL;
564
565 mutex_lock(&data->update_lock);
566 if (bit)
567 data->beep_mask |= (1 << bitnr);
568 else
569 data->beep_mask &= ~(1 << bitnr);
570
571 if (bitnr < 8) {
572 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
573 if (bit)
574 reg |= (1 << bitnr);
575 else
576 reg &= ~(1 << bitnr);
577 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
578 } else if (bitnr < 16) {
579 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
580 if (bit)
581 reg |= (1 << (bitnr - 8));
582 else
583 reg &= ~(1 << (bitnr - 8));
584 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
585 } else {
586 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
587 if (bit)
588 reg |= (1 << (bitnr - 16));
589 else
590 reg &= ~(1 << (bitnr - 16));
591 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
592 }
593 mutex_unlock(&data->update_lock);
594
595 return count;
596}
597
598/* The W83781D has a single beep bit for temp2 and temp3 */
599static ssize_t show_temp3_beep(struct device *dev,
600 struct device_attribute *attr, char *buf)
601{
602 struct w83781d_data *data = w83781d_update_device(dev);
603 int bitnr = (data->type == w83781d) ? 5 : 13;
604 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
605}
606
607static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
608 show_beep, store_beep, 0);
609static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
610 show_beep, store_beep, 1);
611static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
612 show_beep, store_beep, 2);
613static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
614 show_beep, store_beep, 3);
615static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
616 show_beep, store_beep, 8);
617static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
618 show_beep, store_beep, 9);
619static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
620 show_beep, store_beep, 10);
621static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
622 show_beep, store_beep, 16);
623static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
624 show_beep, store_beep, 17);
625static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
626 show_beep, store_beep, 6);
627static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
628 show_beep, store_beep, 7);
629static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
630 show_beep, store_beep, 11);
631static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
632 show_beep, store_beep, 4);
633static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
634 show_beep, store_beep, 5);
635static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
636 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200637static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
638 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200641show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
Jean Delvare34875332007-05-08 17:22:03 +0200643 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 struct w83781d_data *data = w83781d_update_device(dev);
645 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200646 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649/* Note: we save and restore the fan minimum here, because its value is
650 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200651 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 because the divisor changed. */
653static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200654store_fan_div(struct device *dev, struct device_attribute *da,
655 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
Jean Delvare34875332007-05-08 17:22:03 +0200657 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200658 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200660 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 u8 reg;
662 unsigned long val = simple_strtoul(buf, NULL, 10);
663
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100664 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /* Save fan_min */
667 min = FAN_FROM_REG(data->fan_min[nr],
668 DIV_FROM_REG(data->fan_div[nr]));
669
670 data->fan_div[nr] = DIV_TO_REG(val, data->type);
671
Jean Delvare31b8dc42007-05-08 17:22:03 +0200672 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 & (nr==0 ? 0xcf : 0x3f))
674 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200675 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 /* w83781d and as99127f don't have extended divisor bits */
678 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200679 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 & ~(1 << (5 + nr)))
681 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200682 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
684
685 /* Restore fan_min */
686 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200687 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100689 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return count;
691}
692
Jean Delvare34875332007-05-08 17:22:03 +0200693static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
694 show_fan_div, store_fan_div, 0);
695static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
696 show_fan_div, store_fan_div, 1);
697static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
698 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200701show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Jean Delvare34875332007-05-08 17:22:03 +0200703 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200705 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
707
708static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200709show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
711 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200712 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
715static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200716store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
717 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Jean Delvare34875332007-05-08 17:22:03 +0200719 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200720 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200721 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 u32 val;
723
724 val = simple_strtoul(buf, NULL, 10);
725
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100726 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200727 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
728 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100729 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return count;
731}
732
733static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200734store_pwm2_enable(struct device *dev, struct device_attribute *da,
735 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Jean Delvare7666c132007-05-08 17:22:02 +0200737 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 u32 val, reg;
739
740 val = simple_strtoul(buf, NULL, 10);
741
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100742 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 switch (val) {
745 case 0:
746 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200747 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
748 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 (reg & 0xf7) | (val << 3));
750
Jean Delvare31b8dc42007-05-08 17:22:03 +0200751 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
752 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 (reg & 0xef) | (!val << 4));
754
Jean Delvare34875332007-05-08 17:22:03 +0200755 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 break;
757
758 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100759 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return -EINVAL;
761 }
762
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100763 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return count;
765}
766
Jean Delvare34875332007-05-08 17:22:03 +0200767static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
768static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
769static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
770static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
771/* only PWM2 can be enabled/disabled */
772static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
773 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200776show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Jean Delvare34875332007-05-08 17:22:03 +0200778 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200780 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
783static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200784store_sensor(struct device *dev, struct device_attribute *da,
785 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Jean Delvare34875332007-05-08 17:22:03 +0200787 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200788 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200789 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 u32 val, tmp;
791
792 val = simple_strtoul(buf, NULL, 10);
793
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100794 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 switch (val) {
797 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200798 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
799 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200800 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200801 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
802 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200803 tmp | BIT_SCFG2[nr]);
804 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 break;
806 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200807 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
808 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200809 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200810 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
811 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200812 tmp & ~BIT_SCFG2[nr]);
813 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200815 case W83781D_DEFAULT_BETA:
816 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
817 "instead\n", W83781D_DEFAULT_BETA);
818 /* fall through */
819 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200820 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
821 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200822 tmp & ~BIT_SCFG1[nr]);
823 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 break;
825 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200826 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
827 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 break;
829 }
830
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100831 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return count;
833}
834
Jean Delvare34875332007-05-08 17:22:03 +0200835static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
836 show_sensor, store_sensor, 0);
837static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400838 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200839static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400840 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Jean Delvare7666c132007-05-08 17:22:02 +0200842/* I2C devices get this name attribute automatically, but for ISA devices
843 we must create it by ourselves. */
844static ssize_t
845show_name(struct device *dev, struct device_attribute *devattr, char *buf)
846{
847 struct w83781d_data *data = dev_get_drvdata(dev);
848 return sprintf(buf, "%s\n", data->client.name);
849}
850static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852/* This function is called when:
853 * w83781d_driver is inserted (when this module is loaded), for each
854 available adapter
855 * when a new adapter is inserted (and w83781d_driver is still present) */
856static int
857w83781d_attach_adapter(struct i2c_adapter *adapter)
858{
859 if (!(adapter->class & I2C_CLASS_HWMON))
860 return 0;
Jean Delvare2ed2dc32005-07-31 21:42:02 +0200861 return i2c_probe(adapter, &addr_data, w83781d_detect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
864/* Assumes that adapter is of I2C, not ISA variety.
865 * OTHERWISE DON'T CALL THIS
866 */
867static int
868w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
869 struct i2c_client *new_client)
870{
871 int i, val1 = 0, id;
872 int err;
873 const char *client_name = "";
874 struct w83781d_data *data = i2c_get_clientdata(new_client);
875
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200876 data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (!(data->lm75[0])) {
878 err = -ENOMEM;
879 goto ERROR_SC_0;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 id = i2c_adapter_id(adapter);
883
884 if (force_subclients[0] == id && force_subclients[1] == address) {
885 for (i = 2; i <= 3; i++) {
886 if (force_subclients[i] < 0x48 ||
887 force_subclients[i] > 0x4f) {
888 dev_err(&new_client->dev, "Invalid subclient "
889 "address %d; must be 0x48-0x4f\n",
890 force_subclients[i]);
891 err = -EINVAL;
892 goto ERROR_SC_1;
893 }
894 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200895 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 (force_subclients[2] & 0x07) |
897 ((force_subclients[3] & 0x07) << 4));
898 data->lm75[0]->addr = force_subclients[2];
899 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200900 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 data->lm75[0]->addr = 0x48 + (val1 & 0x07);
902 }
903
904 if (kind != w83783s) {
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200905 data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (!(data->lm75[1])) {
907 err = -ENOMEM;
908 goto ERROR_SC_1;
909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 if (force_subclients[0] == id &&
912 force_subclients[1] == address) {
913 data->lm75[1]->addr = force_subclients[3];
914 } else {
915 data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07);
916 }
917 if (data->lm75[0]->addr == data->lm75[1]->addr) {
918 dev_err(&new_client->dev,
919 "Duplicate addresses 0x%x for subclients.\n",
920 data->lm75[0]->addr);
921 err = -EBUSY;
922 goto ERROR_SC_2;
923 }
924 }
925
926 if (kind == w83781d)
927 client_name = "w83781d subclient";
928 else if (kind == w83782d)
929 client_name = "w83782d subclient";
930 else if (kind == w83783s)
931 client_name = "w83783s subclient";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 else if (kind == as99127f)
933 client_name = "as99127f subclient";
934
935 for (i = 0; i <= 1; i++) {
936 /* store all data in w83781d */
937 i2c_set_clientdata(data->lm75[i], NULL);
938 data->lm75[i]->adapter = adapter;
939 data->lm75[i]->driver = &w83781d_driver;
940 data->lm75[i]->flags = 0;
941 strlcpy(data->lm75[i]->name, client_name,
942 I2C_NAME_SIZE);
943 if ((err = i2c_attach_client(data->lm75[i]))) {
944 dev_err(&new_client->dev, "Subclient %d "
945 "registration at address 0x%x "
946 "failed.\n", i, data->lm75[i]->addr);
947 if (i == 1)
948 goto ERROR_SC_3;
949 goto ERROR_SC_2;
950 }
951 if (kind == w83783s)
952 break;
953 }
954
955 return 0;
956
957/* Undo inits in case of errors */
958ERROR_SC_3:
959 i2c_detach_client(data->lm75[0]);
960ERROR_SC_2:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800961 kfree(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962ERROR_SC_1:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800963 kfree(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964ERROR_SC_0:
965 return err;
966}
967
Jean Delvare34875332007-05-08 17:22:03 +0200968#define IN_UNIT_ATTRS(X) \
969 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
970 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100971 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200972 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
973 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200974
Jean Delvare34875332007-05-08 17:22:03 +0200975#define FAN_UNIT_ATTRS(X) \
976 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
977 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200978 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
979 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
980 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200981
Jean Delvare34875332007-05-08 17:22:03 +0200982#define TEMP_UNIT_ATTRS(X) \
983 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
984 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200985 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
986 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
987 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200988
989static struct attribute* w83781d_attributes[] = {
990 IN_UNIT_ATTRS(0),
991 IN_UNIT_ATTRS(2),
992 IN_UNIT_ATTRS(3),
993 IN_UNIT_ATTRS(4),
994 IN_UNIT_ATTRS(5),
995 IN_UNIT_ATTRS(6),
996 FAN_UNIT_ATTRS(1),
997 FAN_UNIT_ATTRS(2),
998 FAN_UNIT_ATTRS(3),
999 TEMP_UNIT_ATTRS(1),
1000 TEMP_UNIT_ATTRS(2),
1001 &dev_attr_cpu0_vid.attr,
1002 &dev_attr_vrm.attr,
1003 &dev_attr_alarms.attr,
1004 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001005 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +02001006 NULL
1007};
1008static const struct attribute_group w83781d_group = {
1009 .attrs = w83781d_attributes,
1010};
1011
1012static struct attribute *w83781d_attributes_opt[] = {
1013 IN_UNIT_ATTRS(1),
1014 IN_UNIT_ATTRS(7),
1015 IN_UNIT_ATTRS(8),
1016 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +02001017 &sensor_dev_attr_pwm1.dev_attr.attr,
1018 &sensor_dev_attr_pwm2.dev_attr.attr,
1019 &sensor_dev_attr_pwm3.dev_attr.attr,
1020 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +02001021 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +02001022 &sensor_dev_attr_temp1_type.dev_attr.attr,
1023 &sensor_dev_attr_temp2_type.dev_attr.attr,
1024 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +02001025 NULL
1026};
1027static const struct attribute_group w83781d_group_opt = {
1028 .attrs = w83781d_attributes_opt,
1029};
1030
Jean Delvare7666c132007-05-08 17:22:02 +02001031/* No clean up is done on error, it's up to the caller */
1032static int
1033w83781d_create_files(struct device *dev, int kind, int is_isa)
1034{
1035 int err;
1036
1037 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
1038 return err;
1039
1040 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001041 if ((err = device_create_file(dev,
1042 &sensor_dev_attr_in1_input.dev_attr))
1043 || (err = device_create_file(dev,
1044 &sensor_dev_attr_in1_min.dev_attr))
1045 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001046 &sensor_dev_attr_in1_max.dev_attr))
1047 || (err = device_create_file(dev,
1048 &sensor_dev_attr_in1_alarm.dev_attr))
1049 || (err = device_create_file(dev,
1050 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001051 return err;
1052 }
1053 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001054 if ((err = device_create_file(dev,
1055 &sensor_dev_attr_in7_input.dev_attr))
1056 || (err = device_create_file(dev,
1057 &sensor_dev_attr_in7_min.dev_attr))
1058 || (err = device_create_file(dev,
1059 &sensor_dev_attr_in7_max.dev_attr))
1060 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001061 &sensor_dev_attr_in7_alarm.dev_attr))
1062 || (err = device_create_file(dev,
1063 &sensor_dev_attr_in7_beep.dev_attr))
1064 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001065 &sensor_dev_attr_in8_input.dev_attr))
1066 || (err = device_create_file(dev,
1067 &sensor_dev_attr_in8_min.dev_attr))
1068 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001069 &sensor_dev_attr_in8_max.dev_attr))
1070 || (err = device_create_file(dev,
1071 &sensor_dev_attr_in8_alarm.dev_attr))
1072 || (err = device_create_file(dev,
1073 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001074 return err;
1075 }
1076 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001077 if ((err = device_create_file(dev,
1078 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001079 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001080 &sensor_dev_attr_temp3_max.dev_attr))
1081 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001082 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1083 || (err = device_create_file(dev,
1084 &sensor_dev_attr_temp3_alarm.dev_attr))
1085 || (err = device_create_file(dev,
1086 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001087 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001088
Jean Delvare7768aa72007-10-25 13:11:01 +02001089 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001090 err = sysfs_chmod_file(&dev->kobj,
1091 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1092 S_IRUGO | S_IWUSR);
1093 if (err)
1094 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001095 }
Jean Delvare7666c132007-05-08 17:22:02 +02001096 }
1097
1098 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001099 if ((err = device_create_file(dev,
1100 &sensor_dev_attr_pwm1.dev_attr))
1101 || (err = device_create_file(dev,
1102 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001103 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1104 return err;
1105 }
1106 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001107 if ((err = device_create_file(dev,
1108 &sensor_dev_attr_pwm3.dev_attr))
1109 || (err = device_create_file(dev,
1110 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001111 return err;
1112 }
1113
1114 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001115 if ((err = device_create_file(dev,
1116 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001117 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001118 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001119 return err;
1120 if (kind != w83783s) {
1121 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001122 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001123 return err;
1124 }
1125 }
1126
1127 if (is_isa) {
1128 err = device_create_file(&pdev->dev, &dev_attr_name);
1129 if (err)
1130 return err;
1131 }
1132
1133 return 0;
1134}
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136static int
1137w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
1138{
Jean Delvare7666c132007-05-08 17:22:02 +02001139 int val1 = 0, val2;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001140 struct i2c_client *client;
1141 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 struct w83781d_data *data;
1143 int err;
1144 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 enum vendor { winbond, asus } vendid;
1146
Jean Delvare7666c132007-05-08 17:22:02 +02001147 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 err = -EINVAL;
Jean Delvare7666c132007-05-08 17:22:02 +02001149 goto ERROR1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
1152 /* OK. For now, we presume we have a valid client. We now create the
1153 client structure, even though we cannot fill it completely yet.
1154 But it allows us to access w83781d_{read,write}_value. */
1155
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001156 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 err = -ENOMEM;
1158 goto ERROR1;
1159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Jim Cromie311ce2e2006-09-24 21:22:52 +02001161 client = &data->client;
1162 i2c_set_clientdata(client, data);
1163 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001164 mutex_init(&data->lock);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001165 client->adapter = adapter;
Jean Delvare7666c132007-05-08 17:22:02 +02001166 client->driver = &w83781d_driver;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001167 dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 /* Now, we do the remaining detection. */
1170
1171 /* The w8378?d may be stuck in some other bank than bank 0. This may
1172 make reading other information impossible. Specify a force=... or
1173 force_*=... parameter, and the Winbond will be reset to the right
1174 bank. */
1175 if (kind < 0) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001176 if (w83781d_read_value(data, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001177 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1178 "failed at step 3\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 err = -ENODEV;
1180 goto ERROR2;
1181 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001182 val1 = w83781d_read_value(data, W83781D_REG_BANK);
1183 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 /* Check for Winbond or Asus ID if in bank 0 */
1185 if ((!(val1 & 0x07)) &&
1186 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1187 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001188 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1189 "failed at step 4\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 err = -ENODEV;
1191 goto ERROR2;
1192 }
1193 /* If Winbond SMBus, check address at 0x48.
1194 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001195 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1196 ((val1 & 0x80) && (val2 == 0x5c))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001198 (data, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001199 dev_dbg(&adapter->dev, "Detection of w83781d "
1200 "chip failed at step 5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 err = -ENODEV;
1202 goto ERROR2;
1203 }
1204 }
1205 }
1206
1207 /* We have either had a force parameter, or we have already detected the
1208 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001209 w83781d_write_value(data, W83781D_REG_BANK,
1210 (w83781d_read_value(data, W83781D_REG_BANK)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001211 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 /* Determine the chip type. */
1214 if (kind <= 0) {
1215 /* get vendor ID */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001216 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 if (val2 == 0x5c)
1218 vendid = winbond;
1219 else if (val2 == 0x12)
1220 vendid = asus;
1221 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001222 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1223 "neither Winbond nor Asus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 err = -ENODEV;
1225 goto ERROR2;
1226 }
1227
Jean Delvare31b8dc42007-05-08 17:22:03 +02001228 val1 = w83781d_read_value(data, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1230 kind = w83781d;
1231 else if (val1 == 0x30 && vendid == winbond)
1232 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001233 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 kind = w83783s;
Jean Delvare6722fea2007-10-07 12:25:46 +02001235 else if (val1 == 0x31)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 else {
1238 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001239 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001241 "address 0x%02x\n", address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 err = -EINVAL;
1243 goto ERROR2;
1244 }
1245 }
1246
1247 if (kind == w83781d) {
1248 client_name = "w83781d";
1249 } else if (kind == w83782d) {
1250 client_name = "w83782d";
1251 } else if (kind == w83783s) {
1252 client_name = "w83783s";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 } else if (kind == as99127f) {
1254 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 }
1256
1257 /* Fill in the remaining client fields and put into the global list */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001258 strlcpy(client->name, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 data->type = kind;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 /* Tell the I2C layer a new client has arrived */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001262 if ((err = i2c_attach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 goto ERROR2;
1264
1265 /* attach secondary i2c lm75-like clients */
Jean Delvare7666c132007-05-08 17:22:02 +02001266 if ((err = w83781d_detect_subclients(adapter, address,
1267 kind, client)))
1268 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001271 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273 /* Register sysfs hooks */
Jean Delvare7666c132007-05-08 17:22:02 +02001274 err = w83781d_create_files(dev, kind, 0);
1275 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001276 goto ERROR4;
1277
Tony Jones1beeffe2007-08-20 13:46:20 -07001278 data->hwmon_dev = hwmon_device_register(dev);
1279 if (IS_ERR(data->hwmon_dev)) {
1280 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001281 goto ERROR4;
1282 }
1283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 return 0;
1285
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001286ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001287 sysfs_remove_group(&dev->kobj, &w83781d_group);
1288 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1289
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001290 if (data->lm75[1]) {
1291 i2c_detach_client(data->lm75[1]);
1292 kfree(data->lm75[1]);
1293 }
1294 if (data->lm75[0]) {
1295 i2c_detach_client(data->lm75[0]);
1296 kfree(data->lm75[0]);
1297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298ERROR3:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001299 i2c_detach_client(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300ERROR2:
1301 kfree(data);
1302ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return err;
1304}
1305
1306static int
1307w83781d_detach_client(struct i2c_client *client)
1308{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001309 struct w83781d_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 int err;
1311
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001312 /* main client */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001313 if (data) {
Tony Jones1beeffe2007-08-20 13:46:20 -07001314 hwmon_device_unregister(data->hwmon_dev);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001315 sysfs_remove_group(&client->dev.kobj, &w83781d_group);
1316 sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
1317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Jean Delvare7bef5592005-07-27 22:14:49 +02001319 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001322 /* main client */
1323 if (data)
1324 kfree(data);
1325
1326 /* subclient */
1327 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 kfree(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 return 0;
1331}
1332
Jean Delvare7666c132007-05-08 17:22:02 +02001333static int __devinit
1334w83781d_isa_probe(struct platform_device *pdev)
1335{
1336 int err, reg;
1337 struct w83781d_data *data;
1338 struct resource *res;
1339 const char *name;
1340
1341 /* Reserve the ISA region */
1342 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
Jean Delvare2961cb22008-03-09 13:34:28 +01001343 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1344 "w83781d")) {
Jean Delvare7666c132007-05-08 17:22:02 +02001345 err = -EBUSY;
1346 goto exit;
1347 }
1348
1349 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
1350 err = -ENOMEM;
1351 goto exit_release_region;
1352 }
1353 mutex_init(&data->lock);
1354 data->client.addr = res->start;
1355 i2c_set_clientdata(&data->client, data);
1356 platform_set_drvdata(pdev, data);
1357
Jean Delvare31b8dc42007-05-08 17:22:03 +02001358 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
Jean Delvare7666c132007-05-08 17:22:02 +02001359 switch (reg) {
Jean Delvare7666c132007-05-08 17:22:02 +02001360 case 0x30:
1361 data->type = w83782d;
1362 name = "w83782d";
1363 break;
1364 default:
1365 data->type = w83781d;
1366 name = "w83781d";
1367 }
1368 strlcpy(data->client.name, name, I2C_NAME_SIZE);
1369
1370 /* Initialize the W83781D chip */
1371 w83781d_init_device(&pdev->dev);
1372
1373 /* Register sysfs hooks */
1374 err = w83781d_create_files(&pdev->dev, data->type, 1);
1375 if (err)
1376 goto exit_remove_files;
1377
Tony Jones1beeffe2007-08-20 13:46:20 -07001378 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1379 if (IS_ERR(data->hwmon_dev)) {
1380 err = PTR_ERR(data->hwmon_dev);
Jean Delvare7666c132007-05-08 17:22:02 +02001381 goto exit_remove_files;
1382 }
1383
1384 return 0;
1385
1386 exit_remove_files:
1387 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1388 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1389 device_remove_file(&pdev->dev, &dev_attr_name);
1390 kfree(data);
1391 exit_release_region:
Jean Delvare2961cb22008-03-09 13:34:28 +01001392 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
Jean Delvare7666c132007-05-08 17:22:02 +02001393 exit:
1394 return err;
1395}
1396
1397static int __devexit
1398w83781d_isa_remove(struct platform_device *pdev)
1399{
1400 struct w83781d_data *data = platform_get_drvdata(pdev);
1401
Tony Jones1beeffe2007-08-20 13:46:20 -07001402 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare7666c132007-05-08 17:22:02 +02001403 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1404 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1405 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare2961cb22008-03-09 13:34:28 +01001406 release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2);
Jean Delvare7666c132007-05-08 17:22:02 +02001407 kfree(data);
1408
1409 return 0;
1410}
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412/* The SMBus locks itself, usually, but nothing may access the Winbond between
Jean Delvare293c0992007-11-30 23:52:44 +01001413 bank switches. ISA access must always be locked explicitly!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
Jean Delvare293c0992007-11-30 23:52:44 +01001415 would slow down the W83781D access and should not be necessary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 There are some ugly typecasts here, but the good news is - they should
1417 nowhere else be necessary! */
1418static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001419w83781d_read_value(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420{
Jean Delvare31b8dc42007-05-08 17:22:03 +02001421 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 int res, word_sized, bank;
1423 struct i2c_client *cl;
1424
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001425 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001426 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 word_sized = (((reg & 0xff00) == 0x100)
1428 || ((reg & 0xff00) == 0x200))
1429 && (((reg & 0x00ff) == 0x50)
1430 || ((reg & 0x00ff) == 0x53)
1431 || ((reg & 0x00ff) == 0x55));
1432 if (reg & 0xff00) {
1433 outb_p(W83781D_REG_BANK,
1434 client->addr + W83781D_ADDR_REG_OFFSET);
1435 outb_p(reg >> 8,
1436 client->addr + W83781D_DATA_REG_OFFSET);
1437 }
1438 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1439 res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
1440 if (word_sized) {
1441 outb_p((reg & 0xff) + 1,
1442 client->addr + W83781D_ADDR_REG_OFFSET);
1443 res =
1444 (res << 8) + inb_p(client->addr +
1445 W83781D_DATA_REG_OFFSET);
1446 }
1447 if (reg & 0xff00) {
1448 outb_p(W83781D_REG_BANK,
1449 client->addr + W83781D_ADDR_REG_OFFSET);
1450 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1451 }
1452 } else {
1453 bank = (reg >> 8) & 0x0f;
1454 if (bank > 2)
1455 /* switch banks */
1456 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1457 bank);
1458 if (bank == 0 || bank > 2) {
1459 res = i2c_smbus_read_byte_data(client, reg & 0xff);
1460 } else {
1461 /* switch to subclient */
1462 cl = data->lm75[bank - 1];
1463 /* convert from ISA to LM75 I2C addresses */
1464 switch (reg & 0xff) {
1465 case 0x50: /* TEMP */
1466 res = swab16(i2c_smbus_read_word_data(cl, 0));
1467 break;
1468 case 0x52: /* CONFIG */
1469 res = i2c_smbus_read_byte_data(cl, 1);
1470 break;
1471 case 0x53: /* HYST */
1472 res = swab16(i2c_smbus_read_word_data(cl, 2));
1473 break;
1474 case 0x55: /* OVER */
1475 default:
1476 res = swab16(i2c_smbus_read_word_data(cl, 3));
1477 break;
1478 }
1479 }
1480 if (bank > 2)
1481 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1482 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001483 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 return res;
1485}
1486
1487static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489{
Jean Delvare31b8dc42007-05-08 17:22:03 +02001490 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 int word_sized, bank;
1492 struct i2c_client *cl;
1493
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001494 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001495 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 word_sized = (((reg & 0xff00) == 0x100)
1497 || ((reg & 0xff00) == 0x200))
1498 && (((reg & 0x00ff) == 0x53)
1499 || ((reg & 0x00ff) == 0x55));
1500 if (reg & 0xff00) {
1501 outb_p(W83781D_REG_BANK,
1502 client->addr + W83781D_ADDR_REG_OFFSET);
1503 outb_p(reg >> 8,
1504 client->addr + W83781D_DATA_REG_OFFSET);
1505 }
1506 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1507 if (word_sized) {
1508 outb_p(value >> 8,
1509 client->addr + W83781D_DATA_REG_OFFSET);
1510 outb_p((reg & 0xff) + 1,
1511 client->addr + W83781D_ADDR_REG_OFFSET);
1512 }
1513 outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
1514 if (reg & 0xff00) {
1515 outb_p(W83781D_REG_BANK,
1516 client->addr + W83781D_ADDR_REG_OFFSET);
1517 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1518 }
1519 } else {
1520 bank = (reg >> 8) & 0x0f;
1521 if (bank > 2)
1522 /* switch banks */
1523 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1524 bank);
1525 if (bank == 0 || bank > 2) {
1526 i2c_smbus_write_byte_data(client, reg & 0xff,
1527 value & 0xff);
1528 } else {
1529 /* switch to subclient */
1530 cl = data->lm75[bank - 1];
1531 /* convert from ISA to LM75 I2C addresses */
1532 switch (reg & 0xff) {
1533 case 0x52: /* CONFIG */
1534 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1535 break;
1536 case 0x53: /* HYST */
1537 i2c_smbus_write_word_data(cl, 2, swab16(value));
1538 break;
1539 case 0x55: /* OVER */
1540 i2c_smbus_write_word_data(cl, 3, swab16(value));
1541 break;
1542 }
1543 }
1544 if (bank > 2)
1545 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1546 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001547 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 return 0;
1549}
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551static void
Jean Delvare7666c132007-05-08 17:22:02 +02001552w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553{
Jean Delvare7666c132007-05-08 17:22:02 +02001554 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 int i, p;
1556 int type = data->type;
1557 u8 tmp;
1558
Jean Delvarefabddcd2006-02-05 23:26:51 +01001559 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001561 /* Resetting the chip has been the default for a long time,
1562 but it causes the BIOS initializations (fan clock dividers,
1563 thermal sensor types...) to be lost, so it is now optional.
1564 It might even go away if nobody reports it as being useful,
1565 as I see very little reason why this would be needed at
1566 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001567 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001568 "having, please report!\n");
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001571 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1572 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 /* Reset all except Watchdog values and last conversion values
1574 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001575 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 /* Restore the registers and disable power-on abnormal beep.
1577 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001578 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1579 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 /* Disable master beep-enable (reset turns it on).
1581 Individual beep_mask should be reset to off but for some reason
1582 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001583 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 }
1585
Jean Delvarefabddcd2006-02-05 23:26:51 +01001586 /* Disable power-on abnormal beep, as advised by the datasheet.
1587 Already done if reset=1. */
1588 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001589 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1590 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001591 }
1592
Jean Delvare303760b2005-07-31 21:52:01 +02001593 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001596 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 for (i = 1; i <= 3; i++) {
1598 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001599 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 } else {
1601 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001602 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1604 data->sens[i - 1] = 1;
1605 else
1606 data->sens[i - 1] = 2;
1607 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001608 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 break;
1610 }
1611 }
1612
1613 if (init && type != as99127f) {
1614 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001615 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001617 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001619 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 tmp & 0xfe);
1621 }
1622
1623 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001624 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001625 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 W83781D_REG_TEMP3_CONFIG);
1627 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001628 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001630 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1632 }
1633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 }
1635
1636 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001637 w83781d_write_value(data, W83781D_REG_CONFIG,
1638 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 W83781D_REG_CONFIG) & 0xf7)
1640 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001641
1642 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001643 for (i = 0; i < 3; i++) {
1644 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001645 W83781D_REG_FAN_MIN(i));
1646 }
Jean Delvare7666c132007-05-08 17:22:02 +02001647
1648 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649}
1650
1651static struct w83781d_data *w83781d_update_device(struct device *dev)
1652{
Jean Delvare7666c132007-05-08 17:22:02 +02001653 struct w83781d_data *data = dev_get_drvdata(dev);
1654 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 int i;
1656
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001657 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1660 || !data->valid) {
1661 dev_dbg(dev, "Starting device update\n");
1662
1663 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001664 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 continue; /* 783S has no in1 */
1666 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001667 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001669 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001671 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001672 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 break;
1674 }
Jean Delvare34875332007-05-08 17:22:03 +02001675 for (i = 0; i < 3; i++) {
1676 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001677 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001678 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001679 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001682 for (i = 0; i < 4; i++) {
1683 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001684 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001685 W83781D_REG_PWM[i]);
Jean Delvare7666c132007-05-08 17:22:02 +02001686 if ((data->type != w83782d || !client->driver)
Jean Delvare34875332007-05-08 17:22:03 +02001687 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 break;
1689 }
1690 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001691 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1693 }
1694
Jean Delvare31b8dc42007-05-08 17:22:03 +02001695 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001697 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001699 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001701 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001703 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001705 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001706 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001708 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001710 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 W83781D_REG_TEMP_OVER(3));
1712 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001713 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 W83781D_REG_TEMP_HYST(3));
1715 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001716 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001717 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001718 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001719 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 data->fan_div[0] = (i >> 4) & 0x03;
1721 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001722 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001723 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001725 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 data->fan_div[0] |= (i >> 3) & 0x04;
1727 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001728 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 }
Jean Delvare05663362007-11-30 23:51:24 +01001730 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001731 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001732 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001733 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001734 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001735 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001736 W83782D_REG_ALARM3) << 16);
1737 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001738 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001739 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001740 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001741 W83782D_REG_ALARM2) << 8);
1742 } else {
1743 /* No real-time status registers, fall back to
1744 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001745 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001746 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001747 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001748 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001750 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001751 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001752 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 if ((data->type != w83781d) && (data->type != as99127f)) {
1754 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001755 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 W83781D_REG_BEEP_INTS3) << 16;
1757 }
1758 data->last_updated = jiffies;
1759 data->valid = 1;
1760 }
1761
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001762 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
1764 return data;
1765}
1766
Jean Delvare7666c132007-05-08 17:22:02 +02001767/* return 1 if a supported chip is found, 0 otherwise */
1768static int __init
1769w83781d_isa_found(unsigned short address)
1770{
1771 int val, save, found = 0;
1772
Jean Delvare2961cb22008-03-09 13:34:28 +01001773 /* We have to request the region in two parts because some
1774 boards declare base+4 to base+7 as a PNP device */
1775 if (!request_region(address, 4, "w83781d")) {
1776 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001777 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001778 }
1779 if (!request_region(address + 4, 4, "w83781d")) {
1780 pr_debug("w83781d: Failed to request high part of region\n");
1781 release_region(address, 4);
1782 return 0;
1783 }
Jean Delvare7666c132007-05-08 17:22:02 +02001784
1785#define REALLY_SLOW_IO
1786 /* We need the timeouts for at least some W83781D-like
1787 chips. But only if we read 'undefined' registers. */
1788 val = inb_p(address + 1);
1789 if (inb_p(address + 2) != val
1790 || inb_p(address + 3) != val
1791 || inb_p(address + 7) != val) {
1792 pr_debug("w83781d: Detection failed at step 1\n");
1793 goto release;
1794 }
1795#undef REALLY_SLOW_IO
1796
1797 /* We should be able to change the 7 LSB of the address port. The
1798 MSB (busy flag) should be clear initially, set after the write. */
1799 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1800 if (save & 0x80) {
1801 pr_debug("w83781d: Detection failed at step 2\n");
1802 goto release;
1803 }
1804 val = ~save & 0x7f;
1805 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1806 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1807 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1808 pr_debug("w83781d: Detection failed at step 3\n");
1809 goto release;
1810 }
1811
1812 /* We found a device, now see if it could be a W83781D */
1813 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1814 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1815 if (val & 0x80) {
1816 pr_debug("w83781d: Detection failed at step 4\n");
1817 goto release;
1818 }
1819 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1820 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1821 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1822 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1823 if ((!(save & 0x80) && (val != 0xa3))
1824 || ((save & 0x80) && (val != 0x5c))) {
1825 pr_debug("w83781d: Detection failed at step 5\n");
1826 goto release;
1827 }
1828 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1829 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1830 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1831 pr_debug("w83781d: Detection failed at step 6\n");
1832 goto release;
1833 }
1834
1835 /* The busy flag should be clear again */
1836 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1837 pr_debug("w83781d: Detection failed at step 7\n");
1838 goto release;
1839 }
1840
1841 /* Determine the chip type */
1842 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1843 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1844 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1845 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1846 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1847 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001848 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001849 found = 1;
1850
1851 if (found)
1852 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001853 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1854
1855 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001856 release_region(address + 4, 4);
1857 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001858 return found;
1859}
1860
1861static int __init
1862w83781d_isa_device_add(unsigned short address)
1863{
1864 struct resource res = {
1865 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001866 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001867 .name = "w83781d",
1868 .flags = IORESOURCE_IO,
1869 };
1870 int err;
1871
1872 pdev = platform_device_alloc("w83781d", address);
1873 if (!pdev) {
1874 err = -ENOMEM;
1875 printk(KERN_ERR "w83781d: Device allocation failed\n");
1876 goto exit;
1877 }
1878
1879 err = platform_device_add_resources(pdev, &res, 1);
1880 if (err) {
1881 printk(KERN_ERR "w83781d: Device resource addition failed "
1882 "(%d)\n", err);
1883 goto exit_device_put;
1884 }
1885
1886 err = platform_device_add(pdev);
1887 if (err) {
1888 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1889 err);
1890 goto exit_device_put;
1891 }
1892
1893 return 0;
1894
1895 exit_device_put:
1896 platform_device_put(pdev);
1897 exit:
1898 pdev = NULL;
1899 return err;
1900}
1901
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902static int __init
1903sensors_w83781d_init(void)
1904{
Jean Delvarefde09502005-07-19 23:51:07 +02001905 int res;
1906
1907 res = i2c_add_driver(&w83781d_driver);
1908 if (res)
Jean Delvare7666c132007-05-08 17:22:02 +02001909 goto exit;
Jean Delvarefde09502005-07-19 23:51:07 +02001910
Jean Delvare7666c132007-05-08 17:22:02 +02001911 if (w83781d_isa_found(isa_address)) {
1912 res = platform_driver_register(&w83781d_isa_driver);
1913 if (res)
1914 goto exit_unreg_i2c_driver;
1915
1916 /* Sets global pdev as a side effect */
1917 res = w83781d_isa_device_add(isa_address);
1918 if (res)
1919 goto exit_unreg_isa_driver;
1920 }
Jean Delvarefde09502005-07-19 23:51:07 +02001921
1922 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02001923
1924 exit_unreg_isa_driver:
1925 platform_driver_unregister(&w83781d_isa_driver);
1926 exit_unreg_i2c_driver:
1927 i2c_del_driver(&w83781d_driver);
1928 exit:
1929 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930}
1931
1932static void __exit
1933sensors_w83781d_exit(void)
1934{
Jean Delvare7666c132007-05-08 17:22:02 +02001935 if (pdev) {
1936 platform_device_unregister(pdev);
1937 platform_driver_unregister(&w83781d_isa_driver);
1938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 i2c_del_driver(&w83781d_driver);
1940}
1941
1942MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1943 "Philip Edelbrock <phil@netroedge.com>, "
1944 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1945MODULE_DESCRIPTION("W83781D driver");
1946MODULE_LICENSE("GPL");
1947
1948module_init(sensors_w83781d_init);
1949module_exit(sensors_w83781d_exit);