blob: 8d4d1acbf6500b1742efcc1e370cddc892d79712 [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>
7 Copyright (c) 2007 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>
Jean Delvare7666c132007-05-08 17:22:02 +020041#include <linux/platform_device.h>
42#include <linux/ioport.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040043#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020044#include <linux/hwmon-vid.h>
Jean Delvare34875332007-05-08 17:22:03 +020045#include <linux/hwmon-sysfs.h>
Jim Cromie311ce2e2006-09-24 21:22:52 +020046#include <linux/sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010048#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/io.h>
50#include "lm75.h"
51
Jean Delvare7666c132007-05-08 17:22:02 +020052/* ISA device, if found */
53static struct platform_device *pdev;
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055/* Addresses to scan */
Jean Delvare6722fea2007-10-07 12:25:46 +020056static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
57 0x2e, 0x2f, I2C_CLIENT_END };
Jean Delvare2d8672c2005-07-19 23:56:35 +020058static unsigned short isa_address = 0x290;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/* Insmod parameters */
Jean Delvare05663362007-11-30 23:51:24 +010061I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
63 "{bus, clientaddr, subclientaddr1, subclientaddr2}");
64
Jean Delvarefabddcd2006-02-05 23:26:51 +010065static int reset;
66module_param(reset, bool, 0);
67MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static int init = 1;
70module_param(init, bool, 0);
71MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
72
73/* Constants specified below */
74
75/* Length of ISA address segment */
76#define W83781D_EXTENT 8
77
78/* Where are the ISA address/data registers relative to the base address */
79#define W83781D_ADDR_REG_OFFSET 5
80#define W83781D_DATA_REG_OFFSET 6
81
Jean Delvare34875332007-05-08 17:22:03 +020082/* The device registers */
83/* in nr from 0 to 8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
85 (0x554 + (((nr) - 7) * 2)))
86#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
87 (0x555 + (((nr) - 7) * 2)))
88#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
89 (0x550 + (nr) - 7))
90
Jean Delvare34875332007-05-08 17:22:03 +020091/* fan nr from 0 to 2 */
92#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
93#define W83781D_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95#define W83781D_REG_BANK 0x4E
96#define W83781D_REG_TEMP2_CONFIG 0x152
97#define W83781D_REG_TEMP3_CONFIG 0x252
Jean Delvare34875332007-05-08 17:22:03 +020098/* temp nr from 1 to 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
100 ((nr == 2) ? (0x0150) : \
101 (0x27)))
102#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
103 ((nr == 2) ? (0x153) : \
104 (0x3A)))
105#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
106 ((nr == 2) ? (0x155) : \
107 (0x39)))
108
109#define W83781D_REG_CONFIG 0x40
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100110
111/* Interrupt status (W83781D, AS99127F) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define W83781D_REG_ALARM1 0x41
113#define W83781D_REG_ALARM2 0x42
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Jean Delvare05663362007-11-30 23:51:24 +0100115/* Real-time status (W83782D, W83783S) */
Jean Delvarec7f5d7e2006-02-05 23:13:48 +0100116#define W83782D_REG_ALARM1 0x459
117#define W83782D_REG_ALARM2 0x45A
118#define W83782D_REG_ALARM3 0x45B
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define W83781D_REG_BEEP_CONFIG 0x4D
121#define W83781D_REG_BEEP_INTS1 0x56
122#define W83781D_REG_BEEP_INTS2 0x57
123#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
124
125#define W83781D_REG_VID_FANDIV 0x47
126
127#define W83781D_REG_CHIPID 0x49
128#define W83781D_REG_WCHIPID 0x58
129#define W83781D_REG_CHIPMAN 0x4F
130#define W83781D_REG_PIN 0x4B
131
132/* 782D/783S only */
133#define W83781D_REG_VBAT 0x5D
134
135/* PWM 782D (1-4) and 783S (1-2) only */
Jean Delvare34875332007-05-08 17:22:03 +0200136static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137#define W83781D_REG_PWMCLK12 0x5C
138#define W83781D_REG_PWMCLK34 0x45C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140#define W83781D_REG_I2C_ADDR 0x48
141#define W83781D_REG_I2C_SUBADDR 0x4A
142
143/* The following are undocumented in the data sheets however we
144 received the information in an email from Winbond tech support */
145/* Sensor selection - not on 781d */
146#define W83781D_REG_SCFG1 0x5D
147static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
148
149#define W83781D_REG_SCFG2 0x59
150static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
151
152#define W83781D_DEFAULT_BETA 3435
153
154/* RT Table registers */
155#define W83781D_REG_RT_IDX 0x50
156#define W83781D_REG_RT_VAL 0x51
157
Jean Delvare474d00a2007-05-08 17:22:03 +0200158/* Conversions */
159#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
160#define IN_FROM_REG(val) ((val) * 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162static inline u8
163FAN_TO_REG(long rpm, int div)
164{
165 if (rpm == 0)
166 return 255;
167 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
168 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
169}
170
Jean Delvare474d00a2007-05-08 17:22:03 +0200171static inline long
172FAN_FROM_REG(u8 val, int div)
173{
174 if (val == 0)
175 return -1;
176 if (val == 255)
177 return 0;
178 return 1350000 / (val * div);
179}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Jean Delvare474d00a2007-05-08 17:22:03 +0200181#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
182#define TEMP_FROM_REG(val) ((val) * 1000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
185 (val) ^ 0x7fff : (val))
186#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
187 (~(val)) & 0x7fff : (val) & 0xffffff)
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#define DIV_FROM_REG(val) (1 << (val))
190
191static inline u8
192DIV_TO_REG(long val, enum chips type)
193{
194 int i;
195 val = SENSORS_LIMIT(val, 1,
196 ((type == w83781d
197 || type == as99127f) ? 8 : 128)) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000198 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if (val == 0)
200 break;
201 val >>= 1;
202 }
Jean Delvare474d00a2007-05-08 17:22:03 +0200203 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
206/* There are some complications in a module like this. First off, W83781D chips
207 may be both present on the SMBus and the ISA bus, and we have to handle
208 those cases separately at some places. Second, there might be several
209 W83781D chips available (well, actually, that is probably never done; but
210 it is a clean illustration of how to handle a case like that). Finally,
211 a specific chip may be attached to *both* ISA and SMBus, and we would
212 not like to detect it double. Fortunately, in the case of the W83781D at
213 least, a register tells us what SMBus address we are on, so that helps
214 a bit - except if there could be more than one SMBus. Groan. No solution
215 for this yet. */
216
Jean Delvare7666c132007-05-08 17:22:02 +0200217/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
218 the driver field to differentiate between I2C and ISA chips. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219struct w83781d_data {
220 struct i2c_client client;
Tony Jones1beeffe2007-08-20 13:46:20 -0700221 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100222 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 enum chips type;
224
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100225 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 char valid; /* !=0 if following fields are valid */
227 unsigned long last_updated; /* In jiffies */
228
229 struct i2c_client *lm75[2]; /* for secondary I2C addresses */
230 /* array of 2 pointers to subclients */
231
232 u8 in[9]; /* Register value - 8 & 9 for 782D only */
233 u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
234 u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
235 u8 fan[3]; /* Register value */
236 u8 fan_min[3]; /* Register value */
Jean Delvare474d00a2007-05-08 17:22:03 +0200237 s8 temp; /* Register value */
238 s8 temp_max; /* Register value */
239 s8 temp_max_hyst; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 u16 temp_add[2]; /* Register value */
241 u16 temp_max_add[2]; /* Register value */
242 u16 temp_max_hyst_add[2]; /* Register value */
243 u8 fan_div[3]; /* Register encoding, shifted right */
244 u8 vid; /* Register encoding, combined */
245 u32 alarms; /* Register encoding, combined */
246 u32 beep_mask; /* Register encoding, combined */
247 u8 beep_enable; /* Boolean */
248 u8 pwm[4]; /* Register value */
Jean Delvare34875332007-05-08 17:22:03 +0200249 u8 pwm2_enable; /* Boolean */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 u16 sens[3]; /* 782D/783S only.
251 1 = pentium diode; 2 = 3904 diode;
Jean Delvareb26f9332007-08-16 14:30:01 +0200252 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 u8 vrm;
254};
255
256static int w83781d_attach_adapter(struct i2c_adapter *adapter);
257static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
258static int w83781d_detach_client(struct i2c_client *client);
259
Jean Delvare7666c132007-05-08 17:22:02 +0200260static int __devinit w83781d_isa_probe(struct platform_device *pdev);
261static int __devexit w83781d_isa_remove(struct platform_device *pdev);
262
Jean Delvare31b8dc42007-05-08 17:22:03 +0200263static int w83781d_read_value(struct w83781d_data *data, u16 reg);
264static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static struct w83781d_data *w83781d_update_device(struct device *dev);
Jean Delvare7666c132007-05-08 17:22:02 +0200266static void w83781d_init_device(struct device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268static struct i2c_driver w83781d_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100269 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100270 .name = "w83781d",
271 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .id = I2C_DRIVERID_W83781D,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .attach_adapter = w83781d_attach_adapter,
274 .detach_client = w83781d_detach_client,
275};
276
Jean Delvare7666c132007-05-08 17:22:02 +0200277static struct platform_driver w83781d_isa_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100278 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200279 .owner = THIS_MODULE,
Jean Delvare7666c132007-05-08 17:22:02 +0200280 .name = "w83781d",
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100281 },
Jean Delvare7666c132007-05-08 17:22:02 +0200282 .probe = w83781d_isa_probe,
283 .remove = w83781d_isa_remove,
Jean Delvarefde09502005-07-19 23:51:07 +0200284};
285
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287/* following are the sysfs callback functions */
288#define show_in_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200289static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
290 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{ \
Jean Delvare34875332007-05-08 17:22:03 +0200292 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200294 return sprintf(buf, "%ld\n", \
295 (long)IN_FROM_REG(data->reg[attr->index])); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297show_in_reg(in);
298show_in_reg(in_min);
299show_in_reg(in_max);
300
301#define store_in_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200302static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
303 *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{ \
Jean Delvare34875332007-05-08 17:22:03 +0200305 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200306 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200307 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 u32 val; \
309 \
Jean Delvare474d00a2007-05-08 17:22:03 +0200310 val = simple_strtoul(buf, NULL, 10); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100312 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 data->in_##reg[nr] = IN_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200314 w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100316 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return count; \
318}
319store_in_reg(MIN, min);
320store_in_reg(MAX, max);
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322#define sysfs_in_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200323static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
324 show_in, NULL, offset); \
325static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
326 show_in_min, store_in_min, offset); \
327static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
328 show_in_max, store_in_max, offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330sysfs_in_offsets(0);
331sysfs_in_offsets(1);
332sysfs_in_offsets(2);
333sysfs_in_offsets(3);
334sysfs_in_offsets(4);
335sysfs_in_offsets(5);
336sysfs_in_offsets(6);
337sysfs_in_offsets(7);
338sysfs_in_offsets(8);
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340#define show_fan_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200341static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
342 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{ \
Jean Delvare34875332007-05-08 17:22:03 +0200344 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 struct w83781d_data *data = w83781d_update_device(dev); \
346 return sprintf(buf,"%ld\n", \
Jean Delvare34875332007-05-08 17:22:03 +0200347 FAN_FROM_REG(data->reg[attr->index], \
348 DIV_FROM_REG(data->fan_div[attr->index]))); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350show_fan_reg(fan);
351show_fan_reg(fan_min);
352
353static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200354store_fan_min(struct device *dev, struct device_attribute *da,
355 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Jean Delvare34875332007-05-08 17:22:03 +0200357 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200358 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200359 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 u32 val;
361
362 val = simple_strtoul(buf, NULL, 10);
363
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100364 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200365 data->fan_min[nr] =
366 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200367 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
Jean Delvare34875332007-05-08 17:22:03 +0200368 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100370 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return count;
372}
373
Jean Delvare34875332007-05-08 17:22:03 +0200374static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
375static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
376 show_fan_min, store_fan_min, 0);
377static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
378static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
379 show_fan_min, store_fan_min, 1);
380static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
381static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
382 show_fan_min, store_fan_min, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384#define show_temp_reg(reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200385static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
386 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{ \
Jean Delvare34875332007-05-08 17:22:03 +0200388 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 struct w83781d_data *data = w83781d_update_device(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200390 int nr = attr->index; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
392 return sprintf(buf,"%d\n", \
393 LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
394 } else { /* TEMP1 */ \
395 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
396 } \
397}
398show_temp_reg(temp);
399show_temp_reg(temp_max);
400show_temp_reg(temp_max_hyst);
401
402#define store_temp_reg(REG, reg) \
Jean Delvare34875332007-05-08 17:22:03 +0200403static ssize_t store_temp_##reg (struct device *dev, \
404 struct device_attribute *da, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{ \
Jean Delvare34875332007-05-08 17:22:03 +0200406 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
Jean Delvare7666c132007-05-08 17:22:02 +0200407 struct w83781d_data *data = dev_get_drvdata(dev); \
Jean Delvare34875332007-05-08 17:22:03 +0200408 int nr = attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200409 long val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 \
411 val = simple_strtol(buf, NULL, 10); \
412 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100413 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 \
415 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
416 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200417 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 data->temp_##reg##_add[nr-2]); \
419 } else { /* TEMP1 */ \
420 data->temp_##reg = TEMP_TO_REG(val); \
Jean Delvare31b8dc42007-05-08 17:22:03 +0200421 w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 data->temp_##reg); \
423 } \
424 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100425 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 return count; \
427}
428store_temp_reg(OVER, max);
429store_temp_reg(HYST, max_hyst);
430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431#define sysfs_temp_offsets(offset) \
Jean Delvare34875332007-05-08 17:22:03 +0200432static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
433 show_temp, NULL, offset); \
434static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
435 show_temp_max, store_temp_max, offset); \
436static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
437 show_temp_max_hyst, store_temp_max_hyst, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439sysfs_temp_offsets(1);
440sysfs_temp_offsets(2);
441sysfs_temp_offsets(3);
442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400444show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 struct w83781d_data *data = w83781d_update_device(dev);
447 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
448}
449
Jim Cromie311ce2e2006-09-24 21:22:52 +0200450static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400453show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454{
Jean Delvare90d66192007-10-08 18:24:35 +0200455 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return sprintf(buf, "%ld\n", (long) data->vrm);
457}
458
459static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400460store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
Jean Delvare7666c132007-05-08 17:22:02 +0200462 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 u32 val;
464
465 val = simple_strtoul(buf, NULL, 10);
466 data->vrm = val;
467
468 return count;
469}
470
Jim Cromie311ce2e2006-09-24 21:22:52 +0200471static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400474show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200477 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
Jim Cromie311ce2e2006-09-24 21:22:52 +0200480static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
481
Jean Delvare7d4a1372007-10-08 18:29:43 +0200482static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
483 char *buf)
484{
485 struct w83781d_data *data = w83781d_update_device(dev);
486 int bitnr = to_sensor_dev_attr(attr)->index;
487 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
488}
489
490/* The W83781D has a single alarm bit for temp2 and temp3 */
491static ssize_t show_temp3_alarm(struct device *dev,
492 struct device_attribute *attr, char *buf)
493{
494 struct w83781d_data *data = w83781d_update_device(dev);
495 int bitnr = (data->type == w83781d) ? 5 : 13;
496 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
497}
498
499static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
500static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
501static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
502static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
503static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
504static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
505static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
506static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
507static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
508static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
509static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
510static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
511static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
512static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
513static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
514
Yani Ioannoue404e272005-05-17 06:42:58 -0400515static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 struct w83781d_data *data = w83781d_update_device(dev);
518 return sprintf(buf, "%ld\n",
519 (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
520}
Yani Ioannoue404e272005-05-17 06:42:58 -0400521static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
523 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare474d00a2007-05-08 17:22:03 +0200524 return sprintf(buf, "%ld\n", (long)data->beep_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525}
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200528store_beep_mask(struct device *dev, struct device_attribute *attr,
529 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
Jean Delvare7666c132007-05-08 17:22:02 +0200531 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200532 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 val = simple_strtoul(buf, NULL, 10);
535
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100536 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200537 data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
538 w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
539 data->beep_mask & 0xff);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200540 w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare34875332007-05-08 17:22:03 +0200541 ((data->beep_mask >> 8) & 0x7f)
542 | data->beep_enable << 7);
543 if (data->type != w83781d && data->type != as99127f) {
544 w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
545 ((data->beep_mask) >> 16) & 0xff);
546 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100547 mutex_unlock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 return count;
550}
551
Jean Delvare34875332007-05-08 17:22:03 +0200552static ssize_t
553store_beep_enable(struct device *dev, struct device_attribute *attr,
554 const char *buf, size_t count)
555{
556 struct w83781d_data *data = dev_get_drvdata(dev);
557 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Jean Delvare34875332007-05-08 17:22:03 +0200559 val = simple_strtoul(buf, NULL, 10);
560 if (val != 0 && val != 1)
561 return -EINVAL;
562
563 mutex_lock(&data->update_lock);
564 data->beep_enable = val;
565 val = w83781d_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
566 val |= data->beep_enable << 7;
567 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, val);
568 mutex_unlock(&data->update_lock);
569
570 return count;
571}
572
573static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
574 show_beep_mask, store_beep_mask);
575static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
576 show_beep_enable, store_beep_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Jean Delvare7d4a1372007-10-08 18:29:43 +0200578static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
579 char *buf)
580{
581 struct w83781d_data *data = w83781d_update_device(dev);
582 int bitnr = to_sensor_dev_attr(attr)->index;
583 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
584}
585
586static ssize_t
587store_beep(struct device *dev, struct device_attribute *attr,
588 const char *buf, size_t count)
589{
590 struct w83781d_data *data = dev_get_drvdata(dev);
591 int bitnr = to_sensor_dev_attr(attr)->index;
592 unsigned long bit;
593 u8 reg;
594
595 bit = simple_strtoul(buf, NULL, 10);
596 if (bit & ~1)
597 return -EINVAL;
598
599 mutex_lock(&data->update_lock);
600 if (bit)
601 data->beep_mask |= (1 << bitnr);
602 else
603 data->beep_mask &= ~(1 << bitnr);
604
605 if (bitnr < 8) {
606 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
607 if (bit)
608 reg |= (1 << bitnr);
609 else
610 reg &= ~(1 << bitnr);
611 w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
612 } else if (bitnr < 16) {
613 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
614 if (bit)
615 reg |= (1 << (bitnr - 8));
616 else
617 reg &= ~(1 << (bitnr - 8));
618 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
619 } else {
620 reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
621 if (bit)
622 reg |= (1 << (bitnr - 16));
623 else
624 reg &= ~(1 << (bitnr - 16));
625 w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
626 }
627 mutex_unlock(&data->update_lock);
628
629 return count;
630}
631
632/* The W83781D has a single beep bit for temp2 and temp3 */
633static ssize_t show_temp3_beep(struct device *dev,
634 struct device_attribute *attr, char *buf)
635{
636 struct w83781d_data *data = w83781d_update_device(dev);
637 int bitnr = (data->type == w83781d) ? 5 : 13;
638 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
639}
640
641static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
642 show_beep, store_beep, 0);
643static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
644 show_beep, store_beep, 1);
645static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
646 show_beep, store_beep, 2);
647static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
648 show_beep, store_beep, 3);
649static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
650 show_beep, store_beep, 8);
651static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
652 show_beep, store_beep, 9);
653static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
654 show_beep, store_beep, 10);
655static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
656 show_beep, store_beep, 16);
657static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
658 show_beep, store_beep, 17);
659static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
660 show_beep, store_beep, 6);
661static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
662 show_beep, store_beep, 7);
663static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
664 show_beep, store_beep, 11);
665static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
666 show_beep, store_beep, 4);
667static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
668 show_beep, store_beep, 5);
669static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
670 show_temp3_beep, store_beep, 13);
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200673show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
Jean Delvare34875332007-05-08 17:22:03 +0200675 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 struct w83781d_data *data = w83781d_update_device(dev);
677 return sprintf(buf, "%ld\n",
Jean Delvare34875332007-05-08 17:22:03 +0200678 (long) DIV_FROM_REG(data->fan_div[attr->index]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681/* Note: we save and restore the fan minimum here, because its value is
682 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200683 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 because the divisor changed. */
685static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200686store_fan_div(struct device *dev, struct device_attribute *da,
687 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
Jean Delvare34875332007-05-08 17:22:03 +0200689 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200690 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 unsigned long min;
Jean Delvare34875332007-05-08 17:22:03 +0200692 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 u8 reg;
694 unsigned long val = simple_strtoul(buf, NULL, 10);
695
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100696 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 /* Save fan_min */
699 min = FAN_FROM_REG(data->fan_min[nr],
700 DIV_FROM_REG(data->fan_div[nr]));
701
702 data->fan_div[nr] = DIV_TO_REG(val, data->type);
703
Jean Delvare31b8dc42007-05-08 17:22:03 +0200704 reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 & (nr==0 ? 0xcf : 0x3f))
706 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200707 w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 /* w83781d and as99127f don't have extended divisor bits */
710 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200711 reg = (w83781d_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 & ~(1 << (5 + nr)))
713 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare31b8dc42007-05-08 17:22:03 +0200714 w83781d_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716
717 /* Restore fan_min */
718 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare34875332007-05-08 17:22:03 +0200719 w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100721 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return count;
723}
724
Jean Delvare34875332007-05-08 17:22:03 +0200725static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
726 show_fan_div, store_fan_div, 0);
727static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
728 show_fan_div, store_fan_div, 1);
729static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
730 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200733show_pwm(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Jean Delvare34875332007-05-08 17:22:03 +0200735 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200737 return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
740static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200741show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200744 return sprintf(buf, "%d\n", (int)data->pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200748store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
749 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
Jean Delvare34875332007-05-08 17:22:03 +0200751 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200752 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200753 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 u32 val;
755
756 val = simple_strtoul(buf, NULL, 10);
757
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100758 mutex_lock(&data->update_lock);
Jean Delvare34875332007-05-08 17:22:03 +0200759 data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
760 w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100761 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return count;
763}
764
765static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200766store_pwm2_enable(struct device *dev, struct device_attribute *da,
767 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Jean Delvare7666c132007-05-08 17:22:02 +0200769 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 u32 val, reg;
771
772 val = simple_strtoul(buf, NULL, 10);
773
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100774 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 switch (val) {
777 case 0:
778 case 1:
Jean Delvare31b8dc42007-05-08 17:22:03 +0200779 reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
780 w83781d_write_value(data, W83781D_REG_PWMCLK12,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 (reg & 0xf7) | (val << 3));
782
Jean Delvare31b8dc42007-05-08 17:22:03 +0200783 reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
784 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 (reg & 0xef) | (!val << 4));
786
Jean Delvare34875332007-05-08 17:22:03 +0200787 data->pwm2_enable = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 break;
789
790 default:
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100791 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return -EINVAL;
793 }
794
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100795 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return count;
797}
798
Jean Delvare34875332007-05-08 17:22:03 +0200799static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
800static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
801static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
802static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
803/* only PWM2 can be enabled/disabled */
804static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
805 show_pwm2_enable, store_pwm2_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200808show_sensor(struct device *dev, struct device_attribute *da, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
Jean Delvare34875332007-05-08 17:22:03 +0200810 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 struct w83781d_data *data = w83781d_update_device(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200812 return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813}
814
815static ssize_t
Jean Delvare34875332007-05-08 17:22:03 +0200816store_sensor(struct device *dev, struct device_attribute *da,
817 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
Jean Delvare34875332007-05-08 17:22:03 +0200819 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
Jean Delvare7666c132007-05-08 17:22:02 +0200820 struct w83781d_data *data = dev_get_drvdata(dev);
Jean Delvare34875332007-05-08 17:22:03 +0200821 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 u32 val, tmp;
823
824 val = simple_strtoul(buf, NULL, 10);
825
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100826 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 switch (val) {
829 case 1: /* PII/Celeron diode */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200830 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
831 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200832 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200833 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
834 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200835 tmp | BIT_SCFG2[nr]);
836 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 break;
838 case 2: /* 3904 */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200839 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
840 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200841 tmp | BIT_SCFG1[nr]);
Jean Delvare31b8dc42007-05-08 17:22:03 +0200842 tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
843 w83781d_write_value(data, W83781D_REG_SCFG2,
Jean Delvare34875332007-05-08 17:22:03 +0200844 tmp & ~BIT_SCFG2[nr]);
845 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200847 case W83781D_DEFAULT_BETA:
848 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
849 "instead\n", W83781D_DEFAULT_BETA);
850 /* fall through */
851 case 4: /* thermistor */
Jean Delvare31b8dc42007-05-08 17:22:03 +0200852 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
853 w83781d_write_value(data, W83781D_REG_SCFG1,
Jean Delvare34875332007-05-08 17:22:03 +0200854 tmp & ~BIT_SCFG1[nr]);
855 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 break;
857 default:
Jean Delvareb26f9332007-08-16 14:30:01 +0200858 dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
859 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 break;
861 }
862
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100863 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return count;
865}
866
Jean Delvare34875332007-05-08 17:22:03 +0200867static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
868 show_sensor, store_sensor, 0);
869static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400870 show_sensor, store_sensor, 1);
Jean Delvare34875332007-05-08 17:22:03 +0200871static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
Mark M. Hoffman393cdad2007-08-09 08:12:46 -0400872 show_sensor, store_sensor, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Jean Delvare7666c132007-05-08 17:22:02 +0200874/* I2C devices get this name attribute automatically, but for ISA devices
875 we must create it by ourselves. */
876static ssize_t
877show_name(struct device *dev, struct device_attribute *devattr, char *buf)
878{
879 struct w83781d_data *data = dev_get_drvdata(dev);
880 return sprintf(buf, "%s\n", data->client.name);
881}
882static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884/* This function is called when:
885 * w83781d_driver is inserted (when this module is loaded), for each
886 available adapter
887 * when a new adapter is inserted (and w83781d_driver is still present) */
888static int
889w83781d_attach_adapter(struct i2c_adapter *adapter)
890{
891 if (!(adapter->class & I2C_CLASS_HWMON))
892 return 0;
Jean Delvare2ed2dc32005-07-31 21:42:02 +0200893 return i2c_probe(adapter, &addr_data, w83781d_detect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
896/* Assumes that adapter is of I2C, not ISA variety.
897 * OTHERWISE DON'T CALL THIS
898 */
899static int
900w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
901 struct i2c_client *new_client)
902{
903 int i, val1 = 0, id;
904 int err;
905 const char *client_name = "";
906 struct w83781d_data *data = i2c_get_clientdata(new_client);
907
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200908 data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (!(data->lm75[0])) {
910 err = -ENOMEM;
911 goto ERROR_SC_0;
912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 id = i2c_adapter_id(adapter);
915
916 if (force_subclients[0] == id && force_subclients[1] == address) {
917 for (i = 2; i <= 3; i++) {
918 if (force_subclients[i] < 0x48 ||
919 force_subclients[i] > 0x4f) {
920 dev_err(&new_client->dev, "Invalid subclient "
921 "address %d; must be 0x48-0x4f\n",
922 force_subclients[i]);
923 err = -EINVAL;
924 goto ERROR_SC_1;
925 }
926 }
Jean Delvare31b8dc42007-05-08 17:22:03 +0200927 w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 (force_subclients[2] & 0x07) |
929 ((force_subclients[3] & 0x07) << 4));
930 data->lm75[0]->addr = force_subclients[2];
931 } else {
Jean Delvare31b8dc42007-05-08 17:22:03 +0200932 val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 data->lm75[0]->addr = 0x48 + (val1 & 0x07);
934 }
935
936 if (kind != w83783s) {
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200937 data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if (!(data->lm75[1])) {
939 err = -ENOMEM;
940 goto ERROR_SC_1;
941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 if (force_subclients[0] == id &&
944 force_subclients[1] == address) {
945 data->lm75[1]->addr = force_subclients[3];
946 } else {
947 data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07);
948 }
949 if (data->lm75[0]->addr == data->lm75[1]->addr) {
950 dev_err(&new_client->dev,
951 "Duplicate addresses 0x%x for subclients.\n",
952 data->lm75[0]->addr);
953 err = -EBUSY;
954 goto ERROR_SC_2;
955 }
956 }
957
958 if (kind == w83781d)
959 client_name = "w83781d subclient";
960 else if (kind == w83782d)
961 client_name = "w83782d subclient";
962 else if (kind == w83783s)
963 client_name = "w83783s subclient";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 else if (kind == as99127f)
965 client_name = "as99127f subclient";
966
967 for (i = 0; i <= 1; i++) {
968 /* store all data in w83781d */
969 i2c_set_clientdata(data->lm75[i], NULL);
970 data->lm75[i]->adapter = adapter;
971 data->lm75[i]->driver = &w83781d_driver;
972 data->lm75[i]->flags = 0;
973 strlcpy(data->lm75[i]->name, client_name,
974 I2C_NAME_SIZE);
975 if ((err = i2c_attach_client(data->lm75[i]))) {
976 dev_err(&new_client->dev, "Subclient %d "
977 "registration at address 0x%x "
978 "failed.\n", i, data->lm75[i]->addr);
979 if (i == 1)
980 goto ERROR_SC_3;
981 goto ERROR_SC_2;
982 }
983 if (kind == w83783s)
984 break;
985 }
986
987 return 0;
988
989/* Undo inits in case of errors */
990ERROR_SC_3:
991 i2c_detach_client(data->lm75[0]);
992ERROR_SC_2:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800993 kfree(data->lm75[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994ERROR_SC_1:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800995 kfree(data->lm75[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996ERROR_SC_0:
997 return err;
998}
999
Jean Delvare34875332007-05-08 17:22:03 +02001000#define IN_UNIT_ATTRS(X) \
1001 &sensor_dev_attr_in##X##_input.dev_attr.attr, \
1002 &sensor_dev_attr_in##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +02001003 &sensor_dev_attr_in##X##_max.dev_attr.attr, \
1004 &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
1005 &sensor_dev_attr_in##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +02001006
Jean Delvare34875332007-05-08 17:22:03 +02001007#define FAN_UNIT_ATTRS(X) \
1008 &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
1009 &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +02001010 &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
1011 &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
1012 &sensor_dev_attr_fan##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +02001013
Jean Delvare34875332007-05-08 17:22:03 +02001014#define TEMP_UNIT_ATTRS(X) \
1015 &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
1016 &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
Jean Delvare7d4a1372007-10-08 18:29:43 +02001017 &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
1018 &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
1019 &sensor_dev_attr_temp##X##_beep.dev_attr.attr
Jim Cromie311ce2e2006-09-24 21:22:52 +02001020
1021static struct attribute* w83781d_attributes[] = {
1022 IN_UNIT_ATTRS(0),
1023 IN_UNIT_ATTRS(2),
1024 IN_UNIT_ATTRS(3),
1025 IN_UNIT_ATTRS(4),
1026 IN_UNIT_ATTRS(5),
1027 IN_UNIT_ATTRS(6),
1028 FAN_UNIT_ATTRS(1),
1029 FAN_UNIT_ATTRS(2),
1030 FAN_UNIT_ATTRS(3),
1031 TEMP_UNIT_ATTRS(1),
1032 TEMP_UNIT_ATTRS(2),
1033 &dev_attr_cpu0_vid.attr,
1034 &dev_attr_vrm.attr,
1035 &dev_attr_alarms.attr,
1036 &dev_attr_beep_mask.attr,
1037 &dev_attr_beep_enable.attr,
1038 NULL
1039};
1040static const struct attribute_group w83781d_group = {
1041 .attrs = w83781d_attributes,
1042};
1043
1044static struct attribute *w83781d_attributes_opt[] = {
1045 IN_UNIT_ATTRS(1),
1046 IN_UNIT_ATTRS(7),
1047 IN_UNIT_ATTRS(8),
1048 TEMP_UNIT_ATTRS(3),
Jean Delvare34875332007-05-08 17:22:03 +02001049 &sensor_dev_attr_pwm1.dev_attr.attr,
1050 &sensor_dev_attr_pwm2.dev_attr.attr,
1051 &sensor_dev_attr_pwm3.dev_attr.attr,
1052 &sensor_dev_attr_pwm4.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +02001053 &dev_attr_pwm2_enable.attr,
Jean Delvare34875332007-05-08 17:22:03 +02001054 &sensor_dev_attr_temp1_type.dev_attr.attr,
1055 &sensor_dev_attr_temp2_type.dev_attr.attr,
1056 &sensor_dev_attr_temp3_type.dev_attr.attr,
Jim Cromie311ce2e2006-09-24 21:22:52 +02001057 NULL
1058};
1059static const struct attribute_group w83781d_group_opt = {
1060 .attrs = w83781d_attributes_opt,
1061};
1062
Jean Delvare7666c132007-05-08 17:22:02 +02001063/* No clean up is done on error, it's up to the caller */
1064static int
1065w83781d_create_files(struct device *dev, int kind, int is_isa)
1066{
1067 int err;
1068
1069 if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
1070 return err;
1071
1072 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001073 if ((err = device_create_file(dev,
1074 &sensor_dev_attr_in1_input.dev_attr))
1075 || (err = device_create_file(dev,
1076 &sensor_dev_attr_in1_min.dev_attr))
1077 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001078 &sensor_dev_attr_in1_max.dev_attr))
1079 || (err = device_create_file(dev,
1080 &sensor_dev_attr_in1_alarm.dev_attr))
1081 || (err = device_create_file(dev,
1082 &sensor_dev_attr_in1_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001083 return err;
1084 }
1085 if (kind != as99127f && kind != w83781d && kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001086 if ((err = device_create_file(dev,
1087 &sensor_dev_attr_in7_input.dev_attr))
1088 || (err = device_create_file(dev,
1089 &sensor_dev_attr_in7_min.dev_attr))
1090 || (err = device_create_file(dev,
1091 &sensor_dev_attr_in7_max.dev_attr))
1092 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001093 &sensor_dev_attr_in7_alarm.dev_attr))
1094 || (err = device_create_file(dev,
1095 &sensor_dev_attr_in7_beep.dev_attr))
1096 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001097 &sensor_dev_attr_in8_input.dev_attr))
1098 || (err = device_create_file(dev,
1099 &sensor_dev_attr_in8_min.dev_attr))
1100 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001101 &sensor_dev_attr_in8_max.dev_attr))
1102 || (err = device_create_file(dev,
1103 &sensor_dev_attr_in8_alarm.dev_attr))
1104 || (err = device_create_file(dev,
1105 &sensor_dev_attr_in8_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001106 return err;
1107 }
1108 if (kind != w83783s) {
Jean Delvare34875332007-05-08 17:22:03 +02001109 if ((err = device_create_file(dev,
1110 &sensor_dev_attr_temp3_input.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001111 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001112 &sensor_dev_attr_temp3_max.dev_attr))
1113 || (err = device_create_file(dev,
Jean Delvare7d4a1372007-10-08 18:29:43 +02001114 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1115 || (err = device_create_file(dev,
1116 &sensor_dev_attr_temp3_alarm.dev_attr))
1117 || (err = device_create_file(dev,
1118 &sensor_dev_attr_temp3_beep.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001119 return err;
Jean Delvare7d4a1372007-10-08 18:29:43 +02001120
Jean Delvare7768aa72007-10-25 13:11:01 +02001121 if (kind != w83781d) {
Jean Delvare7d4a1372007-10-08 18:29:43 +02001122 err = sysfs_chmod_file(&dev->kobj,
1123 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1124 S_IRUGO | S_IWUSR);
1125 if (err)
1126 return err;
Jean Delvare7768aa72007-10-25 13:11:01 +02001127 }
Jean Delvare7666c132007-05-08 17:22:02 +02001128 }
1129
1130 if (kind != w83781d && kind != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001131 if ((err = device_create_file(dev,
1132 &sensor_dev_attr_pwm1.dev_attr))
1133 || (err = device_create_file(dev,
1134 &sensor_dev_attr_pwm2.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001135 || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
1136 return err;
1137 }
1138 if (kind == w83782d && !is_isa) {
Jean Delvare34875332007-05-08 17:22:03 +02001139 if ((err = device_create_file(dev,
1140 &sensor_dev_attr_pwm3.dev_attr))
1141 || (err = device_create_file(dev,
1142 &sensor_dev_attr_pwm4.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001143 return err;
1144 }
1145
1146 if (kind != as99127f && kind != w83781d) {
Jean Delvare34875332007-05-08 17:22:03 +02001147 if ((err = device_create_file(dev,
1148 &sensor_dev_attr_temp1_type.dev_attr))
Jean Delvare7666c132007-05-08 17:22:02 +02001149 || (err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001150 &sensor_dev_attr_temp2_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001151 return err;
1152 if (kind != w83783s) {
1153 if ((err = device_create_file(dev,
Jean Delvare34875332007-05-08 17:22:03 +02001154 &sensor_dev_attr_temp3_type.dev_attr)))
Jean Delvare7666c132007-05-08 17:22:02 +02001155 return err;
1156 }
1157 }
1158
1159 if (is_isa) {
1160 err = device_create_file(&pdev->dev, &dev_attr_name);
1161 if (err)
1162 return err;
1163 }
1164
1165 return 0;
1166}
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168static int
1169w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
1170{
Jean Delvare7666c132007-05-08 17:22:02 +02001171 int val1 = 0, val2;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001172 struct i2c_client *client;
1173 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 struct w83781d_data *data;
1175 int err;
1176 const char *client_name = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 enum vendor { winbond, asus } vendid;
1178
Jean Delvare7666c132007-05-08 17:22:02 +02001179 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 err = -EINVAL;
Jean Delvare7666c132007-05-08 17:22:02 +02001181 goto ERROR1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 }
1183
1184 /* OK. For now, we presume we have a valid client. We now create the
1185 client structure, even though we cannot fill it completely yet.
1186 But it allows us to access w83781d_{read,write}_value. */
1187
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001188 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 err = -ENOMEM;
1190 goto ERROR1;
1191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
Jim Cromie311ce2e2006-09-24 21:22:52 +02001193 client = &data->client;
1194 i2c_set_clientdata(client, data);
1195 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001196 mutex_init(&data->lock);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001197 client->adapter = adapter;
Jean Delvare7666c132007-05-08 17:22:02 +02001198 client->driver = &w83781d_driver;
Jim Cromie311ce2e2006-09-24 21:22:52 +02001199 dev = &client->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 /* Now, we do the remaining detection. */
1202
1203 /* The w8378?d may be stuck in some other bank than bank 0. This may
1204 make reading other information impossible. Specify a force=... or
1205 force_*=... parameter, and the Winbond will be reset to the right
1206 bank. */
1207 if (kind < 0) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001208 if (w83781d_read_value(data, W83781D_REG_CONFIG) & 0x80) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001209 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1210 "failed at step 3\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 err = -ENODEV;
1212 goto ERROR2;
1213 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001214 val1 = w83781d_read_value(data, W83781D_REG_BANK);
1215 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 /* Check for Winbond or Asus ID if in bank 0 */
1217 if ((!(val1 & 0x07)) &&
1218 (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
1219 || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001220 dev_dbg(&adapter->dev, "Detection of w83781d chip "
1221 "failed at step 4\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 err = -ENODEV;
1223 goto ERROR2;
1224 }
1225 /* If Winbond SMBus, check address at 0x48.
1226 Asus doesn't support, except for as99127f rev.2 */
Jean Delvare7666c132007-05-08 17:22:02 +02001227 if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
1228 ((val1 & 0x80) && (val2 == 0x5c))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001230 (data, W83781D_REG_I2C_ADDR) != address) {
Jean Delvarebd452e62006-10-13 17:03:42 +02001231 dev_dbg(&adapter->dev, "Detection of w83781d "
1232 "chip failed at step 5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 err = -ENODEV;
1234 goto ERROR2;
1235 }
1236 }
1237 }
1238
1239 /* We have either had a force parameter, or we have already detected the
1240 Winbond. Put it now into bank 0 and Vendor ID High Byte */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001241 w83781d_write_value(data, W83781D_REG_BANK,
1242 (w83781d_read_value(data, W83781D_REG_BANK)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001243 & 0x78) | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 /* Determine the chip type. */
1246 if (kind <= 0) {
1247 /* get vendor ID */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001248 val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (val2 == 0x5c)
1250 vendid = winbond;
1251 else if (val2 == 0x12)
1252 vendid = asus;
1253 else {
Jean Delvarebd452e62006-10-13 17:03:42 +02001254 dev_dbg(&adapter->dev, "w83781d chip vendor is "
1255 "neither Winbond nor Asus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 err = -ENODEV;
1257 goto ERROR2;
1258 }
1259
Jean Delvare31b8dc42007-05-08 17:22:03 +02001260 val1 = w83781d_read_value(data, W83781D_REG_WCHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1262 kind = w83781d;
1263 else if (val1 == 0x30 && vendid == winbond)
1264 kind = w83782d;
Jean Delvare7666c132007-05-08 17:22:02 +02001265 else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 kind = w83783s;
Jean Delvare6722fea2007-10-07 12:25:46 +02001267 else if (val1 == 0x31)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 kind = as99127f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 else {
1270 if (kind == 0)
Jean Delvarebd452e62006-10-13 17:03:42 +02001271 dev_warn(&adapter->dev, "Ignoring 'force' "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 "parameter for unknown chip at "
Jean Delvarebd452e62006-10-13 17:03:42 +02001273 "address 0x%02x\n", address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 err = -EINVAL;
1275 goto ERROR2;
1276 }
1277 }
1278
1279 if (kind == w83781d) {
1280 client_name = "w83781d";
1281 } else if (kind == w83782d) {
1282 client_name = "w83782d";
1283 } else if (kind == w83783s) {
1284 client_name = "w83783s";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 } else if (kind == as99127f) {
1286 client_name = "as99127f";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 }
1288
1289 /* Fill in the remaining client fields and put into the global list */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001290 strlcpy(client->name, client_name, I2C_NAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 data->type = kind;
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 /* Tell the I2C layer a new client has arrived */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001294 if ((err = i2c_attach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 goto ERROR2;
1296
1297 /* attach secondary i2c lm75-like clients */
Jean Delvare7666c132007-05-08 17:22:02 +02001298 if ((err = w83781d_detect_subclients(adapter, address,
1299 kind, client)))
1300 goto ERROR3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 /* Initialize the chip */
Jean Delvare7666c132007-05-08 17:22:02 +02001303 w83781d_init_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 /* Register sysfs hooks */
Jean Delvare7666c132007-05-08 17:22:02 +02001306 err = w83781d_create_files(dev, kind, 0);
1307 if (err)
Jim Cromie311ce2e2006-09-24 21:22:52 +02001308 goto ERROR4;
1309
Tony Jones1beeffe2007-08-20 13:46:20 -07001310 data->hwmon_dev = hwmon_device_register(dev);
1311 if (IS_ERR(data->hwmon_dev)) {
1312 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001313 goto ERROR4;
1314 }
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 return 0;
1317
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001318ERROR4:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001319 sysfs_remove_group(&dev->kobj, &w83781d_group);
1320 sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1321
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001322 if (data->lm75[1]) {
1323 i2c_detach_client(data->lm75[1]);
1324 kfree(data->lm75[1]);
1325 }
1326 if (data->lm75[0]) {
1327 i2c_detach_client(data->lm75[0]);
1328 kfree(data->lm75[0]);
1329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330ERROR3:
Jim Cromie311ce2e2006-09-24 21:22:52 +02001331 i2c_detach_client(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332ERROR2:
1333 kfree(data);
1334ERROR1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return err;
1336}
1337
1338static int
1339w83781d_detach_client(struct i2c_client *client)
1340{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001341 struct w83781d_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int err;
1343
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001344 /* main client */
Jim Cromie311ce2e2006-09-24 21:22:52 +02001345 if (data) {
Tony Jones1beeffe2007-08-20 13:46:20 -07001346 hwmon_device_unregister(data->hwmon_dev);
Jim Cromie311ce2e2006-09-24 21:22:52 +02001347 sysfs_remove_group(&client->dev.kobj, &w83781d_group);
1348 sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
1349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Jean Delvare7bef5592005-07-27 22:14:49 +02001351 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001354 /* main client */
1355 if (data)
1356 kfree(data);
1357
1358 /* subclient */
1359 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 kfree(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 return 0;
1363}
1364
Jean Delvare7666c132007-05-08 17:22:02 +02001365static int __devinit
1366w83781d_isa_probe(struct platform_device *pdev)
1367{
1368 int err, reg;
1369 struct w83781d_data *data;
1370 struct resource *res;
1371 const char *name;
1372
1373 /* Reserve the ISA region */
1374 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1375 if (!request_region(res->start, W83781D_EXTENT, "w83781d")) {
1376 err = -EBUSY;
1377 goto exit;
1378 }
1379
1380 if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
1381 err = -ENOMEM;
1382 goto exit_release_region;
1383 }
1384 mutex_init(&data->lock);
1385 data->client.addr = res->start;
1386 i2c_set_clientdata(&data->client, data);
1387 platform_set_drvdata(pdev, data);
1388
Jean Delvare31b8dc42007-05-08 17:22:03 +02001389 reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
Jean Delvare7666c132007-05-08 17:22:02 +02001390 switch (reg) {
Jean Delvare7666c132007-05-08 17:22:02 +02001391 case 0x30:
1392 data->type = w83782d;
1393 name = "w83782d";
1394 break;
1395 default:
1396 data->type = w83781d;
1397 name = "w83781d";
1398 }
1399 strlcpy(data->client.name, name, I2C_NAME_SIZE);
1400
1401 /* Initialize the W83781D chip */
1402 w83781d_init_device(&pdev->dev);
1403
1404 /* Register sysfs hooks */
1405 err = w83781d_create_files(&pdev->dev, data->type, 1);
1406 if (err)
1407 goto exit_remove_files;
1408
Tony Jones1beeffe2007-08-20 13:46:20 -07001409 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1410 if (IS_ERR(data->hwmon_dev)) {
1411 err = PTR_ERR(data->hwmon_dev);
Jean Delvare7666c132007-05-08 17:22:02 +02001412 goto exit_remove_files;
1413 }
1414
1415 return 0;
1416
1417 exit_remove_files:
1418 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1419 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1420 device_remove_file(&pdev->dev, &dev_attr_name);
1421 kfree(data);
1422 exit_release_region:
1423 release_region(res->start, W83781D_EXTENT);
1424 exit:
1425 return err;
1426}
1427
1428static int __devexit
1429w83781d_isa_remove(struct platform_device *pdev)
1430{
1431 struct w83781d_data *data = platform_get_drvdata(pdev);
1432
Tony Jones1beeffe2007-08-20 13:46:20 -07001433 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare7666c132007-05-08 17:22:02 +02001434 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1435 sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1436 device_remove_file(&pdev->dev, &dev_attr_name);
1437 release_region(data->client.addr, W83781D_EXTENT);
1438 kfree(data);
1439
1440 return 0;
1441}
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443/* The SMBus locks itself, usually, but nothing may access the Winbond between
1444 bank switches. ISA access must always be locked explicitly!
1445 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1446 would slow down the W83781D access and should not be necessary.
1447 There are some ugly typecasts here, but the good news is - they should
1448 nowhere else be necessary! */
1449static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001450w83781d_read_value(struct w83781d_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
Jean Delvare31b8dc42007-05-08 17:22:03 +02001452 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 int res, word_sized, bank;
1454 struct i2c_client *cl;
1455
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001456 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001457 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 word_sized = (((reg & 0xff00) == 0x100)
1459 || ((reg & 0xff00) == 0x200))
1460 && (((reg & 0x00ff) == 0x50)
1461 || ((reg & 0x00ff) == 0x53)
1462 || ((reg & 0x00ff) == 0x55));
1463 if (reg & 0xff00) {
1464 outb_p(W83781D_REG_BANK,
1465 client->addr + W83781D_ADDR_REG_OFFSET);
1466 outb_p(reg >> 8,
1467 client->addr + W83781D_DATA_REG_OFFSET);
1468 }
1469 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1470 res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
1471 if (word_sized) {
1472 outb_p((reg & 0xff) + 1,
1473 client->addr + W83781D_ADDR_REG_OFFSET);
1474 res =
1475 (res << 8) + inb_p(client->addr +
1476 W83781D_DATA_REG_OFFSET);
1477 }
1478 if (reg & 0xff00) {
1479 outb_p(W83781D_REG_BANK,
1480 client->addr + W83781D_ADDR_REG_OFFSET);
1481 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1482 }
1483 } else {
1484 bank = (reg >> 8) & 0x0f;
1485 if (bank > 2)
1486 /* switch banks */
1487 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1488 bank);
1489 if (bank == 0 || bank > 2) {
1490 res = i2c_smbus_read_byte_data(client, reg & 0xff);
1491 } else {
1492 /* switch to subclient */
1493 cl = data->lm75[bank - 1];
1494 /* convert from ISA to LM75 I2C addresses */
1495 switch (reg & 0xff) {
1496 case 0x50: /* TEMP */
1497 res = swab16(i2c_smbus_read_word_data(cl, 0));
1498 break;
1499 case 0x52: /* CONFIG */
1500 res = i2c_smbus_read_byte_data(cl, 1);
1501 break;
1502 case 0x53: /* HYST */
1503 res = swab16(i2c_smbus_read_word_data(cl, 2));
1504 break;
1505 case 0x55: /* OVER */
1506 default:
1507 res = swab16(i2c_smbus_read_word_data(cl, 3));
1508 break;
1509 }
1510 }
1511 if (bank > 2)
1512 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1513 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001514 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 return res;
1516}
1517
1518static int
Jean Delvare31b8dc42007-05-08 17:22:03 +02001519w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
Jean Delvare31b8dc42007-05-08 17:22:03 +02001521 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 int word_sized, bank;
1523 struct i2c_client *cl;
1524
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001525 mutex_lock(&data->lock);
Jean Delvare7666c132007-05-08 17:22:02 +02001526 if (!client->driver) { /* ISA device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 word_sized = (((reg & 0xff00) == 0x100)
1528 || ((reg & 0xff00) == 0x200))
1529 && (((reg & 0x00ff) == 0x53)
1530 || ((reg & 0x00ff) == 0x55));
1531 if (reg & 0xff00) {
1532 outb_p(W83781D_REG_BANK,
1533 client->addr + W83781D_ADDR_REG_OFFSET);
1534 outb_p(reg >> 8,
1535 client->addr + W83781D_DATA_REG_OFFSET);
1536 }
1537 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1538 if (word_sized) {
1539 outb_p(value >> 8,
1540 client->addr + W83781D_DATA_REG_OFFSET);
1541 outb_p((reg & 0xff) + 1,
1542 client->addr + W83781D_ADDR_REG_OFFSET);
1543 }
1544 outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
1545 if (reg & 0xff00) {
1546 outb_p(W83781D_REG_BANK,
1547 client->addr + W83781D_ADDR_REG_OFFSET);
1548 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1549 }
1550 } else {
1551 bank = (reg >> 8) & 0x0f;
1552 if (bank > 2)
1553 /* switch banks */
1554 i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
1555 bank);
1556 if (bank == 0 || bank > 2) {
1557 i2c_smbus_write_byte_data(client, reg & 0xff,
1558 value & 0xff);
1559 } else {
1560 /* switch to subclient */
1561 cl = data->lm75[bank - 1];
1562 /* convert from ISA to LM75 I2C addresses */
1563 switch (reg & 0xff) {
1564 case 0x52: /* CONFIG */
1565 i2c_smbus_write_byte_data(cl, 1, value & 0xff);
1566 break;
1567 case 0x53: /* HYST */
1568 i2c_smbus_write_word_data(cl, 2, swab16(value));
1569 break;
1570 case 0x55: /* OVER */
1571 i2c_smbus_write_word_data(cl, 3, swab16(value));
1572 break;
1573 }
1574 }
1575 if (bank > 2)
1576 i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1577 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001578 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return 0;
1580}
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582static void
Jean Delvare7666c132007-05-08 17:22:02 +02001583w83781d_init_device(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
Jean Delvare7666c132007-05-08 17:22:02 +02001585 struct w83781d_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 int i, p;
1587 int type = data->type;
1588 u8 tmp;
1589
Jean Delvarefabddcd2006-02-05 23:26:51 +01001590 if (reset && type != as99127f) { /* this resets registers we don't have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 documentation for on the as99127f */
Jean Delvarefabddcd2006-02-05 23:26:51 +01001592 /* Resetting the chip has been the default for a long time,
1593 but it causes the BIOS initializations (fan clock dividers,
1594 thermal sensor types...) to be lost, so it is now optional.
1595 It might even go away if nobody reports it as being useful,
1596 as I see very little reason why this would be needed at
1597 all. */
Jean Delvare7666c132007-05-08 17:22:02 +02001598 dev_info(dev, "If reset=1 solved a problem you were "
Jean Delvarefabddcd2006-02-05 23:26:51 +01001599 "having, please report!\n");
1600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* save these registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001602 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1603 p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 /* Reset all except Watchdog values and last conversion values
1605 This sets fan-divs to 2, among others */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001606 w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* Restore the registers and disable power-on abnormal beep.
1608 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001609 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1610 w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 /* Disable master beep-enable (reset turns it on).
1612 Individual beep_mask should be reset to off but for some reason
1613 disabling this bit helps some people not get beeped */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001614 w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 }
1616
Jean Delvarefabddcd2006-02-05 23:26:51 +01001617 /* Disable power-on abnormal beep, as advised by the datasheet.
1618 Already done if reset=1. */
1619 if (init && !reset && type != as99127f) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001620 i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
1621 w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Jean Delvarefabddcd2006-02-05 23:26:51 +01001622 }
1623
Jean Delvare303760b2005-07-31 21:52:01 +02001624 data->vrm = vid_which_vrm();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
1626 if ((type != w83781d) && (type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001627 tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 for (i = 1; i <= 3; i++) {
1629 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001630 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 } else {
1632 if (w83781d_read_value
Jean Delvare31b8dc42007-05-08 17:22:03 +02001633 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1635 data->sens[i - 1] = 1;
1636 else
1637 data->sens[i - 1] = 2;
1638 }
Jean Delvare7c7a5302005-06-16 19:24:14 +02001639 if (type == w83783s && i == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 break;
1641 }
1642 }
1643
1644 if (init && type != as99127f) {
1645 /* Enable temp2 */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001646 tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001648 dev_warn(dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 "might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001650 w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 tmp & 0xfe);
1652 }
1653
1654 /* Enable temp3 */
Jean Delvare7c7a5302005-06-16 19:24:14 +02001655 if (type != w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001656 tmp = w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 W83781D_REG_TEMP3_CONFIG);
1658 if (tmp & 0x01) {
Jean Delvare7666c132007-05-08 17:22:02 +02001659 dev_warn(dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 "readings might not make sense\n");
Jean Delvare31b8dc42007-05-08 17:22:03 +02001661 w83781d_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1663 }
1664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
1666
1667 /* Start monitoring */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001668 w83781d_write_value(data, W83781D_REG_CONFIG,
1669 (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 W83781D_REG_CONFIG) & 0xf7)
1671 | 0x01);
Jean Delvare7666c132007-05-08 17:22:02 +02001672
1673 /* A few vars need to be filled upon startup */
Jean Delvare34875332007-05-08 17:22:03 +02001674 for (i = 0; i < 3; i++) {
1675 data->fan_min[i] = w83781d_read_value(data,
Jean Delvare7666c132007-05-08 17:22:02 +02001676 W83781D_REG_FAN_MIN(i));
1677 }
Jean Delvare7666c132007-05-08 17:22:02 +02001678
1679 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680}
1681
1682static struct w83781d_data *w83781d_update_device(struct device *dev)
1683{
Jean Delvare7666c132007-05-08 17:22:02 +02001684 struct w83781d_data *data = dev_get_drvdata(dev);
1685 struct i2c_client *client = &data->client;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 int i;
1687
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001688 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1691 || !data->valid) {
1692 dev_dbg(dev, "Starting device update\n");
1693
1694 for (i = 0; i <= 8; i++) {
Jean Delvare7c7a5302005-06-16 19:24:14 +02001695 if (data->type == w83783s && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 continue; /* 783S has no in1 */
1697 data->in[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001698 w83781d_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 data->in_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001700 w83781d_read_value(data, W83781D_REG_IN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 data->in_max[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001702 w83781d_read_value(data, W83781D_REG_IN_MAX(i));
Jean Delvare05663362007-11-30 23:51:24 +01001703 if ((data->type != w83782d) && (i == 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 break;
1705 }
Jean Delvare34875332007-05-08 17:22:03 +02001706 for (i = 0; i < 3; i++) {
1707 data->fan[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001708 w83781d_read_value(data, W83781D_REG_FAN(i));
Jean Delvare34875332007-05-08 17:22:03 +02001709 data->fan_min[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001710 w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 }
1712 if (data->type != w83781d && data->type != as99127f) {
Jean Delvare34875332007-05-08 17:22:03 +02001713 for (i = 0; i < 4; i++) {
1714 data->pwm[i] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001715 w83781d_read_value(data,
Jean Delvare34875332007-05-08 17:22:03 +02001716 W83781D_REG_PWM[i]);
Jean Delvare7666c132007-05-08 17:22:02 +02001717 if ((data->type != w83782d || !client->driver)
Jean Delvare34875332007-05-08 17:22:03 +02001718 && i == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 break;
1720 }
1721 /* Only PWM2 can be disabled */
Jean Delvare34875332007-05-08 17:22:03 +02001722 data->pwm2_enable = (w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 W83781D_REG_PWMCLK12) & 0x08) >> 3;
1724 }
1725
Jean Delvare31b8dc42007-05-08 17:22:03 +02001726 data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 data->temp_max =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001728 w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 data->temp_max_hyst =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001730 w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 data->temp_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001732 w83781d_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 data->temp_max_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001734 w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 data->temp_max_hyst_add[0] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001736 w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
Jean Delvare7c7a5302005-06-16 19:24:14 +02001737 if (data->type != w83783s) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 data->temp_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001739 w83781d_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 data->temp_max_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001741 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 W83781D_REG_TEMP_OVER(3));
1743 data->temp_max_hyst_add[1] =
Jean Delvare31b8dc42007-05-08 17:22:03 +02001744 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 W83781D_REG_TEMP_HYST(3));
1746 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001747 i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
Jean Delvare7c7a5302005-06-16 19:24:14 +02001748 data->vid = i & 0x0f;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001749 data->vid |= (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001750 W83781D_REG_CHIPID) & 0x01) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 data->fan_div[0] = (i >> 4) & 0x03;
1752 data->fan_div[1] = (i >> 6) & 0x03;
Jean Delvare31b8dc42007-05-08 17:22:03 +02001753 data->fan_div[2] = (w83781d_read_value(data,
Jean Delvare7c7a5302005-06-16 19:24:14 +02001754 W83781D_REG_PIN) >> 6) & 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 if ((data->type != w83781d) && (data->type != as99127f)) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001756 i = w83781d_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 data->fan_div[0] |= (i >> 3) & 0x04;
1758 data->fan_div[1] |= (i >> 4) & 0x04;
Jean Delvare7c7a5302005-06-16 19:24:14 +02001759 data->fan_div[2] |= (i >> 5) & 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 }
Jean Delvare05663362007-11-30 23:51:24 +01001761 if (data->type == w83782d) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001762 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001763 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001764 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001765 W83782D_REG_ALARM2) << 8)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001766 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001767 W83782D_REG_ALARM3) << 16);
1768 } else if (data->type == w83783s) {
Jean Delvare31b8dc42007-05-08 17:22:03 +02001769 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001770 W83782D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001771 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001772 W83782D_REG_ALARM2) << 8);
1773 } else {
1774 /* No real-time status registers, fall back to
1775 interrupt status registers */
Jean Delvare31b8dc42007-05-08 17:22:03 +02001776 data->alarms = w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001777 W83781D_REG_ALARM1)
Jean Delvare31b8dc42007-05-08 17:22:03 +02001778 | (w83781d_read_value(data,
Jean Delvarec7f5d7e2006-02-05 23:13:48 +01001779 W83781D_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
Jean Delvare31b8dc42007-05-08 17:22:03 +02001781 i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 data->beep_enable = i >> 7;
1783 data->beep_mask = ((i & 0x7f) << 8) +
Jean Delvare31b8dc42007-05-08 17:22:03 +02001784 w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 if ((data->type != w83781d) && (data->type != as99127f)) {
1786 data->beep_mask |=
Jean Delvare31b8dc42007-05-08 17:22:03 +02001787 w83781d_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 W83781D_REG_BEEP_INTS3) << 16;
1789 }
1790 data->last_updated = jiffies;
1791 data->valid = 1;
1792 }
1793
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001794 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
1796 return data;
1797}
1798
Jean Delvare7666c132007-05-08 17:22:02 +02001799/* return 1 if a supported chip is found, 0 otherwise */
1800static int __init
1801w83781d_isa_found(unsigned short address)
1802{
1803 int val, save, found = 0;
1804
1805 if (!request_region(address, W83781D_EXTENT, "w83781d"))
1806 return 0;
1807
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:
1879 release_region(address, W83781D_EXTENT);
1880 return found;
1881}
1882
1883static int __init
1884w83781d_isa_device_add(unsigned short address)
1885{
1886 struct resource res = {
1887 .start = address,
Jean Delvare15bde2f2007-08-29 10:39:57 +02001888 .end = address + W83781D_EXTENT - 1,
Jean Delvare7666c132007-05-08 17:22:02 +02001889 .name = "w83781d",
1890 .flags = IORESOURCE_IO,
1891 };
1892 int err;
1893
1894 pdev = platform_device_alloc("w83781d", address);
1895 if (!pdev) {
1896 err = -ENOMEM;
1897 printk(KERN_ERR "w83781d: Device allocation failed\n");
1898 goto exit;
1899 }
1900
1901 err = platform_device_add_resources(pdev, &res, 1);
1902 if (err) {
1903 printk(KERN_ERR "w83781d: Device resource addition failed "
1904 "(%d)\n", err);
1905 goto exit_device_put;
1906 }
1907
1908 err = platform_device_add(pdev);
1909 if (err) {
1910 printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
1911 err);
1912 goto exit_device_put;
1913 }
1914
1915 return 0;
1916
1917 exit_device_put:
1918 platform_device_put(pdev);
1919 exit:
1920 pdev = NULL;
1921 return err;
1922}
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924static int __init
1925sensors_w83781d_init(void)
1926{
Jean Delvarefde09502005-07-19 23:51:07 +02001927 int res;
1928
1929 res = i2c_add_driver(&w83781d_driver);
1930 if (res)
Jean Delvare7666c132007-05-08 17:22:02 +02001931 goto exit;
Jean Delvarefde09502005-07-19 23:51:07 +02001932
Jean Delvare7666c132007-05-08 17:22:02 +02001933 if (w83781d_isa_found(isa_address)) {
1934 res = platform_driver_register(&w83781d_isa_driver);
1935 if (res)
1936 goto exit_unreg_i2c_driver;
1937
1938 /* Sets global pdev as a side effect */
1939 res = w83781d_isa_device_add(isa_address);
1940 if (res)
1941 goto exit_unreg_isa_driver;
1942 }
Jean Delvarefde09502005-07-19 23:51:07 +02001943
1944 return 0;
Jean Delvare7666c132007-05-08 17:22:02 +02001945
1946 exit_unreg_isa_driver:
1947 platform_driver_unregister(&w83781d_isa_driver);
1948 exit_unreg_i2c_driver:
1949 i2c_del_driver(&w83781d_driver);
1950 exit:
1951 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952}
1953
1954static void __exit
1955sensors_w83781d_exit(void)
1956{
Jean Delvare7666c132007-05-08 17:22:02 +02001957 if (pdev) {
1958 platform_device_unregister(pdev);
1959 platform_driver_unregister(&w83781d_isa_driver);
1960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 i2c_del_driver(&w83781d_driver);
1962}
1963
1964MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1965 "Philip Edelbrock <phil@netroedge.com>, "
1966 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1967MODULE_DESCRIPTION("W83781D driver");
1968MODULE_LICENSE("GPL");
1969
1970module_init(sensors_w83781d_init);
1971module_exit(sensors_w83781d_exit);