blob: 7738d30a11b84e844603295f60043fb70e43a10a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
5 Philip Edelbrock <phil@netroedge.com>,
6 and Mark Studebaker <mdsxyz123@yahoo.com>
7 Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
8
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 w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC)
29 w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
30 w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC)
Jean Delvarec2db6ce2006-01-18 23:22:12 +010031 w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
33
34 For other winbond chips, and for i2c support in the above chips,
35 use w83781d.c.
36
37 Note: automatic ("cruise") fan control for 697, 637 & 627thf not
38 supported yet.
39*/
40
41#include <linux/module.h>
42#include <linux/init.h>
43#include <linux/slab.h>
44#include <linux/jiffies.h>
45#include <linux/i2c.h>
Jean Delvarefde09502005-07-19 23:51:07 +020046#include <linux/i2c-isa.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/hwmon.h>
Jean Delvare303760b2005-07-31 21:52:01 +020048#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040049#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010050#include <linux/mutex.h>
Jean Delvared27c37c2007-05-08 17:21:59 +020051#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/io.h>
53#include "lm75.h"
54
Jean Delvared27c37c2007-05-08 17:21:59 +020055/* The actual ISA address is read from Super-I/O configuration space */
56static unsigned short address;
57
58#define DRVNAME "w83627hf"
59enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static u16 force_addr;
62module_param(force_addr, ushort, 0);
63MODULE_PARM_DESC(force_addr,
64 "Initialize the base address of the sensors");
65static u8 force_i2c = 0x1f;
66module_param(force_i2c, byte, 0);
67MODULE_PARM_DESC(force_i2c,
68 "Initialize the i2c address of the sensors");
69
Jean Delvare2251cf12005-09-04 22:52:17 +020070static int reset;
71module_param(reset, bool, 0);
72MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int init = 1;
75module_param(init, bool, 0);
76MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
77
78/* modified from kernel/include/traps.c */
79static int REG; /* The register to read/write */
80#define DEV 0x07 /* Register: Logical device select */
81static int VAL; /* The value to read/write */
82
83/* logical device numbers for superio_select (below) */
84#define W83627HF_LD_FDC 0x00
85#define W83627HF_LD_PRT 0x01
86#define W83627HF_LD_UART1 0x02
87#define W83627HF_LD_UART2 0x03
88#define W83627HF_LD_KBC 0x05
89#define W83627HF_LD_CIR 0x06 /* w83627hf only */
90#define W83627HF_LD_GAME 0x07
91#define W83627HF_LD_MIDI 0x07
92#define W83627HF_LD_GPIO1 0x07
93#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
94#define W83627HF_LD_GPIO2 0x08
95#define W83627HF_LD_GPIO3 0x09
96#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
97#define W83627HF_LD_ACPI 0x0a
98#define W83627HF_LD_HWM 0x0b
99
100#define DEVID 0x20 /* Register: Device ID */
101
102#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
103#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
104#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
105
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100106#define W83687THF_VID_EN 0x29 /* w83687thf only */
107#define W83687THF_VID_CFG 0xF0 /* w83687thf only */
108#define W83687THF_VID_DATA 0xF1 /* w83687thf only */
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110static inline void
111superio_outb(int reg, int val)
112{
113 outb(reg, REG);
114 outb(val, VAL);
115}
116
117static inline int
118superio_inb(int reg)
119{
120 outb(reg, REG);
121 return inb(VAL);
122}
123
124static inline void
125superio_select(int ld)
126{
127 outb(DEV, REG);
128 outb(ld, VAL);
129}
130
131static inline void
132superio_enter(void)
133{
134 outb(0x87, REG);
135 outb(0x87, REG);
136}
137
138static inline void
139superio_exit(void)
140{
141 outb(0xAA, REG);
142}
143
144#define W627_DEVID 0x52
145#define W627THF_DEVID 0x82
146#define W697_DEVID 0x60
147#define W637_DEVID 0x70
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100148#define W687THF_DEVID 0x85
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#define WINB_ACT_REG 0x30
150#define WINB_BASE_REG 0x60
151/* Constants specified below */
152
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200153/* Alignment of the base address */
154#define WINB_ALIGNMENT ~7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200156/* Offset & size of I/O region we are interested in */
157#define WINB_REGION_OFFSET 5
158#define WINB_REGION_SIZE 2
159
160/* Where are the sensors address/data registers relative to the base address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161#define W83781D_ADDR_REG_OFFSET 5
162#define W83781D_DATA_REG_OFFSET 6
163
164/* The W83781D registers */
165/* The W83782D registers for nr=7,8 are in bank 5 */
166#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
167 (0x554 + (((nr) - 7) * 2)))
168#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
169 (0x555 + (((nr) - 7) * 2)))
170#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
171 (0x550 + (nr) - 7))
172
173#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
174#define W83781D_REG_FAN(nr) (0x27 + (nr))
175
176#define W83781D_REG_TEMP2_CONFIG 0x152
177#define W83781D_REG_TEMP3_CONFIG 0x252
178#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
179 ((nr == 2) ? (0x0150) : \
180 (0x27)))
181#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
182 ((nr == 2) ? (0x153) : \
183 (0x3A)))
184#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
185 ((nr == 2) ? (0x155) : \
186 (0x39)))
187
188#define W83781D_REG_BANK 0x4E
189
190#define W83781D_REG_CONFIG 0x40
Yuan Mu4a1c44472005-11-07 22:19:04 +0100191#define W83781D_REG_ALARM1 0x459
192#define W83781D_REG_ALARM2 0x45A
193#define W83781D_REG_ALARM3 0x45B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#define W83781D_REG_BEEP_CONFIG 0x4D
196#define W83781D_REG_BEEP_INTS1 0x56
197#define W83781D_REG_BEEP_INTS2 0x57
198#define W83781D_REG_BEEP_INTS3 0x453
199
200#define W83781D_REG_VID_FANDIV 0x47
201
202#define W83781D_REG_CHIPID 0x49
203#define W83781D_REG_WCHIPID 0x58
204#define W83781D_REG_CHIPMAN 0x4F
205#define W83781D_REG_PIN 0x4B
206
207#define W83781D_REG_VBAT 0x5D
208
209#define W83627HF_REG_PWM1 0x5A
210#define W83627HF_REG_PWM2 0x5B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100212#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
213#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
214#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100216#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
219static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
220 W83627THF_REG_PWM3 };
221#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
222 regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
223
224#define W83781D_REG_I2C_ADDR 0x48
225#define W83781D_REG_I2C_SUBADDR 0x4A
226
227/* Sensor selection */
228#define W83781D_REG_SCFG1 0x5D
229static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
230#define W83781D_REG_SCFG2 0x59
231static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
232#define W83781D_DEFAULT_BETA 3435
233
234/* Conversions. Limit checking is only done on the TO_REG
235 variants. Note that you should be a bit careful with which arguments
236 these macros are called: arguments may be evaluated more than once.
237 Fixing this is just not worth it. */
238#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
239#define IN_FROM_REG(val) ((val) * 16)
240
241static inline u8 FAN_TO_REG(long rpm, int div)
242{
243 if (rpm == 0)
244 return 255;
245 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
246 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
247 254);
248}
249
250#define TEMP_MIN (-128000)
251#define TEMP_MAX ( 127000)
252
253/* TEMP: 0.001C/bit (-128C to +127C)
254 REG: 1C/bit, two's complement */
255static u8 TEMP_TO_REG(int temp)
256{
257 int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
258 ntemp += (ntemp<0 ? -500 : 500);
259 return (u8)(ntemp / 1000);
260}
261
262static int TEMP_FROM_REG(u8 reg)
263{
264 return (s8)reg * 1000;
265}
266
267#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
268
269#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
270
271#define BEEP_MASK_FROM_REG(val) (val)
272#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
273#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
274#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
275
276#define DIV_FROM_REG(val) (1 << (val))
277
278static inline u8 DIV_TO_REG(long val)
279{
280 int i;
281 val = SENSORS_LIMIT(val, 1, 128) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000282 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (val == 0)
284 break;
285 val >>= 1;
286 }
287 return ((u8) i);
288}
289
Jean Delvareed6bafb2007-02-14 21:15:03 +0100290/* For each registered chip, we need to keep some data in memory.
291 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292struct w83627hf_data {
293 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400294 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100295 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 enum chips type;
297
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100298 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 char valid; /* !=0 if following fields are valid */
300 unsigned long last_updated; /* In jiffies */
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 u8 in[9]; /* Register value */
303 u8 in_max[9]; /* Register value */
304 u8 in_min[9]; /* Register value */
305 u8 fan[3]; /* Register value */
306 u8 fan_min[3]; /* Register value */
307 u8 temp;
308 u8 temp_max; /* Register value */
309 u8 temp_max_hyst; /* Register value */
310 u16 temp_add[2]; /* Register value */
311 u16 temp_max_add[2]; /* Register value */
312 u16 temp_max_hyst_add[2]; /* Register value */
313 u8 fan_div[3]; /* Register encoding, shifted right */
314 u8 vid; /* Register encoding, combined */
315 u32 alarms; /* Register encoding, combined */
316 u32 beep_mask; /* Register encoding, combined */
317 u8 beep_enable; /* Boolean */
318 u8 pwm[3]; /* Register value */
319 u16 sens[3]; /* 782D/783S only.
320 1 = pentium diode; 2 = 3904 diode;
321 3000-5000 = thermistor beta.
322 Default = 3435.
323 Other Betas unimplemented */
324 u8 vrm;
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100325 u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326};
327
328
Jean Delvare2d8672c2005-07-19 23:56:35 +0200329static int w83627hf_detect(struct i2c_adapter *adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330static int w83627hf_detach_client(struct i2c_client *client);
331
Darren Jenkinsf6c27fc2006-02-27 23:14:58 +0100332static int w83627hf_read_value(struct i2c_client *client, u16 reg);
333static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334static struct w83627hf_data *w83627hf_update_device(struct device *dev);
335static void w83627hf_init_client(struct i2c_client *client);
336
337static struct i2c_driver w83627hf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100338 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200339 .owner = THIS_MODULE,
Jean Delvared27c37c2007-05-08 17:21:59 +0200340 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100341 },
Jean Delvare2d8672c2005-07-19 23:56:35 +0200342 .attach_adapter = w83627hf_detect,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 .detach_client = w83627hf_detach_client,
344};
345
346/* following are the sysfs callback functions */
347#define show_in_reg(reg) \
348static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
349{ \
350 struct w83627hf_data *data = w83627hf_update_device(dev); \
351 return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
352}
353show_in_reg(in)
354show_in_reg(in_min)
355show_in_reg(in_max)
356
357#define store_in_reg(REG, reg) \
358static ssize_t \
359store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
360{ \
361 struct i2c_client *client = to_i2c_client(dev); \
362 struct w83627hf_data *data = i2c_get_clientdata(client); \
363 u32 val; \
364 \
365 val = simple_strtoul(buf, NULL, 10); \
366 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100367 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 data->in_##reg[nr] = IN_TO_REG(val); \
369 w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
370 data->in_##reg[nr]); \
371 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100372 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return count; \
374}
375store_in_reg(MIN, min)
376store_in_reg(MAX, max)
377
378#define sysfs_in_offset(offset) \
379static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400380show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{ \
382 return show_in(dev, buf, offset); \
383} \
384static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
385
386#define sysfs_in_reg_offset(reg, offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400387static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{ \
389 return show_in_##reg (dev, buf, offset); \
390} \
391static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400392store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 const char *buf, size_t count) \
394{ \
395 return store_in_##reg (dev, buf, count, offset); \
396} \
397static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
398 show_regs_in_##reg##offset, store_regs_in_##reg##offset);
399
400#define sysfs_in_offsets(offset) \
401sysfs_in_offset(offset) \
402sysfs_in_reg_offset(min, offset) \
403sysfs_in_reg_offset(max, offset)
404
405sysfs_in_offsets(1);
406sysfs_in_offsets(2);
407sysfs_in_offsets(3);
408sysfs_in_offsets(4);
409sysfs_in_offsets(5);
410sysfs_in_offsets(6);
411sysfs_in_offsets(7);
412sysfs_in_offsets(8);
413
414/* use a different set of functions for in0 */
415static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
416{
417 long in0;
418
419 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100420 (w83627thf == data->type || w83637hf == data->type
421 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423 /* use VRM9 calculation */
424 in0 = (long)((reg * 488 + 70000 + 50) / 100);
425 else
426 /* use VRM8 (standard) calculation */
427 in0 = (long)IN_FROM_REG(reg);
428
429 return sprintf(buf,"%ld\n", in0);
430}
431
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400432static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433{
434 struct w83627hf_data *data = w83627hf_update_device(dev);
435 return show_in_0(data, buf, data->in[0]);
436}
437
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400438static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct w83627hf_data *data = w83627hf_update_device(dev);
441 return show_in_0(data, buf, data->in_min[0]);
442}
443
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400444static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 struct w83627hf_data *data = w83627hf_update_device(dev);
447 return show_in_0(data, buf, data->in_max[0]);
448}
449
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400450static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 const char *buf, size_t count)
452{
453 struct i2c_client *client = to_i2c_client(dev);
454 struct w83627hf_data *data = i2c_get_clientdata(client);
455 u32 val;
456
457 val = simple_strtoul(buf, NULL, 10);
458
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100459 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100462 (w83627thf == data->type || w83637hf == data->type
463 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800466 data->in_min[0] =
467 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
468 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 else
470 /* use VRM8 (standard) calculation */
471 data->in_min[0] = IN_TO_REG(val);
472
473 w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100474 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return count;
476}
477
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400478static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 const char *buf, size_t count)
480{
481 struct i2c_client *client = to_i2c_client(dev);
482 struct w83627hf_data *data = i2c_get_clientdata(client);
483 u32 val;
484
485 val = simple_strtoul(buf, NULL, 10);
486
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100487 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100490 (w83627thf == data->type || w83637hf == data->type
491 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800494 data->in_max[0] =
495 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
496 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 else
498 /* use VRM8 (standard) calculation */
499 data->in_max[0] = IN_TO_REG(val);
500
501 w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100502 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 return count;
504}
505
506static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
507static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
508 show_regs_in_min0, store_regs_in_min0);
509static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
510 show_regs_in_max0, store_regs_in_max0);
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512#define show_fan_reg(reg) \
513static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
514{ \
515 struct w83627hf_data *data = w83627hf_update_device(dev); \
516 return sprintf(buf,"%ld\n", \
517 FAN_FROM_REG(data->reg[nr-1], \
518 (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
519}
520show_fan_reg(fan);
521show_fan_reg(fan_min);
522
523static ssize_t
524store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
525{
526 struct i2c_client *client = to_i2c_client(dev);
527 struct w83627hf_data *data = i2c_get_clientdata(client);
528 u32 val;
529
530 val = simple_strtoul(buf, NULL, 10);
531
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100532 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 data->fan_min[nr - 1] =
534 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
535 w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
536 data->fan_min[nr - 1]);
537
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100538 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return count;
540}
541
542#define sysfs_fan_offset(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400543static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{ \
545 return show_fan(dev, buf, offset); \
546} \
547static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
548
549#define sysfs_fan_min_offset(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400550static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{ \
552 return show_fan_min(dev, buf, offset); \
553} \
554static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400555store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{ \
557 return store_fan_min(dev, buf, count, offset); \
558} \
559static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
560 show_regs_fan_min##offset, store_regs_fan_min##offset);
561
562sysfs_fan_offset(1);
563sysfs_fan_min_offset(1);
564sysfs_fan_offset(2);
565sysfs_fan_min_offset(2);
566sysfs_fan_offset(3);
567sysfs_fan_min_offset(3);
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569#define show_temp_reg(reg) \
570static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
571{ \
572 struct w83627hf_data *data = w83627hf_update_device(dev); \
573 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
574 return sprintf(buf,"%ld\n", \
575 (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
576 } else { /* TEMP1 */ \
577 return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
578 } \
579}
580show_temp_reg(temp);
581show_temp_reg(temp_max);
582show_temp_reg(temp_max_hyst);
583
584#define store_temp_reg(REG, reg) \
585static ssize_t \
586store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
587{ \
588 struct i2c_client *client = to_i2c_client(dev); \
589 struct w83627hf_data *data = i2c_get_clientdata(client); \
590 u32 val; \
591 \
592 val = simple_strtoul(buf, NULL, 10); \
593 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100594 mutex_lock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 \
596 if (nr >= 2) { /* TEMP2 and TEMP3 */ \
597 data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
598 w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
599 data->temp_##reg##_add[nr-2]); \
600 } else { /* TEMP1 */ \
601 data->temp_##reg = TEMP_TO_REG(val); \
602 w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
603 data->temp_##reg); \
604 } \
605 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100606 mutex_unlock(&data->update_lock); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 return count; \
608}
609store_temp_reg(OVER, max);
610store_temp_reg(HYST, max_hyst);
611
612#define sysfs_temp_offset(offset) \
613static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400614show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{ \
616 return show_temp(dev, buf, offset); \
617} \
618static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
619
620#define sysfs_temp_reg_offset(reg, offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400621static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{ \
623 return show_temp_##reg (dev, buf, offset); \
624} \
625static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400626store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 const char *buf, size_t count) \
628{ \
629 return store_temp_##reg (dev, buf, count, offset); \
630} \
631static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
632 show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
633
634#define sysfs_temp_offsets(offset) \
635sysfs_temp_offset(offset) \
636sysfs_temp_reg_offset(max, offset) \
637sysfs_temp_reg_offset(max_hyst, offset)
638
639sysfs_temp_offsets(1);
640sysfs_temp_offsets(2);
641sysfs_temp_offsets(3);
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400644show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 struct w83627hf_data *data = w83627hf_update_device(dev);
647 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
648}
649static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400652show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
654 struct w83627hf_data *data = w83627hf_update_device(dev);
655 return sprintf(buf, "%ld\n", (long) data->vrm);
656}
657static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400658store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
660 struct i2c_client *client = to_i2c_client(dev);
661 struct w83627hf_data *data = i2c_get_clientdata(client);
662 u32 val;
663
664 val = simple_strtoul(buf, NULL, 10);
665 data->vrm = val;
666
667 return count;
668}
669static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400672show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 struct w83627hf_data *data = w83627hf_update_device(dev);
675 return sprintf(buf, "%ld\n", (long) data->alarms);
676}
677static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679#define show_beep_reg(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400680static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{ \
682 struct w83627hf_data *data = w83627hf_update_device(dev); \
683 return sprintf(buf,"%ld\n", \
684 (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
685}
686show_beep_reg(ENABLE, enable)
687show_beep_reg(MASK, mask)
688
689#define BEEP_ENABLE 0 /* Store beep_enable */
690#define BEEP_MASK 1 /* Store beep_mask */
691
692static ssize_t
693store_beep_reg(struct device *dev, const char *buf, size_t count,
694 int update_mask)
695{
696 struct i2c_client *client = to_i2c_client(dev);
697 struct w83627hf_data *data = i2c_get_clientdata(client);
698 u32 val, val2;
699
700 val = simple_strtoul(buf, NULL, 10);
701
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100702 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
705 data->beep_mask = BEEP_MASK_TO_REG(val);
706 w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
707 data->beep_mask & 0xff);
708 w83627hf_write_value(client, W83781D_REG_BEEP_INTS3,
709 ((data->beep_mask) >> 16) & 0xff);
710 val2 = (data->beep_mask >> 8) & 0x7f;
711 } else { /* We are storing beep_enable */
712 val2 =
713 w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
714 data->beep_enable = BEEP_ENABLE_TO_REG(val);
715 }
716
717 w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
718 val2 | data->beep_enable << 7);
719
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100720 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return count;
722}
723
724#define sysfs_beep(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400725static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{ \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400727 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728} \
729static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400730store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{ \
732 return store_beep_reg(dev, buf, count, BEEP_##REG); \
733} \
734static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
735 show_regs_beep_##reg, store_regs_beep_##reg);
736
737sysfs_beep(ENABLE, enable);
738sysfs_beep(MASK, mask);
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740static ssize_t
741show_fan_div_reg(struct device *dev, char *buf, int nr)
742{
743 struct w83627hf_data *data = w83627hf_update_device(dev);
744 return sprintf(buf, "%ld\n",
745 (long) DIV_FROM_REG(data->fan_div[nr - 1]));
746}
747
748/* Note: we save and restore the fan minimum here, because its value is
749 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200750 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 because the divisor changed. */
752static ssize_t
753store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
754{
755 struct i2c_client *client = to_i2c_client(dev);
756 struct w83627hf_data *data = i2c_get_clientdata(client);
757 unsigned long min;
758 u8 reg;
759 unsigned long val = simple_strtoul(buf, NULL, 10);
760
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100761 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 /* Save fan_min */
764 min = FAN_FROM_REG(data->fan_min[nr],
765 DIV_FROM_REG(data->fan_div[nr]));
766
767 data->fan_div[nr] = DIV_TO_REG(val);
768
769 reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
770 & (nr==0 ? 0xcf : 0x3f))
771 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
772 w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
773
774 reg = (w83627hf_read_value(client, W83781D_REG_VBAT)
775 & ~(1 << (5 + nr)))
776 | ((data->fan_div[nr] & 0x04) << (3 + nr));
777 w83627hf_write_value(client, W83781D_REG_VBAT, reg);
778
779 /* Restore fan_min */
780 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
781 w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
782
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100783 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return count;
785}
786
787#define sysfs_fan_div(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400788static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{ \
790 return show_fan_div_reg(dev, buf, offset); \
791} \
792static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400793store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 const char *buf, size_t count) \
795{ \
796 return store_fan_div_reg(dev, buf, count, offset - 1); \
797} \
798static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
799 show_regs_fan_div_##offset, store_regs_fan_div_##offset);
800
801sysfs_fan_div(1);
802sysfs_fan_div(2);
803sysfs_fan_div(3);
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805static ssize_t
806show_pwm_reg(struct device *dev, char *buf, int nr)
807{
808 struct w83627hf_data *data = w83627hf_update_device(dev);
809 return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
810}
811
812static ssize_t
813store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
814{
815 struct i2c_client *client = to_i2c_client(dev);
816 struct w83627hf_data *data = i2c_get_clientdata(client);
817 u32 val;
818
819 val = simple_strtoul(buf, NULL, 10);
820
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100821 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 if (data->type == w83627thf) {
824 /* bits 0-3 are reserved in 627THF */
825 data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
826 w83627hf_write_value(client,
827 W836X7HF_REG_PWM(data->type, nr),
828 data->pwm[nr - 1] |
829 (w83627hf_read_value(client,
830 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
831 } else {
832 data->pwm[nr - 1] = PWM_TO_REG(val);
833 w83627hf_write_value(client,
834 W836X7HF_REG_PWM(data->type, nr),
835 data->pwm[nr - 1]);
836 }
837
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100838 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 return count;
840}
841
842#define sysfs_pwm(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400843static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{ \
845 return show_pwm_reg(dev, buf, offset); \
846} \
847static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400848store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{ \
850 return store_pwm_reg(dev, buf, count, offset); \
851} \
852static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
853 show_regs_pwm_##offset, store_regs_pwm_##offset);
854
855sysfs_pwm(1);
856sysfs_pwm(2);
857sysfs_pwm(3);
858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859static ssize_t
860show_sensor_reg(struct device *dev, char *buf, int nr)
861{
862 struct w83627hf_data *data = w83627hf_update_device(dev);
863 return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
864}
865
866static ssize_t
867store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
868{
869 struct i2c_client *client = to_i2c_client(dev);
870 struct w83627hf_data *data = i2c_get_clientdata(client);
871 u32 val, tmp;
872
873 val = simple_strtoul(buf, NULL, 10);
874
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100875 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 switch (val) {
878 case 1: /* PII/Celeron diode */
879 tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
880 w83627hf_write_value(client, W83781D_REG_SCFG1,
881 tmp | BIT_SCFG1[nr - 1]);
882 tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
883 w83627hf_write_value(client, W83781D_REG_SCFG2,
884 tmp | BIT_SCFG2[nr - 1]);
885 data->sens[nr - 1] = val;
886 break;
887 case 2: /* 3904 */
888 tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
889 w83627hf_write_value(client, W83781D_REG_SCFG1,
890 tmp | BIT_SCFG1[nr - 1]);
891 tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
892 w83627hf_write_value(client, W83781D_REG_SCFG2,
893 tmp & ~BIT_SCFG2[nr - 1]);
894 data->sens[nr - 1] = val;
895 break;
896 case W83781D_DEFAULT_BETA: /* thermistor */
897 tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
898 w83627hf_write_value(client, W83781D_REG_SCFG1,
899 tmp & ~BIT_SCFG1[nr - 1]);
900 data->sens[nr - 1] = val;
901 break;
902 default:
903 dev_err(&client->dev,
904 "Invalid sensor type %ld; must be 1, 2, or %d\n",
905 (long) val, W83781D_DEFAULT_BETA);
906 break;
907 }
908
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100909 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 return count;
911}
912
913#define sysfs_sensor(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400914static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915{ \
916 return show_sensor_reg(dev, buf, offset); \
917} \
918static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400919store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{ \
921 return store_sensor_reg(dev, buf, count, offset); \
922} \
923static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
924 show_regs_sensor_##offset, store_regs_sensor_##offset);
925
926sysfs_sensor(1);
927sysfs_sensor(2);
928sysfs_sensor(3);
929
Jean Delvaree6cfb3a2005-07-27 21:32:02 +0200930static int __init w83627hf_find(int sioaddr, unsigned short *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
Jean Delvared27c37c2007-05-08 17:21:59 +0200932 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 u16 val;
934
935 REG = sioaddr;
936 VAL = sioaddr + 1;
937
938 superio_enter();
939 val= superio_inb(DEVID);
940 if(val != W627_DEVID &&
941 val != W627THF_DEVID &&
942 val != W697_DEVID &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100943 val != W637_DEVID &&
944 val != W687THF_DEVID) {
Jean Delvared27c37c2007-05-08 17:21:59 +0200945 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 }
947
948 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +0200949 force_addr &= WINB_ALIGNMENT;
950 if (force_addr) {
951 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
952 force_addr);
953 superio_outb(WINB_BASE_REG, force_addr >> 8);
954 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 val = (superio_inb(WINB_BASE_REG) << 8) |
957 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200958 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +0200959 if (*addr == 0) {
960 printk(KERN_WARNING DRVNAME ": Base address not set, "
961 "skipping\n");
962 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Jean Delvared27c37c2007-05-08 17:21:59 +0200965 val = superio_inb(WINB_ACT_REG);
966 if (!(val & 0x01)) {
967 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
968 superio_outb(WINB_ACT_REG, val | 0x01);
969 }
970
971 err = 0;
972
973 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +0200975 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976}
977
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +0200978static struct attribute *w83627hf_attributes[] = {
979 &dev_attr_in0_input.attr,
980 &dev_attr_in0_min.attr,
981 &dev_attr_in0_max.attr,
982 &dev_attr_in2_input.attr,
983 &dev_attr_in2_min.attr,
984 &dev_attr_in2_max.attr,
985 &dev_attr_in3_input.attr,
986 &dev_attr_in3_min.attr,
987 &dev_attr_in3_max.attr,
988 &dev_attr_in4_input.attr,
989 &dev_attr_in4_min.attr,
990 &dev_attr_in4_max.attr,
991 &dev_attr_in7_input.attr,
992 &dev_attr_in7_min.attr,
993 &dev_attr_in7_max.attr,
994 &dev_attr_in8_input.attr,
995 &dev_attr_in8_min.attr,
996 &dev_attr_in8_max.attr,
997
998 &dev_attr_fan1_input.attr,
999 &dev_attr_fan1_min.attr,
1000 &dev_attr_fan1_div.attr,
1001 &dev_attr_fan2_input.attr,
1002 &dev_attr_fan2_min.attr,
1003 &dev_attr_fan2_div.attr,
1004
1005 &dev_attr_temp1_input.attr,
1006 &dev_attr_temp1_max.attr,
1007 &dev_attr_temp1_max_hyst.attr,
1008 &dev_attr_temp1_type.attr,
1009 &dev_attr_temp2_input.attr,
1010 &dev_attr_temp2_max.attr,
1011 &dev_attr_temp2_max_hyst.attr,
1012 &dev_attr_temp2_type.attr,
1013
1014 &dev_attr_alarms.attr,
1015 &dev_attr_beep_enable.attr,
1016 &dev_attr_beep_mask.attr,
1017
1018 &dev_attr_pwm1.attr,
1019 &dev_attr_pwm2.attr,
1020
1021 NULL
1022};
1023
1024static const struct attribute_group w83627hf_group = {
1025 .attrs = w83627hf_attributes,
1026};
1027
1028static struct attribute *w83627hf_attributes_opt[] = {
1029 &dev_attr_in1_input.attr,
1030 &dev_attr_in1_min.attr,
1031 &dev_attr_in1_max.attr,
1032 &dev_attr_in5_input.attr,
1033 &dev_attr_in5_min.attr,
1034 &dev_attr_in5_max.attr,
1035 &dev_attr_in6_input.attr,
1036 &dev_attr_in6_min.attr,
1037 &dev_attr_in6_max.attr,
1038
1039 &dev_attr_fan3_input.attr,
1040 &dev_attr_fan3_min.attr,
1041 &dev_attr_fan3_div.attr,
1042
1043 &dev_attr_temp3_input.attr,
1044 &dev_attr_temp3_max.attr,
1045 &dev_attr_temp3_max_hyst.attr,
1046 &dev_attr_temp3_type.attr,
1047
1048 &dev_attr_pwm3.attr,
1049
1050 NULL
1051};
1052
1053static const struct attribute_group w83627hf_group_opt = {
1054 .attrs = w83627hf_attributes_opt,
1055};
1056
Jean Delvare2d8672c2005-07-19 23:56:35 +02001057static int w83627hf_detect(struct i2c_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Jean Delvare2d8672c2005-07-19 23:56:35 +02001059 int val, kind;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 struct i2c_client *new_client;
1061 struct w83627hf_data *data;
1062 int err = 0;
1063 const char *client_name = "";
1064
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001065 if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001066 w83627hf_driver.driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 err = -EBUSY;
1068 goto ERROR0;
1069 }
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 superio_enter();
1072 val= superio_inb(DEVID);
1073 if(val == W627_DEVID)
1074 kind = w83627hf;
1075 else if(val == W697_DEVID)
1076 kind = w83697hf;
1077 else if(val == W627THF_DEVID)
1078 kind = w83627thf;
1079 else if(val == W637_DEVID)
1080 kind = w83637hf;
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001081 else if (val == W687THF_DEVID)
1082 kind = w83687thf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 else {
1084 dev_info(&adapter->dev,
1085 "Unsupported chip (dev_id=0x%02X).\n", val);
1086 goto ERROR1;
1087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 superio_exit();
1089
1090 /* OK. For now, we presume we have a valid client. We now create the
1091 client structure, even though we cannot fill it completely yet.
1092 But it allows us to access w83627hf_{read,write}_value. */
1093
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001094 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 err = -ENOMEM;
1096 goto ERROR1;
1097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 new_client = &data->client;
1100 i2c_set_clientdata(new_client, data);
1101 new_client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001102 mutex_init(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 new_client->adapter = adapter;
1104 new_client->driver = &w83627hf_driver;
1105 new_client->flags = 0;
1106
1107
1108 if (kind == w83627hf) {
1109 client_name = "w83627hf";
1110 } else if (kind == w83627thf) {
1111 client_name = "w83627thf";
1112 } else if (kind == w83697hf) {
1113 client_name = "w83697hf";
1114 } else if (kind == w83637hf) {
1115 client_name = "w83637hf";
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001116 } else if (kind == w83687thf) {
1117 client_name = "w83687thf";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119
1120 /* Fill in the remaining client fields and put into the global list */
1121 strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
1122 data->type = kind;
1123 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001124 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 /* Tell the I2C layer a new client has arrived */
1127 if ((err = i2c_attach_client(new_client)))
1128 goto ERROR2;
1129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 /* Initialize the chip */
1131 w83627hf_init_client(new_client);
1132
1133 /* A few vars need to be filled upon startup */
1134 data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1));
1135 data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
1136 data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
1137
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001138 /* Register common device attributes */
1139 if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
1140 goto ERROR3;
1141
1142 /* Register chip-specific device attributes */
1143 if (kind == w83627hf || kind == w83697hf)
1144 if ((err = device_create_file(&new_client->dev,
1145 &dev_attr_in5_input))
1146 || (err = device_create_file(&new_client->dev,
1147 &dev_attr_in5_min))
1148 || (err = device_create_file(&new_client->dev,
1149 &dev_attr_in5_max))
1150 || (err = device_create_file(&new_client->dev,
1151 &dev_attr_in6_input))
1152 || (err = device_create_file(&new_client->dev,
1153 &dev_attr_in6_min))
1154 || (err = device_create_file(&new_client->dev,
1155 &dev_attr_in6_max)))
1156 goto ERROR4;
1157
1158 if (kind != w83697hf)
1159 if ((err = device_create_file(&new_client->dev,
1160 &dev_attr_in1_input))
1161 || (err = device_create_file(&new_client->dev,
1162 &dev_attr_in1_min))
1163 || (err = device_create_file(&new_client->dev,
1164 &dev_attr_in1_max))
1165 || (err = device_create_file(&new_client->dev,
1166 &dev_attr_fan3_input))
1167 || (err = device_create_file(&new_client->dev,
1168 &dev_attr_fan3_min))
1169 || (err = device_create_file(&new_client->dev,
1170 &dev_attr_fan3_div))
1171 || (err = device_create_file(&new_client->dev,
1172 &dev_attr_temp3_input))
1173 || (err = device_create_file(&new_client->dev,
1174 &dev_attr_temp3_max))
1175 || (err = device_create_file(&new_client->dev,
1176 &dev_attr_temp3_max_hyst))
1177 || (err = device_create_file(&new_client->dev,
1178 &dev_attr_temp3_type)))
1179 goto ERROR4;
1180
Jean Delvare8a665a02007-05-08 17:21:59 +02001181 if (kind != w83697hf && data->vid != 0xff) {
1182 /* Convert VID to voltage based on VRM */
1183 data->vrm = vid_which_vrm();
1184
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001185 if ((err = device_create_file(&new_client->dev,
1186 &dev_attr_cpu0_vid))
1187 || (err = device_create_file(&new_client->dev,
1188 &dev_attr_vrm)))
1189 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001190 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001191
1192 if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
1193 if ((err = device_create_file(&new_client->dev,
1194 &dev_attr_pwm3)))
1195 goto ERROR4;
1196
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001197 data->class_dev = hwmon_device_register(&new_client->dev);
1198 if (IS_ERR(data->class_dev)) {
1199 err = PTR_ERR(data->class_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001200 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001201 }
1202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return 0;
1204
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001205 ERROR4:
1206 sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
1207 sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001208 ERROR3:
1209 i2c_detach_client(new_client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 ERROR2:
1211 kfree(data);
1212 ERROR1:
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001213 release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 ERROR0:
1215 return err;
1216}
1217
1218static int w83627hf_detach_client(struct i2c_client *client)
1219{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001220 struct w83627hf_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 int err;
1222
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001223 hwmon_device_unregister(data->class_dev);
1224
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001225 sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
1226 sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
1227
Jean Delvare7bef5592005-07-27 22:14:49 +02001228 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001231 release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001232 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 return 0;
1235}
1236
1237
1238/*
1239 ISA access must always be locked explicitly!
1240 We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1241 would slow down the W83781D access and should not be necessary.
1242 There are some ugly typecasts here, but the good news is - they should
1243 nowhere else be necessary! */
1244static int w83627hf_read_value(struct i2c_client *client, u16 reg)
1245{
1246 struct w83627hf_data *data = i2c_get_clientdata(client);
1247 int res, word_sized;
1248
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001249 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 word_sized = (((reg & 0xff00) == 0x100)
1251 || ((reg & 0xff00) == 0x200))
1252 && (((reg & 0x00ff) == 0x50)
1253 || ((reg & 0x00ff) == 0x53)
1254 || ((reg & 0x00ff) == 0x55));
1255 if (reg & 0xff00) {
1256 outb_p(W83781D_REG_BANK,
1257 client->addr + W83781D_ADDR_REG_OFFSET);
1258 outb_p(reg >> 8,
1259 client->addr + W83781D_DATA_REG_OFFSET);
1260 }
1261 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1262 res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
1263 if (word_sized) {
1264 outb_p((reg & 0xff) + 1,
1265 client->addr + W83781D_ADDR_REG_OFFSET);
1266 res =
1267 (res << 8) + inb_p(client->addr +
1268 W83781D_DATA_REG_OFFSET);
1269 }
1270 if (reg & 0xff00) {
1271 outb_p(W83781D_REG_BANK,
1272 client->addr + W83781D_ADDR_REG_OFFSET);
1273 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1274 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001275 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 return res;
1277}
1278
1279static int w83627thf_read_gpio5(struct i2c_client *client)
1280{
1281 int res = 0xff, sel;
1282
1283 superio_enter();
1284 superio_select(W83627HF_LD_GPIO5);
1285
1286 /* Make sure these GPIO pins are enabled */
1287 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
1288 dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n");
1289 goto exit;
1290 }
1291
1292 /* Make sure the pins are configured for input
1293 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001294 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if ((sel & 0x1f) != 0x1f) {
1296 dev_dbg(&client->dev, "GPIO5 not configured for VID "
1297 "function\n");
1298 goto exit;
1299 }
1300
1301 dev_info(&client->dev, "Reading VID from GPIO5\n");
1302 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1303
1304exit:
1305 superio_exit();
1306 return res;
1307}
1308
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001309static int w83687thf_read_vid(struct i2c_client *client)
1310{
1311 int res = 0xff;
1312
1313 superio_enter();
1314 superio_select(W83627HF_LD_HWM);
1315
1316 /* Make sure these GPIO pins are enabled */
1317 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
1318 dev_dbg(&client->dev, "VID disabled, no VID function\n");
1319 goto exit;
1320 }
1321
1322 /* Make sure the pins are configured for input */
1323 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
1324 dev_dbg(&client->dev, "VID configured as output, "
1325 "no VID function\n");
1326 goto exit;
1327 }
1328
1329 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1330
1331exit:
1332 superio_exit();
1333 return res;
1334}
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
1337{
1338 struct w83627hf_data *data = i2c_get_clientdata(client);
1339 int word_sized;
1340
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001341 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 word_sized = (((reg & 0xff00) == 0x100)
1343 || ((reg & 0xff00) == 0x200))
1344 && (((reg & 0x00ff) == 0x53)
1345 || ((reg & 0x00ff) == 0x55));
1346 if (reg & 0xff00) {
1347 outb_p(W83781D_REG_BANK,
1348 client->addr + W83781D_ADDR_REG_OFFSET);
1349 outb_p(reg >> 8,
1350 client->addr + W83781D_DATA_REG_OFFSET);
1351 }
1352 outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
1353 if (word_sized) {
1354 outb_p(value >> 8,
1355 client->addr + W83781D_DATA_REG_OFFSET);
1356 outb_p((reg & 0xff) + 1,
1357 client->addr + W83781D_ADDR_REG_OFFSET);
1358 }
1359 outb_p(value & 0xff,
1360 client->addr + W83781D_DATA_REG_OFFSET);
1361 if (reg & 0xff00) {
1362 outb_p(W83781D_REG_BANK,
1363 client->addr + W83781D_ADDR_REG_OFFSET);
1364 outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
1365 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001366 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 return 0;
1368}
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370static void w83627hf_init_client(struct i2c_client *client)
1371{
1372 struct w83627hf_data *data = i2c_get_clientdata(client);
1373 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001374 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 u8 tmp;
1376
Jean Delvare2251cf12005-09-04 22:52:17 +02001377 if (reset) {
1378 /* Resetting the chip has been the default for a long time,
1379 but repeatedly caused problems (fans going to full
1380 speed...) so it is now optional. It might even go away if
1381 nobody reports it as being useful, as I see very little
1382 reason why this would be needed at all. */
1383 dev_info(&client->dev, "If reset=1 solved a problem you were "
1384 "having, please report!\n");
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 /* save this register */
1387 i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
1388 /* Reset all except Watchdog values and last conversion values
1389 This sets fan-divs to 2, among others */
1390 w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);
1391 /* Restore the register and disable power-on abnormal beep.
1392 This saves FAN 1/2/3 input/output values set by BIOS. */
1393 w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
1394 /* Disable master beep-enable (reset turns it on).
1395 Individual beeps should be reset to off but for some reason
1396 disabling this bit helps some people not get beeped */
1397 w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);
1398 }
1399
1400 /* Minimize conflicts with other winbond i2c-only clients... */
1401 /* disable i2c subclients... how to disable main i2c client?? */
1402 /* force i2c address to relatively uncommon address */
1403 w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
1404 w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
1405
1406 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001407 if (type == w83627hf || type == w83637hf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
1409 int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
1410 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001411 } else if (type == w83627thf) {
Yuan Mudd149c52005-11-26 20:13:18 +01001412 data->vid = w83627thf_read_gpio5(client);
Jean Delvared27c37c2007-05-08 17:21:59 +02001413 } else if (type == w83687thf) {
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001414 data->vid = w83687thf_read_vid(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 }
1416
1417 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001418 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 data->vrm_ovt =
1420 w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 }
1422
1423 tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
1424 for (i = 1; i <= 3; i++) {
1425 if (!(tmp & BIT_SCFG1[i - 1])) {
1426 data->sens[i - 1] = W83781D_DEFAULT_BETA;
1427 } else {
1428 if (w83627hf_read_value
1429 (client,
1430 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1431 data->sens[i - 1] = 1;
1432 else
1433 data->sens[i - 1] = 2;
1434 }
1435 if ((type == w83697hf) && (i == 2))
1436 break;
1437 }
1438
1439 if(init) {
1440 /* Enable temp2 */
1441 tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG);
1442 if (tmp & 0x01) {
1443 dev_warn(&client->dev, "Enabling temp2, readings "
1444 "might not make sense\n");
1445 w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG,
1446 tmp & 0xfe);
1447 }
1448
1449 /* Enable temp3 */
1450 if (type != w83697hf) {
1451 tmp = w83627hf_read_value(client,
1452 W83781D_REG_TEMP3_CONFIG);
1453 if (tmp & 0x01) {
1454 dev_warn(&client->dev, "Enabling temp3, "
1455 "readings might not make sense\n");
1456 w83627hf_write_value(client,
1457 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1458 }
1459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 }
1461
1462 /* Start monitoring */
1463 w83627hf_write_value(client, W83781D_REG_CONFIG,
1464 (w83627hf_read_value(client,
1465 W83781D_REG_CONFIG) & 0xf7)
1466 | 0x01);
1467}
1468
1469static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1470{
1471 struct i2c_client *client = to_i2c_client(dev);
1472 struct w83627hf_data *data = i2c_get_clientdata(client);
1473 int i;
1474
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001475 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
1477 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1478 || !data->valid) {
1479 for (i = 0; i <= 8; i++) {
1480 /* skip missing sensors */
1481 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001482 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001483 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 continue;
1485 data->in[i] =
1486 w83627hf_read_value(client, W83781D_REG_IN(i));
1487 data->in_min[i] =
1488 w83627hf_read_value(client,
1489 W83781D_REG_IN_MIN(i));
1490 data->in_max[i] =
1491 w83627hf_read_value(client,
1492 W83781D_REG_IN_MAX(i));
1493 }
1494 for (i = 1; i <= 3; i++) {
1495 data->fan[i - 1] =
1496 w83627hf_read_value(client, W83781D_REG_FAN(i));
1497 data->fan_min[i - 1] =
1498 w83627hf_read_value(client,
1499 W83781D_REG_FAN_MIN(i));
1500 }
1501 for (i = 1; i <= 3; i++) {
1502 u8 tmp = w83627hf_read_value(client,
1503 W836X7HF_REG_PWM(data->type, i));
1504 /* bits 0-3 are reserved in 627THF */
1505 if (data->type == w83627thf)
1506 tmp &= 0xf0;
1507 data->pwm[i - 1] = tmp;
1508 if(i == 2 &&
1509 (data->type == w83627hf || data->type == w83697hf))
1510 break;
1511 }
1512
1513 data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));
1514 data->temp_max =
1515 w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));
1516 data->temp_max_hyst =
1517 w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));
1518 data->temp_add[0] =
1519 w83627hf_read_value(client, W83781D_REG_TEMP(2));
1520 data->temp_max_add[0] =
1521 w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));
1522 data->temp_max_hyst_add[0] =
1523 w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));
1524 if (data->type != w83697hf) {
1525 data->temp_add[1] =
1526 w83627hf_read_value(client, W83781D_REG_TEMP(3));
1527 data->temp_max_add[1] =
1528 w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));
1529 data->temp_max_hyst_add[1] =
1530 w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));
1531 }
1532
1533 i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
1534 data->fan_div[0] = (i >> 4) & 0x03;
1535 data->fan_div[1] = (i >> 6) & 0x03;
1536 if (data->type != w83697hf) {
1537 data->fan_div[2] = (w83627hf_read_value(client,
1538 W83781D_REG_PIN) >> 6) & 0x03;
1539 }
1540 i = w83627hf_read_value(client, W83781D_REG_VBAT);
1541 data->fan_div[0] |= (i >> 3) & 0x04;
1542 data->fan_div[1] |= (i >> 4) & 0x04;
1543 if (data->type != w83697hf)
1544 data->fan_div[2] |= (i >> 5) & 0x04;
1545 data->alarms =
1546 w83627hf_read_value(client, W83781D_REG_ALARM1) |
1547 (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
1548 (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
1549 i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
1550 data->beep_enable = i >> 7;
1551 data->beep_mask = ((i & 0x7f) << 8) |
1552 w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
1553 w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
1554 data->last_updated = jiffies;
1555 data->valid = 1;
1556 }
1557
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001558 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 return data;
1561}
1562
1563static int __init sensors_w83627hf_init(void)
1564{
Jean Delvare2d8672c2005-07-19 23:56:35 +02001565 if (w83627hf_find(0x2e, &address)
1566 && w83627hf_find(0x4e, &address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return -ENODEV;
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
Jean Delvarefde09502005-07-19 23:51:07 +02001570 return i2c_isa_add_driver(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571}
1572
1573static void __exit sensors_w83627hf_exit(void)
1574{
Jean Delvarefde09502005-07-19 23:51:07 +02001575 i2c_isa_del_driver(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576}
1577
1578MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1579 "Philip Edelbrock <phil@netroedge.com>, "
1580 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1581MODULE_DESCRIPTION("W83627HF driver");
1582MODULE_LICENSE("GPL");
1583
1584module_init(sensors_w83627hf_init);
1585module_exit(sensors_w83627hf_exit);