blob: fc12bd412e3a4917b5645339d3dd388af8f0d3a3 [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>
Jean Delvare360782d2008-10-17 17:51:19 +02007 Copyright (c) 2007 - 2008 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>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040041#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020042#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020043#include <linux/hwmon-sysfs.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020044#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040045#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010046#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020048#ifdef CONFIG_ISA
49#include <linux/platform_device.h>
50#include <linux/ioport.h>
51#include <asm/io.h>
52#endif
53
54#include "lm75.h"
Jean Delvare7666c132007-05-08 17:22:02 +020055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050057static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
58 0x2e, 0x2f, I2C_CLIENT_END };
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/* Insmod parameters */
Jean Delvare05663362007-11-30 23:51:24 +010060I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
62 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
63
Jean Delvarefabddcd2006-02-05 23:26:51 +010064static int reset;
65module_param(reset, bool, 0);
66MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static int init = 1;
69module_param(init, bool, 0);
70MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
71
72/* Constants specified below */
73
74/* Length of ISA address segment */
75#define W83781D_EXTENT 8
76
77/* Where are the ISA address/data registers relative to the base address */
78#define W83781D_ADDR_REG_OFFSET 5
79#define W83781D_DATA_REG_OFFSET 6
80
Jean Delvare34875332007-05-08 17:22:03 +020081/* The device registers */
82/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
84 (0x554 + (((nr) - 7) * 2)))
85#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
86 (0x555 + (((nr) - 7) * 2)))
87#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
88 (0x550 + (nr) - 7))
89
Jean Delvare34875332007-05-08 17:22:03 +020090/* fan nr from 0 to 2 */
91#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
92#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94#define W83781D_REG_BANK 0x4E
95#define W83781D_REG_TEMP2_CONFIG 0x152
96#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +020097/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#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 Delvare05663362007-11-30 23:51:24 +0100114/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100115#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 */
Jean Delvare34875332007-05-08 17:22:03 +0200135static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136#define W83781D_REG_PWMCLK12 0x5C
137#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139#define W83781D_REG_I2C_ADDR 0x48
140#define W83781D_REG_I2C_SUBADDR 0x4A
141
142/* The following are undocumented in the data sheets however we
143 received the information in an email from Winbond tech support */
144/* Sensor selection - not on 781d */
145#define W83781D_REG_SCFG1 0x5D
146static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
147
148#define W83781D_REG_SCFG2 0x59
149static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
150
151#define W83781D_DEFAULT_BETA 3435
152
Jean Delvare474d00a2007-05-08 17:22:03 +0200153/* Conversions */
154#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
155#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157static inline u8
158FAN_TO_REG(long rpm, int div)
159{
160 if (rpm == 0)
161 return 255;
162 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
163 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
164}
165
Jean Delvare474d00a2007-05-08 17:22:03 +0200166static inline long
167FAN_FROM_REG(u8 val, int div)
168{
169 if (val == 0)
170 return -1;
171 if (val == 255)
172 return 0;
173 return 1350000 / (val * div);
174}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Jean Delvare474d00a2007-05-08 17:22:03 +0200176#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
177#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200180 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200182 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define DIV_FROM_REG(val) (1 << (val))
185
186static inline u8
187DIV_TO_REG(long val, enum chips type)
188{
189 int i;
190 val = SENSORS_LIMIT(val, 1,
191 ((type == w83781d
192 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000193 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 if (val == 0)
195 break;
196 val >>= 1;
197 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200198 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201struct w83781d_data {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200202 struct i2c_client *client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700203 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100204 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 enum chips type;
206
Jean Delvare360782d2008-10-17 17:51:19 +0200207 /* For ISA device only */
208 const char *name;
209 int isa_addr;
210
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100211 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 char valid; /* !=0 if following fields are valid */
213 unsigned long last_updated; /* In jiffies */
214
215 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
216 /* array of 2 pointers to subclients */
217
218 u8 in[9]; /* Register value - 8 & 9 for 782D only */
219 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
220 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
221 u8 fan[3]; /* Register value */
222 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200223 s8 temp; /* Register value */
224 s8 temp_max; /* Register value */
225 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 u16 temp_add[2]; /* Register value */
227 u16 temp_max_add[2]; /* Register value */
228 u16 temp_max_hyst_add[2]; /* Register value */
229 u8 fan_div[3]; /* Register encoding, shifted right */
230 u8 vid; /* Register encoding, combined */
231 u32 alarms; /* Register encoding, combined */
232 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200234 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 u16 sens[3]; /* 782D/783S only.
236 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200237 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 u8 vrm;
239};
240
Wolfgang Grandegger443850c2008-10-17 17:51:18 +0200241static struct w83781d_data *w83781d_data_if_isa(void);
242static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
243
Jean Delvare31b8dc42007-05-08 17:22:03 +0200244static int w83781d_read_value(struct w83781d_data *data, u16 reg);
245static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200247static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249/* following are the sysfs callback functions */
250#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200251static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
252 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{ \
Jean Delvare34875332007-05-08 17:22:03 +0200254 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200256 return sprintf(buf, "%ld\n", \
257 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259show_in_reg(in);
260show_in_reg(in_min);
261show_in_reg(in_max);
262
263#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200264static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
265 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{ \
Jean Delvare34875332007-05-08 17:22:03 +0200267 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200268 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200269 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 u32 val; \
271 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200272 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100274 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200276 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100278 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return count; \
280}
281store_in_reg(MIN, min);
282store_in_reg(MAX, max);
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200285static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
286 show_in, NULL, offset); \
287static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
288 show_in_min, store_in_min, offset); \
289static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
290 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292sysfs_in_offsets(0);
293sysfs_in_offsets(1);
294sysfs_in_offsets(2);
295sysfs_in_offsets(3);
296sysfs_in_offsets(4);
297sysfs_in_offsets(5);
298sysfs_in_offsets(6);
299sysfs_in_offsets(7);
300sysfs_in_offsets(8);
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200303static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
304 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{ \
Jean Delvare34875332007-05-08 17:22:03 +0200306 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 struct w83781d_data *data = w83781d_update_device(dev); \
308 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200309 FAN_FROM_REG(data->reg[attr->index], \
310 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312show_fan_reg(fan);
313show_fan_reg(fan_min);
314
315static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200316store_fan_min(struct device *dev, struct device_attribute *da,
317 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Jean Delvare34875332007-05-08 17:22:03 +0200319 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200320 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200321 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 u32 val;
323
324 val = simple_strtoul(buf, NULL, 10);
325
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100326 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200327 data->fan_min[nr] =
328 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200329 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200330 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100332 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return count;
334}
335
Jean Delvare34875332007-05-08 17:22:03 +0200336static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
337static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
338 show_fan_min, store_fan_min, 0);
339static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
340static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
341 show_fan_min, store_fan_min, 1);
342static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
343static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
344 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200347static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
348 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{ \
Jean Delvare34875332007-05-08 17:22:03 +0200350 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200352 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
354 return sprintf(buf,"%d\n", \
355 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
356 } else { /* TEMP1 */ \
357 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
358 } \
359}
360show_temp_reg(temp);
361show_temp_reg(temp_max);
362show_temp_reg(temp_max_hyst);
363
364#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200365static ssize_t store_temp_##reg (struct device *dev, \
366 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{ \
Jean Delvare34875332007-05-08 17:22:03 +0200368 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200369 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200370 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200371 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 \
373 val = simple_strtol(buf, NULL, 10); \
374 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100375 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 \
377 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
378 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200379 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 data->temp_##reg##_add[nr-2]); \
381 } else { /* TEMP1 */ \
382 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200383 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 data->temp_##reg); \
385 } \
386 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100387 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return count; \
389}
390store_temp_reg(OVER, max);
391store_temp_reg(HYST, max_hyst);
392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200394static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
395 show_temp, NULL, offset); \
396static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
397 show_temp_max, store_temp_max, offset); \
398static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
399 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401sysfs_temp_offsets(1);
402sysfs_temp_offsets(2);
403sysfs_temp_offsets(3);
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400406show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
408 struct w83781d_data *data = w83781d_update_device(dev);
409 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
410}
411
Jim Cromie311ce2e2006-09-24 21:22:52 +0200412static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400415show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Jean Delvare90d66192007-10-08 18:24:35 +0200417 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return sprintf(buf, "%ld\n", (long) data->vrm);
419}
420
421static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400422store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
Jean Delvare7666c132007-05-08 17:22:02 +0200424 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 u32 val;
426
427 val = simple_strtoul(buf, NULL, 10);
428 data->vrm = val;
429
430 return count;
431}
432
Jim Cromie311ce2e2006-09-24 21:22:52 +0200433static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400436show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200439 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Jim Cromie311ce2e2006-09-24 21:22:52 +0200442static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
443
Jean Delvare7d4a1372007-10-08 18:29:43 +0200444static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
445 char *buf)
446{
447 struct w83781d_data *data = w83781d_update_device(dev);
448 int bitnr = to_sensor_dev_attr(attr)->index;
449 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
450}
451
452/* The W83781D has a single alarm bit for temp2 and temp3 */
453static ssize_t show_temp3_alarm(struct device *dev,
454 struct device_attribute *attr, char *buf)
455{
456 struct w83781d_data *data = w83781d_update_device(dev);
457 int bitnr = (data->type == w83781d) ? 5 : 13;
458 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
459}
460
461static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
462static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
463static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
464static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
465static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
466static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
467static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
468static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
469static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
470static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
471static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
472static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
473static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
474static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
475static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
476
Yani Ioannoue404e272005-05-17 06:42:58 -0400477static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
479 struct w83781d_data *data = w83781d_update_device(dev);
480 return sprintf(buf, "%ld\n",
481 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
482}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200485store_beep_mask(struct device *dev, struct device_attribute *attr,
486 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Jean Delvare7666c132007-05-08 17:22:02 +0200488 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200489 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 val = simple_strtoul(buf, NULL, 10);
492
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100493 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200494 data->beep_mask &= 0x8000; /* preserve beep enable */
495 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200496 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
497 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200498 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200499 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200500 if (data->type != w83781d && data->type != as99127f) {
501 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
502 ((data->beep_mask) >> 16) & 0xff);
503 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100504 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return count;
507}
508
Jean Delvare34875332007-05-08 17:22:03 +0200509static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
510 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Jean Delvare7d4a1372007-10-08 18:29:43 +0200512static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
513 char *buf)
514{
515 struct w83781d_data *data = w83781d_update_device(dev);
516 int bitnr = to_sensor_dev_attr(attr)->index;
517 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
518}
519
520static ssize_t
521store_beep(struct device *dev, struct device_attribute *attr,
522 const char *buf, size_t count)
523{
524 struct w83781d_data *data = dev_get_drvdata(dev);
525 int bitnr = to_sensor_dev_attr(attr)->index;
526 unsigned long bit;
527 u8 reg;
528
529 bit = simple_strtoul(buf, NULL, 10);
530 if (bit & ~1)
531 return -EINVAL;
532
533 mutex_lock(&data->update_lock);
534 if (bit)
535 data->beep_mask |= (1 << bitnr);
536 else
537 data->beep_mask &= ~(1 << bitnr);
538
539 if (bitnr < 8) {
540 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
541 if (bit)
542 reg |= (1 << bitnr);
543 else
544 reg &= ~(1 << bitnr);
545 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
546 } else if (bitnr < 16) {
547 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
548 if (bit)
549 reg |= (1 << (bitnr - 8));
550 else
551 reg &= ~(1 << (bitnr - 8));
552 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
553 } else {
554 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
555 if (bit)
556 reg |= (1 << (bitnr - 16));
557 else
558 reg &= ~(1 << (bitnr - 16));
559 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
560 }
561 mutex_unlock(&data->update_lock);
562
563 return count;
564}
565
566/* The W83781D has a single beep bit for temp2 and temp3 */
567static ssize_t show_temp3_beep(struct device *dev,
568 struct device_attribute *attr, char *buf)
569{
570 struct w83781d_data *data = w83781d_update_device(dev);
571 int bitnr = (data->type == w83781d) ? 5 : 13;
572 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
573}
574
575static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
576 show_beep, store_beep, 0);
577static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
578 show_beep, store_beep, 1);
579static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
580 show_beep, store_beep, 2);
581static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
582 show_beep, store_beep, 3);
583static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
584 show_beep, store_beep, 8);
585static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
586 show_beep, store_beep, 9);
587static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
588 show_beep, store_beep, 10);
589static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
590 show_beep, store_beep, 16);
591static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
592 show_beep, store_beep, 17);
593static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
594 show_beep, store_beep, 6);
595static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
596 show_beep, store_beep, 7);
597static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
598 show_beep, store_beep, 11);
599static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
600 show_beep, store_beep, 4);
601static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
602 show_beep, store_beep, 5);
603static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
604 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200605static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
606 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200609show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
Jean Delvare34875332007-05-08 17:22:03 +0200611 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 struct w83781d_data *data = w83781d_update_device(dev);
613 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200614 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
617/* Note: we save and restore the fan minimum here, because its value is
618 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200619 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 because the divisor changed. */
621static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200622store_fan_div(struct device *dev, struct device_attribute *da,
623 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Jean Delvare34875332007-05-08 17:22:03 +0200625 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200626 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200628 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 u8 reg;
630 unsigned long val = simple_strtoul(buf, NULL, 10);
631
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100632 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 /* Save fan_min */
635 min = FAN_FROM_REG(data->fan_min[nr],
636 DIV_FROM_REG(data->fan_div[nr]));
637
638 data->fan_div[nr] = DIV_TO_REG(val, data->type);
639
Jean Delvare31b8dc42007-05-08 17:22:03 +0200640 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 & (nr==0 ? 0xcf : 0x3f))
642 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200643 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 /* w83781d and as99127f don't have extended divisor bits */
646 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200647 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 & ~(1 << (5 + nr)))
649 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200650 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
652
653 /* Restore fan_min */
654 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200655 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100657 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 return count;
659}
660
Jean Delvare34875332007-05-08 17:22:03 +0200661static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
662 show_fan_div, store_fan_div, 0);
663static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
664 show_fan_div, store_fan_div, 1);
665static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
666 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200669show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Jean Delvare34875332007-05-08 17:22:03 +0200671 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200673 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
676static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200677show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
679 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200680 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681}
682
683static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200684store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
685 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
Jean Delvare34875332007-05-08 17:22:03 +0200687 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200688 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200689 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 u32 val;
691
692 val = simple_strtoul(buf, NULL, 10);
693
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100694 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200695 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
696 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 return count;
699}
700
701static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200702store_pwm2_enable(struct device *dev, struct device_attribute *da,
703 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Jean Delvare7666c132007-05-08 17:22:02 +0200705 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 u32 val, reg;
707
708 val = simple_strtoul(buf, NULL, 10);
709
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100710 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 switch (val) {
713 case 0:
714 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200715 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
716 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 (reg & 0xf7) | (val << 3));
718
Jean Delvare31b8dc42007-05-08 17:22:03 +0200719 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
720 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 (reg & 0xef) | (!val << 4));
722
Jean Delvare34875332007-05-08 17:22:03 +0200723 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 break;
725
726 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100727 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return -EINVAL;
729 }
730
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100731 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return count;
733}
734
Jean Delvare34875332007-05-08 17:22:03 +0200735static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
736static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
737static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
738static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
739/* only PWM2 can be enabled/disabled */
740static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
741 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200744show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Jean Delvare34875332007-05-08 17:22:03 +0200746 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200748 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749}
750
751static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200752store_sensor(struct device *dev, struct device_attribute *da,
753 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
Jean Delvare34875332007-05-08 17:22:03 +0200755 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200756 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200757 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 u32 val, tmp;
759
760 val = simple_strtoul(buf, NULL, 10);
761
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100762 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 switch (val) {
765 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200766 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
767 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200768 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200769 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
770 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200771 tmp | BIT_SCFG2[nr]);
772 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 break;
774 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200775 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
776 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200777 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200778 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
779 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200780 tmp & ~BIT_SCFG2[nr]);
781 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200783 case W83781D_DEFAULT_BETA:
784 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
785 "instead\n", W83781D_DEFAULT_BETA);
786 /* fall through */
787 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200788 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
789 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200790 tmp & ~BIT_SCFG1[nr]);
791 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 break;
793 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200794 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
795 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 break;
797 }
798
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100799 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return count;
801}
802
Jean Delvare34875332007-05-08 17:22:03 +0200803static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
804 show_sensor, store_sensor, 0);
805static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400806 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200807static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400808 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810/* Assumes that adapter is of I2C, not ISA variety.
811 * OTHERWISE DON'T CALL THIS
812 */
813static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200814w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 int i, val1 = 0, id;
817 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200818 int address = new_client->addr;
819 unsigned short sc_addr[2];
820 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200822 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 id = i2c_adapter_id(adapter);
825
826 if (force_subclients[0] == id && force_subclients[1] == address) {
827 for (i = 2; i <= 3; i++) {
828 if (force_subclients[i] < 0x48 ||
829 force_subclients[i] > 0x4f) {
830 dev_err(&new_client->dev, "Invalid subclient "
831 "address %d; must be 0x48-0x4f\n",
832 force_subclients[i]);
833 err = -EINVAL;
834 goto ERROR_SC_1;
835 }
836 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200837 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 (force_subclients[2] & 0x07) |
839 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200840 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200842 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200843 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
845
846 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (force_subclients[0] == id &&
848 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200849 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200851 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200853 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 dev_err(&new_client->dev,
855 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200856 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 err = -EBUSY;
858 goto ERROR_SC_2;
859 }
860 }
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200863 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
864 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 dev_err(&new_client->dev, "Subclient %d "
866 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200867 "failed.\n", i, sc_addr[i]);
868 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (i == 1)
870 goto ERROR_SC_3;
871 goto ERROR_SC_2;
872 }
873 if (kind == w83783s)
874 break;
875 }
876
877 return 0;
878
879/* Undo inits in case of errors */
880ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200881 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return err;
885}
886
Jean Delvare34875332007-05-08 17:22:03 +0200887#define IN_UNIT_ATTRS(X) \
888 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
889 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100890 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200891 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
892 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200893
Jean Delvare34875332007-05-08 17:22:03 +0200894#define FAN_UNIT_ATTRS(X) \
895 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
896 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200897 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
898 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
899 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200900
Jean Delvare34875332007-05-08 17:22:03 +0200901#define TEMP_UNIT_ATTRS(X) \
902 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
903 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200904 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
905 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
906 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200907
908static struct attribute* w83781d_attributes[] = {
909 IN_UNIT_ATTRS(0),
910 IN_UNIT_ATTRS(2),
911 IN_UNIT_ATTRS(3),
912 IN_UNIT_ATTRS(4),
913 IN_UNIT_ATTRS(5),
914 IN_UNIT_ATTRS(6),
915 FAN_UNIT_ATTRS(1),
916 FAN_UNIT_ATTRS(2),
917 FAN_UNIT_ATTRS(3),
918 TEMP_UNIT_ATTRS(1),
919 TEMP_UNIT_ATTRS(2),
920 &dev_attr_cpu0_vid.attr,
921 &dev_attr_vrm.attr,
922 &dev_attr_alarms.attr,
923 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200924 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200925 NULL
926};
927static const struct attribute_group w83781d_group = {
928 .attrs = w83781d_attributes,
929};
930
931static struct attribute *w83781d_attributes_opt[] = {
932 IN_UNIT_ATTRS(1),
933 IN_UNIT_ATTRS(7),
934 IN_UNIT_ATTRS(8),
935 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200936 &sensor_dev_attr_pwm1.dev_attr.attr,
937 &sensor_dev_attr_pwm2.dev_attr.attr,
938 &sensor_dev_attr_pwm3.dev_attr.attr,
939 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200940 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200941 &sensor_dev_attr_temp1_type.dev_attr.attr,
942 &sensor_dev_attr_temp2_type.dev_attr.attr,
943 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200944 NULL
945};
946static const struct attribute_group w83781d_group_opt = {
947 .attrs = w83781d_attributes_opt,
948};
949
Jean Delvare7666c132007-05-08 17:22:02 +0200950/* No clean up is done on error, it's up to the caller */
951static int
952w83781d_create_files(struct device *dev, int kind, int is_isa)
953{
954 int err;
955
956 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
957 return err;
958
959 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200960 if ((err = device_create_file(dev,
961 &sensor_dev_attr_in1_input.dev_attr))
962 || (err = device_create_file(dev,
963 &sensor_dev_attr_in1_min.dev_attr))
964 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200965 &sensor_dev_attr_in1_max.dev_attr))
966 || (err = device_create_file(dev,
967 &sensor_dev_attr_in1_alarm.dev_attr))
968 || (err = device_create_file(dev,
969 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200970 return err;
971 }
972 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200973 if ((err = device_create_file(dev,
974 &sensor_dev_attr_in7_input.dev_attr))
975 || (err = device_create_file(dev,
976 &sensor_dev_attr_in7_min.dev_attr))
977 || (err = device_create_file(dev,
978 &sensor_dev_attr_in7_max.dev_attr))
979 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200980 &sensor_dev_attr_in7_alarm.dev_attr))
981 || (err = device_create_file(dev,
982 &sensor_dev_attr_in7_beep.dev_attr))
983 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200984 &sensor_dev_attr_in8_input.dev_attr))
985 || (err = device_create_file(dev,
986 &sensor_dev_attr_in8_min.dev_attr))
987 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200988 &sensor_dev_attr_in8_max.dev_attr))
989 || (err = device_create_file(dev,
990 &sensor_dev_attr_in8_alarm.dev_attr))
991 || (err = device_create_file(dev,
992 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200993 return err;
994 }
995 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200996 if ((err = device_create_file(dev,
997 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +0200998 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200999 &sensor_dev_attr_temp3_max.dev_attr))
1000 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001001 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1002 || (err = device_create_file(dev,
1003 &sensor_dev_attr_temp3_alarm.dev_attr))
1004 || (err = device_create_file(dev,
1005 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001006 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001007
Jean Delvare7768aa72007-10-25 13:11:01 +02001008 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001009 err = sysfs_chmod_file(&dev->kobj,
1010 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1011 S_IRUGO | S_IWUSR);
1012 if (err)
1013 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001014 }
Jean Delvare7666c132007-05-08 17:22:02 +02001015 }
1016
1017 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001018 if ((err = device_create_file(dev,
1019 &sensor_dev_attr_pwm1.dev_attr))
1020 || (err = device_create_file(dev,
1021 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001022 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1023 return err;
1024 }
1025 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001026 if ((err = device_create_file(dev,
1027 &sensor_dev_attr_pwm3.dev_attr))
1028 || (err = device_create_file(dev,
1029 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001030 return err;
1031 }
1032
1033 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001034 if ((err = device_create_file(dev,
1035 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001036 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001037 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001038 return err;
1039 if (kind != w83783s) {
1040 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001041 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001042 return err;
1043 }
1044 }
1045
Jean Delvare7666c132007-05-08 17:22:02 +02001046 return 0;
1047}
1048
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001049/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001051w83781d_detect(struct i2c_client *client, int kind,
1052 struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
Jean Delvare7666c132007-05-08 17:22:02 +02001054 int val1 = 0, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001055 struct w83781d_data *isa = w83781d_data_if_isa();
1056 struct i2c_adapter *adapter = client->adapter;
1057 int address = client->addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 enum vendor { winbond, asus } vendid;
1060
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001061 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1062 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001064 /* We block updates of the ISA device to minimize the risk of
1065 concurrent access to the same W83781D chip through different
1066 interfaces. */
1067 if (isa)
1068 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 /* The w8378?d may be stuck in some other bank than bank 0. This may
1071 make reading other information impossible. Specify a force=... or
1072 force_*=... parameter, and the Winbond will be reset to the right
1073 bank. */
1074 if (kind < 0) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001075 if (i2c_smbus_read_byte_data
1076 (client, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001077 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1078 "failed at step 3\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001079 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001081 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1082 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 /* Check for Winbond or Asus ID if in bank 0 */
1084 if ((!(val1 & 0x07)) &&
1085 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1086 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001087 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1088 "failed at step 4\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001089 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091 /* If Winbond SMBus, check address at 0x48.
1092 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001093 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1094 ((val1 & 0x80) && (val2 == 0x5c))) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001095 if (i2c_smbus_read_byte_data
1096 (client, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001097 dev_dbg(&adapter->dev, "Detection of w83781d "
1098 "chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001099 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
1101 }
1102 }
1103
1104 /* We have either had a force parameter, or we have already detected the
1105 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001106 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1107 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1108 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 /* Determine the chip type. */
1111 if (kind <= 0) {
1112 /* get vendor ID */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001113 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (val2 == 0x5c)
1115 vendid = winbond;
1116 else if (val2 == 0x12)
1117 vendid = asus;
1118 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001119 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1120 "neither Winbond nor Asus\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001121 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
1123
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001124 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1126 kind = w83781d;
1127 else if (val1 == 0x30 && vendid == winbond)
1128 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001129 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 kind = w83783s;
Jean Delvare6722fea2007-10-07 12:25:46 +02001131 else if (val1 == 0x31)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 else {
1134 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001135 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001137 "address 0x%02x\n", address);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001138 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 }
Jean Delvarec6566202008-10-17 17:51:18 +02001140
1141 if ((kind == w83781d || kind == w83782d)
1142 && w83781d_alias_detect(client, val1)) {
1143 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1144 "be the same as ISA device\n", address);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001145 goto err_nodev;
Jean Delvarec6566202008-10-17 17:51:18 +02001146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001149 if (isa)
1150 mutex_unlock(&isa->update_lock);
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (kind == w83781d) {
1153 client_name = "w83781d";
1154 } else if (kind == w83782d) {
1155 client_name = "w83782d";
1156 } else if (kind == w83783s) {
1157 client_name = "w83783s";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 } else if (kind == as99127f) {
1159 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001162 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001164 return 0;
1165
1166 err_nodev:
1167 if (isa)
1168 mutex_unlock(&isa->update_lock);
1169 return -ENODEV;
1170}
1171
1172static int
1173w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1174{
1175 struct device *dev = &client->dev;
1176 struct w83781d_data *data;
1177 int err;
1178
1179 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1180 if (!data) {
1181 err = -ENOMEM;
1182 goto ERROR1;
1183 }
1184
1185 i2c_set_clientdata(client, data);
1186 mutex_init(&data->lock);
1187 mutex_init(&data->update_lock);
1188
1189 data->type = id->driver_data;
1190 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001193 err = w83781d_detect_subclients(client);
1194 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001195 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001198 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001201 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001202 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001203 goto ERROR4;
1204
Tony Jones1beeffe2007-08-20 13:46:20 -07001205 data->hwmon_dev = hwmon_device_register(dev);
1206 if (IS_ERR(data->hwmon_dev)) {
1207 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001208 goto ERROR4;
1209 }
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return 0;
1212
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001213ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001214 sysfs_remove_group(&dev->kobj, &w83781d_group);
1215 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1216
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001217 if (data->lm75[0])
1218 i2c_unregister_device(data->lm75[0]);
1219 if (data->lm75[1])
1220 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221ERROR3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001222 i2c_set_clientdata(client, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 kfree(data);
1224ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 return err;
1226}
1227
1228static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001229w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001231 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001232 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001234 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001236 sysfs_remove_group(&dev->kobj, &w83781d_group);
1237 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001239 if (data->lm75[0])
1240 i2c_unregister_device(data->lm75[0]);
1241 if (data->lm75[1])
1242 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001243
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001244 i2c_set_clientdata(client, NULL);
1245 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 return 0;
1248}
1249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001251w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001253 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001254 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 struct i2c_client *cl;
1256
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001257 bank = (reg >> 8) & 0x0f;
1258 if (bank > 2)
1259 /* switch banks */
1260 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1261 bank);
1262 if (bank == 0 || bank > 2) {
1263 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001265 /* switch to subclient */
1266 cl = data->lm75[bank - 1];
1267 /* convert from ISA to LM75 I2C addresses */
1268 switch (reg & 0xff) {
1269 case 0x50: /* TEMP */
1270 res = swab16(i2c_smbus_read_word_data(cl, 0));
1271 break;
1272 case 0x52: /* CONFIG */
1273 res = i2c_smbus_read_byte_data(cl, 1);
1274 break;
1275 case 0x53: /* HYST */
1276 res = swab16(i2c_smbus_read_word_data(cl, 2));
1277 break;
1278 case 0x55: /* OVER */
1279 default:
1280 res = swab16(i2c_smbus_read_word_data(cl, 3));
1281 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001284 if (bank > 2)
1285 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return res;
1288}
1289
1290static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001291w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001293 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001294 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 struct i2c_client *cl;
1296
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001297 bank = (reg >> 8) & 0x0f;
1298 if (bank > 2)
1299 /* switch banks */
1300 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1301 bank);
1302 if (bank == 0 || bank > 2) {
1303 i2c_smbus_write_byte_data(client, reg & 0xff,
1304 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001306 /* switch to subclient */
1307 cl = data->lm75[bank - 1];
1308 /* convert from ISA to LM75 I2C addresses */
1309 switch (reg & 0xff) {
1310 case 0x52: /* CONFIG */
1311 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1312 break;
1313 case 0x53: /* HYST */
1314 i2c_smbus_write_word_data(cl, 2, swab16(value));
1315 break;
1316 case 0x55: /* OVER */
1317 i2c_smbus_write_word_data(cl, 3, swab16(value));
1318 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001321 if (bank > 2)
1322 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 return 0;
1325}
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327static void
Jean Delvare7666c132007-05-08 17:22:02 +02001328w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
Jean Delvare7666c132007-05-08 17:22:02 +02001330 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 int i, p;
1332 int type = data->type;
1333 u8 tmp;
1334
Jean Delvarefabddcd2006-02-05 23:26:51 +01001335 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001337 /* Resetting the chip has been the default for a long time,
1338 but it causes the BIOS initializations (fan clock dividers,
1339 thermal sensor types...) to be lost, so it is now optional.
1340 It might even go away if nobody reports it as being useful,
1341 as I see very little reason why this would be needed at
1342 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001343 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001344 "having, please report!\n");
1345
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001347 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1348 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /* Reset all except Watchdog values and last conversion values
1350 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001351 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 /* Restore the registers and disable power-on abnormal beep.
1353 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001354 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1355 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 /* Disable master beep-enable (reset turns it on).
1357 Individual beep_mask should be reset to off but for some reason
1358 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001359 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 }
1361
Jean Delvarefabddcd2006-02-05 23:26:51 +01001362 /* Disable power-on abnormal beep, as advised by the datasheet.
1363 Already done if reset=1. */
1364 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001365 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1366 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001367 }
1368
Jean Delvare303760b2005-07-31 21:52:01 +02001369 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001372 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 for (i = 1; i <= 3; i++) {
1374 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001375 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 } else {
1377 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001378 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1380 data->sens[i - 1] = 1;
1381 else
1382 data->sens[i - 1] = 2;
1383 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001384 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 break;
1386 }
1387 }
1388
1389 if (init && type != as99127f) {
1390 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001391 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001393 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001395 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 tmp & 0xfe);
1397 }
1398
1399 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001400 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001401 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 W83781D_REG_TEMP3_CONFIG);
1403 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001404 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001406 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1408 }
1409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 }
1411
1412 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001413 w83781d_write_value(data, W83781D_REG_CONFIG,
1414 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 W83781D_REG_CONFIG) & 0xf7)
1416 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001417
1418 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001419 for (i = 0; i < 3; i++) {
1420 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001421 W83781D_REG_FAN_MIN(i));
1422 }
Jean Delvare7666c132007-05-08 17:22:02 +02001423
1424 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
1427static struct w83781d_data *w83781d_update_device(struct device *dev)
1428{
Jean Delvare7666c132007-05-08 17:22:02 +02001429 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001430 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 int i;
1432
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001433 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
1435 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1436 || !data->valid) {
1437 dev_dbg(dev, "Starting device update\n");
1438
1439 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001440 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 continue; /* 783S has no in1 */
1442 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001443 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001445 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001447 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001448 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 break;
1450 }
Jean Delvare34875332007-05-08 17:22:03 +02001451 for (i = 0; i < 3; i++) {
1452 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001453 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001454 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001455 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 }
1457 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001458 for (i = 0; i < 4; i++) {
1459 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001460 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001461 W83781D_REG_PWM[i]);
Jean Delvare7666c132007-05-08 17:22:02 +02001462 if ((data->type != w83782d || !client->driver)
Jean Delvare34875332007-05-08 17:22:03 +02001463 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 break;
1465 }
1466 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001467 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1469 }
1470
Jean Delvare31b8dc42007-05-08 17:22:03 +02001471 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001473 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001475 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001477 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001479 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001481 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001482 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001484 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001486 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 W83781D_REG_TEMP_OVER(3));
1488 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001489 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 W83781D_REG_TEMP_HYST(3));
1491 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001492 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001493 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001494 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001495 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 data->fan_div[0] = (i >> 4) & 0x03;
1497 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001498 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001499 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001501 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 data->fan_div[0] |= (i >> 3) & 0x04;
1503 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001504 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 }
Jean Delvare05663362007-11-30 23:51:24 +01001506 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001507 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001508 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001509 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001510 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001511 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001512 W83782D_REG_ALARM3) << 16);
1513 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001514 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001515 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001516 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001517 W83782D_REG_ALARM2) << 8);
1518 } else {
1519 /* No real-time status registers, fall back to
1520 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001521 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001522 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001523 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001524 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001526 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001527 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001528 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 if ((data->type != w83781d) && (data->type != as99127f)) {
1530 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001531 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 W83781D_REG_BEEP_INTS3) << 16;
1533 }
1534 data->last_updated = jiffies;
1535 data->valid = 1;
1536 }
1537
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001538 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540 return data;
1541}
1542
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001543static const struct i2c_device_id w83781d_ids[] = {
1544 { "w83781d", w83781d, },
1545 { "w83782d", w83782d, },
1546 { "w83783s", w83783s, },
1547 { "as99127f", as99127f },
1548 { /* LIST END */ }
1549};
1550MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1551
1552static struct i2c_driver w83781d_driver = {
1553 .class = I2C_CLASS_HWMON,
1554 .driver = {
1555 .name = "w83781d",
1556 },
1557 .probe = w83781d_probe,
1558 .remove = w83781d_remove,
1559 .id_table = w83781d_ids,
1560 .detect = w83781d_detect,
1561 .address_data = &addr_data,
1562};
1563
1564/*
1565 * ISA related code
1566 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001567#ifdef CONFIG_ISA
1568
1569/* ISA device, if found */
1570static struct platform_device *pdev;
1571
1572static unsigned short isa_address = 0x290;
1573
1574/* I2C devices get this name attribute automatically, but for ISA devices
1575 we must create it by ourselves. */
1576static ssize_t
1577show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1578{
1579 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001580 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001581}
1582static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1583
1584static struct w83781d_data *w83781d_data_if_isa(void)
1585{
1586 return pdev ? platform_get_drvdata(pdev) : NULL;
1587}
1588
1589/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1590static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1591{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001592 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001593 int i;
1594
1595 if (!pdev) /* No ISA chip */
1596 return 0;
1597
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001598 isa = platform_get_drvdata(pdev);
1599
1600 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1601 return 0; /* Address doesn't match */
1602 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1603 return 0; /* Chip type doesn't match */
1604
1605 /* We compare all the limit registers, the config register and the
1606 * interrupt mask registers */
1607 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001608 if (w83781d_read_value(isa, i) !=
1609 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001610 return 0;
1611 }
1612 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001613 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001614 return 0;
1615 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001616 if (w83781d_read_value(isa, i) !=
1617 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001618 return 0;
1619 }
1620
1621 return 1;
1622}
1623
1624static int
1625w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1626{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001627 int word_sized, res;
1628
1629 word_sized = (((reg & 0xff00) == 0x100)
1630 || ((reg & 0xff00) == 0x200))
1631 && (((reg & 0x00ff) == 0x50)
1632 || ((reg & 0x00ff) == 0x53)
1633 || ((reg & 0x00ff) == 0x55));
1634 if (reg & 0xff00) {
1635 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001636 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001637 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001638 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001639 }
Jean Delvare360782d2008-10-17 17:51:19 +02001640 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1641 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001642 if (word_sized) {
1643 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001644 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001645 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001646 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001647 W83781D_DATA_REG_OFFSET);
1648 }
1649 if (reg & 0xff00) {
1650 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001651 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1652 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001653 }
1654 return res;
1655}
1656
1657static void
1658w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1659{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001660 int word_sized;
1661
1662 word_sized = (((reg & 0xff00) == 0x100)
1663 || ((reg & 0xff00) == 0x200))
1664 && (((reg & 0x00ff) == 0x53)
1665 || ((reg & 0x00ff) == 0x55));
1666 if (reg & 0xff00) {
1667 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001668 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001669 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001670 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001671 }
Jean Delvare360782d2008-10-17 17:51:19 +02001672 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001673 if (word_sized) {
1674 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001675 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001676 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001677 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001678 }
Jean Delvare360782d2008-10-17 17:51:19 +02001679 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001680 if (reg & 0xff00) {
1681 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001682 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1683 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001684 }
1685}
1686
1687/* The SMBus locks itself, usually, but nothing may access the Winbond between
1688 bank switches. ISA access must always be locked explicitly!
1689 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1690 would slow down the W83781D access and should not be necessary.
1691 There are some ugly typecasts here, but the good news is - they should
1692 nowhere else be necessary! */
1693static int
1694w83781d_read_value(struct w83781d_data *data, u16 reg)
1695{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001696 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001697 int res;
1698
1699 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001700 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001701 res = w83781d_read_value_i2c(data, reg);
1702 else
1703 res = w83781d_read_value_isa(data, reg);
1704 mutex_unlock(&data->lock);
1705 return res;
1706}
1707
1708static int
1709w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1710{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001711 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001712
1713 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001714 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001715 w83781d_write_value_i2c(data, reg, value);
1716 else
1717 w83781d_write_value_isa(data, reg, value);
1718 mutex_unlock(&data->lock);
1719 return 0;
1720}
1721
1722static int __devinit
1723w83781d_isa_probe(struct platform_device *pdev)
1724{
1725 int err, reg;
1726 struct w83781d_data *data;
1727 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001728
1729 /* Reserve the ISA region */
1730 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1731 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1732 "w83781d")) {
1733 err = -EBUSY;
1734 goto exit;
1735 }
1736
1737 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1738 if (!data) {
1739 err = -ENOMEM;
1740 goto exit_release_region;
1741 }
1742 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001743 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001744 platform_set_drvdata(pdev, data);
1745
1746 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1747 switch (reg) {
1748 case 0x30:
1749 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001750 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001751 break;
1752 default:
1753 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001754 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001755 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001756
1757 /* Initialize the W83781D chip */
1758 w83781d_init_device(&pdev->dev);
1759
1760 /* Register sysfs hooks */
1761 err = w83781d_create_files(&pdev->dev, data->type, 1);
1762 if (err)
1763 goto exit_remove_files;
1764
1765 err = device_create_file(&pdev->dev, &dev_attr_name);
1766 if (err)
1767 goto exit_remove_files;
1768
1769 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1770 if (IS_ERR(data->hwmon_dev)) {
1771 err = PTR_ERR(data->hwmon_dev);
1772 goto exit_remove_files;
1773 }
1774
1775 return 0;
1776
1777 exit_remove_files:
1778 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1779 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1780 device_remove_file(&pdev->dev, &dev_attr_name);
1781 kfree(data);
1782 exit_release_region:
1783 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1784 exit:
1785 return err;
1786}
1787
1788static int __devexit
1789w83781d_isa_remove(struct platform_device *pdev)
1790{
1791 struct w83781d_data *data = platform_get_drvdata(pdev);
1792
1793 hwmon_device_unregister(data->hwmon_dev);
1794 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1795 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1796 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001797 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001798 kfree(data);
1799
1800 return 0;
1801}
1802
1803static struct platform_driver w83781d_isa_driver = {
1804 .driver = {
1805 .owner = THIS_MODULE,
1806 .name = "w83781d",
1807 },
1808 .probe = w83781d_isa_probe,
1809 .remove = __devexit_p(w83781d_isa_remove),
1810};
1811
Jean Delvare7666c132007-05-08 17:22:02 +02001812/* return 1 if a supported chip is found, 0 otherwise */
1813static int __init
1814w83781d_isa_found(unsigned short address)
1815{
1816 int val, save, found = 0;
1817
Jean Delvare2961cb22008-03-09 13:34:28 +01001818 /* We have to request the region in two parts because some
1819 boards declare base+4 to base+7 as a PNP device */
1820 if (!request_region(address, 4, "w83781d")) {
1821 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001822 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001823 }
1824 if (!request_region(address + 4, 4, "w83781d")) {
1825 pr_debug("w83781d: Failed to request high part of region\n");
1826 release_region(address, 4);
1827 return 0;
1828 }
Jean Delvare7666c132007-05-08 17:22:02 +02001829
1830#define REALLY_SLOW_IO
1831 /* We need the timeouts for at least some W83781D-like
1832 chips. But only if we read 'undefined' registers. */
1833 val = inb_p(address + 1);
1834 if (inb_p(address + 2) != val
1835 || inb_p(address + 3) != val
1836 || inb_p(address + 7) != val) {
1837 pr_debug("w83781d: Detection failed at step 1\n");
1838 goto release;
1839 }
1840#undef REALLY_SLOW_IO
1841
1842 /* We should be able to change the 7 LSB of the address port. The
1843 MSB (busy flag) should be clear initially, set after the write. */
1844 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1845 if (save & 0x80) {
1846 pr_debug("w83781d: Detection failed at step 2\n");
1847 goto release;
1848 }
1849 val = ~save & 0x7f;
1850 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1851 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1852 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1853 pr_debug("w83781d: Detection failed at step 3\n");
1854 goto release;
1855 }
1856
1857 /* We found a device, now see if it could be a W83781D */
1858 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1859 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1860 if (val & 0x80) {
1861 pr_debug("w83781d: Detection failed at step 4\n");
1862 goto release;
1863 }
1864 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1865 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1866 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1867 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1868 if ((!(save & 0x80) && (val != 0xa3))
1869 || ((save & 0x80) && (val != 0x5c))) {
1870 pr_debug("w83781d: Detection failed at step 5\n");
1871 goto release;
1872 }
1873 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1874 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1875 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1876 pr_debug("w83781d: Detection failed at step 6\n");
1877 goto release;
1878 }
1879
1880 /* The busy flag should be clear again */
1881 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1882 pr_debug("w83781d: Detection failed at step 7\n");
1883 goto release;
1884 }
1885
1886 /* Determine the chip type */
1887 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1888 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1889 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1890 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1891 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1892 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001893 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001894 found = 1;
1895
1896 if (found)
1897 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001898 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1899
1900 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001901 release_region(address + 4, 4);
1902 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001903 return found;
1904}
1905
1906static int __init
1907w83781d_isa_device_add(unsigned short address)
1908{
1909 struct resource res = {
1910 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001911 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001912 .name = "w83781d",
1913 .flags = IORESOURCE_IO,
1914 };
1915 int err;
1916
1917 pdev = platform_device_alloc("w83781d", address);
1918 if (!pdev) {
1919 err = -ENOMEM;
1920 printk(KERN_ERR "w83781d: Device allocation failed\n");
1921 goto exit;
1922 }
1923
1924 err = platform_device_add_resources(pdev, &res, 1);
1925 if (err) {
1926 printk(KERN_ERR "w83781d: Device resource addition failed "
1927 "(%d)\n", err);
1928 goto exit_device_put;
1929 }
1930
1931 err = platform_device_add(pdev);
1932 if (err) {
1933 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1934 err);
1935 goto exit_device_put;
1936 }
1937
1938 return 0;
1939
1940 exit_device_put:
1941 platform_device_put(pdev);
1942 exit:
1943 pdev = NULL;
1944 return err;
1945}
1946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001948w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949{
Jean Delvarefde09502005-07-19 23:51:07 +02001950 int res;
1951
Jean Delvare7666c132007-05-08 17:22:02 +02001952 if (w83781d_isa_found(isa_address)) {
1953 res = platform_driver_register(&w83781d_isa_driver);
1954 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001955 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001956
1957 /* Sets global pdev as a side effect */
1958 res = w83781d_isa_device_add(isa_address);
1959 if (res)
1960 goto exit_unreg_isa_driver;
1961 }
Jean Delvarefde09502005-07-19 23:51:07 +02001962
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001963 return 0;
1964
1965exit_unreg_isa_driver:
1966 platform_driver_unregister(&w83781d_isa_driver);
1967exit:
1968 return res;
1969}
1970
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001971static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001972w83781d_isa_unregister(void)
1973{
1974 if (pdev) {
1975 platform_device_unregister(pdev);
1976 platform_driver_unregister(&w83781d_isa_driver);
1977 }
1978}
1979#else /* !CONFIG_ISA */
1980
1981static struct w83781d_data *w83781d_data_if_isa(void)
1982{
1983 return NULL;
1984}
1985
1986static int
1987w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1988{
1989 return 0;
1990}
1991
1992static int
1993w83781d_read_value(struct w83781d_data *data, u16 reg)
1994{
1995 int res;
1996
1997 mutex_lock(&data->lock);
1998 res = w83781d_read_value_i2c(data, reg);
1999 mutex_unlock(&data->lock);
2000
2001 return res;
2002}
2003
2004static int
2005w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2006{
2007 mutex_lock(&data->lock);
2008 w83781d_write_value_i2c(data, reg, value);
2009 mutex_unlock(&data->lock);
2010
2011 return 0;
2012}
2013
2014static int __init
2015w83781d_isa_register(void)
2016{
2017 return 0;
2018}
2019
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01002020static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002021w83781d_isa_unregister(void)
2022{
2023}
2024#endif /* CONFIG_ISA */
2025
2026static int __init
2027sensors_w83781d_init(void)
2028{
2029 int res;
2030
2031 /* We register the ISA device first, so that we can skip the
2032 * registration of an I2C interface to the same device. */
2033 res = w83781d_isa_register();
2034 if (res)
2035 goto exit;
2036
Jean Delvarec6566202008-10-17 17:51:18 +02002037 res = i2c_add_driver(&w83781d_driver);
2038 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002039 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002040
Jean Delvarefde09502005-07-19 23:51:07 +02002041 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002042
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002043 exit_unreg_isa:
2044 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002045 exit:
2046 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047}
2048
2049static void __exit
2050sensors_w83781d_exit(void)
2051{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002052 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 i2c_del_driver(&w83781d_driver);
2054}
2055
2056MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2057 "Philip Edelbrock <phil@netroedge.com>, "
2058 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2059MODULE_DESCRIPTION("W83781D driver");
2060MODULE_LICENSE("GPL");
2061
2062module_init(sensors_w83781d_init);
2063module_exit(sensors_w83781d_exit);