blob: c84b9b4e69609e70e55419a6faae4f8f1905a63c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
Jean Delvare7666c132007-05-08 17:22:02 +02005 Philip Edelbrock <phil@netroedge.com>,
6 and Mark Studebaker <mdsxyz123@yahoo.com>
Jean Delvare360782d2008-10-17 17:51:19 +02007 Copyright (c) 2007 - 2008 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
25 Supports following chips:
26
27 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
28 as99127f 7 3 0 3 0x31 0x12c3 yes no
29 as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
30 w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
32 w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34*/
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/module.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/jiffies.h>
40#include <linux/i2c.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040041#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020042#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020043#include <linux/hwmon-sysfs.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020044#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040045#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010046#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020048#ifdef CONFIG_ISA
49#include <linux/platform_device.h>
50#include <linux/ioport.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020051#include <linux/io.h>
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020052#endif
53
54#include "lm75.h"
Jean Delvare7666c132007-05-08 17:22:02 +020055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050057static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
58 0x2e, 0x2f, I2C_CLIENT_END };
Jean Delvare3aed1982009-01-07 16:37:32 +010059
Jean Delvaree5e9f442009-12-14 21:17:27 +010060enum chips { w83781d, w83782d, w83783s, as99127f };
61
62/* Insmod parameters */
Jean Delvare3aed1982009-01-07 16:37:32 +010063static unsigned short force_subclients[4];
64module_param_array(force_subclients, short, NULL, 0);
65MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
67
Jean Delvarefabddcd2006-02-05 23:26:51 +010068static int reset;
69module_param(reset, bool, 0);
70MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072static int init = 1;
73module_param(init, bool, 0);
74MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
75
76/* Constants specified below */
77
78/* Length of ISA address segment */
79#define W83781D_EXTENT 8
80
81/* Where are the ISA address/data registers relative to the base address */
82#define W83781D_ADDR_REG_OFFSET 5
83#define W83781D_DATA_REG_OFFSET 6
84
Jean Delvare34875332007-05-08 17:22:03 +020085/* The device registers */
86/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
88 (0x554 + (((nr) - 7) * 2)))
89#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
90 (0x555 + (((nr) - 7) * 2)))
91#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
92 (0x550 + (nr) - 7))
93
Jean Delvare34875332007-05-08 17:22:03 +020094/* fan nr from 0 to 2 */
95#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
96#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98#define W83781D_REG_BANK 0x4E
99#define W83781D_REG_TEMP2_CONFIG 0x152
100#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +0200101/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
103 ((nr == 2) ? (0x0150) : \
104 (0x27)))
105#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
106 ((nr == 2) ? (0x153) : \
107 (0x3A)))
108#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
109 ((nr == 2) ? (0x155) : \
110 (0x39)))
111
112#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100113
114/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define W83781D_REG_ALARM1 0x41
116#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Jean Delvare05663362007-11-30 23:51:24 +0100118/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100119#define W83782D_REG_ALARM1 0x459
120#define W83782D_REG_ALARM2 0x45A
121#define W83782D_REG_ALARM3 0x45B
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define W83781D_REG_BEEP_CONFIG 0x4D
124#define W83781D_REG_BEEP_INTS1 0x56
125#define W83781D_REG_BEEP_INTS2 0x57
126#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
127
128#define W83781D_REG_VID_FANDIV 0x47
129
130#define W83781D_REG_CHIPID 0x49
131#define W83781D_REG_WCHIPID 0x58
132#define W83781D_REG_CHIPMAN 0x4F
133#define W83781D_REG_PIN 0x4B
134
135/* 782D/783S only */
136#define W83781D_REG_VBAT 0x5D
137
138/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200139static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140#define W83781D_REG_PWMCLK12 0x5C
141#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143#define W83781D_REG_I2C_ADDR 0x48
144#define W83781D_REG_I2C_SUBADDR 0x4A
145
146/* The following are undocumented in the data sheets however we
147 received the information in an email from Winbond tech support */
148/* Sensor selection - not on 781d */
149#define W83781D_REG_SCFG1 0x5D
150static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
151
152#define W83781D_REG_SCFG2 0x59
153static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
154
155#define W83781D_DEFAULT_BETA 3435
156
Jean Delvare474d00a2007-05-08 17:22:03 +0200157/* Conversions */
158#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
159#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161static inline u8
162FAN_TO_REG(long rpm, int div)
163{
164 if (rpm == 0)
165 return 255;
166 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
167 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
168}
169
Jean Delvare474d00a2007-05-08 17:22:03 +0200170static inline long
171FAN_FROM_REG(u8 val, int div)
172{
173 if (val == 0)
174 return -1;
175 if (val == 255)
176 return 0;
177 return 1350000 / (val * div);
178}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Jean Delvare474d00a2007-05-08 17:22:03 +0200180#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
181#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200184 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200186 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#define DIV_FROM_REG(val) (1 << (val))
189
190static inline u8
191DIV_TO_REG(long val, enum chips type)
192{
193 int i;
194 val = SENSORS_LIMIT(val, 1,
195 ((type == w83781d
196 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000197 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 if (val == 0)
199 break;
200 val >>= 1;
201 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200202 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205struct w83781d_data {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200206 struct i2c_client *client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700207 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100208 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 enum chips type;
210
Jean Delvare360782d2008-10-17 17:51:19 +0200211 /* For ISA device only */
212 const char *name;
213 int isa_addr;
214
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100215 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 char valid; /* !=0 if following fields are valid */
217 unsigned long last_updated; /* In jiffies */
218
219 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
220 /* array of 2 pointers to subclients */
221
222 u8 in[9]; /* Register value - 8 & 9 for 782D only */
223 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
224 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
225 u8 fan[3]; /* Register value */
226 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200227 s8 temp; /* Register value */
228 s8 temp_max; /* Register value */
229 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 u16 temp_add[2]; /* Register value */
231 u16 temp_max_add[2]; /* Register value */
232 u16 temp_max_hyst_add[2]; /* Register value */
233 u8 fan_div[3]; /* Register encoding, shifted right */
234 u8 vid; /* Register encoding, combined */
235 u32 alarms; /* Register encoding, combined */
236 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200238 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 u16 sens[3]; /* 782D/783S only.
240 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200241 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 u8 vrm;
243};
244
Wolfgang Grandegger443850c2008-10-17 17:51:18 +0200245static struct w83781d_data *w83781d_data_if_isa(void);
246static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
247
Jean Delvare31b8dc42007-05-08 17:22:03 +0200248static int w83781d_read_value(struct w83781d_data *data, u16 reg);
249static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200251static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253/* following are the sysfs callback functions */
254#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200255static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
256 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{ \
Jean Delvare34875332007-05-08 17:22:03 +0200258 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200260 return sprintf(buf, "%ld\n", \
261 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262}
263show_in_reg(in);
264show_in_reg(in_min);
265show_in_reg(in_max);
266
267#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200268static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
269 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{ \
Jean Delvare34875332007-05-08 17:22:03 +0200271 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200272 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200273 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 u32 val; \
275 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200276 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100278 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200280 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100282 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return count; \
284}
285store_in_reg(MIN, min);
286store_in_reg(MAX, max);
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200289static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
290 show_in, NULL, offset); \
291static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
292 show_in_min, store_in_min, offset); \
293static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
294 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296sysfs_in_offsets(0);
297sysfs_in_offsets(1);
298sysfs_in_offsets(2);
299sysfs_in_offsets(3);
300sysfs_in_offsets(4);
301sysfs_in_offsets(5);
302sysfs_in_offsets(6);
303sysfs_in_offsets(7);
304sysfs_in_offsets(8);
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200307static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
308 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{ \
Jean Delvare34875332007-05-08 17:22:03 +0200310 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 struct w83781d_data *data = w83781d_update_device(dev); \
312 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200313 FAN_FROM_REG(data->reg[attr->index], \
314 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316show_fan_reg(fan);
317show_fan_reg(fan_min);
318
319static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200320store_fan_min(struct device *dev, struct device_attribute *da,
321 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Jean Delvare34875332007-05-08 17:22:03 +0200323 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200324 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200325 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 u32 val;
327
328 val = simple_strtoul(buf, NULL, 10);
329
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100330 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200331 data->fan_min[nr] =
332 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200333 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200334 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100336 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return count;
338}
339
Jean Delvare34875332007-05-08 17:22:03 +0200340static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
341static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
342 show_fan_min, store_fan_min, 0);
343static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
344static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
345 show_fan_min, store_fan_min, 1);
346static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
347static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
348 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200351static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
352 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{ \
Jean Delvare34875332007-05-08 17:22:03 +0200354 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200356 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
358 return sprintf(buf,"%d\n", \
359 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
360 } else { /* TEMP1 */ \
361 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
362 } \
363}
364show_temp_reg(temp);
365show_temp_reg(temp_max);
366show_temp_reg(temp_max_hyst);
367
368#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200369static ssize_t store_temp_##reg (struct device *dev, \
370 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{ \
Jean Delvare34875332007-05-08 17:22:03 +0200372 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200373 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200374 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200375 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 \
377 val = simple_strtol(buf, NULL, 10); \
378 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100379 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 \
381 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
382 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200383 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 data->temp_##reg##_add[nr-2]); \
385 } else { /* TEMP1 */ \
386 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200387 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 data->temp_##reg); \
389 } \
390 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100391 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return count; \
393}
394store_temp_reg(OVER, max);
395store_temp_reg(HYST, max_hyst);
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200398static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
399 show_temp, NULL, offset); \
400static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
401 show_temp_max, store_temp_max, offset); \
402static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
403 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405sysfs_temp_offsets(1);
406sysfs_temp_offsets(2);
407sysfs_temp_offsets(3);
408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400410show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 struct w83781d_data *data = w83781d_update_device(dev);
413 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
414}
415
Jim Cromie311ce2e2006-09-24 21:22:52 +0200416static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400419show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
Jean Delvare90d66192007-10-08 18:24:35 +0200421 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return sprintf(buf, "%ld\n", (long) data->vrm);
423}
424
425static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400426store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427{
Jean Delvare7666c132007-05-08 17:22:02 +0200428 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 u32 val;
430
431 val = simple_strtoul(buf, NULL, 10);
432 data->vrm = val;
433
434 return count;
435}
436
Jim Cromie311ce2e2006-09-24 21:22:52 +0200437static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400440show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200443 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
Jim Cromie311ce2e2006-09-24 21:22:52 +0200446static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
447
Jean Delvare7d4a1372007-10-08 18:29:43 +0200448static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
449 char *buf)
450{
451 struct w83781d_data *data = w83781d_update_device(dev);
452 int bitnr = to_sensor_dev_attr(attr)->index;
453 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
454}
455
456/* The W83781D has a single alarm bit for temp2 and temp3 */
457static ssize_t show_temp3_alarm(struct device *dev,
458 struct device_attribute *attr, char *buf)
459{
460 struct w83781d_data *data = w83781d_update_device(dev);
461 int bitnr = (data->type == w83781d) ? 5 : 13;
462 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
463}
464
465static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
466static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
467static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
468static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
469static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
470static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
471static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
472static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
473static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
474static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
475static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
476static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
477static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
478static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
479static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
480
Yani Ioannoue404e272005-05-17 06:42:58 -0400481static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct w83781d_data *data = w83781d_update_device(dev);
484 return sprintf(buf, "%ld\n",
485 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
486}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200489store_beep_mask(struct device *dev, struct device_attribute *attr,
490 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Jean Delvare7666c132007-05-08 17:22:02 +0200492 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200493 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 val = simple_strtoul(buf, NULL, 10);
496
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100497 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200498 data->beep_mask &= 0x8000; /* preserve beep enable */
499 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200500 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
501 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200502 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200503 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200504 if (data->type != w83781d && data->type != as99127f) {
505 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
506 ((data->beep_mask) >> 16) & 0xff);
507 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100508 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return count;
511}
512
Jean Delvare34875332007-05-08 17:22:03 +0200513static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
514 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Jean Delvare7d4a1372007-10-08 18:29:43 +0200516static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
517 char *buf)
518{
519 struct w83781d_data *data = w83781d_update_device(dev);
520 int bitnr = to_sensor_dev_attr(attr)->index;
521 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
522}
523
524static ssize_t
525store_beep(struct device *dev, struct device_attribute *attr,
526 const char *buf, size_t count)
527{
528 struct w83781d_data *data = dev_get_drvdata(dev);
529 int bitnr = to_sensor_dev_attr(attr)->index;
530 unsigned long bit;
531 u8 reg;
532
533 bit = simple_strtoul(buf, NULL, 10);
534 if (bit & ~1)
535 return -EINVAL;
536
537 mutex_lock(&data->update_lock);
538 if (bit)
539 data->beep_mask |= (1 << bitnr);
540 else
541 data->beep_mask &= ~(1 << bitnr);
542
543 if (bitnr < 8) {
544 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
545 if (bit)
546 reg |= (1 << bitnr);
547 else
548 reg &= ~(1 << bitnr);
549 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
550 } else if (bitnr < 16) {
551 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
552 if (bit)
553 reg |= (1 << (bitnr - 8));
554 else
555 reg &= ~(1 << (bitnr - 8));
556 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
557 } else {
558 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
559 if (bit)
560 reg |= (1 << (bitnr - 16));
561 else
562 reg &= ~(1 << (bitnr - 16));
563 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
564 }
565 mutex_unlock(&data->update_lock);
566
567 return count;
568}
569
570/* The W83781D has a single beep bit for temp2 and temp3 */
571static ssize_t show_temp3_beep(struct device *dev,
572 struct device_attribute *attr, char *buf)
573{
574 struct w83781d_data *data = w83781d_update_device(dev);
575 int bitnr = (data->type == w83781d) ? 5 : 13;
576 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
577}
578
579static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
580 show_beep, store_beep, 0);
581static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
582 show_beep, store_beep, 1);
583static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
584 show_beep, store_beep, 2);
585static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
586 show_beep, store_beep, 3);
587static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
588 show_beep, store_beep, 8);
589static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
590 show_beep, store_beep, 9);
591static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
592 show_beep, store_beep, 10);
593static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
594 show_beep, store_beep, 16);
595static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
596 show_beep, store_beep, 17);
597static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
598 show_beep, store_beep, 6);
599static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
600 show_beep, store_beep, 7);
601static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
602 show_beep, store_beep, 11);
603static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
604 show_beep, store_beep, 4);
605static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
606 show_beep, store_beep, 5);
607static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
608 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200609static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
610 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200613show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
Jean Delvare34875332007-05-08 17:22:03 +0200615 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct w83781d_data *data = w83781d_update_device(dev);
617 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200618 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621/* Note: we save and restore the fan minimum here, because its value is
622 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200623 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 because the divisor changed. */
625static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200626store_fan_div(struct device *dev, struct device_attribute *da,
627 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Jean Delvare34875332007-05-08 17:22:03 +0200629 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200630 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200632 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 u8 reg;
634 unsigned long val = simple_strtoul(buf, NULL, 10);
635
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100636 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* Save fan_min */
639 min = FAN_FROM_REG(data->fan_min[nr],
640 DIV_FROM_REG(data->fan_div[nr]));
641
642 data->fan_div[nr] = DIV_TO_REG(val, data->type);
643
Jean Delvare31b8dc42007-05-08 17:22:03 +0200644 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 & (nr==0 ? 0xcf : 0x3f))
646 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200647 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 /* w83781d and as99127f don't have extended divisor bits */
650 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200651 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 & ~(1 << (5 + nr)))
653 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200654 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
656
657 /* Restore fan_min */
658 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200659 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100661 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return count;
663}
664
Jean Delvare34875332007-05-08 17:22:03 +0200665static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
666 show_fan_div, store_fan_div, 0);
667static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
668 show_fan_div, store_fan_div, 1);
669static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
670 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200673show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
Jean Delvare34875332007-05-08 17:22:03 +0200675 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200677 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200681show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200684 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685}
686
687static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200688store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
689 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Jean Delvare34875332007-05-08 17:22:03 +0200691 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200692 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200693 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 u32 val;
695
696 val = simple_strtoul(buf, NULL, 10);
697
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100698 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200699 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
700 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100701 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return count;
703}
704
705static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200706store_pwm2_enable(struct device *dev, struct device_attribute *da,
707 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
Jean Delvare7666c132007-05-08 17:22:02 +0200709 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 u32 val, reg;
711
712 val = simple_strtoul(buf, NULL, 10);
713
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100714 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 switch (val) {
717 case 0:
718 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200719 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
720 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 (reg & 0xf7) | (val << 3));
722
Jean Delvare31b8dc42007-05-08 17:22:03 +0200723 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
724 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 (reg & 0xef) | (!val << 4));
726
Jean Delvare34875332007-05-08 17:22:03 +0200727 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 break;
729
730 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100731 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return -EINVAL;
733 }
734
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100735 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return count;
737}
738
Jean Delvare34875332007-05-08 17:22:03 +0200739static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
740static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
741static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
742static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
743/* only PWM2 can be enabled/disabled */
744static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
745 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200748show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Jean Delvare34875332007-05-08 17:22:03 +0200750 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200752 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
755static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200756store_sensor(struct device *dev, struct device_attribute *da,
757 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Jean Delvare34875332007-05-08 17:22:03 +0200759 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200760 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200761 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 u32 val, tmp;
763
764 val = simple_strtoul(buf, NULL, 10);
765
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100766 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 switch (val) {
769 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200770 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
771 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200772 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200773 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
774 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200775 tmp | BIT_SCFG2[nr]);
776 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
778 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200779 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
780 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200781 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200782 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
783 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200784 tmp & ~BIT_SCFG2[nr]);
785 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200787 case W83781D_DEFAULT_BETA:
788 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
789 "instead\n", W83781D_DEFAULT_BETA);
790 /* fall through */
791 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200792 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
793 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200794 tmp & ~BIT_SCFG1[nr]);
795 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 break;
797 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200798 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
799 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 break;
801 }
802
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100803 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return count;
805}
806
Jean Delvare34875332007-05-08 17:22:03 +0200807static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
808 show_sensor, store_sensor, 0);
809static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400810 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200811static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400812 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814/* Assumes that adapter is of I2C, not ISA variety.
815 * OTHERWISE DON'T CALL THIS
816 */
817static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200818w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
820 int i, val1 = 0, id;
821 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200822 int address = new_client->addr;
823 unsigned short sc_addr[2];
824 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200826 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 id = i2c_adapter_id(adapter);
829
830 if (force_subclients[0] == id && force_subclients[1] == address) {
831 for (i = 2; i <= 3; i++) {
832 if (force_subclients[i] < 0x48 ||
833 force_subclients[i] > 0x4f) {
834 dev_err(&new_client->dev, "Invalid subclient "
835 "address %d; must be 0x48-0x4f\n",
836 force_subclients[i]);
837 err = -EINVAL;
838 goto ERROR_SC_1;
839 }
840 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200841 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 (force_subclients[2] & 0x07) |
843 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200844 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200846 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200847 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849
850 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (force_subclients[0] == id &&
852 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200853 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200855 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200857 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 dev_err(&new_client->dev,
859 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200860 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 err = -EBUSY;
862 goto ERROR_SC_2;
863 }
864 }
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200867 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
868 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 dev_err(&new_client->dev, "Subclient %d "
870 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200871 "failed.\n", i, sc_addr[i]);
872 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (i == 1)
874 goto ERROR_SC_3;
875 goto ERROR_SC_2;
876 }
877 if (kind == w83783s)
878 break;
879 }
880
881 return 0;
882
883/* Undo inits in case of errors */
884ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200885 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return err;
889}
890
Jean Delvare34875332007-05-08 17:22:03 +0200891#define IN_UNIT_ATTRS(X) \
892 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
893 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100894 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200895 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
896 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200897
Jean Delvare34875332007-05-08 17:22:03 +0200898#define FAN_UNIT_ATTRS(X) \
899 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
900 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200901 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
902 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
903 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200904
Jean Delvare34875332007-05-08 17:22:03 +0200905#define TEMP_UNIT_ATTRS(X) \
906 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
907 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200908 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
909 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
910 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200911
912static struct attribute* w83781d_attributes[] = {
913 IN_UNIT_ATTRS(0),
914 IN_UNIT_ATTRS(2),
915 IN_UNIT_ATTRS(3),
916 IN_UNIT_ATTRS(4),
917 IN_UNIT_ATTRS(5),
918 IN_UNIT_ATTRS(6),
919 FAN_UNIT_ATTRS(1),
920 FAN_UNIT_ATTRS(2),
921 FAN_UNIT_ATTRS(3),
922 TEMP_UNIT_ATTRS(1),
923 TEMP_UNIT_ATTRS(2),
924 &dev_attr_cpu0_vid.attr,
925 &dev_attr_vrm.attr,
926 &dev_attr_alarms.attr,
927 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200928 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200929 NULL
930};
931static const struct attribute_group w83781d_group = {
932 .attrs = w83781d_attributes,
933};
934
935static struct attribute *w83781d_attributes_opt[] = {
936 IN_UNIT_ATTRS(1),
937 IN_UNIT_ATTRS(7),
938 IN_UNIT_ATTRS(8),
939 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200940 &sensor_dev_attr_pwm1.dev_attr.attr,
941 &sensor_dev_attr_pwm2.dev_attr.attr,
942 &sensor_dev_attr_pwm3.dev_attr.attr,
943 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200944 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200945 &sensor_dev_attr_temp1_type.dev_attr.attr,
946 &sensor_dev_attr_temp2_type.dev_attr.attr,
947 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200948 NULL
949};
950static const struct attribute_group w83781d_group_opt = {
951 .attrs = w83781d_attributes_opt,
952};
953
Jean Delvare7666c132007-05-08 17:22:02 +0200954/* No clean up is done on error, it's up to the caller */
955static int
956w83781d_create_files(struct device *dev, int kind, int is_isa)
957{
958 int err;
959
960 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
961 return err;
962
963 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200964 if ((err = device_create_file(dev,
965 &sensor_dev_attr_in1_input.dev_attr))
966 || (err = device_create_file(dev,
967 &sensor_dev_attr_in1_min.dev_attr))
968 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200969 &sensor_dev_attr_in1_max.dev_attr))
970 || (err = device_create_file(dev,
971 &sensor_dev_attr_in1_alarm.dev_attr))
972 || (err = device_create_file(dev,
973 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200974 return err;
975 }
976 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200977 if ((err = device_create_file(dev,
978 &sensor_dev_attr_in7_input.dev_attr))
979 || (err = device_create_file(dev,
980 &sensor_dev_attr_in7_min.dev_attr))
981 || (err = device_create_file(dev,
982 &sensor_dev_attr_in7_max.dev_attr))
983 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200984 &sensor_dev_attr_in7_alarm.dev_attr))
985 || (err = device_create_file(dev,
986 &sensor_dev_attr_in7_beep.dev_attr))
987 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200988 &sensor_dev_attr_in8_input.dev_attr))
989 || (err = device_create_file(dev,
990 &sensor_dev_attr_in8_min.dev_attr))
991 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200992 &sensor_dev_attr_in8_max.dev_attr))
993 || (err = device_create_file(dev,
994 &sensor_dev_attr_in8_alarm.dev_attr))
995 || (err = device_create_file(dev,
996 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200997 return err;
998 }
999 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001000 if ((err = device_create_file(dev,
1001 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001002 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001003 &sensor_dev_attr_temp3_max.dev_attr))
1004 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001005 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1006 || (err = device_create_file(dev,
1007 &sensor_dev_attr_temp3_alarm.dev_attr))
1008 || (err = device_create_file(dev,
1009 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001010 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001011
Jean Delvare7768aa72007-10-25 13:11:01 +02001012 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001013 err = sysfs_chmod_file(&dev->kobj,
1014 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1015 S_IRUGO | S_IWUSR);
1016 if (err)
1017 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001018 }
Jean Delvare7666c132007-05-08 17:22:02 +02001019 }
1020
1021 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001022 if ((err = device_create_file(dev,
1023 &sensor_dev_attr_pwm1.dev_attr))
1024 || (err = device_create_file(dev,
1025 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001026 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1027 return err;
1028 }
1029 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001030 if ((err = device_create_file(dev,
1031 &sensor_dev_attr_pwm3.dev_attr))
1032 || (err = device_create_file(dev,
1033 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001034 return err;
1035 }
1036
1037 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001038 if ((err = device_create_file(dev,
1039 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001040 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001041 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001042 return err;
1043 if (kind != w83783s) {
1044 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001045 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001046 return err;
1047 }
1048 }
1049
Jean Delvare7666c132007-05-08 17:22:02 +02001050 return 0;
1051}
1052
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001053/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054static int
Jean Delvare310ec792009-12-14 21:17:23 +01001055w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Jean Delvarebab2bf42009-12-09 20:35:54 +01001057 int val1, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001058 struct w83781d_data *isa = w83781d_data_if_isa();
1059 struct i2c_adapter *adapter = client->adapter;
1060 int address = client->addr;
Jean Delvarebab2bf42009-12-09 20:35:54 +01001061 const char *client_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 enum vendor { winbond, asus } vendid;
1063
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001064 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1065 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001067 /* We block updates of the ISA device to minimize the risk of
1068 concurrent access to the same W83781D chip through different
1069 interfaces. */
1070 if (isa)
1071 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Jean Delvarebab2bf42009-12-09 20:35:54 +01001073 if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1074 dev_dbg(&adapter->dev,
1075 "Detection of w83781d chip failed at step 3\n");
1076 goto err_nodev;
1077 }
1078
1079 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1080 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1081 /* Check for Winbond or Asus ID if in bank 0 */
1082 if (!(val1 & 0x07) &&
1083 ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
1084 ( (val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
1085 dev_dbg(&adapter->dev,
1086 "Detection of w83781d chip failed at step 4\n");
1087 goto err_nodev;
1088 }
1089 /* If Winbond SMBus, check address at 0x48.
1090 Asus doesn't support, except for as99127f rev.2 */
1091 if ((!(val1 & 0x80) && val2 == 0xa3) ||
1092 ( (val1 & 0x80) && val2 == 0x5c)) {
1093 if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1094 != address) {
1095 dev_dbg(&adapter->dev,
1096 "Detection of w83781d chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001097 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
1100
Jean Delvarebab2bf42009-12-09 20:35:54 +01001101 /* Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001102 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1103 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1104 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jean Delvarebab2bf42009-12-09 20:35:54 +01001106 /* Get the vendor ID */
1107 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1108 if (val2 == 0x5c)
1109 vendid = winbond;
1110 else if (val2 == 0x12)
1111 vendid = asus;
1112 else {
1113 dev_dbg(&adapter->dev,
1114 "w83781d chip vendor is neither Winbond nor Asus\n");
1115 goto err_nodev;
1116 }
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 /* Determine the chip type. */
Jean Delvarebab2bf42009-12-09 20:35:54 +01001119 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
1120 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1121 client_name = "w83781d";
1122 else if (val1 == 0x30 && vendid == winbond)
1123 client_name = "w83782d";
1124 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1125 client_name = "w83783s";
1126 else if (val1 == 0x31)
1127 client_name = "as99127f";
1128 else
1129 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Jean Delvarebab2bf42009-12-09 20:35:54 +01001131 if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1132 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1133 "be the same as ISA device\n", address);
1134 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
1136
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001137 if (isa)
1138 mutex_unlock(&isa->update_lock);
1139
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001140 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001142 return 0;
1143
1144 err_nodev:
1145 if (isa)
1146 mutex_unlock(&isa->update_lock);
1147 return -ENODEV;
1148}
1149
1150static int
1151w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1152{
1153 struct device *dev = &client->dev;
1154 struct w83781d_data *data;
1155 int err;
1156
1157 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1158 if (!data) {
1159 err = -ENOMEM;
1160 goto ERROR1;
1161 }
1162
1163 i2c_set_clientdata(client, data);
1164 mutex_init(&data->lock);
1165 mutex_init(&data->update_lock);
1166
1167 data->type = id->driver_data;
1168 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001171 err = w83781d_detect_subclients(client);
1172 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001173 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001176 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001179 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001180 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001181 goto ERROR4;
1182
Tony Jones1beeffe2007-08-20 13:46:20 -07001183 data->hwmon_dev = hwmon_device_register(dev);
1184 if (IS_ERR(data->hwmon_dev)) {
1185 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001186 goto ERROR4;
1187 }
1188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return 0;
1190
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001191ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001192 sysfs_remove_group(&dev->kobj, &w83781d_group);
1193 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1194
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001195 if (data->lm75[0])
1196 i2c_unregister_device(data->lm75[0]);
1197 if (data->lm75[1])
1198 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199ERROR3:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 kfree(data);
1201ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return err;
1203}
1204
1205static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001206w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001208 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001209 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001211 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001213 sysfs_remove_group(&dev->kobj, &w83781d_group);
1214 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001216 if (data->lm75[0])
1217 i2c_unregister_device(data->lm75[0]);
1218 if (data->lm75[1])
1219 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001220
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001221 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223 return 0;
1224}
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001227w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001229 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001230 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 struct i2c_client *cl;
1232
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001233 bank = (reg >> 8) & 0x0f;
1234 if (bank > 2)
1235 /* switch banks */
1236 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1237 bank);
1238 if (bank == 0 || bank > 2) {
1239 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001241 /* switch to subclient */
1242 cl = data->lm75[bank - 1];
1243 /* convert from ISA to LM75 I2C addresses */
1244 switch (reg & 0xff) {
1245 case 0x50: /* TEMP */
1246 res = swab16(i2c_smbus_read_word_data(cl, 0));
1247 break;
1248 case 0x52: /* CONFIG */
1249 res = i2c_smbus_read_byte_data(cl, 1);
1250 break;
1251 case 0x53: /* HYST */
1252 res = swab16(i2c_smbus_read_word_data(cl, 2));
1253 break;
1254 case 0x55: /* OVER */
1255 default:
1256 res = swab16(i2c_smbus_read_word_data(cl, 3));
1257 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001260 if (bank > 2)
1261 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 return res;
1264}
1265
1266static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001267w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001269 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001270 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 struct i2c_client *cl;
1272
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001273 bank = (reg >> 8) & 0x0f;
1274 if (bank > 2)
1275 /* switch banks */
1276 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1277 bank);
1278 if (bank == 0 || bank > 2) {
1279 i2c_smbus_write_byte_data(client, reg & 0xff,
1280 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001282 /* switch to subclient */
1283 cl = data->lm75[bank - 1];
1284 /* convert from ISA to LM75 I2C addresses */
1285 switch (reg & 0xff) {
1286 case 0x52: /* CONFIG */
1287 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1288 break;
1289 case 0x53: /* HYST */
1290 i2c_smbus_write_word_data(cl, 2, swab16(value));
1291 break;
1292 case 0x55: /* OVER */
1293 i2c_smbus_write_word_data(cl, 3, swab16(value));
1294 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001297 if (bank > 2)
1298 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 return 0;
1301}
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303static void
Jean Delvare7666c132007-05-08 17:22:02 +02001304w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
Jean Delvare7666c132007-05-08 17:22:02 +02001306 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 int i, p;
1308 int type = data->type;
1309 u8 tmp;
1310
Jean Delvarefabddcd2006-02-05 23:26:51 +01001311 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001313 /* Resetting the chip has been the default for a long time,
1314 but it causes the BIOS initializations (fan clock dividers,
1315 thermal sensor types...) to be lost, so it is now optional.
1316 It might even go away if nobody reports it as being useful,
1317 as I see very little reason why this would be needed at
1318 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001319 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001320 "having, please report!\n");
1321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001323 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1324 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 /* Reset all except Watchdog values and last conversion values
1326 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001327 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 /* Restore the registers and disable power-on abnormal beep.
1329 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001330 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1331 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* Disable master beep-enable (reset turns it on).
1333 Individual beep_mask should be reset to off but for some reason
1334 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001335 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337
Jean Delvarefabddcd2006-02-05 23:26:51 +01001338 /* Disable power-on abnormal beep, as advised by the datasheet.
1339 Already done if reset=1. */
1340 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001341 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1342 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001343 }
1344
Jean Delvare303760b2005-07-31 21:52:01 +02001345 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001348 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 for (i = 1; i <= 3; i++) {
1350 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001351 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 } else {
1353 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001354 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1356 data->sens[i - 1] = 1;
1357 else
1358 data->sens[i - 1] = 2;
1359 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001360 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 break;
1362 }
1363 }
1364
1365 if (init && type != as99127f) {
1366 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001367 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001369 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001371 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 tmp & 0xfe);
1373 }
1374
1375 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001376 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001377 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 W83781D_REG_TEMP3_CONFIG);
1379 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001380 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001382 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1384 }
1385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 }
1387
1388 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001389 w83781d_write_value(data, W83781D_REG_CONFIG,
1390 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 W83781D_REG_CONFIG) & 0xf7)
1392 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001393
1394 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001395 for (i = 0; i < 3; i++) {
1396 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001397 W83781D_REG_FAN_MIN(i));
1398 }
Jean Delvare7666c132007-05-08 17:22:02 +02001399
1400 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
1402
1403static struct w83781d_data *w83781d_update_device(struct device *dev)
1404{
Jean Delvare7666c132007-05-08 17:22:02 +02001405 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001406 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 int i;
1408
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001409 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1412 || !data->valid) {
1413 dev_dbg(dev, "Starting device update\n");
1414
1415 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001416 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 continue; /* 783S has no in1 */
1418 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001419 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001421 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001423 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001424 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 break;
1426 }
Jean Delvare34875332007-05-08 17:22:03 +02001427 for (i = 0; i < 3; i++) {
1428 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001429 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001430 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001431 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 }
1433 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001434 for (i = 0; i < 4; i++) {
1435 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001436 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001437 W83781D_REG_PWM[i]);
Jean Delvare848ddf12009-05-08 20:27:28 +02001438 /* Only W83782D on SMBus has PWM3 and PWM4 */
1439 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001440 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 break;
1442 }
1443 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001444 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1446 }
1447
Jean Delvare31b8dc42007-05-08 17:22:03 +02001448 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001450 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001452 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001454 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001456 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001458 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001459 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001461 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001463 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 W83781D_REG_TEMP_OVER(3));
1465 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001466 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 W83781D_REG_TEMP_HYST(3));
1468 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001469 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001470 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001471 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001472 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 data->fan_div[0] = (i >> 4) & 0x03;
1474 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001475 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001476 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001478 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 data->fan_div[0] |= (i >> 3) & 0x04;
1480 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001481 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
Jean Delvare05663362007-11-30 23:51:24 +01001483 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001484 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001485 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001486 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001487 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001489 W83782D_REG_ALARM3) << 16);
1490 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001491 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001492 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001493 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001494 W83782D_REG_ALARM2) << 8);
1495 } else {
1496 /* No real-time status registers, fall back to
1497 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001498 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001499 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001500 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001501 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001503 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001504 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001505 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 if ((data->type != w83781d) && (data->type != as99127f)) {
1507 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001508 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 W83781D_REG_BEEP_INTS3) << 16;
1510 }
1511 data->last_updated = jiffies;
1512 data->valid = 1;
1513 }
1514
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001515 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
1517 return data;
1518}
1519
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001520static const struct i2c_device_id w83781d_ids[] = {
1521 { "w83781d", w83781d, },
1522 { "w83782d", w83782d, },
1523 { "w83783s", w83783s, },
1524 { "as99127f", as99127f },
1525 { /* LIST END */ }
1526};
1527MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1528
1529static struct i2c_driver w83781d_driver = {
1530 .class = I2C_CLASS_HWMON,
1531 .driver = {
1532 .name = "w83781d",
1533 },
1534 .probe = w83781d_probe,
1535 .remove = w83781d_remove,
1536 .id_table = w83781d_ids,
1537 .detect = w83781d_detect,
Jean Delvarec3813d62009-12-14 21:17:25 +01001538 .address_list = normal_i2c,
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001539};
1540
1541/*
1542 * ISA related code
1543 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001544#ifdef CONFIG_ISA
1545
1546/* ISA device, if found */
1547static struct platform_device *pdev;
1548
1549static unsigned short isa_address = 0x290;
1550
1551/* I2C devices get this name attribute automatically, but for ISA devices
1552 we must create it by ourselves. */
1553static ssize_t
1554show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1555{
1556 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001557 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001558}
1559static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1560
1561static struct w83781d_data *w83781d_data_if_isa(void)
1562{
1563 return pdev ? platform_get_drvdata(pdev) : NULL;
1564}
1565
1566/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1567static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1568{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001569 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001570 int i;
1571
1572 if (!pdev) /* No ISA chip */
1573 return 0;
1574
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001575 isa = platform_get_drvdata(pdev);
1576
1577 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1578 return 0; /* Address doesn't match */
1579 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1580 return 0; /* Chip type doesn't match */
1581
1582 /* We compare all the limit registers, the config register and the
1583 * interrupt mask registers */
1584 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001585 if (w83781d_read_value(isa, i) !=
1586 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001587 return 0;
1588 }
1589 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001590 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001591 return 0;
1592 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001593 if (w83781d_read_value(isa, i) !=
1594 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001595 return 0;
1596 }
1597
1598 return 1;
1599}
1600
1601static int
1602w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1603{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001604 int word_sized, res;
1605
1606 word_sized = (((reg & 0xff00) == 0x100)
1607 || ((reg & 0xff00) == 0x200))
1608 && (((reg & 0x00ff) == 0x50)
1609 || ((reg & 0x00ff) == 0x53)
1610 || ((reg & 0x00ff) == 0x55));
1611 if (reg & 0xff00) {
1612 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001613 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001614 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001615 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001616 }
Jean Delvare360782d2008-10-17 17:51:19 +02001617 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1618 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001619 if (word_sized) {
1620 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001621 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001622 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001623 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001624 W83781D_DATA_REG_OFFSET);
1625 }
1626 if (reg & 0xff00) {
1627 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001628 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1629 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001630 }
1631 return res;
1632}
1633
1634static void
1635w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1636{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001637 int word_sized;
1638
1639 word_sized = (((reg & 0xff00) == 0x100)
1640 || ((reg & 0xff00) == 0x200))
1641 && (((reg & 0x00ff) == 0x53)
1642 || ((reg & 0x00ff) == 0x55));
1643 if (reg & 0xff00) {
1644 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001645 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001646 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001647 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001648 }
Jean Delvare360782d2008-10-17 17:51:19 +02001649 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001650 if (word_sized) {
1651 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001652 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001653 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001654 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001655 }
Jean Delvare360782d2008-10-17 17:51:19 +02001656 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001657 if (reg & 0xff00) {
1658 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001659 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1660 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001661 }
1662}
1663
1664/* The SMBus locks itself, usually, but nothing may access the Winbond between
1665 bank switches. ISA access must always be locked explicitly!
1666 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1667 would slow down the W83781D access and should not be necessary.
1668 There are some ugly typecasts here, but the good news is - they should
1669 nowhere else be necessary! */
1670static int
1671w83781d_read_value(struct w83781d_data *data, u16 reg)
1672{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001673 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001674 int res;
1675
1676 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001677 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001678 res = w83781d_read_value_i2c(data, reg);
1679 else
1680 res = w83781d_read_value_isa(data, reg);
1681 mutex_unlock(&data->lock);
1682 return res;
1683}
1684
1685static int
1686w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1687{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001688 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001689
1690 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001691 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001692 w83781d_write_value_i2c(data, reg, value);
1693 else
1694 w83781d_write_value_isa(data, reg, value);
1695 mutex_unlock(&data->lock);
1696 return 0;
1697}
1698
1699static int __devinit
1700w83781d_isa_probe(struct platform_device *pdev)
1701{
1702 int err, reg;
1703 struct w83781d_data *data;
1704 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001705
1706 /* Reserve the ISA region */
1707 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1708 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1709 "w83781d")) {
1710 err = -EBUSY;
1711 goto exit;
1712 }
1713
1714 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1715 if (!data) {
1716 err = -ENOMEM;
1717 goto exit_release_region;
1718 }
1719 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001720 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001721 platform_set_drvdata(pdev, data);
1722
1723 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1724 switch (reg) {
1725 case 0x30:
1726 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001727 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001728 break;
1729 default:
1730 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001731 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001732 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001733
1734 /* Initialize the W83781D chip */
1735 w83781d_init_device(&pdev->dev);
1736
1737 /* Register sysfs hooks */
1738 err = w83781d_create_files(&pdev->dev, data->type, 1);
1739 if (err)
1740 goto exit_remove_files;
1741
1742 err = device_create_file(&pdev->dev, &dev_attr_name);
1743 if (err)
1744 goto exit_remove_files;
1745
1746 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1747 if (IS_ERR(data->hwmon_dev)) {
1748 err = PTR_ERR(data->hwmon_dev);
1749 goto exit_remove_files;
1750 }
1751
1752 return 0;
1753
1754 exit_remove_files:
1755 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1756 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1757 device_remove_file(&pdev->dev, &dev_attr_name);
1758 kfree(data);
1759 exit_release_region:
1760 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1761 exit:
1762 return err;
1763}
1764
1765static int __devexit
1766w83781d_isa_remove(struct platform_device *pdev)
1767{
1768 struct w83781d_data *data = platform_get_drvdata(pdev);
1769
1770 hwmon_device_unregister(data->hwmon_dev);
1771 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1772 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1773 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001774 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001775 kfree(data);
1776
1777 return 0;
1778}
1779
1780static struct platform_driver w83781d_isa_driver = {
1781 .driver = {
1782 .owner = THIS_MODULE,
1783 .name = "w83781d",
1784 },
1785 .probe = w83781d_isa_probe,
1786 .remove = __devexit_p(w83781d_isa_remove),
1787};
1788
Jean Delvare7666c132007-05-08 17:22:02 +02001789/* return 1 if a supported chip is found, 0 otherwise */
1790static int __init
1791w83781d_isa_found(unsigned short address)
1792{
1793 int val, save, found = 0;
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001794 int port;
Jean Delvare7666c132007-05-08 17:22:02 +02001795
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001796 /* Some boards declare base+0 to base+7 as a PNP device, some base+4
1797 * to base+7 and some base+5 to base+6. So we better request each port
1798 * individually for the probing phase. */
1799 for (port = address; port < address + W83781D_EXTENT; port++) {
1800 if (!request_region(port, 1, "w83781d")) {
1801 pr_debug("w83781d: Failed to request port 0x%x\n",
1802 port);
1803 goto release;
1804 }
Jean Delvare2961cb22008-03-09 13:34:28 +01001805 }
Jean Delvare7666c132007-05-08 17:22:02 +02001806
1807#define REALLY_SLOW_IO
1808 /* We need the timeouts for at least some W83781D-like
1809 chips. But only if we read 'undefined' registers. */
1810 val = inb_p(address + 1);
1811 if (inb_p(address + 2) != val
1812 || inb_p(address + 3) != val
1813 || inb_p(address + 7) != val) {
1814 pr_debug("w83781d: Detection failed at step 1\n");
1815 goto release;
1816 }
1817#undef REALLY_SLOW_IO
1818
1819 /* We should be able to change the 7 LSB of the address port. The
1820 MSB (busy flag) should be clear initially, set after the write. */
1821 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1822 if (save & 0x80) {
1823 pr_debug("w83781d: Detection failed at step 2\n");
1824 goto release;
1825 }
1826 val = ~save & 0x7f;
1827 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1828 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1829 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1830 pr_debug("w83781d: Detection failed at step 3\n");
1831 goto release;
1832 }
1833
1834 /* We found a device, now see if it could be a W83781D */
1835 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1836 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1837 if (val & 0x80) {
1838 pr_debug("w83781d: Detection failed at step 4\n");
1839 goto release;
1840 }
1841 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1842 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1843 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1844 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1845 if ((!(save & 0x80) && (val != 0xa3))
1846 || ((save & 0x80) && (val != 0x5c))) {
1847 pr_debug("w83781d: Detection failed at step 5\n");
1848 goto release;
1849 }
1850 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1851 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1852 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1853 pr_debug("w83781d: Detection failed at step 6\n");
1854 goto release;
1855 }
1856
1857 /* The busy flag should be clear again */
1858 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1859 pr_debug("w83781d: Detection failed at step 7\n");
1860 goto release;
1861 }
1862
1863 /* Determine the chip type */
1864 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1865 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1866 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1867 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1868 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1869 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001870 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001871 found = 1;
1872
1873 if (found)
1874 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001875 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1876
1877 release:
Jean Delvareb0bcdd32010-02-05 19:58:36 +01001878 for (port--; port >= address; port--)
1879 release_region(port, 1);
Jean Delvare7666c132007-05-08 17:22:02 +02001880 return found;
1881}
1882
1883static int __init
1884w83781d_isa_device_add(unsigned short address)
1885{
1886 struct resource res = {
1887 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001888 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001889 .name = "w83781d",
1890 .flags = IORESOURCE_IO,
1891 };
1892 int err;
1893
1894 pdev = platform_device_alloc("w83781d", address);
1895 if (!pdev) {
1896 err = -ENOMEM;
1897 printk(KERN_ERR "w83781d: Device allocation failed\n");
1898 goto exit;
1899 }
1900
1901 err = platform_device_add_resources(pdev, &res, 1);
1902 if (err) {
1903 printk(KERN_ERR "w83781d: Device resource addition failed "
1904 "(%d)\n", err);
1905 goto exit_device_put;
1906 }
1907
1908 err = platform_device_add(pdev);
1909 if (err) {
1910 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1911 err);
1912 goto exit_device_put;
1913 }
1914
1915 return 0;
1916
1917 exit_device_put:
1918 platform_device_put(pdev);
1919 exit:
1920 pdev = NULL;
1921 return err;
1922}
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001925w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
Jean Delvarefde09502005-07-19 23:51:07 +02001927 int res;
1928
Jean Delvare7666c132007-05-08 17:22:02 +02001929 if (w83781d_isa_found(isa_address)) {
1930 res = platform_driver_register(&w83781d_isa_driver);
1931 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001932 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001933
1934 /* Sets global pdev as a side effect */
1935 res = w83781d_isa_device_add(isa_address);
1936 if (res)
1937 goto exit_unreg_isa_driver;
1938 }
Jean Delvarefde09502005-07-19 23:51:07 +02001939
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001940 return 0;
1941
1942exit_unreg_isa_driver:
1943 platform_driver_unregister(&w83781d_isa_driver);
1944exit:
1945 return res;
1946}
1947
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001948static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001949w83781d_isa_unregister(void)
1950{
1951 if (pdev) {
1952 platform_device_unregister(pdev);
1953 platform_driver_unregister(&w83781d_isa_driver);
1954 }
1955}
1956#else /* !CONFIG_ISA */
1957
1958static struct w83781d_data *w83781d_data_if_isa(void)
1959{
1960 return NULL;
1961}
1962
1963static int
1964w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1965{
1966 return 0;
1967}
1968
1969static int
1970w83781d_read_value(struct w83781d_data *data, u16 reg)
1971{
1972 int res;
1973
1974 mutex_lock(&data->lock);
1975 res = w83781d_read_value_i2c(data, reg);
1976 mutex_unlock(&data->lock);
1977
1978 return res;
1979}
1980
1981static int
1982w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1983{
1984 mutex_lock(&data->lock);
1985 w83781d_write_value_i2c(data, reg, value);
1986 mutex_unlock(&data->lock);
1987
1988 return 0;
1989}
1990
1991static int __init
1992w83781d_isa_register(void)
1993{
1994 return 0;
1995}
1996
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001997static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001998w83781d_isa_unregister(void)
1999{
2000}
2001#endif /* CONFIG_ISA */
2002
2003static int __init
2004sensors_w83781d_init(void)
2005{
2006 int res;
2007
2008 /* We register the ISA device first, so that we can skip the
2009 * registration of an I2C interface to the same device. */
2010 res = w83781d_isa_register();
2011 if (res)
2012 goto exit;
2013
Jean Delvarec6566202008-10-17 17:51:18 +02002014 res = i2c_add_driver(&w83781d_driver);
2015 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002016 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002017
Jean Delvarefde09502005-07-19 23:51:07 +02002018 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002019
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002020 exit_unreg_isa:
2021 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002022 exit:
2023 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024}
2025
2026static void __exit
2027sensors_w83781d_exit(void)
2028{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002029 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 i2c_del_driver(&w83781d_driver);
2031}
2032
2033MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2034 "Philip Edelbrock <phil@netroedge.com>, "
2035 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2036MODULE_DESCRIPTION("W83781D driver");
2037MODULE_LICENSE("GPL");
2038
2039module_init(sensors_w83781d_init);
2040module_exit(sensors_w83781d_exit);