blob: 7ab7967da0a0359fe1dca5f90518c927752aedf5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
Jean Delvare7666c132007-05-08 17:22:02 +02005 Philip Edelbrock <phil@netroedge.com>,
6 and Mark Studebaker <mdsxyz123@yahoo.com>
Jean Delvare360782d2008-10-17 17:51:19 +02007 Copyright (c) 2007 - 2008 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
25 Supports following chips:
26
27 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
28 as99127f 7 3 0 3 0x31 0x12c3 yes no
29 as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
30 w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
32 w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34*/
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/module.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/jiffies.h>
40#include <linux/i2c.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040041#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020042#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020043#include <linux/hwmon-sysfs.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020044#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040045#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010046#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020048#ifdef CONFIG_ISA
49#include <linux/platform_device.h>
50#include <linux/ioport.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020051#include <linux/io.h>
Wolfgang Grandegger443850c2008-10-17 17:51:18 +020052#endif
53
54#include "lm75.h"
Jean Delvare7666c132007-05-08 17:22:02 +020055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050057static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
58 0x2e, 0x2f, I2C_CLIENT_END };
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/* Insmod parameters */
Jean Delvare05663362007-11-30 23:51:24 +010060I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
Jean Delvare3aed1982009-01-07 16:37:32 +010061
62static unsigned short force_subclients[4];
63module_param_array(force_subclients, short, NULL, 0);
64MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
66
Jean Delvarefabddcd2006-02-05 23:26:51 +010067static int reset;
68module_param(reset, bool, 0);
69MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static int init = 1;
72module_param(init, bool, 0);
73MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
74
75/* Constants specified below */
76
77/* Length of ISA address segment */
78#define W83781D_EXTENT 8
79
80/* Where are the ISA address/data registers relative to the base address */
81#define W83781D_ADDR_REG_OFFSET 5
82#define W83781D_DATA_REG_OFFSET 6
83
Jean Delvare34875332007-05-08 17:22:03 +020084/* The device registers */
85/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
87 (0x554 + (((nr) - 7) * 2)))
88#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
89 (0x555 + (((nr) - 7) * 2)))
90#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
91 (0x550 + (nr) - 7))
92
Jean Delvare34875332007-05-08 17:22:03 +020093/* fan nr from 0 to 2 */
94#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
95#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97#define W83781D_REG_BANK 0x4E
98#define W83781D_REG_TEMP2_CONFIG 0x152
99#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +0200100/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
102 ((nr == 2) ? (0x0150) : \
103 (0x27)))
104#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
105 ((nr == 2) ? (0x153) : \
106 (0x3A)))
107#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
108 ((nr == 2) ? (0x155) : \
109 (0x39)))
110
111#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100112
113/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#define W83781D_REG_ALARM1 0x41
115#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Jean Delvare05663362007-11-30 23:51:24 +0100117/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100118#define W83782D_REG_ALARM1 0x459
119#define W83782D_REG_ALARM2 0x45A
120#define W83782D_REG_ALARM3 0x45B
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define W83781D_REG_BEEP_CONFIG 0x4D
123#define W83781D_REG_BEEP_INTS1 0x56
124#define W83781D_REG_BEEP_INTS2 0x57
125#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
126
127#define W83781D_REG_VID_FANDIV 0x47
128
129#define W83781D_REG_CHIPID 0x49
130#define W83781D_REG_WCHIPID 0x58
131#define W83781D_REG_CHIPMAN 0x4F
132#define W83781D_REG_PIN 0x4B
133
134/* 782D/783S only */
135#define W83781D_REG_VBAT 0x5D
136
137/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200138static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139#define W83781D_REG_PWMCLK12 0x5C
140#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142#define W83781D_REG_I2C_ADDR 0x48
143#define W83781D_REG_I2C_SUBADDR 0x4A
144
145/* The following are undocumented in the data sheets however we
146 received the information in an email from Winbond tech support */
147/* Sensor selection - not on 781d */
148#define W83781D_REG_SCFG1 0x5D
149static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
150
151#define W83781D_REG_SCFG2 0x59
152static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
153
154#define W83781D_DEFAULT_BETA 3435
155
Jean Delvare474d00a2007-05-08 17:22:03 +0200156/* Conversions */
157#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
158#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160static inline u8
161FAN_TO_REG(long rpm, int div)
162{
163 if (rpm == 0)
164 return 255;
165 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
166 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
167}
168
Jean Delvare474d00a2007-05-08 17:22:03 +0200169static inline long
170FAN_FROM_REG(u8 val, int div)
171{
172 if (val == 0)
173 return -1;
174 if (val == 255)
175 return 0;
176 return 1350000 / (val * div);
177}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Jean Delvare474d00a2007-05-08 17:22:03 +0200179#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
180#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200183 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200185 (~(val)) & 0x7fff : (val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#define DIV_FROM_REG(val) (1 << (val))
188
189static inline u8
190DIV_TO_REG(long val, enum chips type)
191{
192 int i;
193 val = SENSORS_LIMIT(val, 1,
194 ((type == w83781d
195 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000196 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (val == 0)
198 break;
199 val >>= 1;
200 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200201 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204struct w83781d_data {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200205 struct i2c_client *client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700206 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100207 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 enum chips type;
209
Jean Delvare360782d2008-10-17 17:51:19 +0200210 /* For ISA device only */
211 const char *name;
212 int isa_addr;
213
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100214 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 char valid; /* !=0 if following fields are valid */
216 unsigned long last_updated; /* In jiffies */
217
218 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
219 /* array of 2 pointers to subclients */
220
221 u8 in[9]; /* Register value - 8 & 9 for 782D only */
222 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
223 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
224 u8 fan[3]; /* Register value */
225 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200226 s8 temp; /* Register value */
227 s8 temp_max; /* Register value */
228 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 u16 temp_add[2]; /* Register value */
230 u16 temp_max_add[2]; /* Register value */
231 u16 temp_max_hyst_add[2]; /* Register value */
232 u8 fan_div[3]; /* Register encoding, shifted right */
233 u8 vid; /* Register encoding, combined */
234 u32 alarms; /* Register encoding, combined */
235 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200237 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 u16 sens[3]; /* 782D/783S only.
239 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200240 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 u8 vrm;
242};
243
Wolfgang Grandegger443850c2008-10-17 17:51:18 +0200244static struct w83781d_data *w83781d_data_if_isa(void);
245static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
246
Jean Delvare31b8dc42007-05-08 17:22:03 +0200247static int w83781d_read_value(struct w83781d_data *data, u16 reg);
248static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200250static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252/* following are the sysfs callback functions */
253#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200254static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
255 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{ \
Jean Delvare34875332007-05-08 17:22:03 +0200257 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200259 return sprintf(buf, "%ld\n", \
260 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262show_in_reg(in);
263show_in_reg(in_min);
264show_in_reg(in_max);
265
266#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200267static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
268 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{ \
Jean Delvare34875332007-05-08 17:22:03 +0200270 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200271 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200272 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 u32 val; \
274 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200275 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100277 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200279 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100281 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return count; \
283}
284store_in_reg(MIN, min);
285store_in_reg(MAX, max);
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200288static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
289 show_in, NULL, offset); \
290static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
291 show_in_min, store_in_min, offset); \
292static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
293 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295sysfs_in_offsets(0);
296sysfs_in_offsets(1);
297sysfs_in_offsets(2);
298sysfs_in_offsets(3);
299sysfs_in_offsets(4);
300sysfs_in_offsets(5);
301sysfs_in_offsets(6);
302sysfs_in_offsets(7);
303sysfs_in_offsets(8);
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200306static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
307 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{ \
Jean Delvare34875332007-05-08 17:22:03 +0200309 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 struct w83781d_data *data = w83781d_update_device(dev); \
311 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200312 FAN_FROM_REG(data->reg[attr->index], \
313 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315show_fan_reg(fan);
316show_fan_reg(fan_min);
317
318static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200319store_fan_min(struct device *dev, struct device_attribute *da,
320 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Jean Delvare34875332007-05-08 17:22:03 +0200322 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200323 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200324 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 u32 val;
326
327 val = simple_strtoul(buf, NULL, 10);
328
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100329 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200330 data->fan_min[nr] =
331 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200332 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200333 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100335 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 return count;
337}
338
Jean Delvare34875332007-05-08 17:22:03 +0200339static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
340static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
341 show_fan_min, store_fan_min, 0);
342static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
343static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
344 show_fan_min, store_fan_min, 1);
345static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
346static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
347 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200350static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
351 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{ \
Jean Delvare34875332007-05-08 17:22:03 +0200353 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200355 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
357 return sprintf(buf,"%d\n", \
358 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
359 } else { /* TEMP1 */ \
360 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
361 } \
362}
363show_temp_reg(temp);
364show_temp_reg(temp_max);
365show_temp_reg(temp_max_hyst);
366
367#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200368static ssize_t store_temp_##reg (struct device *dev, \
369 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{ \
Jean Delvare34875332007-05-08 17:22:03 +0200371 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200372 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200373 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200374 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 \
376 val = simple_strtol(buf, NULL, 10); \
377 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100378 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 \
380 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
381 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200382 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->temp_##reg##_add[nr-2]); \
384 } else { /* TEMP1 */ \
385 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200386 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 data->temp_##reg); \
388 } \
389 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100390 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return count; \
392}
393store_temp_reg(OVER, max);
394store_temp_reg(HYST, max_hyst);
395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200397static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
398 show_temp, NULL, offset); \
399static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
400 show_temp_max, store_temp_max, offset); \
401static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
402 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404sysfs_temp_offsets(1);
405sysfs_temp_offsets(2);
406sysfs_temp_offsets(3);
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400409show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 struct w83781d_data *data = w83781d_update_device(dev);
412 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
413}
414
Jim Cromie311ce2e2006-09-24 21:22:52 +0200415static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400418show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
Jean Delvare90d66192007-10-08 18:24:35 +0200420 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return sprintf(buf, "%ld\n", (long) data->vrm);
422}
423
424static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400425store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Jean Delvare7666c132007-05-08 17:22:02 +0200427 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 u32 val;
429
430 val = simple_strtoul(buf, NULL, 10);
431 data->vrm = val;
432
433 return count;
434}
435
Jim Cromie311ce2e2006-09-24 21:22:52 +0200436static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400439show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200442 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
Jim Cromie311ce2e2006-09-24 21:22:52 +0200445static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
446
Jean Delvare7d4a1372007-10-08 18:29:43 +0200447static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
448 char *buf)
449{
450 struct w83781d_data *data = w83781d_update_device(dev);
451 int bitnr = to_sensor_dev_attr(attr)->index;
452 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
453}
454
455/* The W83781D has a single alarm bit for temp2 and temp3 */
456static ssize_t show_temp3_alarm(struct device *dev,
457 struct device_attribute *attr, char *buf)
458{
459 struct w83781d_data *data = w83781d_update_device(dev);
460 int bitnr = (data->type == w83781d) ? 5 : 13;
461 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
462}
463
464static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
465static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
466static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
467static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
468static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
469static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
470static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
471static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
472static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
473static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
474static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
475static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
476static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
477static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
478static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
479
Yani Ioannoue404e272005-05-17 06:42:58 -0400480static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 struct w83781d_data *data = w83781d_update_device(dev);
483 return sprintf(buf, "%ld\n",
484 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
485}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200488store_beep_mask(struct device *dev, struct device_attribute *attr,
489 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
Jean Delvare7666c132007-05-08 17:22:02 +0200491 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200492 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 val = simple_strtoul(buf, NULL, 10);
495
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100496 mutex_lock(&data->update_lock);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200497 data->beep_mask &= 0x8000; /* preserve beep enable */
498 data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
Jean Delvare34875332007-05-08 17:22:03 +0200499 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
500 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200501 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200502 (data->beep_mask >> 8) & 0xff);
Jean Delvare34875332007-05-08 17:22:03 +0200503 if (data->type != w83781d && data->type != as99127f) {
504 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
505 ((data->beep_mask) >> 16) & 0xff);
506 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100507 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 return count;
510}
511
Jean Delvare34875332007-05-08 17:22:03 +0200512static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
513 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Jean Delvare7d4a1372007-10-08 18:29:43 +0200515static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
516 char *buf)
517{
518 struct w83781d_data *data = w83781d_update_device(dev);
519 int bitnr = to_sensor_dev_attr(attr)->index;
520 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
521}
522
523static ssize_t
524store_beep(struct device *dev, struct device_attribute *attr,
525 const char *buf, size_t count)
526{
527 struct w83781d_data *data = dev_get_drvdata(dev);
528 int bitnr = to_sensor_dev_attr(attr)->index;
529 unsigned long bit;
530 u8 reg;
531
532 bit = simple_strtoul(buf, NULL, 10);
533 if (bit & ~1)
534 return -EINVAL;
535
536 mutex_lock(&data->update_lock);
537 if (bit)
538 data->beep_mask |= (1 << bitnr);
539 else
540 data->beep_mask &= ~(1 << bitnr);
541
542 if (bitnr < 8) {
543 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
544 if (bit)
545 reg |= (1 << bitnr);
546 else
547 reg &= ~(1 << bitnr);
548 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
549 } else if (bitnr < 16) {
550 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
551 if (bit)
552 reg |= (1 << (bitnr - 8));
553 else
554 reg &= ~(1 << (bitnr - 8));
555 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
556 } else {
557 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
558 if (bit)
559 reg |= (1 << (bitnr - 16));
560 else
561 reg &= ~(1 << (bitnr - 16));
562 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
563 }
564 mutex_unlock(&data->update_lock);
565
566 return count;
567}
568
569/* The W83781D has a single beep bit for temp2 and temp3 */
570static ssize_t show_temp3_beep(struct device *dev,
571 struct device_attribute *attr, char *buf)
572{
573 struct w83781d_data *data = w83781d_update_device(dev);
574 int bitnr = (data->type == w83781d) ? 5 : 13;
575 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
576}
577
578static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
579 show_beep, store_beep, 0);
580static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
581 show_beep, store_beep, 1);
582static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
583 show_beep, store_beep, 2);
584static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
585 show_beep, store_beep, 3);
586static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
587 show_beep, store_beep, 8);
588static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
589 show_beep, store_beep, 9);
590static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
591 show_beep, store_beep, 10);
592static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
593 show_beep, store_beep, 16);
594static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
595 show_beep, store_beep, 17);
596static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
597 show_beep, store_beep, 6);
598static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
599 show_beep, store_beep, 7);
600static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
601 show_beep, store_beep, 11);
602static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
603 show_beep, store_beep, 4);
604static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
605 show_beep, store_beep, 5);
606static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
607 show_temp3_beep, store_beep, 13);
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200608static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
609 show_beep, store_beep, 15);
Jean Delvare7d4a1372007-10-08 18:29:43 +0200610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200612show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
Jean Delvare34875332007-05-08 17:22:03 +0200614 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 struct w83781d_data *data = w83781d_update_device(dev);
616 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200617 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
620/* Note: we save and restore the fan minimum here, because its value is
621 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200622 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 because the divisor changed. */
624static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200625store_fan_div(struct device *dev, struct device_attribute *da,
626 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Jean Delvare34875332007-05-08 17:22:03 +0200628 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200629 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200631 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 u8 reg;
633 unsigned long val = simple_strtoul(buf, NULL, 10);
634
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100635 mutex_lock(&data->update_lock);
Jean Delvare293c0992007-11-30 23:52:44 +0100636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* Save fan_min */
638 min = FAN_FROM_REG(data->fan_min[nr],
639 DIV_FROM_REG(data->fan_div[nr]));
640
641 data->fan_div[nr] = DIV_TO_REG(val, data->type);
642
Jean Delvare31b8dc42007-05-08 17:22:03 +0200643 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 & (nr==0 ? 0xcf : 0x3f))
645 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200646 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 /* w83781d and as99127f don't have extended divisor bits */
649 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200650 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 & ~(1 << (5 + nr)))
652 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200653 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
655
656 /* Restore fan_min */
657 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200658 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100660 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return count;
662}
663
Jean Delvare34875332007-05-08 17:22:03 +0200664static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
665 show_fan_div, store_fan_div, 0);
666static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
667 show_fan_div, store_fan_div, 1);
668static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
669 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200672show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
Jean Delvare34875332007-05-08 17:22:03 +0200674 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200676 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
679static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200680show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200683 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
686static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200687store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
688 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Jean Delvare34875332007-05-08 17:22:03 +0200690 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200691 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200692 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 u32 val;
694
695 val = simple_strtoul(buf, NULL, 10);
696
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200698 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
699 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100700 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return count;
702}
703
704static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200705store_pwm2_enable(struct device *dev, struct device_attribute *da,
706 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Jean Delvare7666c132007-05-08 17:22:02 +0200708 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 u32 val, reg;
710
711 val = simple_strtoul(buf, NULL, 10);
712
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100713 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 switch (val) {
716 case 0:
717 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200718 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
719 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 (reg & 0xf7) | (val << 3));
721
Jean Delvare31b8dc42007-05-08 17:22:03 +0200722 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
723 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 (reg & 0xef) | (!val << 4));
725
Jean Delvare34875332007-05-08 17:22:03 +0200726 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 break;
728
729 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100730 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return -EINVAL;
732 }
733
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100734 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return count;
736}
737
Jean Delvare34875332007-05-08 17:22:03 +0200738static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
739static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
740static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
741static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
742/* only PWM2 can be enabled/disabled */
743static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
744 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200747show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Jean Delvare34875332007-05-08 17:22:03 +0200749 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200751 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
754static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200755store_sensor(struct device *dev, struct device_attribute *da,
756 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Jean Delvare34875332007-05-08 17:22:03 +0200758 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200759 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200760 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 u32 val, tmp;
762
763 val = simple_strtoul(buf, NULL, 10);
764
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100765 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 switch (val) {
768 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200769 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
770 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200771 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200772 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
773 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200774 tmp | BIT_SCFG2[nr]);
775 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 break;
777 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200778 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
779 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200780 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200781 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
782 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200783 tmp & ~BIT_SCFG2[nr]);
784 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200786 case W83781D_DEFAULT_BETA:
787 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
788 "instead\n", W83781D_DEFAULT_BETA);
789 /* fall through */
790 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200791 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
792 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200793 tmp & ~BIT_SCFG1[nr]);
794 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 break;
796 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200797 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
798 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 break;
800 }
801
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100802 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return count;
804}
805
Jean Delvare34875332007-05-08 17:22:03 +0200806static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
807 show_sensor, store_sensor, 0);
808static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400809 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200810static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400811 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813/* Assumes that adapter is of I2C, not ISA variety.
814 * OTHERWISE DON'T CALL THIS
815 */
816static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200817w83781d_detect_subclients(struct i2c_client *new_client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 int i, val1 = 0, id;
820 int err;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200821 int address = new_client->addr;
822 unsigned short sc_addr[2];
823 struct i2c_adapter *adapter = new_client->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 struct w83781d_data *data = i2c_get_clientdata(new_client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200825 enum chips kind = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827 id = i2c_adapter_id(adapter);
828
829 if (force_subclients[0] == id && force_subclients[1] == address) {
830 for (i = 2; i <= 3; i++) {
831 if (force_subclients[i] < 0x48 ||
832 force_subclients[i] > 0x4f) {
833 dev_err(&new_client->dev, "Invalid subclient "
834 "address %d; must be 0x48-0x4f\n",
835 force_subclients[i]);
836 err = -EINVAL;
837 goto ERROR_SC_1;
838 }
839 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200840 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 (force_subclients[2] & 0x07) |
842 ((force_subclients[3] & 0x07) << 4));
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200843 sc_addr[0] = force_subclients[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200845 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200846 sc_addr[0] = 0x48 + (val1 & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 if (kind != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (force_subclients[0] == id &&
851 force_subclients[1] == address) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200852 sc_addr[1] = force_subclients[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 } else {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200854 sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200856 if (sc_addr[0] == sc_addr[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 dev_err(&new_client->dev,
858 "Duplicate addresses 0x%x for subclients.\n",
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200859 sc_addr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 err = -EBUSY;
861 goto ERROR_SC_2;
862 }
863 }
864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 for (i = 0; i <= 1; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200866 data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
867 if (!data->lm75[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 dev_err(&new_client->dev, "Subclient %d "
869 "registration at address 0x%x "
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200870 "failed.\n", i, sc_addr[i]);
871 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (i == 1)
873 goto ERROR_SC_3;
874 goto ERROR_SC_2;
875 }
876 if (kind == w83783s)
877 break;
878 }
879
880 return 0;
881
882/* Undo inits in case of errors */
883ERROR_SC_3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +0200884 i2c_unregister_device(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885ERROR_SC_2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886ERROR_SC_1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return err;
888}
889
Jean Delvare34875332007-05-08 17:22:03 +0200890#define IN_UNIT_ATTRS(X) \
891 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
892 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare293c0992007-11-30 23:52:44 +0100893 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200894 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
895 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200896
Jean Delvare34875332007-05-08 17:22:03 +0200897#define FAN_UNIT_ATTRS(X) \
898 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
899 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200900 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
901 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
902 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200903
Jean Delvare34875332007-05-08 17:22:03 +0200904#define TEMP_UNIT_ATTRS(X) \
905 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
906 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +0200907 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
908 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
909 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +0200910
911static struct attribute* w83781d_attributes[] = {
912 IN_UNIT_ATTRS(0),
913 IN_UNIT_ATTRS(2),
914 IN_UNIT_ATTRS(3),
915 IN_UNIT_ATTRS(4),
916 IN_UNIT_ATTRS(5),
917 IN_UNIT_ATTRS(6),
918 FAN_UNIT_ATTRS(1),
919 FAN_UNIT_ATTRS(2),
920 FAN_UNIT_ATTRS(3),
921 TEMP_UNIT_ATTRS(1),
922 TEMP_UNIT_ATTRS(2),
923 &dev_attr_cpu0_vid.attr,
924 &dev_attr_vrm.attr,
925 &dev_attr_alarms.attr,
926 &dev_attr_beep_mask.attr,
Jean Delvare2fbbbf12008-10-17 17:51:18 +0200927 &sensor_dev_attr_beep_enable.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200928 NULL
929};
930static const struct attribute_group w83781d_group = {
931 .attrs = w83781d_attributes,
932};
933
934static struct attribute *w83781d_attributes_opt[] = {
935 IN_UNIT_ATTRS(1),
936 IN_UNIT_ATTRS(7),
937 IN_UNIT_ATTRS(8),
938 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +0200939 &sensor_dev_attr_pwm1.dev_attr.attr,
940 &sensor_dev_attr_pwm2.dev_attr.attr,
941 &sensor_dev_attr_pwm3.dev_attr.attr,
942 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200943 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +0200944 &sensor_dev_attr_temp1_type.dev_attr.attr,
945 &sensor_dev_attr_temp2_type.dev_attr.attr,
946 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +0200947 NULL
948};
949static const struct attribute_group w83781d_group_opt = {
950 .attrs = w83781d_attributes_opt,
951};
952
Jean Delvare7666c132007-05-08 17:22:02 +0200953/* No clean up is done on error, it's up to the caller */
954static int
955w83781d_create_files(struct device *dev, int kind, int is_isa)
956{
957 int err;
958
959 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
960 return err;
961
962 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200963 if ((err = device_create_file(dev,
964 &sensor_dev_attr_in1_input.dev_attr))
965 || (err = device_create_file(dev,
966 &sensor_dev_attr_in1_min.dev_attr))
967 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200968 &sensor_dev_attr_in1_max.dev_attr))
969 || (err = device_create_file(dev,
970 &sensor_dev_attr_in1_alarm.dev_attr))
971 || (err = device_create_file(dev,
972 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200973 return err;
974 }
975 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200976 if ((err = device_create_file(dev,
977 &sensor_dev_attr_in7_input.dev_attr))
978 || (err = device_create_file(dev,
979 &sensor_dev_attr_in7_min.dev_attr))
980 || (err = device_create_file(dev,
981 &sensor_dev_attr_in7_max.dev_attr))
982 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200983 &sensor_dev_attr_in7_alarm.dev_attr))
984 || (err = device_create_file(dev,
985 &sensor_dev_attr_in7_beep.dev_attr))
986 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +0200987 &sensor_dev_attr_in8_input.dev_attr))
988 || (err = device_create_file(dev,
989 &sensor_dev_attr_in8_min.dev_attr))
990 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +0200991 &sensor_dev_attr_in8_max.dev_attr))
992 || (err = device_create_file(dev,
993 &sensor_dev_attr_in8_alarm.dev_attr))
994 || (err = device_create_file(dev,
995 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +0200996 return err;
997 }
998 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +0200999 if ((err = device_create_file(dev,
1000 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001001 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001002 &sensor_dev_attr_temp3_max.dev_attr))
1003 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001004 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1005 || (err = device_create_file(dev,
1006 &sensor_dev_attr_temp3_alarm.dev_attr))
1007 || (err = device_create_file(dev,
1008 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001009 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001010
Jean Delvare7768aa72007-10-25 13:11:01 +02001011 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001012 err = sysfs_chmod_file(&dev->kobj,
1013 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1014 S_IRUGO | S_IWUSR);
1015 if (err)
1016 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001017 }
Jean Delvare7666c132007-05-08 17:22:02 +02001018 }
1019
1020 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001021 if ((err = device_create_file(dev,
1022 &sensor_dev_attr_pwm1.dev_attr))
1023 || (err = device_create_file(dev,
1024 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001025 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1026 return err;
1027 }
1028 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001029 if ((err = device_create_file(dev,
1030 &sensor_dev_attr_pwm3.dev_attr))
1031 || (err = device_create_file(dev,
1032 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001033 return err;
1034 }
1035
1036 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001037 if ((err = device_create_file(dev,
1038 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001039 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001040 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001041 return err;
1042 if (kind != w83783s) {
1043 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001044 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001045 return err;
1046 }
1047 }
1048
Jean Delvare7666c132007-05-08 17:22:02 +02001049 return 0;
1050}
1051
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001052/* Return 0 if detection is successful, -ENODEV otherwise */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001054w83781d_detect(struct i2c_client *client, int kind,
1055 struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Jean 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:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001200 i2c_set_clientdata(client, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 kfree(data);
1202ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return err;
1204}
1205
1206static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001207w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001209 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001210 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001212 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001214 sysfs_remove_group(&dev->kobj, &w83781d_group);
1215 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001217 if (data->lm75[0])
1218 i2c_unregister_device(data->lm75[0]);
1219 if (data->lm75[1])
1220 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001221
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001222 i2c_set_clientdata(client, NULL);
1223 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 return 0;
1226}
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001229w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001231 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001232 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct i2c_client *cl;
1234
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001235 bank = (reg >> 8) & 0x0f;
1236 if (bank > 2)
1237 /* switch banks */
1238 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1239 bank);
1240 if (bank == 0 || bank > 2) {
1241 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001243 /* switch to subclient */
1244 cl = data->lm75[bank - 1];
1245 /* convert from ISA to LM75 I2C addresses */
1246 switch (reg & 0xff) {
1247 case 0x50: /* TEMP */
1248 res = swab16(i2c_smbus_read_word_data(cl, 0));
1249 break;
1250 case 0x52: /* CONFIG */
1251 res = i2c_smbus_read_byte_data(cl, 1);
1252 break;
1253 case 0x53: /* HYST */
1254 res = swab16(i2c_smbus_read_word_data(cl, 2));
1255 break;
1256 case 0x55: /* OVER */
1257 default:
1258 res = swab16(i2c_smbus_read_word_data(cl, 3));
1259 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001262 if (bank > 2)
1263 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 return res;
1266}
1267
1268static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001269w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001271 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001272 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 struct i2c_client *cl;
1274
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001275 bank = (reg >> 8) & 0x0f;
1276 if (bank > 2)
1277 /* switch banks */
1278 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1279 bank);
1280 if (bank == 0 || bank > 2) {
1281 i2c_smbus_write_byte_data(client, reg & 0xff,
1282 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001284 /* switch to subclient */
1285 cl = data->lm75[bank - 1];
1286 /* convert from ISA to LM75 I2C addresses */
1287 switch (reg & 0xff) {
1288 case 0x52: /* CONFIG */
1289 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1290 break;
1291 case 0x53: /* HYST */
1292 i2c_smbus_write_word_data(cl, 2, swab16(value));
1293 break;
1294 case 0x55: /* OVER */
1295 i2c_smbus_write_word_data(cl, 3, swab16(value));
1296 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001299 if (bank > 2)
1300 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 return 0;
1303}
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305static void
Jean Delvare7666c132007-05-08 17:22:02 +02001306w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307{
Jean Delvare7666c132007-05-08 17:22:02 +02001308 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 int i, p;
1310 int type = data->type;
1311 u8 tmp;
1312
Jean Delvarefabddcd2006-02-05 23:26:51 +01001313 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001315 /* Resetting the chip has been the default for a long time,
1316 but it causes the BIOS initializations (fan clock dividers,
1317 thermal sensor types...) to be lost, so it is now optional.
1318 It might even go away if nobody reports it as being useful,
1319 as I see very little reason why this would be needed at
1320 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001321 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001322 "having, please report!\n");
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001325 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1326 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 /* Reset all except Watchdog values and last conversion values
1328 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001329 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 /* Restore the registers and disable power-on abnormal beep.
1331 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001332 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1333 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 /* Disable master beep-enable (reset turns it on).
1335 Individual beep_mask should be reset to off but for some reason
1336 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001337 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339
Jean Delvarefabddcd2006-02-05 23:26:51 +01001340 /* Disable power-on abnormal beep, as advised by the datasheet.
1341 Already done if reset=1. */
1342 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001343 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1344 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001345 }
1346
Jean Delvare303760b2005-07-31 21:52:01 +02001347 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001350 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 for (i = 1; i <= 3; i++) {
1352 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001353 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 } else {
1355 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001356 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1358 data->sens[i - 1] = 1;
1359 else
1360 data->sens[i - 1] = 2;
1361 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001362 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 break;
1364 }
1365 }
1366
1367 if (init && type != as99127f) {
1368 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001369 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001371 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001373 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 tmp & 0xfe);
1375 }
1376
1377 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001378 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001379 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 W83781D_REG_TEMP3_CONFIG);
1381 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001382 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001384 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1386 }
1387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
1389
1390 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001391 w83781d_write_value(data, W83781D_REG_CONFIG,
1392 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 W83781D_REG_CONFIG) & 0xf7)
1394 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001395
1396 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001397 for (i = 0; i < 3; i++) {
1398 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001399 W83781D_REG_FAN_MIN(i));
1400 }
Jean Delvare7666c132007-05-08 17:22:02 +02001401
1402 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403}
1404
1405static struct w83781d_data *w83781d_update_device(struct device *dev)
1406{
Jean Delvare7666c132007-05-08 17:22:02 +02001407 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001408 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 int i;
1410
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001411 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1414 || !data->valid) {
1415 dev_dbg(dev, "Starting device update\n");
1416
1417 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001418 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 continue; /* 783S has no in1 */
1420 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001421 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001423 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001425 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001426 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 break;
1428 }
Jean Delvare34875332007-05-08 17:22:03 +02001429 for (i = 0; i < 3; i++) {
1430 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001431 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001432 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001433 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 }
1435 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001436 for (i = 0; i < 4; i++) {
1437 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001438 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001439 W83781D_REG_PWM[i]);
Jean Delvare848ddf12009-05-08 20:27:28 +02001440 /* Only W83782D on SMBus has PWM3 and PWM4 */
1441 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001442 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 break;
1444 }
1445 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001446 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1448 }
1449
Jean Delvare31b8dc42007-05-08 17:22:03 +02001450 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001452 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001454 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001456 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001458 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001460 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001461 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001463 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001465 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 W83781D_REG_TEMP_OVER(3));
1467 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001468 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 W83781D_REG_TEMP_HYST(3));
1470 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001471 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001472 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001473 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001474 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 data->fan_div[0] = (i >> 4) & 0x03;
1476 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001477 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001478 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001480 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 data->fan_div[0] |= (i >> 3) & 0x04;
1482 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001483 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 }
Jean Delvare05663362007-11-30 23:51:24 +01001485 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001486 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001487 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001488 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001489 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001490 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001491 W83782D_REG_ALARM3) << 16);
1492 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001493 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001494 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001495 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001496 W83782D_REG_ALARM2) << 8);
1497 } else {
1498 /* No real-time status registers, fall back to
1499 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001500 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001501 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001502 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001503 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001505 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001506 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001507 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if ((data->type != w83781d) && (data->type != as99127f)) {
1509 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001510 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 W83781D_REG_BEEP_INTS3) << 16;
1512 }
1513 data->last_updated = jiffies;
1514 data->valid = 1;
1515 }
1516
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001517 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
1519 return data;
1520}
1521
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001522static const struct i2c_device_id w83781d_ids[] = {
1523 { "w83781d", w83781d, },
1524 { "w83782d", w83782d, },
1525 { "w83783s", w83783s, },
1526 { "as99127f", as99127f },
1527 { /* LIST END */ }
1528};
1529MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1530
1531static struct i2c_driver w83781d_driver = {
1532 .class = I2C_CLASS_HWMON,
1533 .driver = {
1534 .name = "w83781d",
1535 },
1536 .probe = w83781d_probe,
1537 .remove = w83781d_remove,
1538 .id_table = w83781d_ids,
1539 .detect = w83781d_detect,
1540 .address_data = &addr_data,
1541};
1542
1543/*
1544 * ISA related code
1545 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001546#ifdef CONFIG_ISA
1547
1548/* ISA device, if found */
1549static struct platform_device *pdev;
1550
1551static unsigned short isa_address = 0x290;
1552
1553/* I2C devices get this name attribute automatically, but for ISA devices
1554 we must create it by ourselves. */
1555static ssize_t
1556show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1557{
1558 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001559 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001560}
1561static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1562
1563static struct w83781d_data *w83781d_data_if_isa(void)
1564{
1565 return pdev ? platform_get_drvdata(pdev) : NULL;
1566}
1567
1568/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1569static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1570{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001571 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001572 int i;
1573
1574 if (!pdev) /* No ISA chip */
1575 return 0;
1576
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001577 isa = platform_get_drvdata(pdev);
1578
1579 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1580 return 0; /* Address doesn't match */
1581 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1582 return 0; /* Chip type doesn't match */
1583
1584 /* We compare all the limit registers, the config register and the
1585 * interrupt mask registers */
1586 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001587 if (w83781d_read_value(isa, i) !=
1588 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001589 return 0;
1590 }
1591 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001592 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001593 return 0;
1594 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001595 if (w83781d_read_value(isa, i) !=
1596 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001597 return 0;
1598 }
1599
1600 return 1;
1601}
1602
1603static int
1604w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1605{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001606 int word_sized, res;
1607
1608 word_sized = (((reg & 0xff00) == 0x100)
1609 || ((reg & 0xff00) == 0x200))
1610 && (((reg & 0x00ff) == 0x50)
1611 || ((reg & 0x00ff) == 0x53)
1612 || ((reg & 0x00ff) == 0x55));
1613 if (reg & 0xff00) {
1614 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001615 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001616 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001617 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001618 }
Jean Delvare360782d2008-10-17 17:51:19 +02001619 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1620 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001621 if (word_sized) {
1622 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001623 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001624 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001625 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001626 W83781D_DATA_REG_OFFSET);
1627 }
1628 if (reg & 0xff00) {
1629 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001630 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1631 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001632 }
1633 return res;
1634}
1635
1636static void
1637w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1638{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001639 int word_sized;
1640
1641 word_sized = (((reg & 0xff00) == 0x100)
1642 || ((reg & 0xff00) == 0x200))
1643 && (((reg & 0x00ff) == 0x53)
1644 || ((reg & 0x00ff) == 0x55));
1645 if (reg & 0xff00) {
1646 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001647 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001648 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001649 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001650 }
Jean Delvare360782d2008-10-17 17:51:19 +02001651 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001652 if (word_sized) {
1653 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001654 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001655 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001656 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001657 }
Jean Delvare360782d2008-10-17 17:51:19 +02001658 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001659 if (reg & 0xff00) {
1660 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001661 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1662 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001663 }
1664}
1665
1666/* The SMBus locks itself, usually, but nothing may access the Winbond between
1667 bank switches. ISA access must always be locked explicitly!
1668 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1669 would slow down the W83781D access and should not be necessary.
1670 There are some ugly typecasts here, but the good news is - they should
1671 nowhere else be necessary! */
1672static int
1673w83781d_read_value(struct w83781d_data *data, u16 reg)
1674{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001675 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001676 int res;
1677
1678 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001679 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001680 res = w83781d_read_value_i2c(data, reg);
1681 else
1682 res = w83781d_read_value_isa(data, reg);
1683 mutex_unlock(&data->lock);
1684 return res;
1685}
1686
1687static int
1688w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1689{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001690 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001691
1692 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001693 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001694 w83781d_write_value_i2c(data, reg, value);
1695 else
1696 w83781d_write_value_isa(data, reg, value);
1697 mutex_unlock(&data->lock);
1698 return 0;
1699}
1700
1701static int __devinit
1702w83781d_isa_probe(struct platform_device *pdev)
1703{
1704 int err, reg;
1705 struct w83781d_data *data;
1706 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001707
1708 /* Reserve the ISA region */
1709 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1710 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1711 "w83781d")) {
1712 err = -EBUSY;
1713 goto exit;
1714 }
1715
1716 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1717 if (!data) {
1718 err = -ENOMEM;
1719 goto exit_release_region;
1720 }
1721 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001722 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001723 platform_set_drvdata(pdev, data);
1724
1725 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1726 switch (reg) {
1727 case 0x30:
1728 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001729 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001730 break;
1731 default:
1732 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001733 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001734 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001735
1736 /* Initialize the W83781D chip */
1737 w83781d_init_device(&pdev->dev);
1738
1739 /* Register sysfs hooks */
1740 err = w83781d_create_files(&pdev->dev, data->type, 1);
1741 if (err)
1742 goto exit_remove_files;
1743
1744 err = device_create_file(&pdev->dev, &dev_attr_name);
1745 if (err)
1746 goto exit_remove_files;
1747
1748 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1749 if (IS_ERR(data->hwmon_dev)) {
1750 err = PTR_ERR(data->hwmon_dev);
1751 goto exit_remove_files;
1752 }
1753
1754 return 0;
1755
1756 exit_remove_files:
1757 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1758 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1759 device_remove_file(&pdev->dev, &dev_attr_name);
1760 kfree(data);
1761 exit_release_region:
1762 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1763 exit:
1764 return err;
1765}
1766
1767static int __devexit
1768w83781d_isa_remove(struct platform_device *pdev)
1769{
1770 struct w83781d_data *data = platform_get_drvdata(pdev);
1771
1772 hwmon_device_unregister(data->hwmon_dev);
1773 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1774 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1775 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001776 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001777 kfree(data);
1778
1779 return 0;
1780}
1781
1782static struct platform_driver w83781d_isa_driver = {
1783 .driver = {
1784 .owner = THIS_MODULE,
1785 .name = "w83781d",
1786 },
1787 .probe = w83781d_isa_probe,
1788 .remove = __devexit_p(w83781d_isa_remove),
1789};
1790
Jean Delvare7666c132007-05-08 17:22:02 +02001791/* return 1 if a supported chip is found, 0 otherwise */
1792static int __init
1793w83781d_isa_found(unsigned short address)
1794{
1795 int val, save, found = 0;
1796
Jean Delvare2961cb22008-03-09 13:34:28 +01001797 /* We have to request the region in two parts because some
1798 boards declare base+4 to base+7 as a PNP device */
1799 if (!request_region(address, 4, "w83781d")) {
1800 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001801 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001802 }
1803 if (!request_region(address + 4, 4, "w83781d")) {
1804 pr_debug("w83781d: Failed to request high part of region\n");
1805 release_region(address, 4);
1806 return 0;
1807 }
Jean Delvare7666c132007-05-08 17:22:02 +02001808
1809#define REALLY_SLOW_IO
1810 /* We need the timeouts for at least some W83781D-like
1811 chips. But only if we read 'undefined' registers. */
1812 val = inb_p(address + 1);
1813 if (inb_p(address + 2) != val
1814 || inb_p(address + 3) != val
1815 || inb_p(address + 7) != val) {
1816 pr_debug("w83781d: Detection failed at step 1\n");
1817 goto release;
1818 }
1819#undef REALLY_SLOW_IO
1820
1821 /* We should be able to change the 7 LSB of the address port. The
1822 MSB (busy flag) should be clear initially, set after the write. */
1823 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1824 if (save & 0x80) {
1825 pr_debug("w83781d: Detection failed at step 2\n");
1826 goto release;
1827 }
1828 val = ~save & 0x7f;
1829 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1830 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1831 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1832 pr_debug("w83781d: Detection failed at step 3\n");
1833 goto release;
1834 }
1835
1836 /* We found a device, now see if it could be a W83781D */
1837 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1838 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1839 if (val & 0x80) {
1840 pr_debug("w83781d: Detection failed at step 4\n");
1841 goto release;
1842 }
1843 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1844 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1845 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1846 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1847 if ((!(save & 0x80) && (val != 0xa3))
1848 || ((save & 0x80) && (val != 0x5c))) {
1849 pr_debug("w83781d: Detection failed at step 5\n");
1850 goto release;
1851 }
1852 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1853 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1854 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1855 pr_debug("w83781d: Detection failed at step 6\n");
1856 goto release;
1857 }
1858
1859 /* The busy flag should be clear again */
1860 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1861 pr_debug("w83781d: Detection failed at step 7\n");
1862 goto release;
1863 }
1864
1865 /* Determine the chip type */
1866 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1867 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1868 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1869 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1870 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1871 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001872 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001873 found = 1;
1874
1875 if (found)
1876 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001877 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1878
1879 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001880 release_region(address + 4, 4);
1881 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001882 return found;
1883}
1884
1885static int __init
1886w83781d_isa_device_add(unsigned short address)
1887{
1888 struct resource res = {
1889 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001890 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001891 .name = "w83781d",
1892 .flags = IORESOURCE_IO,
1893 };
1894 int err;
1895
1896 pdev = platform_device_alloc("w83781d", address);
1897 if (!pdev) {
1898 err = -ENOMEM;
1899 printk(KERN_ERR "w83781d: Device allocation failed\n");
1900 goto exit;
1901 }
1902
1903 err = platform_device_add_resources(pdev, &res, 1);
1904 if (err) {
1905 printk(KERN_ERR "w83781d: Device resource addition failed "
1906 "(%d)\n", err);
1907 goto exit_device_put;
1908 }
1909
1910 err = platform_device_add(pdev);
1911 if (err) {
1912 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1913 err);
1914 goto exit_device_put;
1915 }
1916
1917 return 0;
1918
1919 exit_device_put:
1920 platform_device_put(pdev);
1921 exit:
1922 pdev = NULL;
1923 return err;
1924}
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001927w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
Jean Delvarefde09502005-07-19 23:51:07 +02001929 int res;
1930
Jean Delvare7666c132007-05-08 17:22:02 +02001931 if (w83781d_isa_found(isa_address)) {
1932 res = platform_driver_register(&w83781d_isa_driver);
1933 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001934 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001935
1936 /* Sets global pdev as a side effect */
1937 res = w83781d_isa_device_add(isa_address);
1938 if (res)
1939 goto exit_unreg_isa_driver;
1940 }
Jean Delvarefde09502005-07-19 23:51:07 +02001941
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001942 return 0;
1943
1944exit_unreg_isa_driver:
1945 platform_driver_unregister(&w83781d_isa_driver);
1946exit:
1947 return res;
1948}
1949
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001950static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001951w83781d_isa_unregister(void)
1952{
1953 if (pdev) {
1954 platform_device_unregister(pdev);
1955 platform_driver_unregister(&w83781d_isa_driver);
1956 }
1957}
1958#else /* !CONFIG_ISA */
1959
1960static struct w83781d_data *w83781d_data_if_isa(void)
1961{
1962 return NULL;
1963}
1964
1965static int
1966w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1967{
1968 return 0;
1969}
1970
1971static int
1972w83781d_read_value(struct w83781d_data *data, u16 reg)
1973{
1974 int res;
1975
1976 mutex_lock(&data->lock);
1977 res = w83781d_read_value_i2c(data, reg);
1978 mutex_unlock(&data->lock);
1979
1980 return res;
1981}
1982
1983static int
1984w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1985{
1986 mutex_lock(&data->lock);
1987 w83781d_write_value_i2c(data, reg, value);
1988 mutex_unlock(&data->lock);
1989
1990 return 0;
1991}
1992
1993static int __init
1994w83781d_isa_register(void)
1995{
1996 return 0;
1997}
1998
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001999static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002000w83781d_isa_unregister(void)
2001{
2002}
2003#endif /* CONFIG_ISA */
2004
2005static int __init
2006sensors_w83781d_init(void)
2007{
2008 int res;
2009
2010 /* We register the ISA device first, so that we can skip the
2011 * registration of an I2C interface to the same device. */
2012 res = w83781d_isa_register();
2013 if (res)
2014 goto exit;
2015
Jean Delvarec6566202008-10-17 17:51:18 +02002016 res = i2c_add_driver(&w83781d_driver);
2017 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002018 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002019
Jean Delvarefde09502005-07-19 23:51:07 +02002020 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002021
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002022 exit_unreg_isa:
2023 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002024 exit:
2025 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026}
2027
2028static void __exit
2029sensors_w83781d_exit(void)
2030{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002031 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 i2c_del_driver(&w83781d_driver);
2033}
2034
2035MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2036 "Philip Edelbrock <phil@netroedge.com>, "
2037 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2038MODULE_DESCRIPTION("W83781D driver");
2039MODULE_LICENSE("GPL");
2040
2041module_init(sensors_w83781d_init);
2042module_exit(sensors_w83781d_exit);