blob: 44704d2dee6363427a9fa3e42062ca5bdb0e6646 [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
Jean Delvare310ec792009-12-14 21:17:23 +01001054w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
Jean Delvarebab2bf42009-12-09 20:35:54 +01001056 int val1, val2;
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001057 struct w83781d_data *isa = w83781d_data_if_isa();
1058 struct i2c_adapter *adapter = client->adapter;
1059 int address = client->addr;
Jean Delvarebab2bf42009-12-09 20:35:54 +01001060 const char *client_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 enum vendor { winbond, asus } vendid;
1062
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001063 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1064 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001066 /* We block updates of the ISA device to minimize the risk of
1067 concurrent access to the same W83781D chip through different
1068 interfaces. */
1069 if (isa)
1070 mutex_lock(&isa->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Jean Delvarebab2bf42009-12-09 20:35:54 +01001072 if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1073 dev_dbg(&adapter->dev,
1074 "Detection of w83781d chip failed at step 3\n");
1075 goto err_nodev;
1076 }
1077
1078 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
1079 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1080 /* Check for Winbond or Asus ID if in bank 0 */
1081 if (!(val1 & 0x07) &&
1082 ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
1083 ( (val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
1084 dev_dbg(&adapter->dev,
1085 "Detection of w83781d chip failed at step 4\n");
1086 goto err_nodev;
1087 }
1088 /* If Winbond SMBus, check address at 0x48.
1089 Asus doesn't support, except for as99127f rev.2 */
1090 if ((!(val1 & 0x80) && val2 == 0xa3) ||
1091 ( (val1 & 0x80) && val2 == 0x5c)) {
1092 if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1093 != address) {
1094 dev_dbg(&adapter->dev,
1095 "Detection of w83781d chip failed at step 5\n");
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001096 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
1099
Jean Delvarebab2bf42009-12-09 20:35:54 +01001100 /* Put it now into bank 0 and Vendor ID High Byte */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001101 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1102 (i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1103 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jean Delvarebab2bf42009-12-09 20:35:54 +01001105 /* Get the vendor ID */
1106 val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
1107 if (val2 == 0x5c)
1108 vendid = winbond;
1109 else if (val2 == 0x12)
1110 vendid = asus;
1111 else {
1112 dev_dbg(&adapter->dev,
1113 "w83781d chip vendor is neither Winbond nor Asus\n");
1114 goto err_nodev;
1115 }
1116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* Determine the chip type. */
Jean Delvarebab2bf42009-12-09 20:35:54 +01001118 val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
1119 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1120 client_name = "w83781d";
1121 else if (val1 == 0x30 && vendid == winbond)
1122 client_name = "w83782d";
1123 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1124 client_name = "w83783s";
1125 else if (val1 == 0x31)
1126 client_name = "as99127f";
1127 else
1128 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Jean Delvarebab2bf42009-12-09 20:35:54 +01001130 if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1131 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1132 "be the same as ISA device\n", address);
1133 goto err_nodev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
1135
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001136 if (isa)
1137 mutex_unlock(&isa->update_lock);
1138
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001139 strlcpy(info->type, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001141 return 0;
1142
1143 err_nodev:
1144 if (isa)
1145 mutex_unlock(&isa->update_lock);
1146 return -ENODEV;
1147}
1148
1149static int
1150w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
1151{
1152 struct device *dev = &client->dev;
1153 struct w83781d_data *data;
1154 int err;
1155
1156 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1157 if (!data) {
1158 err = -ENOMEM;
1159 goto ERROR1;
1160 }
1161
1162 i2c_set_clientdata(client, data);
1163 mutex_init(&data->lock);
1164 mutex_init(&data->update_lock);
1165
1166 data->type = id->driver_data;
1167 data->client = client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 /* attach secondary i2c lm75-like clients */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001170 err = w83781d_detect_subclients(client);
1171 if (err)
Jean Delvare7666c132007-05-08 17:22:02 +02001172 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001175 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 /* Register sysfs hooks */
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001178 err = w83781d_create_files(dev, data->type, 0);
Jean Delvare7666c132007-05-08 17:22:02 +02001179 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001180 goto ERROR4;
1181
Tony Jones1beeffe2007-08-20 13:46:20 -07001182 data->hwmon_dev = hwmon_device_register(dev);
1183 if (IS_ERR(data->hwmon_dev)) {
1184 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001185 goto ERROR4;
1186 }
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 return 0;
1189
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001190ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001191 sysfs_remove_group(&dev->kobj, &w83781d_group);
1192 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1193
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001194 if (data->lm75[0])
1195 i2c_unregister_device(data->lm75[0]);
1196 if (data->lm75[1])
1197 i2c_unregister_device(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198ERROR3:
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001199 i2c_set_clientdata(client, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 kfree(data);
1201ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return err;
1203}
1204
1205static int
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001206w83781d_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001208 struct w83781d_data *data = i2c_get_clientdata(client);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001209 struct device *dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001211 hwmon_device_unregister(data->hwmon_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001213 sysfs_remove_group(&dev->kobj, &w83781d_group);
1214 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001216 if (data->lm75[0])
1217 i2c_unregister_device(data->lm75[0]);
1218 if (data->lm75[1])
1219 i2c_unregister_device(data->lm75[1]);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001220
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001221 i2c_set_clientdata(client, NULL);
1222 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 return 0;
1225}
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001228w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001230 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001231 int res, bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 struct i2c_client *cl;
1233
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001234 bank = (reg >> 8) & 0x0f;
1235 if (bank > 2)
1236 /* switch banks */
1237 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1238 bank);
1239 if (bank == 0 || bank > 2) {
1240 res = i2c_smbus_read_byte_data(client, reg & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001242 /* switch to subclient */
1243 cl = data->lm75[bank - 1];
1244 /* convert from ISA to LM75 I2C addresses */
1245 switch (reg & 0xff) {
1246 case 0x50: /* TEMP */
1247 res = swab16(i2c_smbus_read_word_data(cl, 0));
1248 break;
1249 case 0x52: /* CONFIG */
1250 res = i2c_smbus_read_byte_data(cl, 1);
1251 break;
1252 case 0x53: /* HYST */
1253 res = swab16(i2c_smbus_read_word_data(cl, 2));
1254 break;
1255 case 0x55: /* OVER */
1256 default:
1257 res = swab16(i2c_smbus_read_word_data(cl, 3));
1258 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001261 if (bank > 2)
1262 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return res;
1265}
1266
1267static int
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001268w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001270 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001271 int bank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 struct i2c_client *cl;
1273
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001274 bank = (reg >> 8) & 0x0f;
1275 if (bank > 2)
1276 /* switch banks */
1277 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1278 bank);
1279 if (bank == 0 || bank > 2) {
1280 i2c_smbus_write_byte_data(client, reg & 0xff,
1281 value & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 } else {
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001283 /* switch to subclient */
1284 cl = data->lm75[bank - 1];
1285 /* convert from ISA to LM75 I2C addresses */
1286 switch (reg & 0xff) {
1287 case 0x52: /* CONFIG */
1288 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1289 break;
1290 case 0x53: /* HYST */
1291 i2c_smbus_write_word_data(cl, 2, swab16(value));
1292 break;
1293 case 0x55: /* OVER */
1294 i2c_smbus_write_word_data(cl, 3, swab16(value));
1295 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001298 if (bank > 2)
1299 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 return 0;
1302}
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304static void
Jean Delvare7666c132007-05-08 17:22:02 +02001305w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Jean Delvare7666c132007-05-08 17:22:02 +02001307 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 int i, p;
1309 int type = data->type;
1310 u8 tmp;
1311
Jean Delvarefabddcd2006-02-05 23:26:51 +01001312 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001314 /* Resetting the chip has been the default for a long time,
1315 but it causes the BIOS initializations (fan clock dividers,
1316 thermal sensor types...) to be lost, so it is now optional.
1317 It might even go away if nobody reports it as being useful,
1318 as I see very little reason why this would be needed at
1319 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001320 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001321 "having, please report!\n");
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001324 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1325 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 /* Reset all except Watchdog values and last conversion values
1327 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001328 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 /* Restore the registers and disable power-on abnormal beep.
1330 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001331 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1332 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* Disable master beep-enable (reset turns it on).
1334 Individual beep_mask should be reset to off but for some reason
1335 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001336 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
1338
Jean Delvarefabddcd2006-02-05 23:26:51 +01001339 /* Disable power-on abnormal beep, as advised by the datasheet.
1340 Already done if reset=1. */
1341 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001342 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1343 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001344 }
1345
Jean Delvare303760b2005-07-31 21:52:01 +02001346 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001349 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 for (i = 1; i <= 3; i++) {
1351 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001352 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 } else {
1354 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001355 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1357 data->sens[i - 1] = 1;
1358 else
1359 data->sens[i - 1] = 2;
1360 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001361 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 break;
1363 }
1364 }
1365
1366 if (init && type != as99127f) {
1367 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001368 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001370 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001372 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 tmp & 0xfe);
1374 }
1375
1376 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001377 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001378 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 W83781D_REG_TEMP3_CONFIG);
1380 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001381 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001383 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1385 }
1386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 }
1388
1389 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001390 w83781d_write_value(data, W83781D_REG_CONFIG,
1391 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 W83781D_REG_CONFIG) & 0xf7)
1393 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001394
1395 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001396 for (i = 0; i < 3; i++) {
1397 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001398 W83781D_REG_FAN_MIN(i));
1399 }
Jean Delvare7666c132007-05-08 17:22:02 +02001400
1401 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402}
1403
1404static struct w83781d_data *w83781d_update_device(struct device *dev)
1405{
Jean Delvare7666c132007-05-08 17:22:02 +02001406 struct w83781d_data *data = dev_get_drvdata(dev);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001407 struct i2c_client *client = data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 int i;
1409
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001410 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1413 || !data->valid) {
1414 dev_dbg(dev, "Starting device update\n");
1415
1416 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001417 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 continue; /* 783S has no in1 */
1419 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001420 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001422 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001424 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001425 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 break;
1427 }
Jean Delvare34875332007-05-08 17:22:03 +02001428 for (i = 0; i < 3; i++) {
1429 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001430 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001431 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001432 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 }
1434 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001435 for (i = 0; i < 4; i++) {
1436 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001437 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001438 W83781D_REG_PWM[i]);
Jean Delvare848ddf12009-05-08 20:27:28 +02001439 /* Only W83782D on SMBus has PWM3 and PWM4 */
1440 if ((data->type != w83782d || !client)
Jean Delvare34875332007-05-08 17:22:03 +02001441 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 break;
1443 }
1444 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001445 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1447 }
1448
Jean Delvare31b8dc42007-05-08 17:22:03 +02001449 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001451 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001453 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001455 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001457 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001459 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001460 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001462 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001464 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 W83781D_REG_TEMP_OVER(3));
1466 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001467 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 W83781D_REG_TEMP_HYST(3));
1469 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001470 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001471 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001472 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001473 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 data->fan_div[0] = (i >> 4) & 0x03;
1475 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001476 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001477 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001479 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 data->fan_div[0] |= (i >> 3) & 0x04;
1481 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001482 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 }
Jean Delvare05663362007-11-30 23:51:24 +01001484 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001485 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001486 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001487 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001488 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001489 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001490 W83782D_REG_ALARM3) << 16);
1491 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001492 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001493 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001494 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001495 W83782D_REG_ALARM2) << 8);
1496 } else {
1497 /* No real-time status registers, fall back to
1498 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001499 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001500 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001501 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001502 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001504 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare2fbbbf12008-10-17 17:51:18 +02001505 data->beep_mask = (i << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001506 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if ((data->type != w83781d) && (data->type != as99127f)) {
1508 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001509 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 W83781D_REG_BEEP_INTS3) << 16;
1511 }
1512 data->last_updated = jiffies;
1513 data->valid = 1;
1514 }
1515
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001516 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518 return data;
1519}
1520
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001521static const struct i2c_device_id w83781d_ids[] = {
1522 { "w83781d", w83781d, },
1523 { "w83782d", w83782d, },
1524 { "w83783s", w83783s, },
1525 { "as99127f", as99127f },
1526 { /* LIST END */ }
1527};
1528MODULE_DEVICE_TABLE(i2c, w83781d_ids);
1529
1530static struct i2c_driver w83781d_driver = {
1531 .class = I2C_CLASS_HWMON,
1532 .driver = {
1533 .name = "w83781d",
1534 },
1535 .probe = w83781d_probe,
1536 .remove = w83781d_remove,
1537 .id_table = w83781d_ids,
1538 .detect = w83781d_detect,
1539 .address_data = &addr_data,
1540};
1541
1542/*
1543 * ISA related code
1544 */
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001545#ifdef CONFIG_ISA
1546
1547/* ISA device, if found */
1548static struct platform_device *pdev;
1549
1550static unsigned short isa_address = 0x290;
1551
1552/* I2C devices get this name attribute automatically, but for ISA devices
1553 we must create it by ourselves. */
1554static ssize_t
1555show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1556{
1557 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare360782d2008-10-17 17:51:19 +02001558 return sprintf(buf, "%s\n", data->name);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001559}
1560static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1561
1562static struct w83781d_data *w83781d_data_if_isa(void)
1563{
1564 return pdev ? platform_get_drvdata(pdev) : NULL;
1565}
1566
1567/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1568static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1569{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001570 struct w83781d_data *isa;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001571 int i;
1572
1573 if (!pdev) /* No ISA chip */
1574 return 0;
1575
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001576 isa = platform_get_drvdata(pdev);
1577
1578 if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1579 return 0; /* Address doesn't match */
1580 if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1581 return 0; /* Chip type doesn't match */
1582
1583 /* We compare all the limit registers, the config register and the
1584 * interrupt mask registers */
1585 for (i = 0x2b; i <= 0x3d; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001586 if (w83781d_read_value(isa, i) !=
1587 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001588 return 0;
1589 }
1590 if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001591 i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001592 return 0;
1593 for (i = 0x43; i <= 0x46; i++) {
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001594 if (w83781d_read_value(isa, i) !=
1595 i2c_smbus_read_byte_data(client, i))
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001596 return 0;
1597 }
1598
1599 return 1;
1600}
1601
1602static int
1603w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1604{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001605 int word_sized, res;
1606
1607 word_sized = (((reg & 0xff00) == 0x100)
1608 || ((reg & 0xff00) == 0x200))
1609 && (((reg & 0x00ff) == 0x50)
1610 || ((reg & 0x00ff) == 0x53)
1611 || ((reg & 0x00ff) == 0x55));
1612 if (reg & 0xff00) {
1613 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001614 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001615 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001616 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001617 }
Jean Delvare360782d2008-10-17 17:51:19 +02001618 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1619 res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001620 if (word_sized) {
1621 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001622 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001623 res =
Jean Delvare360782d2008-10-17 17:51:19 +02001624 (res << 8) + inb_p(data->isa_addr +
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001625 W83781D_DATA_REG_OFFSET);
1626 }
1627 if (reg & 0xff00) {
1628 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001629 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1630 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001631 }
1632 return res;
1633}
1634
1635static void
1636w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1637{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001638 int word_sized;
1639
1640 word_sized = (((reg & 0xff00) == 0x100)
1641 || ((reg & 0xff00) == 0x200))
1642 && (((reg & 0x00ff) == 0x53)
1643 || ((reg & 0x00ff) == 0x55));
1644 if (reg & 0xff00) {
1645 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001646 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001647 outb_p(reg >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001648 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001649 }
Jean Delvare360782d2008-10-17 17:51:19 +02001650 outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001651 if (word_sized) {
1652 outb_p(value >> 8,
Jean Delvare360782d2008-10-17 17:51:19 +02001653 data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001654 outb_p((reg & 0xff) + 1,
Jean Delvare360782d2008-10-17 17:51:19 +02001655 data->isa_addr + W83781D_ADDR_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001656 }
Jean Delvare360782d2008-10-17 17:51:19 +02001657 outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001658 if (reg & 0xff00) {
1659 outb_p(W83781D_REG_BANK,
Jean Delvare360782d2008-10-17 17:51:19 +02001660 data->isa_addr + W83781D_ADDR_REG_OFFSET);
1661 outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001662 }
1663}
1664
1665/* The SMBus locks itself, usually, but nothing may access the Winbond between
1666 bank switches. ISA access must always be locked explicitly!
1667 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1668 would slow down the W83781D access and should not be necessary.
1669 There are some ugly typecasts here, but the good news is - they should
1670 nowhere else be necessary! */
1671static int
1672w83781d_read_value(struct w83781d_data *data, u16 reg)
1673{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001674 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001675 int res;
1676
1677 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001678 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001679 res = w83781d_read_value_i2c(data, reg);
1680 else
1681 res = w83781d_read_value_isa(data, reg);
1682 mutex_unlock(&data->lock);
1683 return res;
1684}
1685
1686static int
1687w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1688{
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001689 struct i2c_client *client = data->client;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001690
1691 mutex_lock(&data->lock);
Wolfgang Grandegger0217eae2008-10-17 17:51:19 +02001692 if (client)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001693 w83781d_write_value_i2c(data, reg, value);
1694 else
1695 w83781d_write_value_isa(data, reg, value);
1696 mutex_unlock(&data->lock);
1697 return 0;
1698}
1699
1700static int __devinit
1701w83781d_isa_probe(struct platform_device *pdev)
1702{
1703 int err, reg;
1704 struct w83781d_data *data;
1705 struct resource *res;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001706
1707 /* Reserve the ISA region */
1708 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1709 if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1710 "w83781d")) {
1711 err = -EBUSY;
1712 goto exit;
1713 }
1714
1715 data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1716 if (!data) {
1717 err = -ENOMEM;
1718 goto exit_release_region;
1719 }
1720 mutex_init(&data->lock);
Jean Delvare360782d2008-10-17 17:51:19 +02001721 data->isa_addr = res->start;
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001722 platform_set_drvdata(pdev, data);
1723
1724 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1725 switch (reg) {
1726 case 0x30:
1727 data->type = w83782d;
Jean Delvare360782d2008-10-17 17:51:19 +02001728 data->name = "w83782d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001729 break;
1730 default:
1731 data->type = w83781d;
Jean Delvare360782d2008-10-17 17:51:19 +02001732 data->name = "w83781d";
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001733 }
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001734
1735 /* Initialize the W83781D chip */
1736 w83781d_init_device(&pdev->dev);
1737
1738 /* Register sysfs hooks */
1739 err = w83781d_create_files(&pdev->dev, data->type, 1);
1740 if (err)
1741 goto exit_remove_files;
1742
1743 err = device_create_file(&pdev->dev, &dev_attr_name);
1744 if (err)
1745 goto exit_remove_files;
1746
1747 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1748 if (IS_ERR(data->hwmon_dev)) {
1749 err = PTR_ERR(data->hwmon_dev);
1750 goto exit_remove_files;
1751 }
1752
1753 return 0;
1754
1755 exit_remove_files:
1756 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1757 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1758 device_remove_file(&pdev->dev, &dev_attr_name);
1759 kfree(data);
1760 exit_release_region:
1761 release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1762 exit:
1763 return err;
1764}
1765
1766static int __devexit
1767w83781d_isa_remove(struct platform_device *pdev)
1768{
1769 struct w83781d_data *data = platform_get_drvdata(pdev);
1770
1771 hwmon_device_unregister(data->hwmon_dev);
1772 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1773 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1774 device_remove_file(&pdev->dev, &dev_attr_name);
Jean Delvare360782d2008-10-17 17:51:19 +02001775 release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001776 kfree(data);
1777
1778 return 0;
1779}
1780
1781static struct platform_driver w83781d_isa_driver = {
1782 .driver = {
1783 .owner = THIS_MODULE,
1784 .name = "w83781d",
1785 },
1786 .probe = w83781d_isa_probe,
1787 .remove = __devexit_p(w83781d_isa_remove),
1788};
1789
Jean Delvare7666c132007-05-08 17:22:02 +02001790/* return 1 if a supported chip is found, 0 otherwise */
1791static int __init
1792w83781d_isa_found(unsigned short address)
1793{
1794 int val, save, found = 0;
1795
Jean Delvare2961cb22008-03-09 13:34:28 +01001796 /* We have to request the region in two parts because some
1797 boards declare base+4 to base+7 as a PNP device */
1798 if (!request_region(address, 4, "w83781d")) {
1799 pr_debug("w83781d: Failed to request low part of region\n");
Jean Delvare7666c132007-05-08 17:22:02 +02001800 return 0;
Jean Delvare2961cb22008-03-09 13:34:28 +01001801 }
1802 if (!request_region(address + 4, 4, "w83781d")) {
1803 pr_debug("w83781d: Failed to request high part of region\n");
1804 release_region(address, 4);
1805 return 0;
1806 }
Jean Delvare7666c132007-05-08 17:22:02 +02001807
1808#define REALLY_SLOW_IO
1809 /* We need the timeouts for at least some W83781D-like
1810 chips. But only if we read 'undefined' registers. */
1811 val = inb_p(address + 1);
1812 if (inb_p(address + 2) != val
1813 || inb_p(address + 3) != val
1814 || inb_p(address + 7) != val) {
1815 pr_debug("w83781d: Detection failed at step 1\n");
1816 goto release;
1817 }
1818#undef REALLY_SLOW_IO
1819
1820 /* We should be able to change the 7 LSB of the address port. The
1821 MSB (busy flag) should be clear initially, set after the write. */
1822 save = inb_p(address + W83781D_ADDR_REG_OFFSET);
1823 if (save & 0x80) {
1824 pr_debug("w83781d: Detection failed at step 2\n");
1825 goto release;
1826 }
1827 val = ~save & 0x7f;
1828 outb_p(val, address + W83781D_ADDR_REG_OFFSET);
1829 if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
1830 outb_p(save, address + W83781D_ADDR_REG_OFFSET);
1831 pr_debug("w83781d: Detection failed at step 3\n");
1832 goto release;
1833 }
1834
1835 /* We found a device, now see if it could be a W83781D */
1836 outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
1837 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1838 if (val & 0x80) {
1839 pr_debug("w83781d: Detection failed at step 4\n");
1840 goto release;
1841 }
1842 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1843 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1844 outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
1845 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1846 if ((!(save & 0x80) && (val != 0xa3))
1847 || ((save & 0x80) && (val != 0x5c))) {
1848 pr_debug("w83781d: Detection failed at step 5\n");
1849 goto release;
1850 }
1851 outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
1852 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1853 if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
1854 pr_debug("w83781d: Detection failed at step 6\n");
1855 goto release;
1856 }
1857
1858 /* The busy flag should be clear again */
1859 if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
1860 pr_debug("w83781d: Detection failed at step 7\n");
1861 goto release;
1862 }
1863
1864 /* Determine the chip type */
1865 outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
1866 save = inb_p(address + W83781D_DATA_REG_OFFSET);
1867 outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
1868 outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
1869 val = inb_p(address + W83781D_DATA_REG_OFFSET);
1870 if ((val & 0xfe) == 0x10 /* W83781D */
Jean Delvare05663362007-11-30 23:51:24 +01001871 || val == 0x30) /* W83782D */
Jean Delvare7666c132007-05-08 17:22:02 +02001872 found = 1;
1873
1874 if (found)
1875 pr_info("w83781d: Found a %s chip at %#x\n",
Jean Delvare7666c132007-05-08 17:22:02 +02001876 val == 0x30 ? "W83782D" : "W83781D", (int)address);
1877
1878 release:
Jean Delvare2961cb22008-03-09 13:34:28 +01001879 release_region(address + 4, 4);
1880 release_region(address, 4);
Jean Delvare7666c132007-05-08 17:22:02 +02001881 return found;
1882}
1883
1884static int __init
1885w83781d_isa_device_add(unsigned short address)
1886{
1887 struct resource res = {
1888 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001889 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001890 .name = "w83781d",
1891 .flags = IORESOURCE_IO,
1892 };
1893 int err;
1894
1895 pdev = platform_device_alloc("w83781d", address);
1896 if (!pdev) {
1897 err = -ENOMEM;
1898 printk(KERN_ERR "w83781d: Device allocation failed\n");
1899 goto exit;
1900 }
1901
1902 err = platform_device_add_resources(pdev, &res, 1);
1903 if (err) {
1904 printk(KERN_ERR "w83781d: Device resource addition failed "
1905 "(%d)\n", err);
1906 goto exit_device_put;
1907 }
1908
1909 err = platform_device_add(pdev);
1910 if (err) {
1911 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1912 err);
1913 goto exit_device_put;
1914 }
1915
1916 return 0;
1917
1918 exit_device_put:
1919 platform_device_put(pdev);
1920 exit:
1921 pdev = NULL;
1922 return err;
1923}
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925static int __init
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001926w83781d_isa_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927{
Jean Delvarefde09502005-07-19 23:51:07 +02001928 int res;
1929
Jean Delvare7666c132007-05-08 17:22:02 +02001930 if (w83781d_isa_found(isa_address)) {
1931 res = platform_driver_register(&w83781d_isa_driver);
1932 if (res)
Jean Delvarec6566202008-10-17 17:51:18 +02001933 goto exit;
Jean Delvare7666c132007-05-08 17:22:02 +02001934
1935 /* Sets global pdev as a side effect */
1936 res = w83781d_isa_device_add(isa_address);
1937 if (res)
1938 goto exit_unreg_isa_driver;
1939 }
Jean Delvarefde09502005-07-19 23:51:07 +02001940
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001941 return 0;
1942
1943exit_unreg_isa_driver:
1944 platform_driver_unregister(&w83781d_isa_driver);
1945exit:
1946 return res;
1947}
1948
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001949static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001950w83781d_isa_unregister(void)
1951{
1952 if (pdev) {
1953 platform_device_unregister(pdev);
1954 platform_driver_unregister(&w83781d_isa_driver);
1955 }
1956}
1957#else /* !CONFIG_ISA */
1958
1959static struct w83781d_data *w83781d_data_if_isa(void)
1960{
1961 return NULL;
1962}
1963
1964static int
1965w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1966{
1967 return 0;
1968}
1969
1970static int
1971w83781d_read_value(struct w83781d_data *data, u16 reg)
1972{
1973 int res;
1974
1975 mutex_lock(&data->lock);
1976 res = w83781d_read_value_i2c(data, reg);
1977 mutex_unlock(&data->lock);
1978
1979 return res;
1980}
1981
1982static int
1983w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1984{
1985 mutex_lock(&data->lock);
1986 w83781d_write_value_i2c(data, reg, value);
1987 mutex_unlock(&data->lock);
1988
1989 return 0;
1990}
1991
1992static int __init
1993w83781d_isa_register(void)
1994{
1995 return 0;
1996}
1997
Geert Uytterhoevendd56b632008-10-26 17:04:38 +01001998static void
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02001999w83781d_isa_unregister(void)
2000{
2001}
2002#endif /* CONFIG_ISA */
2003
2004static int __init
2005sensors_w83781d_init(void)
2006{
2007 int res;
2008
2009 /* We register the ISA device first, so that we can skip the
2010 * registration of an I2C interface to the same device. */
2011 res = w83781d_isa_register();
2012 if (res)
2013 goto exit;
2014
Jean Delvarec6566202008-10-17 17:51:18 +02002015 res = i2c_add_driver(&w83781d_driver);
2016 if (res)
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002017 goto exit_unreg_isa;
Jean Delvarec6566202008-10-17 17:51:18 +02002018
Jean Delvarefde09502005-07-19 23:51:07 +02002019 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02002020
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002021 exit_unreg_isa:
2022 w83781d_isa_unregister();
Jean Delvare7666c132007-05-08 17:22:02 +02002023 exit:
2024 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025}
2026
2027static void __exit
2028sensors_w83781d_exit(void)
2029{
Wolfgang Grandegger443850c2008-10-17 17:51:18 +02002030 w83781d_isa_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 i2c_del_driver(&w83781d_driver);
2032}
2033
2034MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
2035 "Philip Edelbrock <phil@netroedge.com>, "
2036 "and Mark Studebaker <mdsxyz123@yahoo.com>");
2037MODULE_DESCRIPTION("W83781D driver");
2038MODULE_LICENSE("GPL");
2039
2040module_init(sensors_w83781d_init);
2041module_exit(sensors_w83781d_exit);