blob: dbfb30c588d8cfea06d59ab240dce5e2d07cde15 [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);
Jean Delvare3aed1982009-01-07 16:37:32 +010061
62static unsigned short force_subclients[4];
63module_param_array(force_subclients, short, NULL, 0);
64MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
66
Jean Delvarefabddcd2006-02-05 23:26:51 +010067static int reset;
68module_param(reset, bool, 0);
69MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static int init = 1;
72module_param(init, bool, 0);
73MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
74
75/* Constants specified below */
76
77/* Length of ISA address segment */
78#define W83781D_EXTENT 8
79
80/* Where are the ISA address/data registers relative to the base address */
81#define W83781D_ADDR_REG_OFFSET 5
82#define W83781D_DATA_REG_OFFSET 6
83
Jean Delvare34875332007-05-08 17:22:03 +020084/* The device registers */
85/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
87 (0x554 + (((nr) - 7) * 2)))
88#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
89 (0x555 + (((nr) - 7) * 2)))
90#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
91 (0x550 + (nr) - 7))
92
Jean Delvare34875332007-05-08 17:22:03 +020093/* fan nr from 0 to 2 */
94#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
95#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97#define W83781D_REG_BANK 0x4E
98#define W83781D_REG_TEMP2_CONFIG 0x152
99#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +0200100/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
102 ((nr == 2) ? (0x0150) : \
103 (0x27)))
104#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
105 ((nr == 2) ? (0x153) : \
106 (0x3A)))
107#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
108 ((nr == 2) ? (0x155) : \
109 (0x39)))
110
111#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100112
113/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#define W83781D_REG_ALARM1 0x41
115#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Jean Delvare05663362007-11-30 23:51:24 +0100117/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100118#define W83782D_REG_ALARM1 0x459
119#define W83782D_REG_ALARM2 0x45A
120#define W83782D_REG_ALARM3 0x45B
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define W83781D_REG_BEEP_CONFIG 0x4D
123#define W83781D_REG_BEEP_INTS1 0x56
124#define W83781D_REG_BEEP_INTS2 0x57
125#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
126
127#define W83781D_REG_VID_FANDIV 0x47
128
129#define W83781D_REG_CHIPID 0x49
130#define W83781D_REG_WCHIPID 0x58
131#define W83781D_REG_CHIPMAN 0x4F
132#define W83781D_REG_PIN 0x4B
133
134/* 782D/783S only */
135#define W83781D_REG_VBAT 0x5D
136
137/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200138static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139#define W83781D_REG_PWMCLK12 0x5C
140#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142#define W83781D_REG_I2C_ADDR 0x48
143#define W83781D_REG_I2C_SUBADDR 0x4A
144
145/* The following are undocumented in the data sheets however we
146 received the information in an email from Winbond tech support */
147/* Sensor selection - not on 781d */
148#define W83781D_REG_SCFG1 0x5D
149static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
150
151#define W83781D_REG_SCFG2 0x59
152static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
153
154#define W83781D_DEFAULT_BETA 3435
155
Jean Delvare474d00a2007-05-08 17:22:03 +0200156/* Conversions */
157#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
158#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160static inline u8
161FAN_TO_REG(long rpm, int div)
162{
163 if (rpm == 0)
164 return 255;
165 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
166 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
167}
168
Jean Delvare474d00a2007-05-08 17:22:03 +0200169static inline long
170FAN_FROM_REG(u8 val, int div)
171{
172 if (val == 0)
173 return -1;
174 if (val == 255)
175 return 0;
176 return 1350000 / (val * div);
177}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Jean Delvare474d00a2007-05-08 17:22:03 +0200179#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
180#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200183 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200185 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#define DIV_FROM_REG(val) (1 << (val))
188
189static inline u8
190DIV_TO_REG(long val, enum chips type)
191{
192 int i;
193 val = SENSORS_LIMIT(val, 1,
194 ((type == w83781d
195 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000196 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (val == 0)
198 break;
199 val >>= 1;
200 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200201 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204struct w83781d_data {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200205 struct i2c_client *client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700206 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100207 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 enum chips type;
209
Jean Delvare360782d2008-10-17 17:51:19 +0200210 /* For ISA device only */
211 const char *name;
212 int isa_addr;
213
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100214 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 char valid; /* !=0 if following fields are valid */
216 unsigned long last_updated; /* In jiffies */
217
218 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
219 /* array of 2 pointers to subclients */
220
221 u8 in[9]; /* Register value - 8 & 9 for 782D only */
222 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
223 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
224 u8 fan[3]; /* Register value */
225 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200226 s8 temp; /* Register value */
227 s8 temp_max; /* Register value */
228 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 u16 temp_add[2]; /* Register value */
230 u16 temp_max_add[2]; /* Register value */
231 u16 temp_max_hyst_add[2]; /* Register value */
232 u8 fan_div[3]; /* Register encoding, shifted right */
233 u8 vid; /* Register encoding, combined */
234 u32 alarms; /* Register encoding, combined */
235 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200237 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 u16 sens[3]; /* 782D/783S only.
239 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200240 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 u8 vrm;
242};
243
Wolfgang Grandegger443850c2008-10-17 17:51:18 +0200244static struct w83781d_data *w83781d_data_if_isa(void);
245static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
246
Jean Delvare31b8dc42007-05-08 17:22:03 +0200247static int w83781d_read_value(struct w83781d_data *data, u16 reg);
248static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200250static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252/* following are the sysfs callback functions */
253#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200254static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
255 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{ \
Jean Delvare34875332007-05-08 17:22:03 +0200257 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200259 return sprintf(buf, "%ld\n", \
260 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262show_in_reg(in);
263show_in_reg(in_min);
264show_in_reg(in_max);
265
266#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200267static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
268 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{ \
Jean Delvare34875332007-05-08 17:22:03 +0200270 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200271 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200272 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 u32 val; \
274 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200275 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100277 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200279 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100281 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return count; \
283}
284store_in_reg(MIN, min);
285store_in_reg(MAX, max);
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200288static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
289 show_in, NULL, offset); \
290static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
291 show_in_min, store_in_min, offset); \
292static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
293 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295sysfs_in_offsets(0);
296sysfs_in_offsets(1);
297sysfs_in_offsets(2);
298sysfs_in_offsets(3);
299sysfs_in_offsets(4);
300sysfs_in_offsets(5);
301sysfs_in_offsets(6);
302sysfs_in_offsets(7);
303sysfs_in_offsets(8);
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200306static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
307 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{ \
Jean Delvare34875332007-05-08 17:22:03 +0200309 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 struct w83781d_data *data = w83781d_update_device(dev); \
311 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200312 FAN_FROM_REG(data->reg[attr->index], \
313 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315show_fan_reg(fan);
316show_fan_reg(fan_min);
317
318static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200319store_fan_min(struct device *dev, struct device_attribute *da,
320 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Jean Delvare34875332007-05-08 17:22:03 +0200322 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200323 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200324 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 u32 val;
326
327 val = simple_strtoul(buf, NULL, 10);
328
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100329 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200330 data->fan_min[nr] =
331 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200332 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200333 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100335 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 return count;
337}
338
Jean Delvare34875332007-05-08 17:22:03 +0200339static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
340static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
341 show_fan_min, store_fan_min, 0);
342static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
343static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
344 show_fan_min, store_fan_min, 1);
345static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
346static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
347 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200350static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
351 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{ \
Jean Delvare34875332007-05-08 17:22:03 +0200353 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200355 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
357 return sprintf(buf,"%d\n", \
358 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
359 } else { /* TEMP1 */ \
360 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
361 } \
362}
363show_temp_reg(temp);
364show_temp_reg(temp_max);
365show_temp_reg(temp_max_hyst);
366
367#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200368static ssize_t store_temp_##reg (struct device *dev, \
369 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{ \
Jean Delvare34875332007-05-08 17:22:03 +0200371 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200372 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200373 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200374 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 \
376 val = simple_strtol(buf, NULL, 10); \
377 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100378 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 \
380 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
381 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200382 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->temp_##reg##_add[nr-2]); \
384 } else { /* TEMP1 */ \
385 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200386 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 data->temp_##reg); \
388 } \
389 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100390 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return count; \
392}
393store_temp_reg(OVER, max);
394store_temp_reg(HYST, max_hyst);
395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200397static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
398 show_temp, NULL, offset); \
399static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
400 show_temp_max, store_temp_max, offset); \
401static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
402 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404sysfs_temp_offsets(1);
405sysfs_temp_offsets(2);
406sysfs_temp_offsets(3);
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400409show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 struct w83781d_data *data = w83781d_update_device(dev);
412 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
413}
414
Jim Cromie311ce2e2006-09-24 21:22:52 +0200415static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400418show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
Jean Delvare90d66192007-10-08 18:24:35 +0200420 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return sprintf(buf, "%ld\n", (long) data->vrm);
422}
423
424static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400425store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Jean Delvare7666c132007-05-08 17:22:02 +0200427 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 u32 val;
429
430 val = simple_strtoul(buf, NULL, 10);
431 data->vrm = val;
432
433 return count;
434}
435
Jim Cromie311ce2e2006-09-24 21:22:52 +0200436static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400439show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200442 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
Jim Cromie311ce2e2006-09-24 21:22:52 +0200445static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
446
Jean Delvare7d4a1372007-10-08 18:29:43 +0200447static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
448 char *buf)
449{
450 struct w83781d_data *data = w83781d_update_device(dev);
451 int bitnr = to_sensor_dev_attr(attr)->index;
452 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
453}
454
455/* The W83781D has a single alarm bit for temp2 and temp3 */
456static ssize_t show_temp3_alarm(struct device *dev,
457 struct device_attribute *attr, char *buf)
458{
459 struct w83781d_data *data = w83781d_update_device(dev);
460 int bitnr = (data->type == w83781d) ? 5 : 13;
461 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
462}
463
464static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
465static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
466static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
467static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
468static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
469static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
470static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
471static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
472static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
473static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
474static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
475static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
476static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
477static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
478static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
479
Yani Ioannoue404e272005-05-17 06:42:58 -0400480static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 struct w83781d_data *data = w83781d_update_device(dev);
483 return sprintf(buf, "%ld\n",
484 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
485}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200488store_beep_mask(struct device *dev, struct device_attribute *attr,
489 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
Jean Delvare7666c132007-05-08 17:22:02 +0200491 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200492 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 val = simple_strtoul(buf, NULL, 10);
495
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100496 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200497 data->beep_mask &= 0x8000; /* preserve beep enable */
498 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200499 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
500 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200501 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200502 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200503 if (data->type != w83781d && data->type != as99127f) {
504 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
505 ((data->beep_mask) >> 16) & 0xff);
506 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100507 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 return count;
510}
511
Jean Delvare34875332007-05-08 17:22:03 +0200512static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
513 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Jean Delvare7d4a1372007-10-08 18:29:43 +0200515static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
516 char *buf)
517{
518 struct w83781d_data *data = w83781d_update_device(dev);
519 int bitnr = to_sensor_dev_attr(attr)->index;
520 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
521}
522
523static ssize_t
524store_beep(struct device *dev, struct device_attribute *attr,
525 const char *buf, size_t count)
526{
527 struct w83781d_data *data = dev_get_drvdata(dev);
528 int bitnr = to_sensor_dev_attr(attr)->index;
529 unsigned long bit;
530 u8 reg;
531
532 bit = simple_strtoul(buf, NULL, 10);
533 if (bit & ~1)
534 return -EINVAL;
535
536 mutex_lock(&data->update_lock);
537 if (bit)
538 data->beep_mask |= (1 << bitnr);
539 else
540 data->beep_mask &= ~(1 << bitnr);
541
542 if (bitnr < 8) {
543 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
544 if (bit)
545 reg |= (1 << bitnr);
546 else
547 reg &= ~(1 << bitnr);
548 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
549 } else if (bitnr < 16) {
550 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
551 if (bit)
552 reg |= (1 << (bitnr - 8));
553 else
554 reg &= ~(1 << (bitnr - 8));
555 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
556 } else {
557 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
558 if (bit)
559 reg |= (1 << (bitnr - 16));
560 else
561 reg &= ~(1 << (bitnr - 16));
562 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
563 }
564 mutex_unlock(&data->update_lock);
565
566 return count;
567}
568
569/* The W83781D has a single beep bit for temp2 and temp3 */
570static ssize_t show_temp3_beep(struct device *dev,
571 struct device_attribute *attr, char *buf)
572{
573 struct w83781d_data *data = w83781d_update_device(dev);
574 int bitnr = (data->type == w83781d) ? 5 : 13;
575 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
576}
577
578static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
579 show_beep, store_beep, 0);
580static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
581 show_beep, store_beep, 1);
582static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
583 show_beep, store_beep, 2);
584static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
585 show_beep, store_beep, 3);
586static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
587 show_beep, store_beep, 8);
588static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
589 show_beep, store_beep, 9);
590static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
591 show_beep, store_beep, 10);
592static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
593 show_beep, store_beep, 16);
594static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
595 show_beep, store_beep, 17);
596static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
597 show_beep, store_beep, 6);
598static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
599 show_beep, store_beep, 7);
600static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
601 show_beep, store_beep, 11);
602static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
603 show_beep, store_beep, 4);
604static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
605 show_beep, store_beep, 5);
606static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
607 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200608static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
609 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200612show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
Jean Delvare34875332007-05-08 17:22:03 +0200614 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 struct w83781d_data *data = w83781d_update_device(dev);
616 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200617 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
620/* Note: we save and restore the fan minimum here, because its value is
621 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200622 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 because the divisor changed. */
624static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200625store_fan_div(struct device *dev, struct device_attribute *da,
626 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Jean Delvare34875332007-05-08 17:22:03 +0200628 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200629 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200631 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 u8 reg;
633 unsigned long val = simple_strtoul(buf, NULL, 10);
634
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100635 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* Save fan_min */
638 min = FAN_FROM_REG(data->fan_min[nr],
639 DIV_FROM_REG(data->fan_div[nr]));
640
641 data->fan_div[nr] = DIV_TO_REG(val, data->type);
642
Jean Delvare31b8dc42007-05-08 17:22:03 +0200643 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 & (nr==0 ? 0xcf : 0x3f))
645 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200646 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 /* w83781d and as99127f don't have extended divisor bits */
649 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200650 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 & ~(1 << (5 + nr)))
652 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200653 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
655
656 /* Restore fan_min */
657 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200658 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100660 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return count;
662}
663
Jean Delvare34875332007-05-08 17:22:03 +0200664static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
665 show_fan_div, store_fan_div, 0);
666static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
667 show_fan_div, store_fan_div, 1);
668static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
669 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200672show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
Jean Delvare34875332007-05-08 17:22:03 +0200674 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200676 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
679static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200680show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200683 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
686static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200687store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
688 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Jean Delvare34875332007-05-08 17:22:03 +0200690 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200691 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200692 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 u32 val;
694
695 val = simple_strtoul(buf, NULL, 10);
696
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200698 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
699 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100700 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return count;
702}
703
704static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200705store_pwm2_enable(struct device *dev, struct device_attribute *da,
706 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Jean Delvare7666c132007-05-08 17:22:02 +0200708 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 u32 val, reg;
710
711 val = simple_strtoul(buf, NULL, 10);
712
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100713 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 switch (val) {
716 case 0:
717 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200718 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
719 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 (reg & 0xf7) | (val << 3));
721
Jean Delvare31b8dc42007-05-08 17:22:03 +0200722 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
723 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 (reg & 0xef) | (!val << 4));
725
Jean Delvare34875332007-05-08 17:22:03 +0200726 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 break;
728
729 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100730 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return -EINVAL;
732 }
733
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100734 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return count;
736}
737
Jean Delvare34875332007-05-08 17:22:03 +0200738static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
739static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
740static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
741static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
742/* only PWM2 can be enabled/disabled */
743static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
744 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200747show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Jean Delvare34875332007-05-08 17:22:03 +0200749 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200751 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
754static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200755store_sensor(struct device *dev, struct device_attribute *da,
756 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Jean Delvare34875332007-05-08 17:22:03 +0200758 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200759 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200760 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 u32 val, tmp;
762
763 val = simple_strtoul(buf, NULL, 10);
764
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100765 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 switch (val) {
768 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200769 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
770 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200771 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200772 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
773 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200774 tmp | BIT_SCFG2[nr]);
775 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 break;
777 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200778 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
779 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200780 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200781 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
782 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200783 tmp & ~BIT_SCFG2[nr]);
784 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200786 case W83781D_DEFAULT_BETA:
787 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
788 "instead\n", W83781D_DEFAULT_BETA);
789 /* fall through */
790 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200791 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
792 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200793 tmp & ~BIT_SCFG1[nr]);
794 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 break;
796 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200797 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
798 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 break;
800 }
801
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100802 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return count;
804}
805
Jean Delvare34875332007-05-08 17:22:03 +0200806static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
807 show_sensor, store_sensor, 0);
808static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400809 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200810static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400811 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813/* Assumes that adapter is of I2C, not ISA variety.
814 * OTHERWISE DON'T CALL THIS
815 */
816static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200817w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 int i, val1 = 0, id;
820 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200821 int address = new_client->addr;
822 unsigned short sc_addr[2];
823 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200825 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827 id = i2c_adapter_id(adapter);
828
829 if (force_subclients[0] == id && force_subclients[1] == address) {
830 for (i = 2; i <= 3; i++) {
831 if (force_subclients[i] < 0x48 ||
832 force_subclients[i] > 0x4f) {
833 dev_err(&new_client->dev, "Invalid subclient "
834 "address %d; must be 0x48-0x4f\n",
835 force_subclients[i]);
836 err = -EINVAL;
837 goto ERROR_SC_1;
838 }
839 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200840 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 (force_subclients[2] & 0x07) |
842 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200843 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200845 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200846 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (force_subclients[0] == id &&
851 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200852 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200854 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200856 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 dev_err(&new_client->dev,
858 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200859 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 err = -EBUSY;
861 goto ERROR_SC_2;
862 }
863 }
864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200866 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
867 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 dev_err(&new_client->dev, "Subclient %d "
869 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200870 "failed.\n", i, sc_addr[i]);
871 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (i == 1)
873 goto ERROR_SC_3;
874 goto ERROR_SC_2;
875 }
876 if (kind == w83783s)
877 break;
878 }
879
880 return 0;
881
882/* Undo inits in case of errors */
883ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200884 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return err;
888}
889
Jean Delvare34875332007-05-08 17:22:03 +0200890#define IN_UNIT_ATTRS(X) \
891 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
892 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100893 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200894 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
895 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200896
Jean Delvare34875332007-05-08 17:22:03 +0200897#define FAN_UNIT_ATTRS(X) \
898 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
899 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200900 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
901 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
902 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200903
Jean Delvare34875332007-05-08 17:22:03 +0200904#define TEMP_UNIT_ATTRS(X) \
905 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
906 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200907 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
908 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
909 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200910
911static struct attribute* w83781d_attributes[] = {
912 IN_UNIT_ATTRS(0),
913 IN_UNIT_ATTRS(2),
914 IN_UNIT_ATTRS(3),
915 IN_UNIT_ATTRS(4),
916 IN_UNIT_ATTRS(5),
917 IN_UNIT_ATTRS(6),
918 FAN_UNIT_ATTRS(1),
919 FAN_UNIT_ATTRS(2),
920 FAN_UNIT_ATTRS(3),
921 TEMP_UNIT_ATTRS(1),
922 TEMP_UNIT_ATTRS(2),
923 &dev_attr_cpu0_vid.attr,
924 &dev_attr_vrm.attr,
925 &dev_attr_alarms.attr,
926 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200927 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200928 NULL
929};
930static const struct attribute_group w83781d_group = {
931 .attrs = w83781d_attributes,
932};
933
934static struct attribute *w83781d_attributes_opt[] = {
935 IN_UNIT_ATTRS(1),
936 IN_UNIT_ATTRS(7),
937 IN_UNIT_ATTRS(8),
938 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200939 &sensor_dev_attr_pwm1.dev_attr.attr,
940 &sensor_dev_attr_pwm2.dev_attr.attr,
941 &sensor_dev_attr_pwm3.dev_attr.attr,
942 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200943 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200944 &sensor_dev_attr_temp1_type.dev_attr.attr,
945 &sensor_dev_attr_temp2_type.dev_attr.attr,
946 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200947 NULL
948};
949static const struct attribute_group w83781d_group_opt = {
950 .attrs = w83781d_attributes_opt,
951};
952
Jean Delvare7666c132007-05-08 17:22:02 +0200953/* No clean up is done on error, it's up to the caller */
954static int
955w83781d_create_files(struct device *dev, int kind, int is_isa)
956{
957 int err;
958
959 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
960 return err;
961
962 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200963 if ((err = device_create_file(dev,
964 &sensor_dev_attr_in1_input.dev_attr))
965 || (err = device_create_file(dev,
966 &sensor_dev_attr_in1_min.dev_attr))
967 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200968 &sensor_dev_attr_in1_max.dev_attr))
969 || (err = device_create_file(dev,
970 &sensor_dev_attr_in1_alarm.dev_attr))
971 || (err = device_create_file(dev,
972 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200973 return err;
974 }
975 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200976 if ((err = device_create_file(dev,
977 &sensor_dev_attr_in7_input.dev_attr))
978 || (err = device_create_file(dev,
979 &sensor_dev_attr_in7_min.dev_attr))
980 || (err = device_create_file(dev,
981 &sensor_dev_attr_in7_max.dev_attr))
982 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200983 &sensor_dev_attr_in7_alarm.dev_attr))
984 || (err = device_create_file(dev,
985 &sensor_dev_attr_in7_beep.dev_attr))
986 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200987 &sensor_dev_attr_in8_input.dev_attr))
988 || (err = device_create_file(dev,
989 &sensor_dev_attr_in8_min.dev_attr))
990 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200991 &sensor_dev_attr_in8_max.dev_attr))
992 || (err = device_create_file(dev,
993 &sensor_dev_attr_in8_alarm.dev_attr))
994 || (err = device_create_file(dev,
995 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200996 return err;
997 }
998 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200999 if ((err = device_create_file(dev,
1000 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001001 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001002 &sensor_dev_attr_temp3_max.dev_attr))
1003 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001004 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1005 || (err = device_create_file(dev,
1006 &sensor_dev_attr_temp3_alarm.dev_attr))
1007 || (err = device_create_file(dev,
1008 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001009 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001010
Jean Delvare7768aa72007-10-25 13:11:01 +02001011 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001012 err = sysfs_chmod_file(&dev->kobj,
1013 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1014 S_IRUGO | S_IWUSR);
1015 if (err)
1016 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001017 }
Jean Delvare7666c132007-05-08 17:22:02 +02001018 }
1019
1020 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001021 if ((err = device_create_file(dev,
1022 &sensor_dev_attr_pwm1.dev_attr))
1023 || (err = device_create_file(dev,
1024 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001025 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1026 return err;
1027 }
1028 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001029 if ((err = device_create_file(dev,
1030 &sensor_dev_attr_pwm3.dev_attr))
1031 || (err = device_create_file(dev,
1032 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001033 return err;
1034 }
1035
1036 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001037 if ((err = device_create_file(dev,
1038 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001039 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001040 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001041 return err;
1042 if (kind != w83783s) {
1043 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001044 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001045 return err;
1046 }
1047 }
1048
Jean Delvare7666c132007-05-08 17:22:02 +02001049 return 0;
1050}
1051
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001052/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001054w83781d_detect(struct i2c_client *client, int kind,
1055 struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Jean Delvare7666c132007-05-08 17:22:02 +02001057 int val1 = 0, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001058 struct w83781d_data *isa = w83781d_data_if_isa();
1059 struct i2c_adapter *adapter = client->adapter;
1060 int address = client->addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 enum vendor { winbond, asus } vendid;
1063
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001064 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1065 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001067 /* We block updates of the ISA device to minimize the risk of
1068 concurrent access to the same W83781D chip through different
1069 interfaces. */
1070 if (isa)
1071 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 /* The w8378?d may be stuck in some other bank than bank 0. This may
1074 make reading other information impossible. Specify a force=... or
1075 force_*=... parameter, and the Winbond will be reset to the right
1076 bank. */
1077 if (kind < 0) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001078 if (i2c_smbus_read_byte_data
1079 (client, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001080 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1081 "failed at step 3\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001082 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001084 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1085 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 /* Check for Winbond or Asus ID if in bank 0 */
1087 if ((!(val1 & 0x07)) &&
1088 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1089 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001090 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1091 "failed at step 4\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001092 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
1094 /* If Winbond SMBus, check address at 0x48.
1095 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001096 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1097 ((val1 & 0x80) && (val2 == 0x5c))) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001098 if (i2c_smbus_read_byte_data
1099 (client, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001100 dev_dbg(&adapter->dev, "Detection of w83781d "
1101 "chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001102 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
1104 }
1105 }
1106
1107 /* We have either had a force parameter, or we have already detected the
1108 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001109 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1110 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1111 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 /* Determine the chip type. */
1114 if (kind <= 0) {
1115 /* get vendor ID */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001116 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (val2 == 0x5c)
1118 vendid = winbond;
1119 else if (val2 == 0x12)
1120 vendid = asus;
1121 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001122 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1123 "neither Winbond nor Asus\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001124 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001127 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1129 kind = w83781d;
1130 else if (val1 == 0x30 && vendid == winbond)
1131 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001132 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 kind = w83783s;
Jean Delvare6722fea2007-10-07 12:25:46 +02001134 else if (val1 == 0x31)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 else {
1137 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001138 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001140 "address 0x%02x\n", address);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001141 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 }
Jean Delvarec6566202008-10-17 17:51:18 +02001143
1144 if ((kind == w83781d || kind == w83782d)
1145 && w83781d_alias_detect(client, val1)) {
1146 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1147 "be the same as ISA device\n", address);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001148 goto err_nodev;
Jean Delvarec6566202008-10-17 17:51:18 +02001149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001152 if (isa)
1153 mutex_unlock(&isa->update_lock);
1154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (kind == w83781d) {
1156 client_name = "w83781d";
1157 } else if (kind == w83782d) {
1158 client_name = "w83782d";
1159 } else if (kind == w83783s) {
1160 client_name = "w83783s";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 } else if (kind == as99127f) {
1162 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001165 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001167 return 0;
1168
1169 err_nodev:
1170 if (isa)
1171 mutex_unlock(&isa->update_lock);
1172 return -ENODEV;
1173}
1174
1175static int
1176w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1177{
1178 struct device *dev = &client->dev;
1179 struct w83781d_data *data;
1180 int err;
1181
1182 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1183 if (!data) {
1184 err = -ENOMEM;
1185 goto ERROR1;
1186 }
1187
1188 i2c_set_clientdata(client, data);
1189 mutex_init(&data->lock);
1190 mutex_init(&data->update_lock);
1191
1192 data->type = id->driver_data;
1193 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001196 err = w83781d_detect_subclients(client);
1197 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001198 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001201 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001204 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001205 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001206 goto ERROR4;
1207
Tony Jones1beeffe2007-08-20 13:46:20 -07001208 data->hwmon_dev = hwmon_device_register(dev);
1209 if (IS_ERR(data->hwmon_dev)) {
1210 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001211 goto ERROR4;
1212 }
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 return 0;
1215
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001216ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001217 sysfs_remove_group(&dev->kobj, &w83781d_group);
1218 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1219
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001220 if (data->lm75[0])
1221 i2c_unregister_device(data->lm75[0]);
1222 if (data->lm75[1])
1223 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224ERROR3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001225 i2c_set_clientdata(client, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 kfree(data);
1227ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 return err;
1229}
1230
1231static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001232w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001234 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001235 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001237 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001239 sysfs_remove_group(&dev->kobj, &w83781d_group);
1240 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001242 if (data->lm75[0])
1243 i2c_unregister_device(data->lm75[0]);
1244 if (data->lm75[1])
1245 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001246
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001247 i2c_set_clientdata(client, NULL);
1248 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 return 0;
1251}
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001254w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001256 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001257 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 struct i2c_client *cl;
1259
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001260 bank = (reg >> 8) & 0x0f;
1261 if (bank > 2)
1262 /* switch banks */
1263 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1264 bank);
1265 if (bank == 0 || bank > 2) {
1266 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001268 /* switch to subclient */
1269 cl = data->lm75[bank - 1];
1270 /* convert from ISA to LM75 I2C addresses */
1271 switch (reg & 0xff) {
1272 case 0x50: /* TEMP */
1273 res = swab16(i2c_smbus_read_word_data(cl, 0));
1274 break;
1275 case 0x52: /* CONFIG */
1276 res = i2c_smbus_read_byte_data(cl, 1);
1277 break;
1278 case 0x53: /* HYST */
1279 res = swab16(i2c_smbus_read_word_data(cl, 2));
1280 break;
1281 case 0x55: /* OVER */
1282 default:
1283 res = swab16(i2c_smbus_read_word_data(cl, 3));
1284 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001287 if (bank > 2)
1288 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 return res;
1291}
1292
1293static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001294w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001296 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001297 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 struct i2c_client *cl;
1299
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001300 bank = (reg >> 8) & 0x0f;
1301 if (bank > 2)
1302 /* switch banks */
1303 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1304 bank);
1305 if (bank == 0 || bank > 2) {
1306 i2c_smbus_write_byte_data(client, reg & 0xff,
1307 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001309 /* switch to subclient */
1310 cl = data->lm75[bank - 1];
1311 /* convert from ISA to LM75 I2C addresses */
1312 switch (reg & 0xff) {
1313 case 0x52: /* CONFIG */
1314 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1315 break;
1316 case 0x53: /* HYST */
1317 i2c_smbus_write_word_data(cl, 2, swab16(value));
1318 break;
1319 case 0x55: /* OVER */
1320 i2c_smbus_write_word_data(cl, 3, swab16(value));
1321 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001324 if (bank > 2)
1325 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 return 0;
1328}
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330static void
Jean Delvare7666c132007-05-08 17:22:02 +02001331w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332{
Jean Delvare7666c132007-05-08 17:22:02 +02001333 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 int i, p;
1335 int type = data->type;
1336 u8 tmp;
1337
Jean Delvarefabddcd2006-02-05 23:26:51 +01001338 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001340 /* Resetting the chip has been the default for a long time,
1341 but it causes the BIOS initializations (fan clock dividers,
1342 thermal sensor types...) to be lost, so it is now optional.
1343 It might even go away if nobody reports it as being useful,
1344 as I see very little reason why this would be needed at
1345 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001346 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001347 "having, please report!\n");
1348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001350 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1351 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 /* Reset all except Watchdog values and last conversion values
1353 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001354 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 /* Restore the registers and disable power-on abnormal beep.
1356 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001357 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1358 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 /* Disable master beep-enable (reset turns it on).
1360 Individual beep_mask should be reset to off but for some reason
1361 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001362 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 }
1364
Jean Delvarefabddcd2006-02-05 23:26:51 +01001365 /* Disable power-on abnormal beep, as advised by the datasheet.
1366 Already done if reset=1. */
1367 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001368 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1369 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001370 }
1371
Jean Delvare303760b2005-07-31 21:52:01 +02001372 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001375 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 for (i = 1; i <= 3; i++) {
1377 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001378 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 } else {
1380 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001381 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1383 data->sens[i - 1] = 1;
1384 else
1385 data->sens[i - 1] = 2;
1386 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001387 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 break;
1389 }
1390 }
1391
1392 if (init && type != as99127f) {
1393 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001394 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001396 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001398 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 tmp & 0xfe);
1400 }
1401
1402 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001403 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001404 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 W83781D_REG_TEMP3_CONFIG);
1406 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001407 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001409 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1411 }
1412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
1414
1415 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001416 w83781d_write_value(data, W83781D_REG_CONFIG,
1417 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 W83781D_REG_CONFIG) & 0xf7)
1419 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001420
1421 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001422 for (i = 0; i < 3; i++) {
1423 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001424 W83781D_REG_FAN_MIN(i));
1425 }
Jean Delvare7666c132007-05-08 17:22:02 +02001426
1427 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428}
1429
1430static struct w83781d_data *w83781d_update_device(struct device *dev)
1431{
Jean Delvare7666c132007-05-08 17:22:02 +02001432 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001433 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 int i;
1435
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001436 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1439 || !data->valid) {
1440 dev_dbg(dev, "Starting device update\n");
1441
1442 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001443 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 continue; /* 783S has no in1 */
1445 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001446 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001448 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001450 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001451 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 break;
1453 }
Jean Delvare34875332007-05-08 17:22:03 +02001454 for (i = 0; i < 3; i++) {
1455 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001456 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001457 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001458 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 }
1460 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001461 for (i = 0; i < 4; i++) {
1462 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001463 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001464 W83781D_REG_PWM[i]);
Jean Delvare7666c132007-05-08 17:22:02 +02001465 if ((data->type != w83782d || !client->driver)
Jean Delvare34875332007-05-08 17:22:03 +02001466 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 break;
1468 }
1469 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001470 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1472 }
1473
Jean Delvare31b8dc42007-05-08 17:22:03 +02001474 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001476 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001478 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001480 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001482 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001484 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001485 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001487 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 data->temp_max_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_OVER(3));
1491 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001492 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 W83781D_REG_TEMP_HYST(3));
1494 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001495 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001496 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001497 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001498 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 data->fan_div[0] = (i >> 4) & 0x03;
1500 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001501 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001502 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001504 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 data->fan_div[0] |= (i >> 3) & 0x04;
1506 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001507 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
Jean Delvare05663362007-11-30 23:51:24 +01001509 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001510 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001511 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001512 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001513 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001514 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001515 W83782D_REG_ALARM3) << 16);
1516 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001517 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001518 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001519 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001520 W83782D_REG_ALARM2) << 8);
1521 } else {
1522 /* No real-time status registers, fall back to
1523 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001524 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001525 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001526 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001527 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001529 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001530 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001531 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 if ((data->type != w83781d) && (data->type != as99127f)) {
1533 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001534 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 W83781D_REG_BEEP_INTS3) << 16;
1536 }
1537 data->last_updated = jiffies;
1538 data->valid = 1;
1539 }
1540
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001541 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
1543 return data;
1544}
1545
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001546static const struct i2c_device_id w83781d_ids[] = {
1547 { "w83781d", w83781d, },
1548 { "w83782d", w83782d, },
1549 { "w83783s", w83783s, },
1550 { "as99127f", as99127f },
1551 { /* LIST END */ }
1552};
1553MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1554
1555static struct i2c_driver w83781d_driver = {
1556 .class = I2C_CLASS_HWMON,
1557 .driver = {
1558 .name = "w83781d",
1559 },
1560 .probe = w83781d_probe,
1561 .remove = w83781d_remove,
1562 .id_table = w83781d_ids,
1563 .detect = w83781d_detect,
1564 .address_data = &addr_data,
1565};
1566
1567/*
1568 * ISA related code
1569 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001570#ifdef CONFIG_ISA
1571
1572/* ISA device, if found */
1573static struct platform_device *pdev;
1574
1575static unsigned short isa_address = 0x290;
1576
1577/* I2C devices get this name attribute automatically, but for ISA devices
1578 we must create it by ourselves. */
1579static ssize_t
1580show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1581{
1582 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001583 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001584}
1585static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1586
1587static struct w83781d_data *w83781d_data_if_isa(void)
1588{
1589 return pdev ? platform_get_drvdata(pdev) : NULL;
1590}
1591
1592/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1593static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1594{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001595 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001596 int i;
1597
1598 if (!pdev) /* No ISA chip */
1599 return 0;
1600
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001601 isa = platform_get_drvdata(pdev);
1602
1603 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1604 return 0; /* Address doesn't match */
1605 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1606 return 0; /* Chip type doesn't match */
1607
1608 /* We compare all the limit registers, the config register and the
1609 * interrupt mask registers */
1610 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001611 if (w83781d_read_value(isa, i) !=
1612 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001613 return 0;
1614 }
1615 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001616 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001617 return 0;
1618 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001619 if (w83781d_read_value(isa, i) !=
1620 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001621 return 0;
1622 }
1623
1624 return 1;
1625}
1626
1627static int
1628w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1629{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001630 int word_sized, res;
1631
1632 word_sized = (((reg & 0xff00) == 0x100)
1633 || ((reg & 0xff00) == 0x200))
1634 && (((reg & 0x00ff) == 0x50)
1635 || ((reg & 0x00ff) == 0x53)
1636 || ((reg & 0x00ff) == 0x55));
1637 if (reg & 0xff00) {
1638 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001639 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001640 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001641 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001642 }
Jean Delvare360782d2008-10-17 17:51:19 +02001643 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1644 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001645 if (word_sized) {
1646 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001647 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001648 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001649 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001650 W83781D_DATA_REG_OFFSET);
1651 }
1652 if (reg & 0xff00) {
1653 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001654 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1655 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001656 }
1657 return res;
1658}
1659
1660static void
1661w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1662{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001663 int word_sized;
1664
1665 word_sized = (((reg & 0xff00) == 0x100)
1666 || ((reg & 0xff00) == 0x200))
1667 && (((reg & 0x00ff) == 0x53)
1668 || ((reg & 0x00ff) == 0x55));
1669 if (reg & 0xff00) {
1670 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001671 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001672 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001673 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001674 }
Jean Delvare360782d2008-10-17 17:51:19 +02001675 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001676 if (word_sized) {
1677 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001678 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001679 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001680 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001681 }
Jean Delvare360782d2008-10-17 17:51:19 +02001682 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001683 if (reg & 0xff00) {
1684 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001685 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1686 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001687 }
1688}
1689
1690/* The SMBus locks itself, usually, but nothing may access the Winbond between
1691 bank switches. ISA access must always be locked explicitly!
1692 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1693 would slow down the W83781D access and should not be necessary.
1694 There are some ugly typecasts here, but the good news is - they should
1695 nowhere else be necessary! */
1696static int
1697w83781d_read_value(struct w83781d_data *data, u16 reg)
1698{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001699 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001700 int res;
1701
1702 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001703 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001704 res = w83781d_read_value_i2c(data, reg);
1705 else
1706 res = w83781d_read_value_isa(data, reg);
1707 mutex_unlock(&data->lock);
1708 return res;
1709}
1710
1711static int
1712w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1713{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001714 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001715
1716 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001717 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001718 w83781d_write_value_i2c(data, reg, value);
1719 else
1720 w83781d_write_value_isa(data, reg, value);
1721 mutex_unlock(&data->lock);
1722 return 0;
1723}
1724
1725static int __devinit
1726w83781d_isa_probe(struct platform_device *pdev)
1727{
1728 int err, reg;
1729 struct w83781d_data *data;
1730 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001731
1732 /* Reserve the ISA region */
1733 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1734 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1735 "w83781d")) {
1736 err = -EBUSY;
1737 goto exit;
1738 }
1739
1740 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1741 if (!data) {
1742 err = -ENOMEM;
1743 goto exit_release_region;
1744 }
1745 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001746 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001747 platform_set_drvdata(pdev, data);
1748
1749 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1750 switch (reg) {
1751 case 0x30:
1752 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001753 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001754 break;
1755 default:
1756 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001757 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001758 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001759
1760 /* Initialize the W83781D chip */
1761 w83781d_init_device(&pdev->dev);
1762
1763 /* Register sysfs hooks */
1764 err = w83781d_create_files(&pdev->dev, data->type, 1);
1765 if (err)
1766 goto exit_remove_files;
1767
1768 err = device_create_file(&pdev->dev, &dev_attr_name);
1769 if (err)
1770 goto exit_remove_files;
1771
1772 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1773 if (IS_ERR(data->hwmon_dev)) {
1774 err = PTR_ERR(data->hwmon_dev);
1775 goto exit_remove_files;
1776 }
1777
1778 return 0;
1779
1780 exit_remove_files:
1781 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1782 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1783 device_remove_file(&pdev->dev, &dev_attr_name);
1784 kfree(data);
1785 exit_release_region:
1786 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1787 exit:
1788 return err;
1789}
1790
1791static int __devexit
1792w83781d_isa_remove(struct platform_device *pdev)
1793{
1794 struct w83781d_data *data = platform_get_drvdata(pdev);
1795
1796 hwmon_device_unregister(data->hwmon_dev);
1797 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1798 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1799 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001800 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001801 kfree(data);
1802
1803 return 0;
1804}
1805
1806static struct platform_driver w83781d_isa_driver = {
1807 .driver = {
1808 .owner = THIS_MODULE,
1809 .name = "w83781d",
1810 },
1811 .probe = w83781d_isa_probe,
1812 .remove = __devexit_p(w83781d_isa_remove),
1813};
1814
Jean Delvare7666c132007-05-08 17:22:02 +02001815/* return 1 if a supported chip is found, 0 otherwise */
1816static int __init
1817w83781d_isa_found(unsigned short address)
1818{
1819 int val, save, found = 0;
1820
Jean Delvare2961cb22008-03-09 13:34:28 +01001821 /* We have to request the region in two parts because some
1822 boards declare base+4 to base+7 as a PNP device */
1823 if (!request_region(address, 4, "w83781d")) {
1824 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001825 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001826 }
1827 if (!request_region(address + 4, 4, "w83781d")) {
1828 pr_debug("w83781d: Failed to request high part of region\n");
1829 release_region(address, 4);
1830 return 0;
1831 }
Jean Delvare7666c132007-05-08 17:22:02 +02001832
1833#define REALLY_SLOW_IO
1834 /* We need the timeouts for at least some W83781D-like
1835 chips. But only if we read 'undefined' registers. */
1836 val = inb_p(address + 1);
1837 if (inb_p(address + 2) != val
1838 || inb_p(address + 3) != val
1839 || inb_p(address + 7) != val) {
1840 pr_debug("w83781d: Detection failed at step 1\n");
1841 goto release;
1842 }
1843#undef REALLY_SLOW_IO
1844
1845 /* We should be able to change the 7 LSB of the address port. The
1846 MSB (busy flag) should be clear initially, set after the write. */
1847 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1848 if (save & 0x80) {
1849 pr_debug("w83781d: Detection failed at step 2\n");
1850 goto release;
1851 }
1852 val = ~save & 0x7f;
1853 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1854 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1855 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1856 pr_debug("w83781d: Detection failed at step 3\n");
1857 goto release;
1858 }
1859
1860 /* We found a device, now see if it could be a W83781D */
1861 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1862 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1863 if (val & 0x80) {
1864 pr_debug("w83781d: Detection failed at step 4\n");
1865 goto release;
1866 }
1867 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1868 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1869 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1870 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1871 if ((!(save & 0x80) && (val != 0xa3))
1872 || ((save & 0x80) && (val != 0x5c))) {
1873 pr_debug("w83781d: Detection failed at step 5\n");
1874 goto release;
1875 }
1876 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1877 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1878 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1879 pr_debug("w83781d: Detection failed at step 6\n");
1880 goto release;
1881 }
1882
1883 /* The busy flag should be clear again */
1884 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1885 pr_debug("w83781d: Detection failed at step 7\n");
1886 goto release;
1887 }
1888
1889 /* Determine the chip type */
1890 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1891 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1892 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1893 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1894 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1895 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001896 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001897 found = 1;
1898
1899 if (found)
1900 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001901 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1902
1903 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001904 release_region(address + 4, 4);
1905 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001906 return found;
1907}
1908
1909static int __init
1910w83781d_isa_device_add(unsigned short address)
1911{
1912 struct resource res = {
1913 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001914 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001915 .name = "w83781d",
1916 .flags = IORESOURCE_IO,
1917 };
1918 int err;
1919
1920 pdev = platform_device_alloc("w83781d", address);
1921 if (!pdev) {
1922 err = -ENOMEM;
1923 printk(KERN_ERR "w83781d: Device allocation failed\n");
1924 goto exit;
1925 }
1926
1927 err = platform_device_add_resources(pdev, &res, 1);
1928 if (err) {
1929 printk(KERN_ERR "w83781d: Device resource addition failed "
1930 "(%d)\n", err);
1931 goto exit_device_put;
1932 }
1933
1934 err = platform_device_add(pdev);
1935 if (err) {
1936 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1937 err);
1938 goto exit_device_put;
1939 }
1940
1941 return 0;
1942
1943 exit_device_put:
1944 platform_device_put(pdev);
1945 exit:
1946 pdev = NULL;
1947 return err;
1948}
1949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001951w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{
Jean Delvarefde09502005-07-19 23:51:07 +02001953 int res;
1954
Jean Delvare7666c132007-05-08 17:22:02 +02001955 if (w83781d_isa_found(isa_address)) {
1956 res = platform_driver_register(&w83781d_isa_driver);
1957 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001958 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001959
1960 /* Sets global pdev as a side effect */
1961 res = w83781d_isa_device_add(isa_address);
1962 if (res)
1963 goto exit_unreg_isa_driver;
1964 }
Jean Delvarefde09502005-07-19 23:51:07 +02001965
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001966 return 0;
1967
1968exit_unreg_isa_driver:
1969 platform_driver_unregister(&w83781d_isa_driver);
1970exit:
1971 return res;
1972}
1973
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001974static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001975w83781d_isa_unregister(void)
1976{
1977 if (pdev) {
1978 platform_device_unregister(pdev);
1979 platform_driver_unregister(&w83781d_isa_driver);
1980 }
1981}
1982#else /* !CONFIG_ISA */
1983
1984static struct w83781d_data *w83781d_data_if_isa(void)
1985{
1986 return NULL;
1987}
1988
1989static int
1990w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1991{
1992 return 0;
1993}
1994
1995static int
1996w83781d_read_value(struct w83781d_data *data, u16 reg)
1997{
1998 int res;
1999
2000 mutex_lock(&data->lock);
2001 res = w83781d_read_value_i2c(data, reg);
2002 mutex_unlock(&data->lock);
2003
2004 return res;
2005}
2006
2007static int
2008w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2009{
2010 mutex_lock(&data->lock);
2011 w83781d_write_value_i2c(data, reg, value);
2012 mutex_unlock(&data->lock);
2013
2014 return 0;
2015}
2016
2017static int __init
2018w83781d_isa_register(void)
2019{
2020 return 0;
2021}
2022
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01002023static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002024w83781d_isa_unregister(void)
2025{
2026}
2027#endif /* CONFIG_ISA */
2028
2029static int __init
2030sensors_w83781d_init(void)
2031{
2032 int res;
2033
2034 /* We register the ISA device first, so that we can skip the
2035 * registration of an I2C interface to the same device. */
2036 res = w83781d_isa_register();
2037 if (res)
2038 goto exit;
2039
Jean Delvarec6566202008-10-17 17:51:18 +02002040 res = i2c_add_driver(&w83781d_driver);
2041 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002042 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002043
Jean Delvarefde09502005-07-19 23:51:07 +02002044 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002045
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002046 exit_unreg_isa:
2047 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002048 exit:
2049 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050}
2051
2052static void __exit
2053sensors_w83781d_exit(void)
2054{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002055 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 i2c_del_driver(&w83781d_driver);
2057}
2058
2059MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2060 "Philip Edelbrock <phil@netroedge.com>, "
2061 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2062MODULE_DESCRIPTION("W83781D driver");
2063MODULE_LICENSE("GPL");
2064
2065module_init(sensors_w83781d_init);
2066module_exit(sensors_w83781d_exit);