blob: ad6b6ca90f6b94568fb905ac3886c73f6e15d941 [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
Jean Delvare474d00a2007-05-08 17:22:03 +0200167/* Conversions */
168#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
169#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171static inline u8
172FAN_TO_REG(long rpm, int div)
173{
174 if (rpm == 0)
175 return 255;
176 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
177 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
178}
179
Jean Delvare474d00a2007-05-08 17:22:03 +0200180static inline long
181FAN_FROM_REG(u8 val, int div)
182{
183 if (val == 0)
184 return -1;
185 if (val == 255)
186 return 0;
187 return 1350000 / (val * div);
188}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Jean Delvare474d00a2007-05-08 17:22:03 +0200190#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
191#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198#define DIV_FROM_REG(val) (1 << (val))
199
200static inline u8
201DIV_TO_REG(long val, enum chips type)
202{
203 int i;
204 val = SENSORS_LIMIT(val, 1,
205 ((type == w83781d
206 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000207 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (val == 0)
209 break;
210 val >>= 1;
211 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200212 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
215/* There are some complications in a module like this. First off, W83781D chips
216 may be both present on the SMBus and the ISA bus, and we have to handle
217 those cases separately at some places. Second, there might be several
218 W83781D chips available (well, actually, that is probably never done; but
219 it is a clean illustration of how to handle a case like that). Finally,
220 a specific chip may be attached to *both* ISA and SMBus, and we would
221 not like to detect it double. Fortunately, in the case of the W83781D at
222 least, a register tells us what SMBus address we are on, so that helps
223 a bit - except if there could be more than one SMBus. Groan. No solution
224 for this yet. */
225
Jean Delvare7666c132007-05-08 17:22:02 +0200226/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
227 the driver field to differentiate between I2C and ISA chips. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228struct w83781d_data {
229 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400230 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100231 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 enum chips type;
233
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100234 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 char valid; /* !=0 if following fields are valid */
236 unsigned long last_updated; /* In jiffies */
237
238 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
239 /* array of 2 pointers to subclients */
240
241 u8 in[9]; /* Register value - 8 & 9 for 782D only */
242 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
243 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
244 u8 fan[3]; /* Register value */
245 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200246 s8 temp; /* Register value */
247 s8 temp_max; /* Register value */
248 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 u16 temp_add[2]; /* Register value */
250 u16 temp_max_add[2]; /* Register value */
251 u16 temp_max_hyst_add[2]; /* Register value */
252 u8 fan_div[3]; /* Register encoding, shifted right */
253 u8 vid; /* Register encoding, combined */
254 u32 alarms; /* Register encoding, combined */
255 u32 beep_mask; /* Register encoding, combined */
256 u8 beep_enable; /* Boolean */
257 u8 pwm[4]; /* Register value */
258 u8 pwmenable[4]; /* Boolean */
259 u16 sens[3]; /* 782D/783S only.
260 1 = pentium diode; 2 = 3904 diode;
261 3000-5000 = thermistor beta.
262 Default = 3435.
263 Other Betas unimplemented */
264 u8 vrm;
265};
266
267static int w83781d_attach_adapter(struct i2c_adapter *adapter);
268static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
269static int w83781d_detach_client(struct i2c_client *client);
270
Jean Delvare7666c132007-05-08 17:22:02 +0200271static int __devinit w83781d_isa_probe(struct platform_device *pdev);
272static int __devexit w83781d_isa_remove(struct platform_device *pdev);
273
Jean Delvare31b8dc42007-05-08 17:22:03 +0200274static int w83781d_read_value(struct w83781d_data *data, u16 reg);
275static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200277static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279static struct i2c_driver w83781d_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100280 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100281 .name = "w83781d",
282 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .id = I2C_DRIVERID_W83781D,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 .attach_adapter = w83781d_attach_adapter,
285 .detach_client = w83781d_detach_client,
286};
287
Jean Delvare7666c132007-05-08 17:22:02 +0200288static struct platform_driver w83781d_isa_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100289 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200290 .owner = THIS_MODULE,
Jean Delvare7666c132007-05-08 17:22:02 +0200291 .name = "w83781d",
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100292 },
Jean Delvare7666c132007-05-08 17:22:02 +0200293 .probe = w83781d_isa_probe,
294 .remove = w83781d_isa_remove,
Jean Delvarefde09502005-07-19 23:51:07 +0200295};
296
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298/* following are the sysfs callback functions */
299#define show_in_reg(reg) \
300static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
301{ \
302 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare474d00a2007-05-08 17:22:03 +0200303 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304}
305show_in_reg(in);
306show_in_reg(in_min);
307show_in_reg(in_max);
308
309#define store_in_reg(REG, reg) \
310static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
311{ \
Jean Delvare7666c132007-05-08 17:22:02 +0200312 struct w83781d_data *data = dev_get_drvdata(dev); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 u32 val; \
314 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200315 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100317 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200319 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100321 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 return count; \
323}
324store_in_reg(MIN, min);
325store_in_reg(MAX, max);
326
327#define sysfs_in_offset(offset) \
328static ssize_t \
Yani Ioannoue404e272005-05-17 06:42:58 -0400329show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{ \
331 return show_in(dev, buf, offset); \
332} \
333static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
334
335#define sysfs_in_reg_offset(reg, offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400336static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{ \
338 return show_in_##reg (dev, buf, offset); \
339} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400340static 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 -0700341{ \
342 return store_in_##reg (dev, buf, count, offset); \
343} \
344static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
345
346#define sysfs_in_offsets(offset) \
347sysfs_in_offset(offset); \
348sysfs_in_reg_offset(min, offset); \
349sysfs_in_reg_offset(max, offset);
350
351sysfs_in_offsets(0);
352sysfs_in_offsets(1);
353sysfs_in_offsets(2);
354sysfs_in_offsets(3);
355sysfs_in_offsets(4);
356sysfs_in_offsets(5);
357sysfs_in_offsets(6);
358sysfs_in_offsets(7);
359sysfs_in_offsets(8);
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361#define show_fan_reg(reg) \
362static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
363{ \
364 struct w83781d_data *data = w83781d_update_device(dev); \
365 return sprintf(buf,"%ld\n", \
366 FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
367}
368show_fan_reg(fan);
369show_fan_reg(fan_min);
370
371static ssize_t
372store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
373{
Jean Delvare7666c132007-05-08 17:22:02 +0200374 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 u32 val;
376
377 val = simple_strtoul(buf, NULL, 10);
378
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100379 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 data->fan_min[nr - 1] =
381 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200382 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->fan_min[nr - 1]);
384
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100385 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 return count;
387}
388
389#define sysfs_fan_offset(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400390static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{ \
392 return show_fan(dev, buf, offset); \
393} \
394static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
395
396#define sysfs_fan_min_offset(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400397static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{ \
399 return show_fan_min(dev, buf, offset); \
400} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400401static 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 -0700402{ \
403 return store_fan_min(dev, buf, count, offset); \
404} \
405static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
406
407sysfs_fan_offset(1);
408sysfs_fan_min_offset(1);
409sysfs_fan_offset(2);
410sysfs_fan_min_offset(2);
411sysfs_fan_offset(3);
412sysfs_fan_min_offset(3);
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414#define show_temp_reg(reg) \
415static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
416{ \
417 struct w83781d_data *data = w83781d_update_device(dev); \
418 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
419 return sprintf(buf,"%d\n", \
420 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
421 } else { /* TEMP1 */ \
422 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
423 } \
424}
425show_temp_reg(temp);
426show_temp_reg(temp_max);
427show_temp_reg(temp_max_hyst);
428
429#define store_temp_reg(REG, reg) \
430static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
431{ \
Jean Delvare7666c132007-05-08 17:22:02 +0200432 struct w83781d_data *data = dev_get_drvdata(dev); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 s32 val; \
434 \
435 val = simple_strtol(buf, NULL, 10); \
436 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100437 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 \
439 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
440 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200441 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 data->temp_##reg##_add[nr-2]); \
443 } else { /* TEMP1 */ \
444 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200445 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 data->temp_##reg); \
447 } \
448 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100449 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return count; \
451}
452store_temp_reg(OVER, max);
453store_temp_reg(HYST, max_hyst);
454
455#define sysfs_temp_offset(offset) \
456static ssize_t \
Yani Ioannoue404e272005-05-17 06:42:58 -0400457show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{ \
459 return show_temp(dev, buf, offset); \
460} \
461static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
462
463#define sysfs_temp_reg_offset(reg, offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400464static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{ \
466 return show_temp_##reg (dev, buf, offset); \
467} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400468static 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 -0700469{ \
470 return store_temp_##reg (dev, buf, count, offset); \
471} \
472static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
473
474#define sysfs_temp_offsets(offset) \
475sysfs_temp_offset(offset); \
476sysfs_temp_reg_offset(max, offset); \
477sysfs_temp_reg_offset(max_hyst, offset);
478
479sysfs_temp_offsets(1);
480sysfs_temp_offsets(2);
481sysfs_temp_offsets(3);
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400484show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
486 struct w83781d_data *data = w83781d_update_device(dev);
487 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
488}
489
Jim Cromie311ce2e2006-09-24 21:22:52 +0200490static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400493show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 struct w83781d_data *data = w83781d_update_device(dev);
496 return sprintf(buf, "%ld\n", (long) data->vrm);
497}
498
499static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400500store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Jean Delvare7666c132007-05-08 17:22:02 +0200502 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 u32 val;
504
505 val = simple_strtoul(buf, NULL, 10);
506 data->vrm = val;
507
508 return count;
509}
510
Jim Cromie311ce2e2006-09-24 21:22:52 +0200511static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400514show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200517 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
Jim Cromie311ce2e2006-09-24 21:22:52 +0200520static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
521
Yani Ioannoue404e272005-05-17 06:42:58 -0400522static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
524 struct w83781d_data *data = w83781d_update_device(dev);
525 return sprintf(buf, "%ld\n",
526 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
527}
Yani Ioannoue404e272005-05-17 06:42:58 -0400528static ssize_t show_beep_enable (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);
Jean Delvare474d00a2007-05-08 17:22:03 +0200531 return sprintf(buf, "%ld\n", (long)data->beep_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
534#define BEEP_ENABLE 0 /* Store beep_enable */
535#define BEEP_MASK 1 /* Store beep_mask */
536
537static ssize_t
538store_beep_reg(struct device *dev, const char *buf, size_t count,
539 int update_mask)
540{
Jean Delvare7666c132007-05-08 17:22:02 +0200541 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 u32 val, val2;
543
544 val = simple_strtoul(buf, NULL, 10);
545
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100546 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
549 data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200550 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 data->beep_mask & 0xff);
552
553 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200554 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 ((data->beep_mask) >> 16) & 0xff);
556 }
557
558 val2 = (data->beep_mask >> 8) & 0x7f;
559 } else { /* We are storing beep_enable */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200560 val2 = w83781d_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
Jean Delvare474d00a2007-05-08 17:22:03 +0200561 data->beep_enable = !!val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
563
Jean Delvare31b8dc42007-05-08 17:22:03 +0200564 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 val2 | data->beep_enable << 7);
566
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100567 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 return count;
569}
570
571#define sysfs_beep(REG, reg) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400572static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{ \
Yani Ioannoue404e272005-05-17 06:42:58 -0400574 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400576static 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 -0700577{ \
578 return store_beep_reg(dev, buf, count, BEEP_##REG); \
579} \
580static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
581
582sysfs_beep(ENABLE, enable);
583sysfs_beep(MASK, mask);
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585static ssize_t
586show_fan_div_reg(struct device *dev, char *buf, int nr)
587{
588 struct w83781d_data *data = w83781d_update_device(dev);
589 return sprintf(buf, "%ld\n",
590 (long) DIV_FROM_REG(data->fan_div[nr - 1]));
591}
592
593/* Note: we save and restore the fan minimum here, because its value is
594 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200595 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 because the divisor changed. */
597static ssize_t
598store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
599{
Jean Delvare7666c132007-05-08 17:22:02 +0200600 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 unsigned long min;
602 u8 reg;
603 unsigned long val = simple_strtoul(buf, NULL, 10);
604
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100605 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 /* Save fan_min */
608 min = FAN_FROM_REG(data->fan_min[nr],
609 DIV_FROM_REG(data->fan_div[nr]));
610
611 data->fan_div[nr] = DIV_TO_REG(val, data->type);
612
Jean Delvare31b8dc42007-05-08 17:22:03 +0200613 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 & (nr==0 ? 0xcf : 0x3f))
615 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200616 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 /* w83781d and as99127f don't have extended divisor bits */
619 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200620 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 & ~(1 << (5 + nr)))
622 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200623 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
625
626 /* Restore fan_min */
627 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200628 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100630 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return count;
632}
633
634#define sysfs_fan_div(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400635static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{ \
637 return show_fan_div_reg(dev, buf, offset); \
638} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400639static 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 -0700640{ \
641 return store_fan_div_reg(dev, buf, count, offset - 1); \
642} \
643static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
644
645sysfs_fan_div(1);
646sysfs_fan_div(2);
647sysfs_fan_div(3);
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649static ssize_t
650show_pwm_reg(struct device *dev, char *buf, int nr)
651{
652 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare474d00a2007-05-08 17:22:03 +0200653 return sprintf(buf, "%ld\n", (long)data->pwm[nr - 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
656static ssize_t
657show_pwmenable_reg(struct device *dev, char *buf, int nr)
658{
659 struct w83781d_data *data = w83781d_update_device(dev);
660 return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]);
661}
662
663static ssize_t
664store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
665{
Jean Delvare7666c132007-05-08 17:22:02 +0200666 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 u32 val;
668
669 val = simple_strtoul(buf, NULL, 10);
670
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100671 mutex_lock(&data->update_lock);
Jean Delvare474d00a2007-05-08 17:22:03 +0200672 data->pwm[nr - 1] = SENSORS_LIMIT(val, 0, 255);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200673 w83781d_write_value(data, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100674 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 return count;
676}
677
678static ssize_t
679store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
680{
Jean Delvare7666c132007-05-08 17:22:02 +0200681 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 u32 val, reg;
683
684 val = simple_strtoul(buf, NULL, 10);
685
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100686 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 switch (val) {
689 case 0:
690 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200691 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
692 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 (reg & 0xf7) | (val << 3));
694
Jean Delvare31b8dc42007-05-08 17:22:03 +0200695 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
696 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 (reg & 0xef) | (!val << 4));
698
699 data->pwmenable[nr - 1] = val;
700 break;
701
702 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100703 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -EINVAL;
705 }
706
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100707 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return count;
709}
710
711#define sysfs_pwm(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400712static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{ \
714 return show_pwm_reg(dev, buf, offset); \
715} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400716static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 const char *buf, size_t count) \
718{ \
719 return store_pwm_reg(dev, buf, count, offset); \
720} \
721static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
722 show_regs_pwm_##offset, store_regs_pwm_##offset);
723
724#define sysfs_pwmenable(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400725static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{ \
727 return show_pwmenable_reg(dev, buf, offset); \
728} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400729static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 const char *buf, size_t count) \
731{ \
732 return store_pwmenable_reg(dev, buf, count, offset); \
733} \
734static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
735 show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
736
737sysfs_pwm(1);
738sysfs_pwm(2);
739sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
740sysfs_pwm(3);
741sysfs_pwm(4);
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743static ssize_t
744show_sensor_reg(struct device *dev, char *buf, int nr)
745{
746 struct w83781d_data *data = w83781d_update_device(dev);
747 return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
748}
749
750static ssize_t
751store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
752{
Jean Delvare7666c132007-05-08 17:22:02 +0200753 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 u32 val, tmp;
755
756 val = simple_strtoul(buf, NULL, 10);
757
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100758 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 switch (val) {
761 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200762 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
763 w83781d_write_value(data, W83781D_REG_SCFG1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 tmp | BIT_SCFG1[nr - 1]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200765 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
766 w83781d_write_value(data, W83781D_REG_SCFG2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 tmp | BIT_SCFG2[nr - 1]);
768 data->sens[nr - 1] = val;
769 break;
770 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200771 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
772 w83781d_write_value(data, W83781D_REG_SCFG1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 tmp | BIT_SCFG1[nr - 1]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200774 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
775 w83781d_write_value(data, W83781D_REG_SCFG2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 tmp & ~BIT_SCFG2[nr - 1]);
777 data->sens[nr - 1] = val;
778 break;
779 case W83781D_DEFAULT_BETA: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200780 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
781 w83781d_write_value(data, W83781D_REG_SCFG1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 tmp & ~BIT_SCFG1[nr - 1]);
783 data->sens[nr - 1] = val;
784 break;
785 default:
786 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
787 (long) val, W83781D_DEFAULT_BETA);
788 break;
789 }
790
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100791 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return count;
793}
794
795#define sysfs_sensor(offset) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400796static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{ \
798 return show_sensor_reg(dev, buf, offset); \
799} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400800static 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 -0700801{ \
802 return store_sensor_reg(dev, buf, count, offset); \
803} \
804static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
805
806sysfs_sensor(1);
807sysfs_sensor(2);
808sysfs_sensor(3);
809
Jean Delvare7666c132007-05-08 17:22:02 +0200810/* I2C devices get this name attribute automatically, but for ISA devices
811 we must create it by ourselves. */
812static ssize_t
813show_name(struct device *dev, struct device_attribute *devattr, char *buf)
814{
815 struct w83781d_data *data = dev_get_drvdata(dev);
816 return sprintf(buf, "%s\n", data->client.name);
817}
818static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820/* This function is called when:
821 * w83781d_driver is inserted (when this module is loaded), for each
822 available adapter
823 * when a new adapter is inserted (and w83781d_driver is still present) */
824static int
825w83781d_attach_adapter(struct i2c_adapter *adapter)
826{
827 if (!(adapter->class & I2C_CLASS_HWMON))
828 return 0;
Jean Delvare2ed2dc32005-07-31 21:42:02 +0200829 return i2c_probe(adapter, &addr_data, w83781d_detect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830}
831
832/* Assumes that adapter is of I2C, not ISA variety.
833 * OTHERWISE DON'T CALL THIS
834 */
835static int
836w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
837 struct i2c_client *new_client)
838{
839 int i, val1 = 0, id;
840 int err;
841 const char *client_name = "";
842 struct w83781d_data *data = i2c_get_clientdata(new_client);
843
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200844 data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (!(data->lm75[0])) {
846 err = -ENOMEM;
847 goto ERROR_SC_0;
848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 id = i2c_adapter_id(adapter);
851
852 if (force_subclients[0] == id && force_subclients[1] == address) {
853 for (i = 2; i <= 3; i++) {
854 if (force_subclients[i] < 0x48 ||
855 force_subclients[i] > 0x4f) {
856 dev_err(&new_client->dev, "Invalid subclient "
857 "address %d; must be 0x48-0x4f\n",
858 force_subclients[i]);
859 err = -EINVAL;
860 goto ERROR_SC_1;
861 }
862 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200863 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 (force_subclients[2] & 0x07) |
865 ((force_subclients[3] & 0x07) << 4));
866 data->lm75[0]->addr = force_subclients[2];
867 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200868 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 data->lm75[0]->addr = 0x48 + (val1 & 0x07);
870 }
871
872 if (kind != w83783s) {
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200873 data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (!(data->lm75[1])) {
875 err = -ENOMEM;
876 goto ERROR_SC_1;
877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 if (force_subclients[0] == id &&
880 force_subclients[1] == address) {
881 data->lm75[1]->addr = force_subclients[3];
882 } else {
883 data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07);
884 }
885 if (data->lm75[0]->addr == data->lm75[1]->addr) {
886 dev_err(&new_client->dev,
887 "Duplicate addresses 0x%x for subclients.\n",
888 data->lm75[0]->addr);
889 err = -EBUSY;
890 goto ERROR_SC_2;
891 }
892 }
893
894 if (kind == w83781d)
895 client_name = "w83781d subclient";
896 else if (kind == w83782d)
897 client_name = "w83782d subclient";
898 else if (kind == w83783s)
899 client_name = "w83783s subclient";
900 else if (kind == w83627hf)
901 client_name = "w83627hf subclient";
902 else if (kind == as99127f)
903 client_name = "as99127f subclient";
904
905 for (i = 0; i <= 1; i++) {
906 /* store all data in w83781d */
907 i2c_set_clientdata(data->lm75[i], NULL);
908 data->lm75[i]->adapter = adapter;
909 data->lm75[i]->driver = &w83781d_driver;
910 data->lm75[i]->flags = 0;
911 strlcpy(data->lm75[i]->name, client_name,
912 I2C_NAME_SIZE);
913 if ((err = i2c_attach_client(data->lm75[i]))) {
914 dev_err(&new_client->dev, "Subclient %d "
915 "registration at address 0x%x "
916 "failed.\n", i, data->lm75[i]->addr);
917 if (i == 1)
918 goto ERROR_SC_3;
919 goto ERROR_SC_2;
920 }
921 if (kind == w83783s)
922 break;
923 }
924
925 return 0;
926
927/* Undo inits in case of errors */
928ERROR_SC_3:
929 i2c_detach_client(data->lm75[0]);
930ERROR_SC_2:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800931 kfree(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932ERROR_SC_1:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800933 kfree(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934ERROR_SC_0:
935 return err;
936}
937
Jim Cromie311ce2e2006-09-24 21:22:52 +0200938#define IN_UNIT_ATTRS(X) \
939 &dev_attr_in##X##_input.attr, \
940 &dev_attr_in##X##_min.attr, \
941 &dev_attr_in##X##_max.attr
942
943#define FAN_UNIT_ATTRS(X) \
944 &dev_attr_fan##X##_input.attr, \
945 &dev_attr_fan##X##_min.attr, \
946 &dev_attr_fan##X##_div.attr
947
948#define TEMP_UNIT_ATTRS(X) \
949 &dev_attr_temp##X##_input.attr, \
950 &dev_attr_temp##X##_max.attr, \
951 &dev_attr_temp##X##_max_hyst.attr
952
953static struct attribute* w83781d_attributes[] = {
954 IN_UNIT_ATTRS(0),
955 IN_UNIT_ATTRS(2),
956 IN_UNIT_ATTRS(3),
957 IN_UNIT_ATTRS(4),
958 IN_UNIT_ATTRS(5),
959 IN_UNIT_ATTRS(6),
960 FAN_UNIT_ATTRS(1),
961 FAN_UNIT_ATTRS(2),
962 FAN_UNIT_ATTRS(3),
963 TEMP_UNIT_ATTRS(1),
964 TEMP_UNIT_ATTRS(2),
965 &dev_attr_cpu0_vid.attr,
966 &dev_attr_vrm.attr,
967 &dev_attr_alarms.attr,
968 &dev_attr_beep_mask.attr,
969 &dev_attr_beep_enable.attr,
970 NULL
971};
972static const struct attribute_group w83781d_group = {
973 .attrs = w83781d_attributes,
974};
975
976static struct attribute *w83781d_attributes_opt[] = {
977 IN_UNIT_ATTRS(1),
978 IN_UNIT_ATTRS(7),
979 IN_UNIT_ATTRS(8),
980 TEMP_UNIT_ATTRS(3),
981 &dev_attr_pwm1.attr,
982 &dev_attr_pwm2.attr,
983 &dev_attr_pwm2_enable.attr,
984 &dev_attr_pwm3.attr,
985 &dev_attr_pwm4.attr,
986 &dev_attr_temp1_type.attr,
987 &dev_attr_temp2_type.attr,
988 &dev_attr_temp3_type.attr,
989 NULL
990};
991static const struct attribute_group w83781d_group_opt = {
992 .attrs = w83781d_attributes_opt,
993};
994
Jean Delvare7666c132007-05-08 17:22:02 +0200995/* No clean up is done on error, it's up to the caller */
996static int
997w83781d_create_files(struct device *dev, int kind, int is_isa)
998{
999 int err;
1000
1001 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
1002 return err;
1003
1004 if (kind != w83783s) {
1005 if ((err = device_create_file(dev, &dev_attr_in1_input))
1006 || (err = device_create_file(dev, &dev_attr_in1_min))
1007 || (err = device_create_file(dev, &dev_attr_in1_max)))
1008 return err;
1009 }
1010 if (kind != as99127f && kind != w83781d && kind != w83783s) {
1011 if ((err = device_create_file(dev, &dev_attr_in7_input))
1012 || (err = device_create_file(dev, &dev_attr_in7_min))
1013 || (err = device_create_file(dev, &dev_attr_in7_max))
1014 || (err = device_create_file(dev, &dev_attr_in8_input))
1015 || (err = device_create_file(dev, &dev_attr_in8_min))
1016 || (err = device_create_file(dev, &dev_attr_in8_max)))
1017 return err;
1018 }
1019 if (kind != w83783s) {
1020 if ((err = device_create_file(dev, &dev_attr_temp3_input))
1021 || (err = device_create_file(dev, &dev_attr_temp3_max))
1022 || (err = device_create_file(dev,
1023 &dev_attr_temp3_max_hyst)))
1024 return err;
1025 }
1026
1027 if (kind != w83781d && kind != as99127f) {
1028 if ((err = device_create_file(dev, &dev_attr_pwm1))
1029 || (err = device_create_file(dev, &dev_attr_pwm2))
1030 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1031 return err;
1032 }
1033 if (kind == w83782d && !is_isa) {
1034 if ((err = device_create_file(dev, &dev_attr_pwm3))
1035 || (err = device_create_file(dev, &dev_attr_pwm4)))
1036 return err;
1037 }
1038
1039 if (kind != as99127f && kind != w83781d) {
1040 if ((err = device_create_file(dev, &dev_attr_temp1_type))
1041 || (err = device_create_file(dev,
1042 &dev_attr_temp2_type)))
1043 return err;
1044 if (kind != w83783s) {
1045 if ((err = device_create_file(dev,
1046 &dev_attr_temp3_type)))
1047 return err;
1048 }
1049 }
1050
1051 if (is_isa) {
1052 err = device_create_file(&pdev->dev, &dev_attr_name);
1053 if (err)
1054 return err;
1055 }
1056
1057 return 0;
1058}
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060static int
1061w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
1062{
Jean Delvare7666c132007-05-08 17:22:02 +02001063 int val1 = 0, val2;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001064 struct i2c_client *client;
1065 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 struct w83781d_data *data;
1067 int err;
1068 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 enum vendor { winbond, asus } vendid;
1070
Jean Delvare7666c132007-05-08 17:22:02 +02001071 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 err = -EINVAL;
Jean Delvare7666c132007-05-08 17:22:02 +02001073 goto ERROR1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 }
1075
1076 /* OK. For now, we presume we have a valid client. We now create the
1077 client structure, even though we cannot fill it completely yet.
1078 But it allows us to access w83781d_{read,write}_value. */
1079
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001080 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 err = -ENOMEM;
1082 goto ERROR1;
1083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Jim Cromie311ce2e2006-09-24 21:22:52 +02001085 client = &data->client;
1086 i2c_set_clientdata(client, data);
1087 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001088 mutex_init(&data->lock);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001089 client->adapter = adapter;
Jean Delvare7666c132007-05-08 17:22:02 +02001090 client->driver = &w83781d_driver;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001091 dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093 /* Now, we do the remaining detection. */
1094
1095 /* The w8378?d may be stuck in some other bank than bank 0. This may
1096 make reading other information impossible. Specify a force=... or
1097 force_*=... parameter, and the Winbond will be reset to the right
1098 bank. */
1099 if (kind < 0) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001100 if (w83781d_read_value(data, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001101 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1102 "failed at step 3\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 err = -ENODEV;
1104 goto ERROR2;
1105 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001106 val1 = w83781d_read_value(data, W83781D_REG_BANK);
1107 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 /* Check for Winbond or Asus ID if in bank 0 */
1109 if ((!(val1 & 0x07)) &&
1110 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1111 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001112 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1113 "failed at step 4\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 err = -ENODEV;
1115 goto ERROR2;
1116 }
1117 /* If Winbond SMBus, check address at 0x48.
1118 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001119 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1120 ((val1 & 0x80) && (val2 == 0x5c))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001122 (data, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001123 dev_dbg(&adapter->dev, "Detection of w83781d "
1124 "chip failed at step 5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 err = -ENODEV;
1126 goto ERROR2;
1127 }
1128 }
1129 }
1130
1131 /* We have either had a force parameter, or we have already detected the
1132 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001133 w83781d_write_value(data, W83781D_REG_BANK,
1134 (w83781d_read_value(data, W83781D_REG_BANK)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001135 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137 /* Determine the chip type. */
1138 if (kind <= 0) {
1139 /* get vendor ID */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001140 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 if (val2 == 0x5c)
1142 vendid = winbond;
1143 else if (val2 == 0x12)
1144 vendid = asus;
1145 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001146 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1147 "neither Winbond nor Asus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 err = -ENODEV;
1149 goto ERROR2;
1150 }
1151
Jean Delvare31b8dc42007-05-08 17:22:03 +02001152 val1 = w83781d_read_value(data, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1154 kind = w83781d;
1155 else if (val1 == 0x30 && vendid == winbond)
1156 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001157 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 kind = w83783s;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001159 else if (val1 == 0x21 && vendid == winbond)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 kind = w83627hf;
Jean Delvare7666c132007-05-08 17:22:02 +02001161 else if (val1 == 0x31 && address >= 0x28)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 else {
1164 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001165 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001167 "address 0x%02x\n", address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 err = -EINVAL;
1169 goto ERROR2;
1170 }
1171 }
1172
1173 if (kind == w83781d) {
1174 client_name = "w83781d";
1175 } else if (kind == w83782d) {
1176 client_name = "w83782d";
1177 } else if (kind == w83783s) {
1178 client_name = "w83783s";
1179 } else if (kind == w83627hf) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001180 client_name = "w83627hf";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 } else if (kind == as99127f) {
1182 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 }
1184
1185 /* Fill in the remaining client fields and put into the global list */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001186 strlcpy(client->name, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 data->type = kind;
1188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 /* Tell the I2C layer a new client has arrived */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001190 if ((err = i2c_attach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 goto ERROR2;
1192
1193 /* attach secondary i2c lm75-like clients */
Jean Delvare7666c132007-05-08 17:22:02 +02001194 if ((err = w83781d_detect_subclients(adapter, address,
1195 kind, client)))
1196 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
1198 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001199 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 /* Register sysfs hooks */
Jean Delvare7666c132007-05-08 17:22:02 +02001202 err = w83781d_create_files(dev, kind, 0);
1203 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001204 goto ERROR4;
1205
Jim Cromie311ce2e2006-09-24 21:22:52 +02001206 data->class_dev = hwmon_device_register(dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001207 if (IS_ERR(data->class_dev)) {
1208 err = PTR_ERR(data->class_dev);
1209 goto ERROR4;
1210 }
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return 0;
1213
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001214ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001215 sysfs_remove_group(&dev->kobj, &w83781d_group);
1216 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1217
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001218 if (data->lm75[1]) {
1219 i2c_detach_client(data->lm75[1]);
1220 kfree(data->lm75[1]);
1221 }
1222 if (data->lm75[0]) {
1223 i2c_detach_client(data->lm75[0]);
1224 kfree(data->lm75[0]);
1225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226ERROR3:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001227 i2c_detach_client(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228ERROR2:
1229 kfree(data);
1230ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 return err;
1232}
1233
1234static int
1235w83781d_detach_client(struct i2c_client *client)
1236{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001237 struct w83781d_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 int err;
1239
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001240 /* main client */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001241 if (data) {
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001242 hwmon_device_unregister(data->class_dev);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001243 sysfs_remove_group(&client->dev.kobj, &w83781d_group);
1244 sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
1245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Jean Delvare7bef5592005-07-27 22:14:49 +02001247 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001250 /* main client */
1251 if (data)
1252 kfree(data);
1253
1254 /* subclient */
1255 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 kfree(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 return 0;
1259}
1260
Jean Delvare7666c132007-05-08 17:22:02 +02001261static int __devinit
1262w83781d_isa_probe(struct platform_device *pdev)
1263{
1264 int err, reg;
1265 struct w83781d_data *data;
1266 struct resource *res;
1267 const char *name;
1268
1269 /* Reserve the ISA region */
1270 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1271 if (!request_region(res->start, W83781D_EXTENT, "w83781d")) {
1272 err = -EBUSY;
1273 goto exit;
1274 }
1275
1276 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
1277 err = -ENOMEM;
1278 goto exit_release_region;
1279 }
1280 mutex_init(&data->lock);
1281 data->client.addr = res->start;
1282 i2c_set_clientdata(&data->client, data);
1283 platform_set_drvdata(pdev, data);
1284
Jean Delvare31b8dc42007-05-08 17:22:03 +02001285 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
Jean Delvare7666c132007-05-08 17:22:02 +02001286 switch (reg) {
1287 case 0x21:
1288 data->type = w83627hf;
1289 name = "w83627hf";
1290 break;
1291 case 0x30:
1292 data->type = w83782d;
1293 name = "w83782d";
1294 break;
1295 default:
1296 data->type = w83781d;
1297 name = "w83781d";
1298 }
1299 strlcpy(data->client.name, name, I2C_NAME_SIZE);
1300
1301 /* Initialize the W83781D chip */
1302 w83781d_init_device(&pdev->dev);
1303
1304 /* Register sysfs hooks */
1305 err = w83781d_create_files(&pdev->dev, data->type, 1);
1306 if (err)
1307 goto exit_remove_files;
1308
1309 data->class_dev = hwmon_device_register(&pdev->dev);
1310 if (IS_ERR(data->class_dev)) {
1311 err = PTR_ERR(data->class_dev);
1312 goto exit_remove_files;
1313 }
1314
1315 return 0;
1316
1317 exit_remove_files:
1318 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1319 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1320 device_remove_file(&pdev->dev, &dev_attr_name);
1321 kfree(data);
1322 exit_release_region:
1323 release_region(res->start, W83781D_EXTENT);
1324 exit:
1325 return err;
1326}
1327
1328static int __devexit
1329w83781d_isa_remove(struct platform_device *pdev)
1330{
1331 struct w83781d_data *data = platform_get_drvdata(pdev);
1332
1333 hwmon_device_unregister(data->class_dev);
1334 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1335 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1336 device_remove_file(&pdev->dev, &dev_attr_name);
1337 release_region(data->client.addr, W83781D_EXTENT);
1338 kfree(data);
1339
1340 return 0;
1341}
1342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343/* The SMBus locks itself, usually, but nothing may access the Winbond between
1344 bank switches. ISA access must always be locked explicitly!
1345 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1346 would slow down the W83781D access and should not be necessary.
1347 There are some ugly typecasts here, but the good news is - they should
1348 nowhere else be necessary! */
1349static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001350w83781d_read_value(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Jean Delvare31b8dc42007-05-08 17:22:03 +02001352 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 int res, word_sized, bank;
1354 struct i2c_client *cl;
1355
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001356 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001357 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 word_sized = (((reg & 0xff00) == 0x100)
1359 || ((reg & 0xff00) == 0x200))
1360 && (((reg & 0x00ff) == 0x50)
1361 || ((reg & 0x00ff) == 0x53)
1362 || ((reg & 0x00ff) == 0x55));
1363 if (reg & 0xff00) {
1364 outb_p(W83781D_REG_BANK,
1365 client->addr + W83781D_ADDR_REG_OFFSET);
1366 outb_p(reg >> 8,
1367 client->addr + W83781D_DATA_REG_OFFSET);
1368 }
1369 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1370 res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
1371 if (word_sized) {
1372 outb_p((reg & 0xff) + 1,
1373 client->addr + W83781D_ADDR_REG_OFFSET);
1374 res =
1375 (res << 8) + inb_p(client->addr +
1376 W83781D_DATA_REG_OFFSET);
1377 }
1378 if (reg & 0xff00) {
1379 outb_p(W83781D_REG_BANK,
1380 client->addr + W83781D_ADDR_REG_OFFSET);
1381 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1382 }
1383 } else {
1384 bank = (reg >> 8) & 0x0f;
1385 if (bank > 2)
1386 /* switch banks */
1387 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1388 bank);
1389 if (bank == 0 || bank > 2) {
1390 res = i2c_smbus_read_byte_data(client, reg & 0xff);
1391 } else {
1392 /* switch to subclient */
1393 cl = data->lm75[bank - 1];
1394 /* convert from ISA to LM75 I2C addresses */
1395 switch (reg & 0xff) {
1396 case 0x50: /* TEMP */
1397 res = swab16(i2c_smbus_read_word_data(cl, 0));
1398 break;
1399 case 0x52: /* CONFIG */
1400 res = i2c_smbus_read_byte_data(cl, 1);
1401 break;
1402 case 0x53: /* HYST */
1403 res = swab16(i2c_smbus_read_word_data(cl, 2));
1404 break;
1405 case 0x55: /* OVER */
1406 default:
1407 res = swab16(i2c_smbus_read_word_data(cl, 3));
1408 break;
1409 }
1410 }
1411 if (bank > 2)
1412 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1413 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001414 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 return res;
1416}
1417
1418static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001419w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
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 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) == 0x53)
1430 || ((reg & 0x00ff) == 0x55));
1431 if (reg & 0xff00) {
1432 outb_p(W83781D_REG_BANK,
1433 client->addr + W83781D_ADDR_REG_OFFSET);
1434 outb_p(reg >> 8,
1435 client->addr + W83781D_DATA_REG_OFFSET);
1436 }
1437 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1438 if (word_sized) {
1439 outb_p(value >> 8,
1440 client->addr + W83781D_DATA_REG_OFFSET);
1441 outb_p((reg & 0xff) + 1,
1442 client->addr + W83781D_ADDR_REG_OFFSET);
1443 }
1444 outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
1445 if (reg & 0xff00) {
1446 outb_p(W83781D_REG_BANK,
1447 client->addr + W83781D_ADDR_REG_OFFSET);
1448 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1449 }
1450 } else {
1451 bank = (reg >> 8) & 0x0f;
1452 if (bank > 2)
1453 /* switch banks */
1454 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1455 bank);
1456 if (bank == 0 || bank > 2) {
1457 i2c_smbus_write_byte_data(client, reg & 0xff,
1458 value & 0xff);
1459 } else {
1460 /* switch to subclient */
1461 cl = data->lm75[bank - 1];
1462 /* convert from ISA to LM75 I2C addresses */
1463 switch (reg & 0xff) {
1464 case 0x52: /* CONFIG */
1465 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1466 break;
1467 case 0x53: /* HYST */
1468 i2c_smbus_write_word_data(cl, 2, swab16(value));
1469 break;
1470 case 0x55: /* OVER */
1471 i2c_smbus_write_word_data(cl, 3, swab16(value));
1472 break;
1473 }
1474 }
1475 if (bank > 2)
1476 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1477 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001478 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return 0;
1480}
1481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482static void
Jean Delvare7666c132007-05-08 17:22:02 +02001483w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
Jean Delvare7666c132007-05-08 17:22:02 +02001485 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 int i, p;
1487 int type = data->type;
1488 u8 tmp;
1489
Jean Delvarefabddcd2006-02-05 23:26:51 +01001490 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001492 /* Resetting the chip has been the default for a long time,
1493 but it causes the BIOS initializations (fan clock dividers,
1494 thermal sensor types...) to be lost, so it is now optional.
1495 It might even go away if nobody reports it as being useful,
1496 as I see very little reason why this would be needed at
1497 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001498 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001499 "having, please report!\n");
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001502 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1503 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 /* Reset all except Watchdog values and last conversion values
1505 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001506 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 /* Restore the registers and disable power-on abnormal beep.
1508 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001509 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1510 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 /* Disable master beep-enable (reset turns it on).
1512 Individual beep_mask should be reset to off but for some reason
1513 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001514 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 }
1516
Jean Delvarefabddcd2006-02-05 23:26:51 +01001517 /* Disable power-on abnormal beep, as advised by the datasheet.
1518 Already done if reset=1. */
1519 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001520 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1521 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001522 }
1523
Jean Delvare303760b2005-07-31 21:52:01 +02001524 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
1526 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001527 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 for (i = 1; i <= 3; i++) {
1529 if (!(tmp & BIT_SCFG1[i - 1])) {
1530 data->sens[i - 1] = W83781D_DEFAULT_BETA;
1531 } else {
1532 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001533 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1535 data->sens[i - 1] = 1;
1536 else
1537 data->sens[i - 1] = 2;
1538 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001539 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 break;
1541 }
1542 }
1543
1544 if (init && type != as99127f) {
1545 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001546 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001548 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001550 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 tmp & 0xfe);
1552 }
1553
1554 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001555 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001556 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 W83781D_REG_TEMP3_CONFIG);
1558 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001559 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001561 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1563 }
1564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 }
1566
1567 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001568 w83781d_write_value(data, W83781D_REG_CONFIG,
1569 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 W83781D_REG_CONFIG) & 0xf7)
1571 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001572
1573 /* A few vars need to be filled upon startup */
1574 for (i = 1; i <= 3; i++) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001575 data->fan_min[i - 1] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001576 W83781D_REG_FAN_MIN(i));
1577 }
1578 if (type != w83781d && type != as99127f)
1579 for (i = 0; i < 4; i++)
1580 data->pwmenable[i] = 1;
1581
1582 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583}
1584
1585static struct w83781d_data *w83781d_update_device(struct device *dev)
1586{
Jean Delvare7666c132007-05-08 17:22:02 +02001587 struct w83781d_data *data = dev_get_drvdata(dev);
1588 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 int i;
1590
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001591 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1594 || !data->valid) {
1595 dev_dbg(dev, "Starting device update\n");
1596
1597 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001598 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 continue; /* 783S has no in1 */
1600 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001601 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001603 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001605 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001606 if ((data->type != w83782d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 && (data->type != w83627hf) && (i == 6))
1608 break;
1609 }
1610 for (i = 1; i <= 3; i++) {
1611 data->fan[i - 1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001612 w83781d_read_value(data, W83781D_REG_FAN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 data->fan_min[i - 1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001614 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 }
1616 if (data->type != w83781d && data->type != as99127f) {
1617 for (i = 1; i <= 4; i++) {
1618 data->pwm[i - 1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001619 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 W83781D_REG_PWM(i));
Jean Delvare7666c132007-05-08 17:22:02 +02001621 if ((data->type != w83782d || !client->driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 && i == 2)
1623 break;
1624 }
1625 /* Only PWM2 can be disabled */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001626 data->pwmenable[1] = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1628 }
1629
Jean Delvare31b8dc42007-05-08 17:22:03 +02001630 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001632 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001634 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001636 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001638 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001640 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001641 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001643 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001645 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 W83781D_REG_TEMP_OVER(3));
1647 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001648 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 W83781D_REG_TEMP_HYST(3));
1650 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001651 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001652 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001653 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001654 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 data->fan_div[0] = (i >> 4) & 0x03;
1656 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001657 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001658 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001660 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 data->fan_div[0] |= (i >> 3) & 0x04;
1662 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001663 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if ((data->type == w83782d) || (data->type == w83627hf)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001666 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001667 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001668 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001669 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001670 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001671 W83782D_REG_ALARM3) << 16);
1672 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001673 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001674 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001675 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001676 W83782D_REG_ALARM2) << 8);
1677 } else {
1678 /* No real-time status registers, fall back to
1679 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001680 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001681 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001682 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001683 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001685 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 data->beep_enable = i >> 7;
1687 data->beep_mask = ((i & 0x7f) << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001688 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 if ((data->type != w83781d) && (data->type != as99127f)) {
1690 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001691 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 W83781D_REG_BEEP_INTS3) << 16;
1693 }
1694 data->last_updated = jiffies;
1695 data->valid = 1;
1696 }
1697
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001698 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 return data;
1701}
1702
Jean Delvare7666c132007-05-08 17:22:02 +02001703/* return 1 if a supported chip is found, 0 otherwise */
1704static int __init
1705w83781d_isa_found(unsigned short address)
1706{
1707 int val, save, found = 0;
1708
1709 if (!request_region(address, W83781D_EXTENT, "w83781d"))
1710 return 0;
1711
1712#define REALLY_SLOW_IO
1713 /* We need the timeouts for at least some W83781D-like
1714 chips. But only if we read 'undefined' registers. */
1715 val = inb_p(address + 1);
1716 if (inb_p(address + 2) != val
1717 || inb_p(address + 3) != val
1718 || inb_p(address + 7) != val) {
1719 pr_debug("w83781d: Detection failed at step 1\n");
1720 goto release;
1721 }
1722#undef REALLY_SLOW_IO
1723
1724 /* We should be able to change the 7 LSB of the address port. The
1725 MSB (busy flag) should be clear initially, set after the write. */
1726 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1727 if (save & 0x80) {
1728 pr_debug("w83781d: Detection failed at step 2\n");
1729 goto release;
1730 }
1731 val = ~save & 0x7f;
1732 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1733 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1734 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1735 pr_debug("w83781d: Detection failed at step 3\n");
1736 goto release;
1737 }
1738
1739 /* We found a device, now see if it could be a W83781D */
1740 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1741 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1742 if (val & 0x80) {
1743 pr_debug("w83781d: Detection failed at step 4\n");
1744 goto release;
1745 }
1746 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1747 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1748 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1749 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1750 if ((!(save & 0x80) && (val != 0xa3))
1751 || ((save & 0x80) && (val != 0x5c))) {
1752 pr_debug("w83781d: Detection failed at step 5\n");
1753 goto release;
1754 }
1755 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1756 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1757 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1758 pr_debug("w83781d: Detection failed at step 6\n");
1759 goto release;
1760 }
1761
1762 /* The busy flag should be clear again */
1763 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1764 pr_debug("w83781d: Detection failed at step 7\n");
1765 goto release;
1766 }
1767
1768 /* Determine the chip type */
1769 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1770 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1771 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1772 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1773 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1774 if ((val & 0xfe) == 0x10 /* W83781D */
1775 || val == 0x30 /* W83782D */
1776 || val == 0x21) /* W83627HF */
1777 found = 1;
1778
1779 if (found)
1780 pr_info("w83781d: Found a %s chip at %#x\n",
1781 val == 0x21 ? "W83627HF" :
1782 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1783
1784 release:
1785 release_region(address, W83781D_EXTENT);
1786 return found;
1787}
1788
1789static int __init
1790w83781d_isa_device_add(unsigned short address)
1791{
1792 struct resource res = {
1793 .start = address,
1794 .end = address + W83781D_EXTENT,
1795 .name = "w83781d",
1796 .flags = IORESOURCE_IO,
1797 };
1798 int err;
1799
1800 pdev = platform_device_alloc("w83781d", address);
1801 if (!pdev) {
1802 err = -ENOMEM;
1803 printk(KERN_ERR "w83781d: Device allocation failed\n");
1804 goto exit;
1805 }
1806
1807 err = platform_device_add_resources(pdev, &res, 1);
1808 if (err) {
1809 printk(KERN_ERR "w83781d: Device resource addition failed "
1810 "(%d)\n", err);
1811 goto exit_device_put;
1812 }
1813
1814 err = platform_device_add(pdev);
1815 if (err) {
1816 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1817 err);
1818 goto exit_device_put;
1819 }
1820
1821 return 0;
1822
1823 exit_device_put:
1824 platform_device_put(pdev);
1825 exit:
1826 pdev = NULL;
1827 return err;
1828}
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830static int __init
1831sensors_w83781d_init(void)
1832{
Jean Delvarefde09502005-07-19 23:51:07 +02001833 int res;
1834
1835 res = i2c_add_driver(&w83781d_driver);
1836 if (res)
Jean Delvare7666c132007-05-08 17:22:02 +02001837 goto exit;
Jean Delvarefde09502005-07-19 23:51:07 +02001838
Jean Delvare7666c132007-05-08 17:22:02 +02001839 if (w83781d_isa_found(isa_address)) {
1840 res = platform_driver_register(&w83781d_isa_driver);
1841 if (res)
1842 goto exit_unreg_i2c_driver;
1843
1844 /* Sets global pdev as a side effect */
1845 res = w83781d_isa_device_add(isa_address);
1846 if (res)
1847 goto exit_unreg_isa_driver;
1848 }
Jean Delvarefde09502005-07-19 23:51:07 +02001849
1850 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02001851
1852 exit_unreg_isa_driver:
1853 platform_driver_unregister(&w83781d_isa_driver);
1854 exit_unreg_i2c_driver:
1855 i2c_del_driver(&w83781d_driver);
1856 exit:
1857 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858}
1859
1860static void __exit
1861sensors_w83781d_exit(void)
1862{
Jean Delvare7666c132007-05-08 17:22:02 +02001863 if (pdev) {
1864 platform_device_unregister(pdev);
1865 platform_driver_unregister(&w83781d_isa_driver);
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 i2c_del_driver(&w83781d_driver);
1868}
1869
1870MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1871 "Philip Edelbrock <phil@netroedge.com>, "
1872 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1873MODULE_DESCRIPTION("W83781D driver");
1874MODULE_LICENSE("GPL");
1875
1876module_init(sensors_w83781d_init);
1877module_exit(sensors_w83781d_exit);