blob: 65b685e2c7b739634fd62f6d17238a1003945604 [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
Joe Perches1ca28212011-01-12 21:55:11 +010036#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/slab.h>
41#include <linux/jiffies.h>
42#include <linux/i2c.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040043#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020044#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020045#include <linux/hwmon-sysfs.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020046#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010048#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020050#ifdef CONFIG_ISA
51#include <linux/platform_device.h>
52#include <linux/ioport.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020053#include <linux/io.h>
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020054#endif
55
56#include "lm75.h"
Jean Delvare7666c132007-05-08 17:22:02 +020057
Linus Torvalds1da177e2005-04-16 15:20:36 -070058/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050059static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
60 0x2e, 0x2f, I2C_CLIENT_END };
Jean Delvare3aed1982009-01-07 16:37:32 +010061
Jean Delvaree5e9f442009-12-14 21:17:27 +010062enum chips { w83781d, w83782d, w83783s, as99127f };
63
64/* Insmod parameters */
Jean Delvare3aed1982009-01-07 16:37:32 +010065static unsigned short force_subclients[4];
66module_param_array(force_subclients, short, NULL, 0);
67MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
69
Jean Delvarefabddcd2006-02-05 23:26:51 +010070static int reset;
71module_param(reset, bool, 0);
72MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int init = 1;
75module_param(init, bool, 0);
76MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
77
78/* Constants specified below */
79
80/* Length of ISA address segment */
81#define W83781D_EXTENT 8
82
83/* Where are the ISA address/data registers relative to the base address */
84#define W83781D_ADDR_REG_OFFSET 5
85#define W83781D_DATA_REG_OFFSET 6
86
Jean Delvare34875332007-05-08 17:22:03 +020087/* The device registers */
88/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
90 (0x554 + (((nr) - 7) * 2)))
91#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
92 (0x555 + (((nr) - 7) * 2)))
93#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
94 (0x550 + (nr) - 7))
95
Jean Delvare34875332007-05-08 17:22:03 +020096/* fan nr from 0 to 2 */
97#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
98#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100#define W83781D_REG_BANK 0x4E
101#define W83781D_REG_TEMP2_CONFIG 0x152
102#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +0200103/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
105 ((nr == 2) ? (0x0150) : \
106 (0x27)))
107#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
108 ((nr == 2) ? (0x153) : \
109 (0x3A)))
110#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
111 ((nr == 2) ? (0x155) : \
112 (0x39)))
113
114#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100115
116/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#define W83781D_REG_ALARM1 0x41
118#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Jean Delvare05663362007-11-30 23:51:24 +0100120/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100121#define W83782D_REG_ALARM1 0x459
122#define W83782D_REG_ALARM2 0x45A
123#define W83782D_REG_ALARM3 0x45B
124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#define W83781D_REG_BEEP_CONFIG 0x4D
126#define W83781D_REG_BEEP_INTS1 0x56
127#define W83781D_REG_BEEP_INTS2 0x57
128#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
129
130#define W83781D_REG_VID_FANDIV 0x47
131
132#define W83781D_REG_CHIPID 0x49
133#define W83781D_REG_WCHIPID 0x58
134#define W83781D_REG_CHIPMAN 0x4F
135#define W83781D_REG_PIN 0x4B
136
137/* 782D/783S only */
138#define W83781D_REG_VBAT 0x5D
139
140/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200141static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142#define W83781D_REG_PWMCLK12 0x5C
143#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145#define W83781D_REG_I2C_ADDR 0x48
146#define W83781D_REG_I2C_SUBADDR 0x4A
147
148/* The following are undocumented in the data sheets however we
149 received the information in an email from Winbond tech support */
150/* Sensor selection - not on 781d */
151#define W83781D_REG_SCFG1 0x5D
152static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
153
154#define W83781D_REG_SCFG2 0x59
155static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
156
157#define W83781D_DEFAULT_BETA 3435
158
Jean Delvare474d00a2007-05-08 17:22:03 +0200159/* Conversions */
160#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
161#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163static inline u8
164FAN_TO_REG(long rpm, int div)
165{
166 if (rpm == 0)
167 return 255;
168 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
169 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
170}
171
Jean Delvare474d00a2007-05-08 17:22:03 +0200172static inline long
173FAN_FROM_REG(u8 val, int div)
174{
175 if (val == 0)
176 return -1;
177 if (val == 255)
178 return 0;
179 return 1350000 / (val * div);
180}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Jean Delvare474d00a2007-05-08 17:22:03 +0200182#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
183#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200186 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200188 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define DIV_FROM_REG(val) (1 << (val))
191
192static inline u8
193DIV_TO_REG(long val, enum chips type)
194{
195 int i;
196 val = SENSORS_LIMIT(val, 1,
197 ((type == w83781d
198 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000199 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 if (val == 0)
201 break;
202 val >>= 1;
203 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200204 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207struct w83781d_data {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200208 struct i2c_client *client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700209 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100210 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 enum chips type;
212
Jean Delvare360782d2008-10-17 17:51:19 +0200213 /* For ISA device only */
214 const char *name;
215 int isa_addr;
216
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100217 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 char valid; /* !=0 if following fields are valid */
219 unsigned long last_updated; /* In jiffies */
220
221 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
222 /* array of 2 pointers to subclients */
223
224 u8 in[9]; /* Register value - 8 & 9 for 782D only */
225 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
226 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
227 u8 fan[3]; /* Register value */
228 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200229 s8 temp; /* Register value */
230 s8 temp_max; /* Register value */
231 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 u16 temp_add[2]; /* Register value */
233 u16 temp_max_add[2]; /* Register value */
234 u16 temp_max_hyst_add[2]; /* Register value */
235 u8 fan_div[3]; /* Register encoding, shifted right */
236 u8 vid; /* Register encoding, combined */
237 u32 alarms; /* Register encoding, combined */
238 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200240 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 u16 sens[3]; /* 782D/783S only.
242 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200243 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 u8 vrm;
245};
246
Wolfgang Grandegger443850c2008-10-17 17:51:18 +0200247static struct w83781d_data *w83781d_data_if_isa(void);
248static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
249
Jean Delvare31b8dc42007-05-08 17:22:03 +0200250static int w83781d_read_value(struct w83781d_data *data, u16 reg);
251static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200253static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255/* following are the sysfs callback functions */
256#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200257static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
258 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{ \
Jean Delvare34875332007-05-08 17:22:03 +0200260 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200262 return sprintf(buf, "%ld\n", \
263 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265show_in_reg(in);
266show_in_reg(in_min);
267show_in_reg(in_max);
268
269#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200270static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
271 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{ \
Jean Delvare34875332007-05-08 17:22:03 +0200273 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200274 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200275 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 u32 val; \
277 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200278 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100280 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200282 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100284 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return count; \
286}
287store_in_reg(MIN, min);
288store_in_reg(MAX, max);
289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200291static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
292 show_in, NULL, offset); \
293static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
294 show_in_min, store_in_min, offset); \
295static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
296 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298sysfs_in_offsets(0);
299sysfs_in_offsets(1);
300sysfs_in_offsets(2);
301sysfs_in_offsets(3);
302sysfs_in_offsets(4);
303sysfs_in_offsets(5);
304sysfs_in_offsets(6);
305sysfs_in_offsets(7);
306sysfs_in_offsets(8);
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200309static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
310 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{ \
Jean Delvare34875332007-05-08 17:22:03 +0200312 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct w83781d_data *data = w83781d_update_device(dev); \
314 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200315 FAN_FROM_REG(data->reg[attr->index], \
316 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318show_fan_reg(fan);
319show_fan_reg(fan_min);
320
321static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200322store_fan_min(struct device *dev, struct device_attribute *da,
323 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Jean Delvare34875332007-05-08 17:22:03 +0200325 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200326 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200327 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 u32 val;
329
330 val = simple_strtoul(buf, NULL, 10);
331
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100332 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200333 data->fan_min[nr] =
334 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200335 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200336 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100338 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return count;
340}
341
Jean Delvare34875332007-05-08 17:22:03 +0200342static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
343static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
344 show_fan_min, store_fan_min, 0);
345static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
346static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
347 show_fan_min, store_fan_min, 1);
348static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
349static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
350 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200353static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
354 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{ \
Jean Delvare34875332007-05-08 17:22:03 +0200356 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200358 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
360 return sprintf(buf,"%d\n", \
361 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
362 } else { /* TEMP1 */ \
363 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
364 } \
365}
366show_temp_reg(temp);
367show_temp_reg(temp_max);
368show_temp_reg(temp_max_hyst);
369
370#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200371static ssize_t store_temp_##reg (struct device *dev, \
372 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{ \
Jean Delvare34875332007-05-08 17:22:03 +0200374 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200375 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200376 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200377 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 \
379 val = simple_strtol(buf, NULL, 10); \
380 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100381 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 \
383 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
384 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200385 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 data->temp_##reg##_add[nr-2]); \
387 } else { /* TEMP1 */ \
388 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200389 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 data->temp_##reg); \
391 } \
392 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100393 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return count; \
395}
396store_temp_reg(OVER, max);
397store_temp_reg(HYST, max_hyst);
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200400static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
401 show_temp, NULL, offset); \
402static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
403 show_temp_max, store_temp_max, offset); \
404static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
405 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407sysfs_temp_offsets(1);
408sysfs_temp_offsets(2);
409sysfs_temp_offsets(3);
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400412show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
414 struct w83781d_data *data = w83781d_update_device(dev);
415 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
416}
417
Jim Cromie311ce2e2006-09-24 21:22:52 +0200418static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400421show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
Jean Delvare90d66192007-10-08 18:24:35 +0200423 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return sprintf(buf, "%ld\n", (long) data->vrm);
425}
426
427static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400428store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
Jean Delvare7666c132007-05-08 17:22:02 +0200430 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 u32 val;
432
433 val = simple_strtoul(buf, NULL, 10);
434 data->vrm = val;
435
436 return count;
437}
438
Jim Cromie311ce2e2006-09-24 21:22:52 +0200439static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400442show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200445 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
Jim Cromie311ce2e2006-09-24 21:22:52 +0200448static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
449
Jean Delvare7d4a1372007-10-08 18:29:43 +0200450static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
451 char *buf)
452{
453 struct w83781d_data *data = w83781d_update_device(dev);
454 int bitnr = to_sensor_dev_attr(attr)->index;
455 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
456}
457
458/* The W83781D has a single alarm bit for temp2 and temp3 */
459static ssize_t show_temp3_alarm(struct device *dev,
460 struct device_attribute *attr, char *buf)
461{
462 struct w83781d_data *data = w83781d_update_device(dev);
463 int bitnr = (data->type == w83781d) ? 5 : 13;
464 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
465}
466
467static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
468static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
469static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
470static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
471static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
472static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
473static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
474static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
475static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
476static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
477static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
478static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
479static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
480static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
481static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
482
Yani Ioannoue404e272005-05-17 06:42:58 -0400483static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct w83781d_data *data = w83781d_update_device(dev);
486 return sprintf(buf, "%ld\n",
487 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
488}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200491store_beep_mask(struct device *dev, struct device_attribute *attr,
492 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
Jean Delvare7666c132007-05-08 17:22:02 +0200494 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200495 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 val = simple_strtoul(buf, NULL, 10);
498
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100499 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200500 data->beep_mask &= 0x8000; /* preserve beep enable */
501 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200502 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
503 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200504 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200505 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200506 if (data->type != w83781d && data->type != as99127f) {
507 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
508 ((data->beep_mask) >> 16) & 0xff);
509 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100510 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return count;
513}
514
Jean Delvare34875332007-05-08 17:22:03 +0200515static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
516 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Jean Delvare7d4a1372007-10-08 18:29:43 +0200518static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
519 char *buf)
520{
521 struct w83781d_data *data = w83781d_update_device(dev);
522 int bitnr = to_sensor_dev_attr(attr)->index;
523 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
524}
525
526static ssize_t
527store_beep(struct device *dev, struct device_attribute *attr,
528 const char *buf, size_t count)
529{
530 struct w83781d_data *data = dev_get_drvdata(dev);
531 int bitnr = to_sensor_dev_attr(attr)->index;
532 unsigned long bit;
533 u8 reg;
534
535 bit = simple_strtoul(buf, NULL, 10);
536 if (bit & ~1)
537 return -EINVAL;
538
539 mutex_lock(&data->update_lock);
540 if (bit)
541 data->beep_mask |= (1 << bitnr);
542 else
543 data->beep_mask &= ~(1 << bitnr);
544
545 if (bitnr < 8) {
546 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
547 if (bit)
548 reg |= (1 << bitnr);
549 else
550 reg &= ~(1 << bitnr);
551 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
552 } else if (bitnr < 16) {
553 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
554 if (bit)
555 reg |= (1 << (bitnr - 8));
556 else
557 reg &= ~(1 << (bitnr - 8));
558 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
559 } else {
560 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
561 if (bit)
562 reg |= (1 << (bitnr - 16));
563 else
564 reg &= ~(1 << (bitnr - 16));
565 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
566 }
567 mutex_unlock(&data->update_lock);
568
569 return count;
570}
571
572/* The W83781D has a single beep bit for temp2 and temp3 */
573static ssize_t show_temp3_beep(struct device *dev,
574 struct device_attribute *attr, char *buf)
575{
576 struct w83781d_data *data = w83781d_update_device(dev);
577 int bitnr = (data->type == w83781d) ? 5 : 13;
578 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
579}
580
581static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
582 show_beep, store_beep, 0);
583static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
584 show_beep, store_beep, 1);
585static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
586 show_beep, store_beep, 2);
587static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
588 show_beep, store_beep, 3);
589static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
590 show_beep, store_beep, 8);
591static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
592 show_beep, store_beep, 9);
593static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
594 show_beep, store_beep, 10);
595static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
596 show_beep, store_beep, 16);
597static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
598 show_beep, store_beep, 17);
599static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
600 show_beep, store_beep, 6);
601static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
602 show_beep, store_beep, 7);
603static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
604 show_beep, store_beep, 11);
605static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
606 show_beep, store_beep, 4);
607static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
608 show_beep, store_beep, 5);
609static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
610 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200611static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
612 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200615show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
Jean Delvare34875332007-05-08 17:22:03 +0200617 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 struct w83781d_data *data = w83781d_update_device(dev);
619 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200620 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
623/* Note: we save and restore the fan minimum here, because its value is
624 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200625 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 because the divisor changed. */
627static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200628store_fan_div(struct device *dev, struct device_attribute *da,
629 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Jean Delvare34875332007-05-08 17:22:03 +0200631 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200632 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200634 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 u8 reg;
636 unsigned long val = simple_strtoul(buf, NULL, 10);
637
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100638 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 /* Save fan_min */
641 min = FAN_FROM_REG(data->fan_min[nr],
642 DIV_FROM_REG(data->fan_div[nr]));
643
644 data->fan_div[nr] = DIV_TO_REG(val, data->type);
645
Jean Delvare31b8dc42007-05-08 17:22:03 +0200646 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 & (nr==0 ? 0xcf : 0x3f))
648 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200649 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 /* w83781d and as99127f don't have extended divisor bits */
652 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200653 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 & ~(1 << (5 + nr)))
655 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200656 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658
659 /* Restore fan_min */
660 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200661 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100663 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return count;
665}
666
Jean Delvare34875332007-05-08 17:22:03 +0200667static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
668 show_fan_div, store_fan_div, 0);
669static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
670 show_fan_div, store_fan_div, 1);
671static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
672 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200675show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Jean Delvare34875332007-05-08 17:22:03 +0200677 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200679 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200683show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200686 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200690store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
691 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
Jean Delvare34875332007-05-08 17:22:03 +0200693 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200694 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200695 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 u32 val;
697
698 val = simple_strtoul(buf, NULL, 10);
699
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100700 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200701 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
702 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100703 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return count;
705}
706
707static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200708store_pwm2_enable(struct device *dev, struct device_attribute *da,
709 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Jean Delvare7666c132007-05-08 17:22:02 +0200711 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 u32 val, reg;
713
714 val = simple_strtoul(buf, NULL, 10);
715
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100716 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 switch (val) {
719 case 0:
720 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200721 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
722 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 (reg & 0xf7) | (val << 3));
724
Jean Delvare31b8dc42007-05-08 17:22:03 +0200725 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
726 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 (reg & 0xef) | (!val << 4));
728
Jean Delvare34875332007-05-08 17:22:03 +0200729 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 break;
731
732 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100733 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return -EINVAL;
735 }
736
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100737 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return count;
739}
740
Jean Delvare34875332007-05-08 17:22:03 +0200741static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
742static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
743static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
744static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
745/* only PWM2 can be enabled/disabled */
746static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
747 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200750show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Jean Delvare34875332007-05-08 17:22:03 +0200752 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200754 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755}
756
757static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200758store_sensor(struct device *dev, struct device_attribute *da,
759 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Jean Delvare34875332007-05-08 17:22:03 +0200761 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200762 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200763 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 u32 val, tmp;
765
766 val = simple_strtoul(buf, NULL, 10);
767
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100768 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 switch (val) {
771 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200772 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
773 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200774 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200775 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
776 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200777 tmp | BIT_SCFG2[nr]);
778 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 break;
780 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200781 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
782 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200783 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200784 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
785 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200786 tmp & ~BIT_SCFG2[nr]);
787 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200789 case W83781D_DEFAULT_BETA:
790 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
791 "instead\n", W83781D_DEFAULT_BETA);
792 /* fall through */
793 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200794 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
795 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200796 tmp & ~BIT_SCFG1[nr]);
797 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 break;
799 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200800 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
801 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 break;
803 }
804
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100805 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return count;
807}
808
Jean Delvare34875332007-05-08 17:22:03 +0200809static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
810 show_sensor, store_sensor, 0);
811static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400812 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200813static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400814 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816/* Assumes that adapter is of I2C, not ISA variety.
817 * OTHERWISE DON'T CALL THIS
818 */
819static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200820w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
822 int i, val1 = 0, id;
823 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200824 int address = new_client->addr;
825 unsigned short sc_addr[2];
826 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200828 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 id = i2c_adapter_id(adapter);
831
832 if (force_subclients[0] == id && force_subclients[1] == address) {
833 for (i = 2; i <= 3; i++) {
834 if (force_subclients[i] < 0x48 ||
835 force_subclients[i] > 0x4f) {
836 dev_err(&new_client->dev, "Invalid subclient "
837 "address %d; must be 0x48-0x4f\n",
838 force_subclients[i]);
839 err = -EINVAL;
840 goto ERROR_SC_1;
841 }
842 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200843 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 (force_subclients[2] & 0x07) |
845 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200846 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200848 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200849 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851
852 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (force_subclients[0] == id &&
854 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200855 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200857 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200859 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 dev_err(&new_client->dev,
861 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200862 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 err = -EBUSY;
864 goto ERROR_SC_2;
865 }
866 }
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200869 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
870 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 dev_err(&new_client->dev, "Subclient %d "
872 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200873 "failed.\n", i, sc_addr[i]);
874 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (i == 1)
876 goto ERROR_SC_3;
877 goto ERROR_SC_2;
878 }
879 if (kind == w83783s)
880 break;
881 }
882
883 return 0;
884
885/* Undo inits in case of errors */
886ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200887 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return err;
891}
892
Jean Delvare34875332007-05-08 17:22:03 +0200893#define IN_UNIT_ATTRS(X) \
894 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
895 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100896 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200897 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
898 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200899
Jean Delvare34875332007-05-08 17:22:03 +0200900#define FAN_UNIT_ATTRS(X) \
901 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
902 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200903 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
904 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
905 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200906
Jean Delvare34875332007-05-08 17:22:03 +0200907#define TEMP_UNIT_ATTRS(X) \
908 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
909 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200910 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
911 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
912 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200913
914static struct attribute* w83781d_attributes[] = {
915 IN_UNIT_ATTRS(0),
916 IN_UNIT_ATTRS(2),
917 IN_UNIT_ATTRS(3),
918 IN_UNIT_ATTRS(4),
919 IN_UNIT_ATTRS(5),
920 IN_UNIT_ATTRS(6),
921 FAN_UNIT_ATTRS(1),
922 FAN_UNIT_ATTRS(2),
923 FAN_UNIT_ATTRS(3),
924 TEMP_UNIT_ATTRS(1),
925 TEMP_UNIT_ATTRS(2),
926 &dev_attr_cpu0_vid.attr,
927 &dev_attr_vrm.attr,
928 &dev_attr_alarms.attr,
929 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200930 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200931 NULL
932};
933static const struct attribute_group w83781d_group = {
934 .attrs = w83781d_attributes,
935};
936
937static struct attribute *w83781d_attributes_opt[] = {
938 IN_UNIT_ATTRS(1),
939 IN_UNIT_ATTRS(7),
940 IN_UNIT_ATTRS(8),
941 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200942 &sensor_dev_attr_pwm1.dev_attr.attr,
943 &sensor_dev_attr_pwm2.dev_attr.attr,
944 &sensor_dev_attr_pwm3.dev_attr.attr,
945 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200946 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200947 &sensor_dev_attr_temp1_type.dev_attr.attr,
948 &sensor_dev_attr_temp2_type.dev_attr.attr,
949 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200950 NULL
951};
952static const struct attribute_group w83781d_group_opt = {
953 .attrs = w83781d_attributes_opt,
954};
955
Jean Delvare7666c132007-05-08 17:22:02 +0200956/* No clean up is done on error, it's up to the caller */
957static int
958w83781d_create_files(struct device *dev, int kind, int is_isa)
959{
960 int err;
961
962 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
963 return err;
964
965 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200966 if ((err = device_create_file(dev,
967 &sensor_dev_attr_in1_input.dev_attr))
968 || (err = device_create_file(dev,
969 &sensor_dev_attr_in1_min.dev_attr))
970 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200971 &sensor_dev_attr_in1_max.dev_attr))
972 || (err = device_create_file(dev,
973 &sensor_dev_attr_in1_alarm.dev_attr))
974 || (err = device_create_file(dev,
975 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200976 return err;
977 }
978 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200979 if ((err = device_create_file(dev,
980 &sensor_dev_attr_in7_input.dev_attr))
981 || (err = device_create_file(dev,
982 &sensor_dev_attr_in7_min.dev_attr))
983 || (err = device_create_file(dev,
984 &sensor_dev_attr_in7_max.dev_attr))
985 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200986 &sensor_dev_attr_in7_alarm.dev_attr))
987 || (err = device_create_file(dev,
988 &sensor_dev_attr_in7_beep.dev_attr))
989 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200990 &sensor_dev_attr_in8_input.dev_attr))
991 || (err = device_create_file(dev,
992 &sensor_dev_attr_in8_min.dev_attr))
993 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200994 &sensor_dev_attr_in8_max.dev_attr))
995 || (err = device_create_file(dev,
996 &sensor_dev_attr_in8_alarm.dev_attr))
997 || (err = device_create_file(dev,
998 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200999 return err;
1000 }
1001 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001002 if ((err = device_create_file(dev,
1003 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001004 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001005 &sensor_dev_attr_temp3_max.dev_attr))
1006 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001007 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1008 || (err = device_create_file(dev,
1009 &sensor_dev_attr_temp3_alarm.dev_attr))
1010 || (err = device_create_file(dev,
1011 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001012 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001013
Jean Delvare7768aa72007-10-25 13:11:01 +02001014 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001015 err = sysfs_chmod_file(&dev->kobj,
1016 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1017 S_IRUGO | S_IWUSR);
1018 if (err)
1019 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001020 }
Jean Delvare7666c132007-05-08 17:22:02 +02001021 }
1022
1023 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001024 if ((err = device_create_file(dev,
1025 &sensor_dev_attr_pwm1.dev_attr))
1026 || (err = device_create_file(dev,
1027 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001028 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1029 return err;
1030 }
1031 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001032 if ((err = device_create_file(dev,
1033 &sensor_dev_attr_pwm3.dev_attr))
1034 || (err = device_create_file(dev,
1035 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001036 return err;
1037 }
1038
1039 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001040 if ((err = device_create_file(dev,
1041 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001042 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001043 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001044 return err;
1045 if (kind != w83783s) {
1046 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001047 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001048 return err;
1049 }
1050 }
1051
Jean Delvare7666c132007-05-08 17:22:02 +02001052 return 0;
1053}
1054
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001055/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056static int
Jean Delvare310ec792009-12-14 21:17:23 +01001057w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Jean Delvarebab2bf42009-12-09 20:35:54 +01001059 int val1, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001060 struct w83781d_data *isa = w83781d_data_if_isa();
1061 struct i2c_adapter *adapter = client->adapter;
1062 int address = client->addr;
Jean Delvarebab2bf42009-12-09 20:35:54 +01001063 const char *client_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 enum vendor { winbond, asus } vendid;
1065
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001066 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1067 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001069 /* We block updates of the ISA device to minimize the risk of
1070 concurrent access to the same W83781D chip through different
1071 interfaces. */
1072 if (isa)
1073 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jean Delvarebab2bf42009-12-09 20:35:54 +01001075 if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1076 dev_dbg(&adapter->dev,
1077 "Detection of w83781d chip failed at step 3\n");
1078 goto err_nodev;
1079 }
1080
1081 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1082 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1083 /* Check for Winbond or Asus ID if in bank 0 */
1084 if (!(val1 & 0x07) &&
1085 ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
1086 ( (val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
1087 dev_dbg(&adapter->dev,
1088 "Detection of w83781d chip failed at step 4\n");
1089 goto err_nodev;
1090 }
1091 /* If Winbond SMBus, check address at 0x48.
1092 Asus doesn't support, except for as99127f rev.2 */
1093 if ((!(val1 & 0x80) && val2 == 0xa3) ||
1094 ( (val1 & 0x80) && val2 == 0x5c)) {
1095 if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1096 != address) {
1097 dev_dbg(&adapter->dev,
1098 "Detection of w83781d chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001099 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102
Jean Delvarebab2bf42009-12-09 20:35:54 +01001103 /* Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001104 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1105 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1106 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Jean Delvarebab2bf42009-12-09 20:35:54 +01001108 /* Get the vendor ID */
1109 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1110 if (val2 == 0x5c)
1111 vendid = winbond;
1112 else if (val2 == 0x12)
1113 vendid = asus;
1114 else {
1115 dev_dbg(&adapter->dev,
1116 "w83781d chip vendor is neither Winbond nor Asus\n");
1117 goto err_nodev;
1118 }
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 /* Determine the chip type. */
Jean Delvarebab2bf42009-12-09 20:35:54 +01001121 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
1122 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1123 client_name = "w83781d";
1124 else if (val1 == 0x30 && vendid == winbond)
1125 client_name = "w83782d";
1126 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1127 client_name = "w83783s";
1128 else if (val1 == 0x31)
1129 client_name = "as99127f";
1130 else
1131 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jean Delvarebab2bf42009-12-09 20:35:54 +01001133 if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1134 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1135 "be the same as ISA device\n", address);
1136 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001139 if (isa)
1140 mutex_unlock(&isa->update_lock);
1141
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001142 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001144 return 0;
1145
1146 err_nodev:
1147 if (isa)
1148 mutex_unlock(&isa->update_lock);
1149 return -ENODEV;
1150}
1151
1152static int
1153w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1154{
1155 struct device *dev = &client->dev;
1156 struct w83781d_data *data;
1157 int err;
1158
1159 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1160 if (!data) {
1161 err = -ENOMEM;
1162 goto ERROR1;
1163 }
1164
1165 i2c_set_clientdata(client, data);
1166 mutex_init(&data->lock);
1167 mutex_init(&data->update_lock);
1168
1169 data->type = id->driver_data;
1170 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001173 err = w83781d_detect_subclients(client);
1174 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001175 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001178 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001181 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001182 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001183 goto ERROR4;
1184
Tony Jones1beeffe2007-08-20 13:46:20 -07001185 data->hwmon_dev = hwmon_device_register(dev);
1186 if (IS_ERR(data->hwmon_dev)) {
1187 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001188 goto ERROR4;
1189 }
1190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 return 0;
1192
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001193ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001194 sysfs_remove_group(&dev->kobj, &w83781d_group);
1195 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1196
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001197 if (data->lm75[0])
1198 i2c_unregister_device(data->lm75[0]);
1199 if (data->lm75[1])
1200 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201ERROR3:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 kfree(data);
1203ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return err;
1205}
1206
1207static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001208w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001210 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001211 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001213 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001215 sysfs_remove_group(&dev->kobj, &w83781d_group);
1216 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001218 if (data->lm75[0])
1219 i2c_unregister_device(data->lm75[0]);
1220 if (data->lm75[1])
1221 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001222
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001223 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 return 0;
1226}
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001229w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001231 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001232 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct i2c_client *cl;
1234
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001235 bank = (reg >> 8) & 0x0f;
1236 if (bank > 2)
1237 /* switch banks */
1238 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1239 bank);
1240 if (bank == 0 || bank > 2) {
1241 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001243 /* switch to subclient */
1244 cl = data->lm75[bank - 1];
1245 /* convert from ISA to LM75 I2C addresses */
1246 switch (reg & 0xff) {
1247 case 0x50: /* TEMP */
Jean Delvare90f41022011-11-04 12:00:47 +01001248 res = i2c_smbus_read_word_swapped(cl, 0);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001249 break;
1250 case 0x52: /* CONFIG */
1251 res = i2c_smbus_read_byte_data(cl, 1);
1252 break;
1253 case 0x53: /* HYST */
Jean Delvare90f41022011-11-04 12:00:47 +01001254 res = i2c_smbus_read_word_swapped(cl, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001255 break;
1256 case 0x55: /* OVER */
1257 default:
Jean Delvare90f41022011-11-04 12:00:47 +01001258 res = i2c_smbus_read_word_swapped(cl, 3);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001259 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001262 if (bank > 2)
1263 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 return res;
1266}
1267
1268static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001269w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001271 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001272 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 struct i2c_client *cl;
1274
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001275 bank = (reg >> 8) & 0x0f;
1276 if (bank > 2)
1277 /* switch banks */
1278 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1279 bank);
1280 if (bank == 0 || bank > 2) {
1281 i2c_smbus_write_byte_data(client, reg & 0xff,
1282 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001284 /* switch to subclient */
1285 cl = data->lm75[bank - 1];
1286 /* convert from ISA to LM75 I2C addresses */
1287 switch (reg & 0xff) {
1288 case 0x52: /* CONFIG */
1289 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1290 break;
1291 case 0x53: /* HYST */
Jean Delvare90f41022011-11-04 12:00:47 +01001292 i2c_smbus_write_word_swapped(cl, 2, value);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001293 break;
1294 case 0x55: /* OVER */
Jean Delvare90f41022011-11-04 12:00:47 +01001295 i2c_smbus_write_word_swapped(cl, 3, value);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001296 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001299 if (bank > 2)
1300 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 return 0;
1303}
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305static void
Jean Delvare7666c132007-05-08 17:22:02 +02001306w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307{
Jean Delvare7666c132007-05-08 17:22:02 +02001308 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 int i, p;
1310 int type = data->type;
1311 u8 tmp;
1312
Jean Delvarefabddcd2006-02-05 23:26:51 +01001313 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001315 /* Resetting the chip has been the default for a long time,
1316 but it causes the BIOS initializations (fan clock dividers,
1317 thermal sensor types...) to be lost, so it is now optional.
1318 It might even go away if nobody reports it as being useful,
1319 as I see very little reason why this would be needed at
1320 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001321 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001322 "having, please report!\n");
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001325 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1326 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 /* Reset all except Watchdog values and last conversion values
1328 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001329 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 /* Restore the registers and disable power-on abnormal beep.
1331 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001332 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1333 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 /* Disable master beep-enable (reset turns it on).
1335 Individual beep_mask should be reset to off but for some reason
1336 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001337 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339
Jean Delvarefabddcd2006-02-05 23:26:51 +01001340 /* Disable power-on abnormal beep, as advised by the datasheet.
1341 Already done if reset=1. */
1342 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001343 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1344 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001345 }
1346
Jean Delvare303760b2005-07-31 21:52:01 +02001347 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001350 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 for (i = 1; i <= 3; i++) {
1352 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001353 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 } else {
1355 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001356 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1358 data->sens[i - 1] = 1;
1359 else
1360 data->sens[i - 1] = 2;
1361 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001362 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 break;
1364 }
1365 }
1366
1367 if (init && type != as99127f) {
1368 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001369 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001371 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001373 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 tmp & 0xfe);
1375 }
1376
1377 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001378 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001379 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 W83781D_REG_TEMP3_CONFIG);
1381 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001382 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001384 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1386 }
1387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
1389
1390 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001391 w83781d_write_value(data, W83781D_REG_CONFIG,
1392 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 W83781D_REG_CONFIG) & 0xf7)
1394 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001395
1396 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001397 for (i = 0; i < 3; i++) {
1398 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001399 W83781D_REG_FAN_MIN(i));
1400 }
Jean Delvare7666c132007-05-08 17:22:02 +02001401
1402 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403}
1404
1405static struct w83781d_data *w83781d_update_device(struct device *dev)
1406{
Jean Delvare7666c132007-05-08 17:22:02 +02001407 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001408 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 int i;
1410
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001411 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1414 || !data->valid) {
1415 dev_dbg(dev, "Starting device update\n");
1416
1417 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001418 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 continue; /* 783S has no in1 */
1420 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001421 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001423 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001425 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001426 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 break;
1428 }
Jean Delvare34875332007-05-08 17:22:03 +02001429 for (i = 0; i < 3; i++) {
1430 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001431 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001432 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001433 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 }
1435 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001436 for (i = 0; i < 4; i++) {
1437 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001438 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001439 W83781D_REG_PWM[i]);
Jean Delvare848ddf12009-05-08 20:27:28 +02001440 /* Only W83782D on SMBus has PWM3 and PWM4 */
1441 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001442 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 break;
1444 }
1445 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001446 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1448 }
1449
Jean Delvare31b8dc42007-05-08 17:22:03 +02001450 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001452 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001454 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001456 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001458 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001460 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001461 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001463 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001465 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 W83781D_REG_TEMP_OVER(3));
1467 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001468 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 W83781D_REG_TEMP_HYST(3));
1470 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001471 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001472 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001473 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001474 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 data->fan_div[0] = (i >> 4) & 0x03;
1476 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001477 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001478 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001480 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 data->fan_div[0] |= (i >> 3) & 0x04;
1482 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001483 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 }
Jean Delvare05663362007-11-30 23:51:24 +01001485 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001486 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001487 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001489 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001490 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001491 W83782D_REG_ALARM3) << 16);
1492 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001493 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001494 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001495 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001496 W83782D_REG_ALARM2) << 8);
1497 } else {
1498 /* No real-time status registers, fall back to
1499 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001500 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001501 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001502 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001503 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001505 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001506 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001507 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if ((data->type != w83781d) && (data->type != as99127f)) {
1509 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001510 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 W83781D_REG_BEEP_INTS3) << 16;
1512 }
1513 data->last_updated = jiffies;
1514 data->valid = 1;
1515 }
1516
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001517 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
1519 return data;
1520}
1521
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001522static const struct i2c_device_id w83781d_ids[] = {
1523 { "w83781d", w83781d, },
1524 { "w83782d", w83782d, },
1525 { "w83783s", w83783s, },
1526 { "as99127f", as99127f },
1527 { /* LIST END */ }
1528};
1529MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1530
1531static struct i2c_driver w83781d_driver = {
1532 .class = I2C_CLASS_HWMON,
1533 .driver = {
1534 .name = "w83781d",
1535 },
1536 .probe = w83781d_probe,
1537 .remove = w83781d_remove,
1538 .id_table = w83781d_ids,
1539 .detect = w83781d_detect,
Jean Delvarec3813d62009-12-14 21:17:25 +01001540 .address_list = normal_i2c,
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001541};
1542
1543/*
1544 * ISA related code
1545 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001546#ifdef CONFIG_ISA
1547
1548/* ISA device, if found */
1549static struct platform_device *pdev;
1550
1551static unsigned short isa_address = 0x290;
1552
1553/* I2C devices get this name attribute automatically, but for ISA devices
1554 we must create it by ourselves. */
1555static ssize_t
1556show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1557{
1558 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001559 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001560}
1561static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1562
1563static struct w83781d_data *w83781d_data_if_isa(void)
1564{
1565 return pdev ? platform_get_drvdata(pdev) : NULL;
1566}
1567
1568/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1569static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1570{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001571 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001572 int i;
1573
1574 if (!pdev) /* No ISA chip */
1575 return 0;
1576
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001577 isa = platform_get_drvdata(pdev);
1578
1579 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1580 return 0; /* Address doesn't match */
1581 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1582 return 0; /* Chip type doesn't match */
1583
1584 /* We compare all the limit registers, the config register and the
1585 * interrupt mask registers */
1586 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001587 if (w83781d_read_value(isa, i) !=
1588 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001589 return 0;
1590 }
1591 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001592 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001593 return 0;
1594 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001595 if (w83781d_read_value(isa, i) !=
1596 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001597 return 0;
1598 }
1599
1600 return 1;
1601}
1602
1603static int
1604w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1605{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001606 int word_sized, res;
1607
1608 word_sized = (((reg & 0xff00) == 0x100)
1609 || ((reg & 0xff00) == 0x200))
1610 && (((reg & 0x00ff) == 0x50)
1611 || ((reg & 0x00ff) == 0x53)
1612 || ((reg & 0x00ff) == 0x55));
1613 if (reg & 0xff00) {
1614 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001615 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001616 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001617 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001618 }
Jean Delvare360782d2008-10-17 17:51:19 +02001619 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1620 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001621 if (word_sized) {
1622 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001623 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001624 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001625 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001626 W83781D_DATA_REG_OFFSET);
1627 }
1628 if (reg & 0xff00) {
1629 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001630 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1631 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001632 }
1633 return res;
1634}
1635
1636static void
1637w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1638{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001639 int word_sized;
1640
1641 word_sized = (((reg & 0xff00) == 0x100)
1642 || ((reg & 0xff00) == 0x200))
1643 && (((reg & 0x00ff) == 0x53)
1644 || ((reg & 0x00ff) == 0x55));
1645 if (reg & 0xff00) {
1646 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001647 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001648 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001649 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001650 }
Jean Delvare360782d2008-10-17 17:51:19 +02001651 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001652 if (word_sized) {
1653 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001654 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001655 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001656 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001657 }
Jean Delvare360782d2008-10-17 17:51:19 +02001658 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001659 if (reg & 0xff00) {
1660 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001661 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1662 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001663 }
1664}
1665
1666/* The SMBus locks itself, usually, but nothing may access the Winbond between
1667 bank switches. ISA access must always be locked explicitly!
1668 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1669 would slow down the W83781D access and should not be necessary.
1670 There are some ugly typecasts here, but the good news is - they should
1671 nowhere else be necessary! */
1672static int
1673w83781d_read_value(struct w83781d_data *data, u16 reg)
1674{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001675 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001676 int res;
1677
1678 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001679 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001680 res = w83781d_read_value_i2c(data, reg);
1681 else
1682 res = w83781d_read_value_isa(data, reg);
1683 mutex_unlock(&data->lock);
1684 return res;
1685}
1686
1687static int
1688w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1689{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001690 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001691
1692 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001693 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001694 w83781d_write_value_i2c(data, reg, value);
1695 else
1696 w83781d_write_value_isa(data, reg, value);
1697 mutex_unlock(&data->lock);
1698 return 0;
1699}
1700
1701static int __devinit
1702w83781d_isa_probe(struct platform_device *pdev)
1703{
1704 int err, reg;
1705 struct w83781d_data *data;
1706 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001707
1708 /* Reserve the ISA region */
1709 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1710 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1711 "w83781d")) {
1712 err = -EBUSY;
1713 goto exit;
1714 }
1715
1716 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1717 if (!data) {
1718 err = -ENOMEM;
1719 goto exit_release_region;
1720 }
1721 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001722 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001723 platform_set_drvdata(pdev, data);
1724
1725 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1726 switch (reg) {
1727 case 0x30:
1728 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001729 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001730 break;
1731 default:
1732 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001733 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001734 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001735
1736 /* Initialize the W83781D chip */
1737 w83781d_init_device(&pdev->dev);
1738
1739 /* Register sysfs hooks */
1740 err = w83781d_create_files(&pdev->dev, data->type, 1);
1741 if (err)
1742 goto exit_remove_files;
1743
1744 err = device_create_file(&pdev->dev, &dev_attr_name);
1745 if (err)
1746 goto exit_remove_files;
1747
1748 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1749 if (IS_ERR(data->hwmon_dev)) {
1750 err = PTR_ERR(data->hwmon_dev);
1751 goto exit_remove_files;
1752 }
1753
1754 return 0;
1755
1756 exit_remove_files:
1757 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1758 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1759 device_remove_file(&pdev->dev, &dev_attr_name);
1760 kfree(data);
1761 exit_release_region:
1762 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1763 exit:
1764 return err;
1765}
1766
1767static int __devexit
1768w83781d_isa_remove(struct platform_device *pdev)
1769{
1770 struct w83781d_data *data = platform_get_drvdata(pdev);
1771
1772 hwmon_device_unregister(data->hwmon_dev);
1773 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1774 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1775 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001776 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001777 kfree(data);
1778
1779 return 0;
1780}
1781
1782static struct platform_driver w83781d_isa_driver = {
1783 .driver = {
1784 .owner = THIS_MODULE,
1785 .name = "w83781d",
1786 },
1787 .probe = w83781d_isa_probe,
1788 .remove = __devexit_p(w83781d_isa_remove),
1789};
1790
Jean Delvare7666c132007-05-08 17:22:02 +02001791/* return 1 if a supported chip is found, 0 otherwise */
1792static int __init
1793w83781d_isa_found(unsigned short address)
1794{
1795 int val, save, found = 0;
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001796 int port;
Jean Delvare7666c132007-05-08 17:22:02 +02001797
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001798 /* Some boards declare base+0 to base+7 as a PNP device, some base+4
1799 * to base+7 and some base+5 to base+6. So we better request each port
1800 * individually for the probing phase. */
1801 for (port = address; port < address + W83781D_EXTENT; port++) {
1802 if (!request_region(port, 1, "w83781d")) {
Joe Perches1ca28212011-01-12 21:55:11 +01001803 pr_debug("Failed to request port 0x%x\n", port);
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001804 goto release;
1805 }
Jean Delvare2961cb22008-03-09 13:34:28 +01001806 }
Jean Delvare7666c132007-05-08 17:22:02 +02001807
1808#define REALLY_SLOW_IO
1809 /* We need the timeouts for at least some W83781D-like
1810 chips. But only if we read 'undefined' registers. */
1811 val = inb_p(address + 1);
1812 if (inb_p(address + 2) != val
1813 || inb_p(address + 3) != val
1814 || inb_p(address + 7) != val) {
Joe Perches1ca28212011-01-12 21:55:11 +01001815 pr_debug("Detection failed at step %d\n", 1);
Jean Delvare7666c132007-05-08 17:22:02 +02001816 goto release;
1817 }
1818#undef REALLY_SLOW_IO
1819
1820 /* We should be able to change the 7 LSB of the address port. The
1821 MSB (busy flag) should be clear initially, set after the write. */
1822 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1823 if (save & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001824 pr_debug("Detection failed at step %d\n", 2);
Jean Delvare7666c132007-05-08 17:22:02 +02001825 goto release;
1826 }
1827 val = ~save & 0x7f;
1828 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1829 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1830 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
Joe Perches1ca28212011-01-12 21:55:11 +01001831 pr_debug("Detection failed at step %d\n", 3);
Jean Delvare7666c132007-05-08 17:22:02 +02001832 goto release;
1833 }
1834
1835 /* We found a device, now see if it could be a W83781D */
1836 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1837 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1838 if (val & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001839 pr_debug("Detection failed at step %d\n", 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001840 goto release;
1841 }
1842 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1843 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1844 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1845 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1846 if ((!(save & 0x80) && (val != 0xa3))
1847 || ((save & 0x80) && (val != 0x5c))) {
Joe Perches1ca28212011-01-12 21:55:11 +01001848 pr_debug("Detection failed at step %d\n", 5);
Jean Delvare7666c132007-05-08 17:22:02 +02001849 goto release;
1850 }
1851 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1852 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1853 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
Joe Perches1ca28212011-01-12 21:55:11 +01001854 pr_debug("Detection failed at step %d\n", 6);
Jean Delvare7666c132007-05-08 17:22:02 +02001855 goto release;
1856 }
1857
1858 /* The busy flag should be clear again */
1859 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001860 pr_debug("Detection failed at step %d\n", 7);
Jean Delvare7666c132007-05-08 17:22:02 +02001861 goto release;
1862 }
1863
1864 /* Determine the chip type */
1865 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1866 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1867 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1868 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1869 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1870 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001871 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001872 found = 1;
1873
1874 if (found)
Joe Perches1ca28212011-01-12 21:55:11 +01001875 pr_info("Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001876 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1877
1878 release:
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001879 for (port--; port >= address; port--)
1880 release_region(port, 1);
Jean Delvare7666c132007-05-08 17:22:02 +02001881 return found;
1882}
1883
1884static int __init
1885w83781d_isa_device_add(unsigned short address)
1886{
1887 struct resource res = {
1888 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001889 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001890 .name = "w83781d",
1891 .flags = IORESOURCE_IO,
1892 };
1893 int err;
1894
1895 pdev = platform_device_alloc("w83781d", address);
1896 if (!pdev) {
1897 err = -ENOMEM;
Joe Perches1ca28212011-01-12 21:55:11 +01001898 pr_err("Device allocation failed\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001899 goto exit;
1900 }
1901
1902 err = platform_device_add_resources(pdev, &res, 1);
1903 if (err) {
Joe Perches1ca28212011-01-12 21:55:11 +01001904 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare7666c132007-05-08 17:22:02 +02001905 goto exit_device_put;
1906 }
1907
1908 err = platform_device_add(pdev);
1909 if (err) {
Joe Perches1ca28212011-01-12 21:55:11 +01001910 pr_err("Device addition failed (%d)\n", err);
Jean Delvare7666c132007-05-08 17:22:02 +02001911 goto exit_device_put;
1912 }
1913
1914 return 0;
1915
1916 exit_device_put:
1917 platform_device_put(pdev);
1918 exit:
1919 pdev = NULL;
1920 return err;
1921}
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001924w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925{
Jean Delvarefde09502005-07-19 23:51:07 +02001926 int res;
1927
Jean Delvare7666c132007-05-08 17:22:02 +02001928 if (w83781d_isa_found(isa_address)) {
1929 res = platform_driver_register(&w83781d_isa_driver);
1930 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001931 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001932
1933 /* Sets global pdev as a side effect */
1934 res = w83781d_isa_device_add(isa_address);
1935 if (res)
1936 goto exit_unreg_isa_driver;
1937 }
Jean Delvarefde09502005-07-19 23:51:07 +02001938
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001939 return 0;
1940
1941exit_unreg_isa_driver:
1942 platform_driver_unregister(&w83781d_isa_driver);
1943exit:
1944 return res;
1945}
1946
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001947static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001948w83781d_isa_unregister(void)
1949{
1950 if (pdev) {
1951 platform_device_unregister(pdev);
1952 platform_driver_unregister(&w83781d_isa_driver);
1953 }
1954}
1955#else /* !CONFIG_ISA */
1956
1957static struct w83781d_data *w83781d_data_if_isa(void)
1958{
1959 return NULL;
1960}
1961
1962static int
1963w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1964{
1965 return 0;
1966}
1967
1968static int
1969w83781d_read_value(struct w83781d_data *data, u16 reg)
1970{
1971 int res;
1972
1973 mutex_lock(&data->lock);
1974 res = w83781d_read_value_i2c(data, reg);
1975 mutex_unlock(&data->lock);
1976
1977 return res;
1978}
1979
1980static int
1981w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1982{
1983 mutex_lock(&data->lock);
1984 w83781d_write_value_i2c(data, reg, value);
1985 mutex_unlock(&data->lock);
1986
1987 return 0;
1988}
1989
1990static int __init
1991w83781d_isa_register(void)
1992{
1993 return 0;
1994}
1995
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001996static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001997w83781d_isa_unregister(void)
1998{
1999}
2000#endif /* CONFIG_ISA */
2001
2002static int __init
2003sensors_w83781d_init(void)
2004{
2005 int res;
2006
2007 /* We register the ISA device first, so that we can skip the
2008 * registration of an I2C interface to the same device. */
2009 res = w83781d_isa_register();
2010 if (res)
2011 goto exit;
2012
Jean Delvarec6566202008-10-17 17:51:18 +02002013 res = i2c_add_driver(&w83781d_driver);
2014 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002015 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002016
Jean Delvarefde09502005-07-19 23:51:07 +02002017 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002018
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002019 exit_unreg_isa:
2020 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002021 exit:
2022 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023}
2024
2025static void __exit
2026sensors_w83781d_exit(void)
2027{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002028 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 i2c_del_driver(&w83781d_driver);
2030}
2031
2032MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2033 "Philip Edelbrock <phil@netroedge.com>, "
2034 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2035MODULE_DESCRIPTION("W83781D driver");
2036MODULE_LICENSE("GPL");
2037
2038module_init(sensors_w83781d_init);
2039module_exit(sensors_w83781d_exit);