blob: e8a19005b7d2681b5fe5dc732cf5b791ba0a65b5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
Guenter Roeckc531eb32012-01-15 09:19:16 -08003 monitoring
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
Guenter Roeckc531eb32012-01-15 09:19:16 -08005 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
Rusty Russell90ab5ee2012-01-13 09:32:20 +103070static bool reset;
Jean Delvarefabddcd2006-02-05 23:26:51 +010071module_param(reset, bool, 0);
72MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
73
Rusty Russell90ab5ee2012-01-13 09:32:20 +103074static bool init = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075module_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
Guenter Roeckc531eb32012-01-15 09:19:16 -0800185#define BEEP_MASK_FROM_REG(val, type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200186 (~(val)) & 0x7fff : (val) & 0xff7fff)
Guenter Roeckc531eb32012-01-15 09:19:16 -0800187#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) \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800257static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
Jean Delvare34875332007-05-08 17:22:03 +0200258 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) \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800270static ssize_t store_in_##reg(struct device *dev, struct device_attribute \
Jean Delvare34875332007-05-08 17:22:03 +0200271 *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; \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800276 unsigned long val; \
277 int err = kstrtoul(buf, 10, &val); \
278 if (err) \
279 return err; \
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); \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800282 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), \
283 data->in_##reg[nr]); \
284 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100285 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 return count; \
287}
288store_in_reg(MIN, min);
289store_in_reg(MAX, max);
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200292static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
293 show_in, NULL, offset); \
294static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
295 show_in_min, store_in_min, offset); \
296static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
297 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299sysfs_in_offsets(0);
300sysfs_in_offsets(1);
301sysfs_in_offsets(2);
302sysfs_in_offsets(3);
303sysfs_in_offsets(4);
304sysfs_in_offsets(5);
305sysfs_in_offsets(6);
306sysfs_in_offsets(7);
307sysfs_in_offsets(8);
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309#define show_fan_reg(reg) \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800310static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
Jean Delvare34875332007-05-08 17:22:03 +0200311 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{ \
Jean Delvare34875332007-05-08 17:22:03 +0200313 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 struct w83781d_data *data = w83781d_update_device(dev); \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800315 return sprintf(buf, "%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200316 FAN_FROM_REG(data->reg[attr->index], \
317 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
319show_fan_reg(fan);
320show_fan_reg(fan_min);
321
322static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200323store_fan_min(struct device *dev, struct device_attribute *da,
324 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Jean Delvare34875332007-05-08 17:22:03 +0200326 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200327 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200328 int nr = attr->index;
Guenter Roeckc531eb32012-01-15 09:19:16 -0800329 unsigned long val;
330 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Guenter Roeckc531eb32012-01-15 09:19:16 -0800332 err = kstrtoul(buf, 10, &val);
333 if (err)
334 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100336 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200337 data->fan_min[nr] =
338 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200339 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200340 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100342 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return count;
344}
345
Jean Delvare34875332007-05-08 17:22:03 +0200346static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
347static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
348 show_fan_min, store_fan_min, 0);
349static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
350static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
351 show_fan_min, store_fan_min, 1);
352static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
353static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
354 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#define show_temp_reg(reg) \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800357static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
Jean Delvare34875332007-05-08 17:22:03 +0200358 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{ \
Jean Delvare34875332007-05-08 17:22:03 +0200360 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200362 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800364 return sprintf(buf, "%d\n", \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
366 } else { /* TEMP1 */ \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800367 return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->reg)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 } \
369}
370show_temp_reg(temp);
371show_temp_reg(temp_max);
372show_temp_reg(temp_max_hyst);
373
374#define store_temp_reg(REG, reg) \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800375static ssize_t store_temp_##reg(struct device *dev, \
Jean Delvare34875332007-05-08 17:22:03 +0200376 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{ \
Jean Delvare34875332007-05-08 17:22:03 +0200378 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200379 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200380 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200381 long val; \
Guenter Roeckc531eb32012-01-15 09:19:16 -0800382 int err = kstrtol(buf, 10, &val); \
383 if (err) \
384 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100385 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 \
387 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
388 data->temp_##reg##_add[nr-2] = LM75_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##_add[nr-2]); \
391 } else { /* TEMP1 */ \
392 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200393 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 data->temp_##reg); \
395 } \
396 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100397 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return count; \
399}
400store_temp_reg(OVER, max);
401store_temp_reg(HYST, max_hyst);
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200404static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
405 show_temp, NULL, offset); \
406static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
407 show_temp_max, store_temp_max, offset); \
408static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
409 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
411sysfs_temp_offsets(1);
412sysfs_temp_offsets(2);
413sysfs_temp_offsets(3);
414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400416show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct w83781d_data *data = w83781d_update_device(dev);
419 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
420}
421
Jim Cromie311ce2e2006-09-24 21:22:52 +0200422static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400425show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Jean Delvare90d66192007-10-08 18:24:35 +0200427 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return sprintf(buf, "%ld\n", (long) data->vrm);
429}
430
431static ssize_t
Guenter Roeckc531eb32012-01-15 09:19:16 -0800432store_vrm_reg(struct device *dev, struct device_attribute *attr,
433 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Jean Delvare7666c132007-05-08 17:22:02 +0200435 struct w83781d_data *data = dev_get_drvdata(dev);
Guenter Roeckc531eb32012-01-15 09:19:16 -0800436 unsigned long val;
437 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Guenter Roeckc531eb32012-01-15 09:19:16 -0800439 err = kstrtoul(buf, 10, &val);
440 if (err)
441 return err;
442 data->vrm = SENSORS_LIMIT(val, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 return count;
445}
446
Jim Cromie311ce2e2006-09-24 21:22:52 +0200447static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400450show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200453 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Jim Cromie311ce2e2006-09-24 21:22:52 +0200456static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
457
Jean Delvare7d4a1372007-10-08 18:29:43 +0200458static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
459 char *buf)
460{
461 struct w83781d_data *data = w83781d_update_device(dev);
462 int bitnr = to_sensor_dev_attr(attr)->index;
463 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
464}
465
466/* The W83781D has a single alarm bit for temp2 and temp3 */
467static ssize_t show_temp3_alarm(struct device *dev,
468 struct device_attribute *attr, char *buf)
469{
470 struct w83781d_data *data = w83781d_update_device(dev);
471 int bitnr = (data->type == w83781d) ? 5 : 13;
472 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
473}
474
475static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
476static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
477static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
478static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
479static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
480static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
481static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
482static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
483static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
484static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
485static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
486static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
487static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
488static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
489static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
490
Guenter Roeckc531eb32012-01-15 09:19:16 -0800491static ssize_t show_beep_mask(struct device *dev,
492 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct w83781d_data *data = w83781d_update_device(dev);
495 return sprintf(buf, "%ld\n",
496 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
497}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200500store_beep_mask(struct device *dev, struct device_attribute *attr,
501 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Jean Delvare7666c132007-05-08 17:22:02 +0200503 struct w83781d_data *data = dev_get_drvdata(dev);
Guenter Roeckc531eb32012-01-15 09:19:16 -0800504 unsigned long val;
505 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Guenter Roeckc531eb32012-01-15 09:19:16 -0800507 err = kstrtoul(buf, 10, &val);
508 if (err)
509 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100511 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200512 data->beep_mask &= 0x8000; /* preserve beep enable */
513 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200514 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
515 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200516 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200517 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200518 if (data->type != w83781d && data->type != as99127f) {
519 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
520 ((data->beep_mask) >> 16) & 0xff);
521 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100522 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return count;
525}
526
Jean Delvare34875332007-05-08 17:22:03 +0200527static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
528 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Jean Delvare7d4a1372007-10-08 18:29:43 +0200530static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
531 char *buf)
532{
533 struct w83781d_data *data = w83781d_update_device(dev);
534 int bitnr = to_sensor_dev_attr(attr)->index;
535 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
536}
537
538static ssize_t
539store_beep(struct device *dev, struct device_attribute *attr,
540 const char *buf, size_t count)
541{
542 struct w83781d_data *data = dev_get_drvdata(dev);
543 int bitnr = to_sensor_dev_attr(attr)->index;
Jean Delvare7d4a1372007-10-08 18:29:43 +0200544 u8 reg;
Guenter Roeckc531eb32012-01-15 09:19:16 -0800545 unsigned long bit;
546 int err;
Jean Delvare7d4a1372007-10-08 18:29:43 +0200547
Guenter Roeckc531eb32012-01-15 09:19:16 -0800548 err = kstrtoul(buf, 10, &bit);
549 if (err)
550 return err;
551
Jean Delvare7d4a1372007-10-08 18:29:43 +0200552 if (bit & ~1)
553 return -EINVAL;
554
555 mutex_lock(&data->update_lock);
556 if (bit)
557 data->beep_mask |= (1 << bitnr);
558 else
559 data->beep_mask &= ~(1 << bitnr);
560
561 if (bitnr < 8) {
562 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
563 if (bit)
564 reg |= (1 << bitnr);
565 else
566 reg &= ~(1 << bitnr);
567 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
568 } else if (bitnr < 16) {
569 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
570 if (bit)
571 reg |= (1 << (bitnr - 8));
572 else
573 reg &= ~(1 << (bitnr - 8));
574 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
575 } else {
576 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
577 if (bit)
578 reg |= (1 << (bitnr - 16));
579 else
580 reg &= ~(1 << (bitnr - 16));
581 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
582 }
583 mutex_unlock(&data->update_lock);
584
585 return count;
586}
587
588/* The W83781D has a single beep bit for temp2 and temp3 */
589static ssize_t show_temp3_beep(struct device *dev,
590 struct device_attribute *attr, char *buf)
591{
592 struct w83781d_data *data = w83781d_update_device(dev);
593 int bitnr = (data->type == w83781d) ? 5 : 13;
594 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
595}
596
597static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
598 show_beep, store_beep, 0);
599static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
600 show_beep, store_beep, 1);
601static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
602 show_beep, store_beep, 2);
603static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
604 show_beep, store_beep, 3);
605static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
606 show_beep, store_beep, 8);
607static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
608 show_beep, store_beep, 9);
609static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
610 show_beep, store_beep, 10);
611static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
612 show_beep, store_beep, 16);
613static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
614 show_beep, store_beep, 17);
615static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
616 show_beep, store_beep, 6);
617static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
618 show_beep, store_beep, 7);
619static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
620 show_beep, store_beep, 11);
621static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
622 show_beep, store_beep, 4);
623static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
624 show_beep, store_beep, 5);
625static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
626 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200627static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
628 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200631show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
Jean Delvare34875332007-05-08 17:22:03 +0200633 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 struct w83781d_data *data = w83781d_update_device(dev);
635 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200636 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639/* Note: we save and restore the fan minimum here, because its value is
640 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200641 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 because the divisor changed. */
643static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200644store_fan_div(struct device *dev, struct device_attribute *da,
645 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Jean Delvare34875332007-05-08 17:22:03 +0200647 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200648 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200650 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 u8 reg;
Guenter Roeckc531eb32012-01-15 09:19:16 -0800652 unsigned long val;
653 int err;
654
655 err = kstrtoul(buf, 10, &val);
656 if (err)
657 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100659 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /* Save fan_min */
662 min = FAN_FROM_REG(data->fan_min[nr],
663 DIV_FROM_REG(data->fan_div[nr]));
664
665 data->fan_div[nr] = DIV_TO_REG(val, data->type);
666
Guenter Roeckc531eb32012-01-15 09:19:16 -0800667 reg = (w83781d_read_value(data, nr == 2 ?
668 W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
669 & (nr == 0 ? 0xcf : 0x3f))
670 | ((data->fan_div[nr] & 0x03) << (nr == 0 ? 4 : 6));
671 w83781d_write_value(data, nr == 2 ?
672 W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 /* w83781d and as99127f don't have extended divisor bits */
675 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200676 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 & ~(1 << (5 + nr)))
678 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200679 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681
682 /* Restore fan_min */
683 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200684 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100686 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return count;
688}
689
Jean Delvare34875332007-05-08 17:22:03 +0200690static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
691 show_fan_div, store_fan_div, 0);
692static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
693 show_fan_div, store_fan_div, 1);
694static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
695 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200698show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699{
Jean Delvare34875332007-05-08 17:22:03 +0200700 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200702 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703}
704
705static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200706show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200709 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
712static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200713store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
714 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
Jean Delvare34875332007-05-08 17:22:03 +0200716 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200717 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200718 int nr = attr->index;
Guenter Roeckc531eb32012-01-15 09:19:16 -0800719 unsigned long val;
720 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Guenter Roeckc531eb32012-01-15 09:19:16 -0800722 err = kstrtoul(buf, 10, &val);
723 if (err)
724 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100726 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200727 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
728 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100729 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return count;
731}
732
733static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200734store_pwm2_enable(struct device *dev, struct device_attribute *da,
735 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Jean Delvare7666c132007-05-08 17:22:02 +0200737 struct w83781d_data *data = dev_get_drvdata(dev);
Guenter Roeckc531eb32012-01-15 09:19:16 -0800738 unsigned long val;
739 u32 reg;
740 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Guenter Roeckc531eb32012-01-15 09:19:16 -0800742 err = kstrtoul(buf, 10, &val);
743 if (err)
744 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100746 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 switch (val) {
749 case 0:
750 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200751 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
752 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 (reg & 0xf7) | (val << 3));
754
Jean Delvare31b8dc42007-05-08 17:22:03 +0200755 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
756 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 (reg & 0xef) | (!val << 4));
758
Jean Delvare34875332007-05-08 17:22:03 +0200759 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
761
762 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100763 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -EINVAL;
765 }
766
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100767 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return count;
769}
770
Jean Delvare34875332007-05-08 17:22:03 +0200771static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
772static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
773static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
774static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
775/* only PWM2 can be enabled/disabled */
776static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
777 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200780show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
Jean Delvare34875332007-05-08 17:22:03 +0200782 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200784 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
787static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200788store_sensor(struct device *dev, struct device_attribute *da,
789 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Jean Delvare34875332007-05-08 17:22:03 +0200791 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200792 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200793 int nr = attr->index;
Guenter Roeckc531eb32012-01-15 09:19:16 -0800794 unsigned long val;
795 u32 tmp;
796 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Guenter Roeckc531eb32012-01-15 09:19:16 -0800798 err = kstrtoul(buf, 10, &val);
799 if (err)
800 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100802 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 switch (val) {
805 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200806 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
807 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200808 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200809 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
810 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200811 tmp | BIT_SCFG2[nr]);
812 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 break;
814 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200815 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
816 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200817 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200818 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
819 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200820 tmp & ~BIT_SCFG2[nr]);
821 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200823 case W83781D_DEFAULT_BETA:
824 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
825 "instead\n", W83781D_DEFAULT_BETA);
826 /* fall through */
827 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200828 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
829 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200830 tmp & ~BIT_SCFG1[nr]);
831 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 break;
833 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200834 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
835 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 break;
837 }
838
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100839 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 return count;
841}
842
Jean Delvare34875332007-05-08 17:22:03 +0200843static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
844 show_sensor, store_sensor, 0);
845static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400846 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200847static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400848 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850/* Assumes that adapter is of I2C, not ISA variety.
851 * OTHERWISE DON'T CALL THIS
852 */
853static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200854w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
856 int i, val1 = 0, id;
857 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200858 int address = new_client->addr;
859 unsigned short sc_addr[2];
860 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200862 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
864 id = i2c_adapter_id(adapter);
865
866 if (force_subclients[0] == id && force_subclients[1] == address) {
867 for (i = 2; i <= 3; i++) {
868 if (force_subclients[i] < 0x48 ||
869 force_subclients[i] > 0x4f) {
870 dev_err(&new_client->dev, "Invalid subclient "
871 "address %d; must be 0x48-0x4f\n",
872 force_subclients[i]);
873 err = -EINVAL;
874 goto ERROR_SC_1;
875 }
876 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200877 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 (force_subclients[2] & 0x07) |
879 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200880 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200882 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200883 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885
886 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (force_subclients[0] == id &&
888 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200889 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200891 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200893 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 dev_err(&new_client->dev,
895 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200896 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 err = -EBUSY;
898 goto ERROR_SC_2;
899 }
900 }
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200903 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
904 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 dev_err(&new_client->dev, "Subclient %d "
906 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200907 "failed.\n", i, sc_addr[i]);
908 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (i == 1)
910 goto ERROR_SC_3;
911 goto ERROR_SC_2;
912 }
913 if (kind == w83783s)
914 break;
915 }
916
917 return 0;
918
919/* Undo inits in case of errors */
920ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200921 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return err;
925}
926
Jean Delvare34875332007-05-08 17:22:03 +0200927#define IN_UNIT_ATTRS(X) \
928 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
929 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100930 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200931 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
932 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200933
Jean Delvare34875332007-05-08 17:22:03 +0200934#define FAN_UNIT_ATTRS(X) \
935 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
936 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200937 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
938 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
939 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200940
Jean Delvare34875332007-05-08 17:22:03 +0200941#define TEMP_UNIT_ATTRS(X) \
942 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
943 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200944 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
945 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
946 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200947
Guenter Roeckc531eb32012-01-15 09:19:16 -0800948static struct attribute *w83781d_attributes[] = {
Jim Cromie311ce2e2006-09-24 21:22:52 +0200949 IN_UNIT_ATTRS(0),
950 IN_UNIT_ATTRS(2),
951 IN_UNIT_ATTRS(3),
952 IN_UNIT_ATTRS(4),
953 IN_UNIT_ATTRS(5),
954 IN_UNIT_ATTRS(6),
955 FAN_UNIT_ATTRS(1),
956 FAN_UNIT_ATTRS(2),
957 FAN_UNIT_ATTRS(3),
958 TEMP_UNIT_ATTRS(1),
959 TEMP_UNIT_ATTRS(2),
960 &dev_attr_cpu0_vid.attr,
961 &dev_attr_vrm.attr,
962 &dev_attr_alarms.attr,
963 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200964 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200965 NULL
966};
967static const struct attribute_group w83781d_group = {
968 .attrs = w83781d_attributes,
969};
970
971static struct attribute *w83781d_attributes_opt[] = {
972 IN_UNIT_ATTRS(1),
973 IN_UNIT_ATTRS(7),
974 IN_UNIT_ATTRS(8),
975 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200976 &sensor_dev_attr_pwm1.dev_attr.attr,
977 &sensor_dev_attr_pwm2.dev_attr.attr,
978 &sensor_dev_attr_pwm3.dev_attr.attr,
979 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200980 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200981 &sensor_dev_attr_temp1_type.dev_attr.attr,
982 &sensor_dev_attr_temp2_type.dev_attr.attr,
983 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200984 NULL
985};
986static const struct attribute_group w83781d_group_opt = {
987 .attrs = w83781d_attributes_opt,
988};
989
Jean Delvare7666c132007-05-08 17:22:02 +0200990/* No clean up is done on error, it's up to the caller */
991static int
992w83781d_create_files(struct device *dev, int kind, int is_isa)
993{
994 int err;
995
Guenter Roeckc531eb32012-01-15 09:19:16 -0800996 err = sysfs_create_group(&dev->kobj, &w83781d_group);
997 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +0200998 return err;
999
1000 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001001 if ((err = device_create_file(dev,
1002 &sensor_dev_attr_in1_input.dev_attr))
1003 || (err = device_create_file(dev,
1004 &sensor_dev_attr_in1_min.dev_attr))
1005 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001006 &sensor_dev_attr_in1_max.dev_attr))
1007 || (err = device_create_file(dev,
1008 &sensor_dev_attr_in1_alarm.dev_attr))
1009 || (err = device_create_file(dev,
1010 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001011 return err;
1012 }
1013 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001014 if ((err = device_create_file(dev,
1015 &sensor_dev_attr_in7_input.dev_attr))
1016 || (err = device_create_file(dev,
1017 &sensor_dev_attr_in7_min.dev_attr))
1018 || (err = device_create_file(dev,
1019 &sensor_dev_attr_in7_max.dev_attr))
1020 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001021 &sensor_dev_attr_in7_alarm.dev_attr))
1022 || (err = device_create_file(dev,
1023 &sensor_dev_attr_in7_beep.dev_attr))
1024 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001025 &sensor_dev_attr_in8_input.dev_attr))
1026 || (err = device_create_file(dev,
1027 &sensor_dev_attr_in8_min.dev_attr))
1028 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001029 &sensor_dev_attr_in8_max.dev_attr))
1030 || (err = device_create_file(dev,
1031 &sensor_dev_attr_in8_alarm.dev_attr))
1032 || (err = device_create_file(dev,
1033 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001034 return err;
1035 }
1036 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001037 if ((err = device_create_file(dev,
1038 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001039 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001040 &sensor_dev_attr_temp3_max.dev_attr))
1041 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001042 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1043 || (err = device_create_file(dev,
1044 &sensor_dev_attr_temp3_alarm.dev_attr))
1045 || (err = device_create_file(dev,
1046 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001047 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001048
Jean Delvare7768aa72007-10-25 13:11:01 +02001049 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001050 err = sysfs_chmod_file(&dev->kobj,
1051 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1052 S_IRUGO | S_IWUSR);
1053 if (err)
1054 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001055 }
Jean Delvare7666c132007-05-08 17:22:02 +02001056 }
1057
1058 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001059 if ((err = device_create_file(dev,
1060 &sensor_dev_attr_pwm1.dev_attr))
1061 || (err = device_create_file(dev,
1062 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001063 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1064 return err;
1065 }
1066 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001067 if ((err = device_create_file(dev,
1068 &sensor_dev_attr_pwm3.dev_attr))
1069 || (err = device_create_file(dev,
1070 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001071 return err;
1072 }
1073
1074 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001075 if ((err = device_create_file(dev,
1076 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001077 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001078 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001079 return err;
1080 if (kind != w83783s) {
Guenter Roeckc531eb32012-01-15 09:19:16 -08001081 err = device_create_file(dev,
1082 &sensor_dev_attr_temp3_type.dev_attr);
1083 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001084 return err;
1085 }
1086 }
1087
Jean Delvare7666c132007-05-08 17:22:02 +02001088 return 0;
1089}
1090
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001091/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092static int
Jean Delvare310ec792009-12-14 21:17:23 +01001093w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
Jean Delvarebab2bf42009-12-09 20:35:54 +01001095 int val1, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001096 struct w83781d_data *isa = w83781d_data_if_isa();
1097 struct i2c_adapter *adapter = client->adapter;
1098 int address = client->addr;
Jean Delvarebab2bf42009-12-09 20:35:54 +01001099 const char *client_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 enum vendor { winbond, asus } vendid;
1101
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001102 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1103 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001105 /* We block updates of the ISA device to minimize the risk of
1106 concurrent access to the same W83781D chip through different
1107 interfaces. */
1108 if (isa)
1109 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Jean Delvarebab2bf42009-12-09 20:35:54 +01001111 if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1112 dev_dbg(&adapter->dev,
1113 "Detection of w83781d chip failed at step 3\n");
1114 goto err_nodev;
1115 }
1116
1117 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1118 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1119 /* Check for Winbond or Asus ID if in bank 0 */
1120 if (!(val1 & 0x07) &&
1121 ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
Guenter Roeckc531eb32012-01-15 09:19:16 -08001122 ((val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
Jean Delvarebab2bf42009-12-09 20:35:54 +01001123 dev_dbg(&adapter->dev,
1124 "Detection of w83781d chip failed at step 4\n");
1125 goto err_nodev;
1126 }
1127 /* If Winbond SMBus, check address at 0x48.
1128 Asus doesn't support, except for as99127f rev.2 */
1129 if ((!(val1 & 0x80) && val2 == 0xa3) ||
Guenter Roeckc531eb32012-01-15 09:19:16 -08001130 ((val1 & 0x80) && val2 == 0x5c)) {
Jean Delvarebab2bf42009-12-09 20:35:54 +01001131 if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1132 != address) {
1133 dev_dbg(&adapter->dev,
1134 "Detection of w83781d chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001135 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
Jean Delvarebab2bf42009-12-09 20:35:54 +01001139 /* Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001140 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1141 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1142 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Jean Delvarebab2bf42009-12-09 20:35:54 +01001144 /* Get the vendor ID */
1145 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1146 if (val2 == 0x5c)
1147 vendid = winbond;
1148 else if (val2 == 0x12)
1149 vendid = asus;
1150 else {
1151 dev_dbg(&adapter->dev,
1152 "w83781d chip vendor is neither Winbond nor Asus\n");
1153 goto err_nodev;
1154 }
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 /* Determine the chip type. */
Jean Delvarebab2bf42009-12-09 20:35:54 +01001157 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
1158 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1159 client_name = "w83781d";
1160 else if (val1 == 0x30 && vendid == winbond)
1161 client_name = "w83782d";
1162 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1163 client_name = "w83783s";
1164 else if (val1 == 0x31)
1165 client_name = "as99127f";
1166 else
1167 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Jean Delvarebab2bf42009-12-09 20:35:54 +01001169 if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1170 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1171 "be the same as ISA device\n", address);
1172 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 }
1174
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001175 if (isa)
1176 mutex_unlock(&isa->update_lock);
1177
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001178 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001180 return 0;
1181
1182 err_nodev:
1183 if (isa)
1184 mutex_unlock(&isa->update_lock);
1185 return -ENODEV;
1186}
1187
1188static int
1189w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1190{
1191 struct device *dev = &client->dev;
1192 struct w83781d_data *data;
1193 int err;
1194
1195 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1196 if (!data) {
1197 err = -ENOMEM;
1198 goto ERROR1;
1199 }
1200
1201 i2c_set_clientdata(client, data);
1202 mutex_init(&data->lock);
1203 mutex_init(&data->update_lock);
1204
1205 data->type = id->driver_data;
1206 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001209 err = w83781d_detect_subclients(client);
1210 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001211 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001214 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
1216 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001217 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001218 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001219 goto ERROR4;
1220
Tony Jones1beeffe2007-08-20 13:46:20 -07001221 data->hwmon_dev = hwmon_device_register(dev);
1222 if (IS_ERR(data->hwmon_dev)) {
1223 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001224 goto ERROR4;
1225 }
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 return 0;
1228
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001229ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001230 sysfs_remove_group(&dev->kobj, &w83781d_group);
1231 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1232
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001233 if (data->lm75[0])
1234 i2c_unregister_device(data->lm75[0]);
1235 if (data->lm75[1])
1236 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237ERROR3:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 kfree(data);
1239ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 return err;
1241}
1242
1243static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001244w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001246 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001247 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001249 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001251 sysfs_remove_group(&dev->kobj, &w83781d_group);
1252 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001254 if (data->lm75[0])
1255 i2c_unregister_device(data->lm75[0]);
1256 if (data->lm75[1])
1257 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001258
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001259 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 return 0;
1262}
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001265w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001267 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001268 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 struct i2c_client *cl;
1270
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001271 bank = (reg >> 8) & 0x0f;
1272 if (bank > 2)
1273 /* switch banks */
1274 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1275 bank);
1276 if (bank == 0 || bank > 2) {
1277 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001279 /* switch to subclient */
1280 cl = data->lm75[bank - 1];
1281 /* convert from ISA to LM75 I2C addresses */
1282 switch (reg & 0xff) {
1283 case 0x50: /* TEMP */
Jean Delvare90f41022011-11-04 12:00:47 +01001284 res = i2c_smbus_read_word_swapped(cl, 0);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001285 break;
1286 case 0x52: /* CONFIG */
1287 res = i2c_smbus_read_byte_data(cl, 1);
1288 break;
1289 case 0x53: /* HYST */
Jean Delvare90f41022011-11-04 12:00:47 +01001290 res = i2c_smbus_read_word_swapped(cl, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001291 break;
1292 case 0x55: /* OVER */
1293 default:
Jean Delvare90f41022011-11-04 12:00:47 +01001294 res = i2c_smbus_read_word_swapped(cl, 3);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001295 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001298 if (bank > 2)
1299 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 return res;
1302}
1303
1304static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001305w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001307 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001308 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 struct i2c_client *cl;
1310
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001311 bank = (reg >> 8) & 0x0f;
1312 if (bank > 2)
1313 /* switch banks */
1314 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1315 bank);
1316 if (bank == 0 || bank > 2) {
1317 i2c_smbus_write_byte_data(client, reg & 0xff,
1318 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001320 /* switch to subclient */
1321 cl = data->lm75[bank - 1];
1322 /* convert from ISA to LM75 I2C addresses */
1323 switch (reg & 0xff) {
1324 case 0x52: /* CONFIG */
1325 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1326 break;
1327 case 0x53: /* HYST */
Jean Delvare90f41022011-11-04 12:00:47 +01001328 i2c_smbus_write_word_swapped(cl, 2, value);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001329 break;
1330 case 0x55: /* OVER */
Jean Delvare90f41022011-11-04 12:00:47 +01001331 i2c_smbus_write_word_swapped(cl, 3, value);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001332 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001335 if (bank > 2)
1336 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return 0;
1339}
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341static void
Jean Delvare7666c132007-05-08 17:22:02 +02001342w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
Jean Delvare7666c132007-05-08 17:22:02 +02001344 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 int i, p;
1346 int type = data->type;
1347 u8 tmp;
1348
Jean Delvarefabddcd2006-02-05 23:26:51 +01001349 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001351 /* Resetting the chip has been the default for a long time,
1352 but it causes the BIOS initializations (fan clock dividers,
1353 thermal sensor types...) to be lost, so it is now optional.
1354 It might even go away if nobody reports it as being useful,
1355 as I see very little reason why this would be needed at
1356 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001357 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001358 "having, please report!\n");
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001361 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1362 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* Reset all except Watchdog values and last conversion values
1364 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001365 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 /* Restore the registers and disable power-on abnormal beep.
1367 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001368 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1369 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Guenter Roeckc531eb32012-01-15 09:19:16 -08001370 /*
1371 * Disable master beep-enable (reset turns it on).
1372 * Individual beep_mask should be reset to off but for some
1373 * reason disabling this bit helps some people not get beeped
1374 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001375 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
1377
Jean Delvarefabddcd2006-02-05 23:26:51 +01001378 /* Disable power-on abnormal beep, as advised by the datasheet.
1379 Already done if reset=1. */
1380 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001381 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1382 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001383 }
1384
Jean Delvare303760b2005-07-31 21:52:01 +02001385 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
1387 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001388 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 for (i = 1; i <= 3; i++) {
1390 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001391 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
1393 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001394 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1396 data->sens[i - 1] = 1;
1397 else
1398 data->sens[i - 1] = 2;
1399 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001400 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 break;
1402 }
1403 }
1404
1405 if (init && type != as99127f) {
1406 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001407 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001409 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001411 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 tmp & 0xfe);
1413 }
1414
1415 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001416 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001417 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 W83781D_REG_TEMP3_CONFIG);
1419 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001420 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001422 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1424 }
1425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 }
1427
1428 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001429 w83781d_write_value(data, W83781D_REG_CONFIG,
1430 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 W83781D_REG_CONFIG) & 0xf7)
1432 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001433
1434 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001435 for (i = 0; i < 3; i++) {
1436 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001437 W83781D_REG_FAN_MIN(i));
1438 }
Jean Delvare7666c132007-05-08 17:22:02 +02001439
1440 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441}
1442
1443static struct w83781d_data *w83781d_update_device(struct device *dev)
1444{
Jean Delvare7666c132007-05-08 17:22:02 +02001445 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001446 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 int i;
1448
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001449 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1452 || !data->valid) {
1453 dev_dbg(dev, "Starting device update\n");
1454
1455 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001456 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 continue; /* 783S has no in1 */
1458 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001459 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001461 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001463 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001464 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 break;
1466 }
Jean Delvare34875332007-05-08 17:22:03 +02001467 for (i = 0; i < 3; i++) {
1468 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001469 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001470 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001471 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001474 for (i = 0; i < 4; i++) {
1475 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001476 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001477 W83781D_REG_PWM[i]);
Jean Delvare848ddf12009-05-08 20:27:28 +02001478 /* Only W83782D on SMBus has PWM3 and PWM4 */
1479 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001480 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
1482 }
1483 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001484 data->pwm2_enable = (w83781d_read_value(data,
Guenter Roeckc531eb32012-01-15 09:19:16 -08001485 W83781D_REG_PWMCLK12) & 0x08) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 }
1487
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001490 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001492 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001494 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001496 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001498 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001499 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001501 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001503 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 W83781D_REG_TEMP_OVER(3));
1505 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001506 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 W83781D_REG_TEMP_HYST(3));
1508 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001509 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001510 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001511 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001512 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 data->fan_div[0] = (i >> 4) & 0x03;
1514 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001515 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001516 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001518 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 data->fan_div[0] |= (i >> 3) & 0x04;
1520 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001521 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 }
Jean Delvare05663362007-11-30 23:51:24 +01001523 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001524 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001525 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001526 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001527 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001528 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001529 W83782D_REG_ALARM3) << 16);
1530 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001531 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001532 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001533 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001534 W83782D_REG_ALARM2) << 8);
1535 } else {
1536 /* No real-time status registers, fall back to
1537 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001538 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001539 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001540 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001541 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001543 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001544 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001545 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 if ((data->type != w83781d) && (data->type != as99127f)) {
1547 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001548 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 W83781D_REG_BEEP_INTS3) << 16;
1550 }
1551 data->last_updated = jiffies;
1552 data->valid = 1;
1553 }
1554
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001555 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 return data;
1558}
1559
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001560static const struct i2c_device_id w83781d_ids[] = {
1561 { "w83781d", w83781d, },
1562 { "w83782d", w83782d, },
1563 { "w83783s", w83783s, },
1564 { "as99127f", as99127f },
1565 { /* LIST END */ }
1566};
1567MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1568
1569static struct i2c_driver w83781d_driver = {
1570 .class = I2C_CLASS_HWMON,
1571 .driver = {
1572 .name = "w83781d",
1573 },
1574 .probe = w83781d_probe,
1575 .remove = w83781d_remove,
1576 .id_table = w83781d_ids,
1577 .detect = w83781d_detect,
Jean Delvarec3813d62009-12-14 21:17:25 +01001578 .address_list = normal_i2c,
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001579};
1580
1581/*
1582 * ISA related code
1583 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001584#ifdef CONFIG_ISA
1585
1586/* ISA device, if found */
1587static struct platform_device *pdev;
1588
1589static unsigned short isa_address = 0x290;
1590
1591/* I2C devices get this name attribute automatically, but for ISA devices
1592 we must create it by ourselves. */
1593static ssize_t
1594show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1595{
1596 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001597 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001598}
1599static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1600
1601static struct w83781d_data *w83781d_data_if_isa(void)
1602{
1603 return pdev ? platform_get_drvdata(pdev) : NULL;
1604}
1605
1606/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1607static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1608{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001609 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001610 int i;
1611
1612 if (!pdev) /* No ISA chip */
1613 return 0;
1614
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001615 isa = platform_get_drvdata(pdev);
1616
1617 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1618 return 0; /* Address doesn't match */
1619 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1620 return 0; /* Chip type doesn't match */
1621
1622 /* We compare all the limit registers, the config register and the
1623 * interrupt mask registers */
1624 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001625 if (w83781d_read_value(isa, i) !=
1626 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001627 return 0;
1628 }
1629 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001630 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001631 return 0;
1632 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001633 if (w83781d_read_value(isa, i) !=
1634 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001635 return 0;
1636 }
1637
1638 return 1;
1639}
1640
1641static int
1642w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1643{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001644 int word_sized, res;
1645
1646 word_sized = (((reg & 0xff00) == 0x100)
1647 || ((reg & 0xff00) == 0x200))
1648 && (((reg & 0x00ff) == 0x50)
1649 || ((reg & 0x00ff) == 0x53)
1650 || ((reg & 0x00ff) == 0x55));
1651 if (reg & 0xff00) {
1652 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001653 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001654 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001655 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001656 }
Jean Delvare360782d2008-10-17 17:51:19 +02001657 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1658 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001659 if (word_sized) {
1660 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001661 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001662 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001663 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001664 W83781D_DATA_REG_OFFSET);
1665 }
1666 if (reg & 0xff00) {
1667 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001668 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1669 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001670 }
1671 return res;
1672}
1673
1674static void
1675w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1676{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001677 int word_sized;
1678
1679 word_sized = (((reg & 0xff00) == 0x100)
1680 || ((reg & 0xff00) == 0x200))
1681 && (((reg & 0x00ff) == 0x53)
1682 || ((reg & 0x00ff) == 0x55));
1683 if (reg & 0xff00) {
1684 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001685 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001686 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001687 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001688 }
Jean Delvare360782d2008-10-17 17:51:19 +02001689 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001690 if (word_sized) {
1691 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001692 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001693 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001694 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001695 }
Jean Delvare360782d2008-10-17 17:51:19 +02001696 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001697 if (reg & 0xff00) {
1698 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001699 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1700 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001701 }
1702}
1703
1704/* The SMBus locks itself, usually, but nothing may access the Winbond between
1705 bank switches. ISA access must always be locked explicitly!
1706 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1707 would slow down the W83781D access and should not be necessary.
1708 There are some ugly typecasts here, but the good news is - they should
1709 nowhere else be necessary! */
1710static int
1711w83781d_read_value(struct w83781d_data *data, u16 reg)
1712{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001713 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001714 int res;
1715
1716 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001717 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001718 res = w83781d_read_value_i2c(data, reg);
1719 else
1720 res = w83781d_read_value_isa(data, reg);
1721 mutex_unlock(&data->lock);
1722 return res;
1723}
1724
1725static int
1726w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1727{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001728 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001729
1730 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001731 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001732 w83781d_write_value_i2c(data, reg, value);
1733 else
1734 w83781d_write_value_isa(data, reg, value);
1735 mutex_unlock(&data->lock);
1736 return 0;
1737}
1738
1739static int __devinit
1740w83781d_isa_probe(struct platform_device *pdev)
1741{
1742 int err, reg;
1743 struct w83781d_data *data;
1744 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001745
1746 /* Reserve the ISA region */
1747 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1748 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1749 "w83781d")) {
1750 err = -EBUSY;
1751 goto exit;
1752 }
1753
1754 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1755 if (!data) {
1756 err = -ENOMEM;
1757 goto exit_release_region;
1758 }
1759 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001760 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001761 platform_set_drvdata(pdev, data);
1762
1763 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1764 switch (reg) {
1765 case 0x30:
1766 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001767 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001768 break;
1769 default:
1770 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001771 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001772 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001773
1774 /* Initialize the W83781D chip */
1775 w83781d_init_device(&pdev->dev);
1776
1777 /* Register sysfs hooks */
1778 err = w83781d_create_files(&pdev->dev, data->type, 1);
1779 if (err)
1780 goto exit_remove_files;
1781
1782 err = device_create_file(&pdev->dev, &dev_attr_name);
1783 if (err)
1784 goto exit_remove_files;
1785
1786 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1787 if (IS_ERR(data->hwmon_dev)) {
1788 err = PTR_ERR(data->hwmon_dev);
1789 goto exit_remove_files;
1790 }
1791
1792 return 0;
1793
1794 exit_remove_files:
1795 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1796 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1797 device_remove_file(&pdev->dev, &dev_attr_name);
1798 kfree(data);
1799 exit_release_region:
1800 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1801 exit:
1802 return err;
1803}
1804
1805static int __devexit
1806w83781d_isa_remove(struct platform_device *pdev)
1807{
1808 struct w83781d_data *data = platform_get_drvdata(pdev);
1809
1810 hwmon_device_unregister(data->hwmon_dev);
1811 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1812 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1813 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001814 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001815 kfree(data);
1816
1817 return 0;
1818}
1819
1820static struct platform_driver w83781d_isa_driver = {
1821 .driver = {
1822 .owner = THIS_MODULE,
1823 .name = "w83781d",
1824 },
1825 .probe = w83781d_isa_probe,
1826 .remove = __devexit_p(w83781d_isa_remove),
1827};
1828
Jean Delvare7666c132007-05-08 17:22:02 +02001829/* return 1 if a supported chip is found, 0 otherwise */
1830static int __init
1831w83781d_isa_found(unsigned short address)
1832{
1833 int val, save, found = 0;
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001834 int port;
Jean Delvare7666c132007-05-08 17:22:02 +02001835
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001836 /* Some boards declare base+0 to base+7 as a PNP device, some base+4
1837 * to base+7 and some base+5 to base+6. So we better request each port
1838 * individually for the probing phase. */
1839 for (port = address; port < address + W83781D_EXTENT; port++) {
1840 if (!request_region(port, 1, "w83781d")) {
Joe Perches1ca28212011-01-12 21:55:11 +01001841 pr_debug("Failed to request port 0x%x\n", port);
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001842 goto release;
1843 }
Jean Delvare2961cb22008-03-09 13:34:28 +01001844 }
Jean Delvare7666c132007-05-08 17:22:02 +02001845
1846#define REALLY_SLOW_IO
1847 /* We need the timeouts for at least some W83781D-like
1848 chips. But only if we read 'undefined' registers. */
1849 val = inb_p(address + 1);
1850 if (inb_p(address + 2) != val
1851 || inb_p(address + 3) != val
1852 || inb_p(address + 7) != val) {
Joe Perches1ca28212011-01-12 21:55:11 +01001853 pr_debug("Detection failed at step %d\n", 1);
Jean Delvare7666c132007-05-08 17:22:02 +02001854 goto release;
1855 }
1856#undef REALLY_SLOW_IO
1857
1858 /* We should be able to change the 7 LSB of the address port. The
1859 MSB (busy flag) should be clear initially, set after the write. */
1860 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1861 if (save & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001862 pr_debug("Detection failed at step %d\n", 2);
Jean Delvare7666c132007-05-08 17:22:02 +02001863 goto release;
1864 }
1865 val = ~save & 0x7f;
1866 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1867 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1868 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
Joe Perches1ca28212011-01-12 21:55:11 +01001869 pr_debug("Detection failed at step %d\n", 3);
Jean Delvare7666c132007-05-08 17:22:02 +02001870 goto release;
1871 }
1872
1873 /* We found a device, now see if it could be a W83781D */
1874 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1875 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1876 if (val & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001877 pr_debug("Detection failed at step %d\n", 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001878 goto release;
1879 }
1880 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1881 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1882 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1883 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1884 if ((!(save & 0x80) && (val != 0xa3))
1885 || ((save & 0x80) && (val != 0x5c))) {
Joe Perches1ca28212011-01-12 21:55:11 +01001886 pr_debug("Detection failed at step %d\n", 5);
Jean Delvare7666c132007-05-08 17:22:02 +02001887 goto release;
1888 }
1889 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1890 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1891 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
Joe Perches1ca28212011-01-12 21:55:11 +01001892 pr_debug("Detection failed at step %d\n", 6);
Jean Delvare7666c132007-05-08 17:22:02 +02001893 goto release;
1894 }
1895
1896 /* The busy flag should be clear again */
1897 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
Joe Perches1ca28212011-01-12 21:55:11 +01001898 pr_debug("Detection failed at step %d\n", 7);
Jean Delvare7666c132007-05-08 17:22:02 +02001899 goto release;
1900 }
1901
1902 /* Determine the chip type */
1903 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1904 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1905 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1906 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1907 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1908 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001909 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001910 found = 1;
1911
1912 if (found)
Joe Perches1ca28212011-01-12 21:55:11 +01001913 pr_info("Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001914 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1915
1916 release:
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001917 for (port--; port >= address; port--)
1918 release_region(port, 1);
Jean Delvare7666c132007-05-08 17:22:02 +02001919 return found;
1920}
1921
1922static int __init
1923w83781d_isa_device_add(unsigned short address)
1924{
1925 struct resource res = {
1926 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001927 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001928 .name = "w83781d",
1929 .flags = IORESOURCE_IO,
1930 };
1931 int err;
1932
1933 pdev = platform_device_alloc("w83781d", address);
1934 if (!pdev) {
1935 err = -ENOMEM;
Joe Perches1ca28212011-01-12 21:55:11 +01001936 pr_err("Device allocation failed\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001937 goto exit;
1938 }
1939
1940 err = platform_device_add_resources(pdev, &res, 1);
1941 if (err) {
Joe Perches1ca28212011-01-12 21:55:11 +01001942 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare7666c132007-05-08 17:22:02 +02001943 goto exit_device_put;
1944 }
1945
1946 err = platform_device_add(pdev);
1947 if (err) {
Joe Perches1ca28212011-01-12 21:55:11 +01001948 pr_err("Device addition failed (%d)\n", err);
Jean Delvare7666c132007-05-08 17:22:02 +02001949 goto exit_device_put;
1950 }
1951
1952 return 0;
1953
1954 exit_device_put:
1955 platform_device_put(pdev);
1956 exit:
1957 pdev = NULL;
1958 return err;
1959}
1960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001962w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
Jean Delvarefde09502005-07-19 23:51:07 +02001964 int res;
1965
Jean Delvare7666c132007-05-08 17:22:02 +02001966 if (w83781d_isa_found(isa_address)) {
1967 res = platform_driver_register(&w83781d_isa_driver);
1968 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001969 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001970
1971 /* Sets global pdev as a side effect */
1972 res = w83781d_isa_device_add(isa_address);
1973 if (res)
1974 goto exit_unreg_isa_driver;
1975 }
Jean Delvarefde09502005-07-19 23:51:07 +02001976
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001977 return 0;
1978
1979exit_unreg_isa_driver:
1980 platform_driver_unregister(&w83781d_isa_driver);
1981exit:
1982 return res;
1983}
1984
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001985static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001986w83781d_isa_unregister(void)
1987{
1988 if (pdev) {
1989 platform_device_unregister(pdev);
1990 platform_driver_unregister(&w83781d_isa_driver);
1991 }
1992}
1993#else /* !CONFIG_ISA */
1994
1995static struct w83781d_data *w83781d_data_if_isa(void)
1996{
1997 return NULL;
1998}
1999
2000static int
2001w83781d_alias_detect(struct i2c_client *client, u8 chipid)
2002{
2003 return 0;
2004}
2005
2006static int
2007w83781d_read_value(struct w83781d_data *data, u16 reg)
2008{
2009 int res;
2010
2011 mutex_lock(&data->lock);
2012 res = w83781d_read_value_i2c(data, reg);
2013 mutex_unlock(&data->lock);
2014
2015 return res;
2016}
2017
2018static int
2019w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2020{
2021 mutex_lock(&data->lock);
2022 w83781d_write_value_i2c(data, reg, value);
2023 mutex_unlock(&data->lock);
2024
2025 return 0;
2026}
2027
2028static int __init
2029w83781d_isa_register(void)
2030{
2031 return 0;
2032}
2033
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01002034static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002035w83781d_isa_unregister(void)
2036{
2037}
2038#endif /* CONFIG_ISA */
2039
2040static int __init
2041sensors_w83781d_init(void)
2042{
2043 int res;
2044
2045 /* We register the ISA device first, so that we can skip the
2046 * registration of an I2C interface to the same device. */
2047 res = w83781d_isa_register();
2048 if (res)
2049 goto exit;
2050
Jean Delvarec6566202008-10-17 17:51:18 +02002051 res = i2c_add_driver(&w83781d_driver);
2052 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002053 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002054
Jean Delvarefde09502005-07-19 23:51:07 +02002055 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002056
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002057 exit_unreg_isa:
2058 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002059 exit:
2060 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061}
2062
2063static void __exit
2064sensors_w83781d_exit(void)
2065{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002066 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 i2c_del_driver(&w83781d_driver);
2068}
2069
2070MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2071 "Philip Edelbrock <phil@netroedge.com>, "
2072 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2073MODULE_DESCRIPTION("W83781D driver");
2074MODULE_LICENSE("GPL");
2075
2076module_init(sensors_w83781d_init);
2077module_exit(sensors_w83781d_exit);