blob: d27ed1bac002cd1c35c8c55b41be32253c5a9936 [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>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020051#include <linux/io.h>
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020052#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 Delvare848ddf12009-05-08 20:27:28 +02001465 /* Only W83782D on SMBus has PWM3 and PWM4 */
1466 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001467 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 break;
1469 }
1470 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001471 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1473 }
1474
Jean Delvare31b8dc42007-05-08 17:22:03 +02001475 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001477 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001479 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001481 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001483 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001485 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001486 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001490 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 W83781D_REG_TEMP_OVER(3));
1492 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001493 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 W83781D_REG_TEMP_HYST(3));
1495 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001496 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001497 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001498 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001499 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 data->fan_div[0] = (i >> 4) & 0x03;
1501 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001502 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001503 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001505 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 data->fan_div[0] |= (i >> 3) & 0x04;
1507 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001508 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 }
Jean Delvare05663362007-11-30 23:51:24 +01001510 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001511 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001512 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001513 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001514 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001515 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001516 W83782D_REG_ALARM3) << 16);
1517 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001518 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001519 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001520 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001521 W83782D_REG_ALARM2) << 8);
1522 } else {
1523 /* No real-time status registers, fall back to
1524 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001525 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001526 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001527 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001528 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001530 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001531 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001532 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 if ((data->type != w83781d) && (data->type != as99127f)) {
1534 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001535 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 W83781D_REG_BEEP_INTS3) << 16;
1537 }
1538 data->last_updated = jiffies;
1539 data->valid = 1;
1540 }
1541
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001542 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544 return data;
1545}
1546
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001547static const struct i2c_device_id w83781d_ids[] = {
1548 { "w83781d", w83781d, },
1549 { "w83782d", w83782d, },
1550 { "w83783s", w83783s, },
1551 { "as99127f", as99127f },
1552 { /* LIST END */ }
1553};
1554MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1555
1556static struct i2c_driver w83781d_driver = {
1557 .class = I2C_CLASS_HWMON,
1558 .driver = {
1559 .name = "w83781d",
1560 },
1561 .probe = w83781d_probe,
1562 .remove = w83781d_remove,
1563 .id_table = w83781d_ids,
1564 .detect = w83781d_detect,
1565 .address_data = &addr_data,
1566};
1567
1568/*
1569 * ISA related code
1570 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001571#ifdef CONFIG_ISA
1572
1573/* ISA device, if found */
1574static struct platform_device *pdev;
1575
1576static unsigned short isa_address = 0x290;
1577
1578/* I2C devices get this name attribute automatically, but for ISA devices
1579 we must create it by ourselves. */
1580static ssize_t
1581show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1582{
1583 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001584 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001585}
1586static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1587
1588static struct w83781d_data *w83781d_data_if_isa(void)
1589{
1590 return pdev ? platform_get_drvdata(pdev) : NULL;
1591}
1592
1593/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1594static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1595{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001596 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001597 int i;
1598
1599 if (!pdev) /* No ISA chip */
1600 return 0;
1601
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001602 isa = platform_get_drvdata(pdev);
1603
1604 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1605 return 0; /* Address doesn't match */
1606 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1607 return 0; /* Chip type doesn't match */
1608
1609 /* We compare all the limit registers, the config register and the
1610 * interrupt mask registers */
1611 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001612 if (w83781d_read_value(isa, i) !=
1613 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001614 return 0;
1615 }
1616 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001617 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001618 return 0;
1619 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001620 if (w83781d_read_value(isa, i) !=
1621 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001622 return 0;
1623 }
1624
1625 return 1;
1626}
1627
1628static int
1629w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1630{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001631 int word_sized, res;
1632
1633 word_sized = (((reg & 0xff00) == 0x100)
1634 || ((reg & 0xff00) == 0x200))
1635 && (((reg & 0x00ff) == 0x50)
1636 || ((reg & 0x00ff) == 0x53)
1637 || ((reg & 0x00ff) == 0x55));
1638 if (reg & 0xff00) {
1639 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001640 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001641 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001642 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001643 }
Jean Delvare360782d2008-10-17 17:51:19 +02001644 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1645 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001646 if (word_sized) {
1647 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001648 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001649 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001650 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001651 W83781D_DATA_REG_OFFSET);
1652 }
1653 if (reg & 0xff00) {
1654 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001655 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1656 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001657 }
1658 return res;
1659}
1660
1661static void
1662w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1663{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001664 int word_sized;
1665
1666 word_sized = (((reg & 0xff00) == 0x100)
1667 || ((reg & 0xff00) == 0x200))
1668 && (((reg & 0x00ff) == 0x53)
1669 || ((reg & 0x00ff) == 0x55));
1670 if (reg & 0xff00) {
1671 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001672 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001673 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001674 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001675 }
Jean Delvare360782d2008-10-17 17:51:19 +02001676 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001677 if (word_sized) {
1678 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001679 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001680 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001681 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001682 }
Jean Delvare360782d2008-10-17 17:51:19 +02001683 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001684 if (reg & 0xff00) {
1685 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001686 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1687 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001688 }
1689}
1690
1691/* The SMBus locks itself, usually, but nothing may access the Winbond between
1692 bank switches. ISA access must always be locked explicitly!
1693 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1694 would slow down the W83781D access and should not be necessary.
1695 There are some ugly typecasts here, but the good news is - they should
1696 nowhere else be necessary! */
1697static int
1698w83781d_read_value(struct w83781d_data *data, u16 reg)
1699{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001700 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001701 int res;
1702
1703 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001704 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001705 res = w83781d_read_value_i2c(data, reg);
1706 else
1707 res = w83781d_read_value_isa(data, reg);
1708 mutex_unlock(&data->lock);
1709 return res;
1710}
1711
1712static int
1713w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1714{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001715 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001716
1717 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001718 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001719 w83781d_write_value_i2c(data, reg, value);
1720 else
1721 w83781d_write_value_isa(data, reg, value);
1722 mutex_unlock(&data->lock);
1723 return 0;
1724}
1725
1726static int __devinit
1727w83781d_isa_probe(struct platform_device *pdev)
1728{
1729 int err, reg;
1730 struct w83781d_data *data;
1731 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001732
1733 /* Reserve the ISA region */
1734 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1735 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1736 "w83781d")) {
1737 err = -EBUSY;
1738 goto exit;
1739 }
1740
1741 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1742 if (!data) {
1743 err = -ENOMEM;
1744 goto exit_release_region;
1745 }
1746 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001747 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001748 platform_set_drvdata(pdev, data);
1749
1750 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1751 switch (reg) {
1752 case 0x30:
1753 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001754 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001755 break;
1756 default:
1757 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001758 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001759 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001760
1761 /* Initialize the W83781D chip */
1762 w83781d_init_device(&pdev->dev);
1763
1764 /* Register sysfs hooks */
1765 err = w83781d_create_files(&pdev->dev, data->type, 1);
1766 if (err)
1767 goto exit_remove_files;
1768
1769 err = device_create_file(&pdev->dev, &dev_attr_name);
1770 if (err)
1771 goto exit_remove_files;
1772
1773 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1774 if (IS_ERR(data->hwmon_dev)) {
1775 err = PTR_ERR(data->hwmon_dev);
1776 goto exit_remove_files;
1777 }
1778
1779 return 0;
1780
1781 exit_remove_files:
1782 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1783 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1784 device_remove_file(&pdev->dev, &dev_attr_name);
1785 kfree(data);
1786 exit_release_region:
1787 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1788 exit:
1789 return err;
1790}
1791
1792static int __devexit
1793w83781d_isa_remove(struct platform_device *pdev)
1794{
1795 struct w83781d_data *data = platform_get_drvdata(pdev);
1796
1797 hwmon_device_unregister(data->hwmon_dev);
1798 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1799 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1800 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001801 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001802 kfree(data);
1803
1804 return 0;
1805}
1806
1807static struct platform_driver w83781d_isa_driver = {
1808 .driver = {
1809 .owner = THIS_MODULE,
1810 .name = "w83781d",
1811 },
1812 .probe = w83781d_isa_probe,
1813 .remove = __devexit_p(w83781d_isa_remove),
1814};
1815
Jean Delvare7666c132007-05-08 17:22:02 +02001816/* return 1 if a supported chip is found, 0 otherwise */
1817static int __init
1818w83781d_isa_found(unsigned short address)
1819{
1820 int val, save, found = 0;
1821
Jean Delvare2961cb22008-03-09 13:34:28 +01001822 /* We have to request the region in two parts because some
1823 boards declare base+4 to base+7 as a PNP device */
1824 if (!request_region(address, 4, "w83781d")) {
1825 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001826 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001827 }
1828 if (!request_region(address + 4, 4, "w83781d")) {
1829 pr_debug("w83781d: Failed to request high part of region\n");
1830 release_region(address, 4);
1831 return 0;
1832 }
Jean Delvare7666c132007-05-08 17:22:02 +02001833
1834#define REALLY_SLOW_IO
1835 /* We need the timeouts for at least some W83781D-like
1836 chips. But only if we read 'undefined' registers. */
1837 val = inb_p(address + 1);
1838 if (inb_p(address + 2) != val
1839 || inb_p(address + 3) != val
1840 || inb_p(address + 7) != val) {
1841 pr_debug("w83781d: Detection failed at step 1\n");
1842 goto release;
1843 }
1844#undef REALLY_SLOW_IO
1845
1846 /* We should be able to change the 7 LSB of the address port. The
1847 MSB (busy flag) should be clear initially, set after the write. */
1848 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1849 if (save & 0x80) {
1850 pr_debug("w83781d: Detection failed at step 2\n");
1851 goto release;
1852 }
1853 val = ~save & 0x7f;
1854 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1855 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1856 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1857 pr_debug("w83781d: Detection failed at step 3\n");
1858 goto release;
1859 }
1860
1861 /* We found a device, now see if it could be a W83781D */
1862 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1863 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1864 if (val & 0x80) {
1865 pr_debug("w83781d: Detection failed at step 4\n");
1866 goto release;
1867 }
1868 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1869 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1870 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1871 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1872 if ((!(save & 0x80) && (val != 0xa3))
1873 || ((save & 0x80) && (val != 0x5c))) {
1874 pr_debug("w83781d: Detection failed at step 5\n");
1875 goto release;
1876 }
1877 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1878 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1879 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1880 pr_debug("w83781d: Detection failed at step 6\n");
1881 goto release;
1882 }
1883
1884 /* The busy flag should be clear again */
1885 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1886 pr_debug("w83781d: Detection failed at step 7\n");
1887 goto release;
1888 }
1889
1890 /* Determine the chip type */
1891 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1892 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1893 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1894 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1895 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1896 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001897 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001898 found = 1;
1899
1900 if (found)
1901 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001902 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1903
1904 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001905 release_region(address + 4, 4);
1906 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001907 return found;
1908}
1909
1910static int __init
1911w83781d_isa_device_add(unsigned short address)
1912{
1913 struct resource res = {
1914 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001915 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001916 .name = "w83781d",
1917 .flags = IORESOURCE_IO,
1918 };
1919 int err;
1920
1921 pdev = platform_device_alloc("w83781d", address);
1922 if (!pdev) {
1923 err = -ENOMEM;
1924 printk(KERN_ERR "w83781d: Device allocation failed\n");
1925 goto exit;
1926 }
1927
1928 err = platform_device_add_resources(pdev, &res, 1);
1929 if (err) {
1930 printk(KERN_ERR "w83781d: Device resource addition failed "
1931 "(%d)\n", err);
1932 goto exit_device_put;
1933 }
1934
1935 err = platform_device_add(pdev);
1936 if (err) {
1937 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1938 err);
1939 goto exit_device_put;
1940 }
1941
1942 return 0;
1943
1944 exit_device_put:
1945 platform_device_put(pdev);
1946 exit:
1947 pdev = NULL;
1948 return err;
1949}
1950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001952w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
Jean Delvarefde09502005-07-19 23:51:07 +02001954 int res;
1955
Jean Delvare7666c132007-05-08 17:22:02 +02001956 if (w83781d_isa_found(isa_address)) {
1957 res = platform_driver_register(&w83781d_isa_driver);
1958 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001959 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001960
1961 /* Sets global pdev as a side effect */
1962 res = w83781d_isa_device_add(isa_address);
1963 if (res)
1964 goto exit_unreg_isa_driver;
1965 }
Jean Delvarefde09502005-07-19 23:51:07 +02001966
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001967 return 0;
1968
1969exit_unreg_isa_driver:
1970 platform_driver_unregister(&w83781d_isa_driver);
1971exit:
1972 return res;
1973}
1974
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001975static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001976w83781d_isa_unregister(void)
1977{
1978 if (pdev) {
1979 platform_device_unregister(pdev);
1980 platform_driver_unregister(&w83781d_isa_driver);
1981 }
1982}
1983#else /* !CONFIG_ISA */
1984
1985static struct w83781d_data *w83781d_data_if_isa(void)
1986{
1987 return NULL;
1988}
1989
1990static int
1991w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1992{
1993 return 0;
1994}
1995
1996static int
1997w83781d_read_value(struct w83781d_data *data, u16 reg)
1998{
1999 int res;
2000
2001 mutex_lock(&data->lock);
2002 res = w83781d_read_value_i2c(data, reg);
2003 mutex_unlock(&data->lock);
2004
2005 return res;
2006}
2007
2008static int
2009w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2010{
2011 mutex_lock(&data->lock);
2012 w83781d_write_value_i2c(data, reg, value);
2013 mutex_unlock(&data->lock);
2014
2015 return 0;
2016}
2017
2018static int __init
2019w83781d_isa_register(void)
2020{
2021 return 0;
2022}
2023
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01002024static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002025w83781d_isa_unregister(void)
2026{
2027}
2028#endif /* CONFIG_ISA */
2029
2030static int __init
2031sensors_w83781d_init(void)
2032{
2033 int res;
2034
2035 /* We register the ISA device first, so that we can skip the
2036 * registration of an I2C interface to the same device. */
2037 res = w83781d_isa_register();
2038 if (res)
2039 goto exit;
2040
Jean Delvarec6566202008-10-17 17:51:18 +02002041 res = i2c_add_driver(&w83781d_driver);
2042 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002043 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002044
Jean Delvarefde09502005-07-19 23:51:07 +02002045 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002046
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002047 exit_unreg_isa:
2048 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002049 exit:
2050 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}
2052
2053static void __exit
2054sensors_w83781d_exit(void)
2055{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002056 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 i2c_del_driver(&w83781d_driver);
2058}
2059
2060MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2061 "Philip Edelbrock <phil@netroedge.com>, "
2062 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2063MODULE_DESCRIPTION("W83781D driver");
2064MODULE_LICENSE("GPL");
2065
2066module_init(sensors_w83781d_init);
2067module_exit(sensors_w83781d_exit);