blob: ba8b069b1082bb61b44be33f0b7e5e5f10194c76 [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>
Jean Delvare787c72b2007-05-08 17:22:00 +02008 Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25/*
26 Supports following chips:
27
28 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
29 w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC)
30 w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
31 w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC)
Jean Delvarec2db6ce2006-01-18 23:22:12 +010032 w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
34
35 For other winbond chips, and for i2c support in the above chips,
36 use w83781d.c.
37
38 Note: automatic ("cruise") fan control for 697, 637 & 627thf not
39 supported yet.
40*/
41
42#include <linux/module.h>
43#include <linux/init.h>
44#include <linux/slab.h>
45#include <linux/jiffies.h>
Jean Delvare787c72b2007-05-08 17:22:00 +020046#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/hwmon.h>
Jim Cromie07584c72007-10-12 21:08:00 +020048#include <linux/hwmon-sysfs.h>
Jean Delvare303760b2005-07-31 21:52:01 +020049#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040050#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010051#include <linux/mutex.h>
Jean Delvared27c37c2007-05-08 17:21:59 +020052#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/io.h>
54#include "lm75.h"
55
Jean Delvare787c72b2007-05-08 17:22:00 +020056static struct platform_device *pdev;
Jean Delvared27c37c2007-05-08 17:21:59 +020057
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
Jean Delvare67b671b2007-12-06 23:13:42 +010078static unsigned short force_id;
79module_param(force_id, ushort, 0);
80MODULE_PARM_DESC(force_id, "Override the detected device ID");
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082/* modified from kernel/include/traps.c */
83static int REG; /* The register to read/write */
84#define DEV 0x07 /* Register: Logical device select */
85static int VAL; /* The value to read/write */
86
87/* logical device numbers for superio_select (below) */
88#define W83627HF_LD_FDC 0x00
89#define W83627HF_LD_PRT 0x01
90#define W83627HF_LD_UART1 0x02
91#define W83627HF_LD_UART2 0x03
92#define W83627HF_LD_KBC 0x05
93#define W83627HF_LD_CIR 0x06 /* w83627hf only */
94#define W83627HF_LD_GAME 0x07
95#define W83627HF_LD_MIDI 0x07
96#define W83627HF_LD_GPIO1 0x07
97#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
98#define W83627HF_LD_GPIO2 0x08
99#define W83627HF_LD_GPIO3 0x09
100#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
101#define W83627HF_LD_ACPI 0x0a
102#define W83627HF_LD_HWM 0x0b
103
104#define DEVID 0x20 /* Register: Device ID */
105
106#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
107#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
108#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
109
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100110#define W83687THF_VID_EN 0x29 /* w83687thf only */
111#define W83687THF_VID_CFG 0xF0 /* w83687thf only */
112#define W83687THF_VID_DATA 0xF1 /* w83687thf only */
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114static inline void
115superio_outb(int reg, int val)
116{
117 outb(reg, REG);
118 outb(val, VAL);
119}
120
121static inline int
122superio_inb(int reg)
123{
124 outb(reg, REG);
125 return inb(VAL);
126}
127
128static inline void
129superio_select(int ld)
130{
131 outb(DEV, REG);
132 outb(ld, VAL);
133}
134
135static inline void
136superio_enter(void)
137{
138 outb(0x87, REG);
139 outb(0x87, REG);
140}
141
142static inline void
143superio_exit(void)
144{
145 outb(0xAA, REG);
146}
147
148#define W627_DEVID 0x52
149#define W627THF_DEVID 0x82
150#define W697_DEVID 0x60
151#define W637_DEVID 0x70
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100152#define W687THF_DEVID 0x85
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153#define WINB_ACT_REG 0x30
154#define WINB_BASE_REG 0x60
155/* Constants specified below */
156
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200157/* Alignment of the base address */
158#define WINB_ALIGNMENT ~7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200160/* Offset & size of I/O region we are interested in */
161#define WINB_REGION_OFFSET 5
162#define WINB_REGION_SIZE 2
163
Jean Delvare787c72b2007-05-08 17:22:00 +0200164/* Where are the sensors address/data registers relative to the region offset */
165#define W83781D_ADDR_REG_OFFSET 0
166#define W83781D_DATA_REG_OFFSET 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168/* The W83781D registers */
169/* The W83782D registers for nr=7,8 are in bank 5 */
170#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
171 (0x554 + (((nr) - 7) * 2)))
172#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
173 (0x555 + (((nr) - 7) * 2)))
174#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
175 (0x550 + (nr) - 7))
176
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600177/* nr:0-2 for fans:1-3 */
178#define W83627HF_REG_FAN_MIN(nr) (0x3b + (nr))
179#define W83627HF_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Jim Cromiedf48ed82007-10-14 17:10:52 -0600181#define W83627HF_REG_TEMP2_CONFIG 0x152
182#define W83627HF_REG_TEMP3_CONFIG 0x252
183/* these are zero-based, unlike config constants above */
184static const u16 w83627hf_reg_temp[] = { 0x27, 0x150, 0x250 };
185static const u16 w83627hf_reg_temp_hyst[] = { 0x3A, 0x153, 0x253 };
186static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
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
Dominik Geyera95a5ed2008-08-06 22:41:04 +0200212static const u8 W83627THF_REG_PWM_ENABLE[] = {
213 0x04, /* FAN 1 mode */
214 0x04, /* FAN 2 mode */
215 0x12, /* FAN AUX mode */
216};
217static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
218
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100219#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
220#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
221#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100223#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
226static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
227 W83627THF_REG_PWM3 };
228#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
Jim Cromie07584c72007-10-12 21:08:00 +0200229 regpwm_627hf[nr] : regpwm[nr])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400231#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
232
233#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
234#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
235#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
236
237static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
238 W83637HF_REG_PWM_FREQ2,
239 W83637HF_REG_PWM_FREQ3 };
240
241#define W83627HF_BASE_PWM_FREQ 46870
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243#define W83781D_REG_I2C_ADDR 0x48
244#define W83781D_REG_I2C_SUBADDR 0x4A
245
246/* Sensor selection */
247#define W83781D_REG_SCFG1 0x5D
248static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
249#define W83781D_REG_SCFG2 0x59
250static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
251#define W83781D_DEFAULT_BETA 3435
252
253/* Conversions. Limit checking is only done on the TO_REG
254 variants. Note that you should be a bit careful with which arguments
255 these macros are called: arguments may be evaluated more than once.
256 Fixing this is just not worth it. */
257#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
258#define IN_FROM_REG(val) ((val) * 16)
259
260static inline u8 FAN_TO_REG(long rpm, int div)
261{
262 if (rpm == 0)
263 return 255;
264 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
265 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
266 254);
267}
268
269#define TEMP_MIN (-128000)
270#define TEMP_MAX ( 127000)
271
272/* TEMP: 0.001C/bit (-128C to +127C)
273 REG: 1C/bit, two's complement */
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200274static u8 TEMP_TO_REG(long temp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
276 int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
277 ntemp += (ntemp<0 ? -500 : 500);
278 return (u8)(ntemp / 1000);
279}
280
281static int TEMP_FROM_REG(u8 reg)
282{
283 return (s8)reg * 1000;
284}
285
286#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
287
288#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
289
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400290static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
291{
292 unsigned long freq;
293 freq = W83627HF_BASE_PWM_FREQ >> reg;
294 return freq;
295}
296static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
297{
298 u8 i;
299 /* Only 5 dividers (1 2 4 8 16)
300 Search for the nearest available frequency */
301 for (i = 0; i < 4; i++) {
302 if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
303 (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
304 break;
305 }
306 return i;
307}
308
309static inline unsigned long pwm_freq_from_reg(u8 reg)
310{
311 /* Clock bit 8 -> 180 kHz or 24 MHz */
312 unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
313
314 reg &= 0x7f;
315 /* This should not happen but anyway... */
316 if (reg == 0)
317 reg++;
318 return (clock / (reg << 8));
319}
320static inline u8 pwm_freq_to_reg(unsigned long val)
321{
322 /* Minimum divider value is 0x01 and maximum is 0x7F */
323 if (val >= 93750) /* The highest we can do */
324 return 0x01;
325 if (val >= 720) /* Use 24 MHz clock */
326 return (24000000UL / (val << 8));
327 if (val < 6) /* The lowest we can do */
328 return 0xFF;
329 else /* Use 180 kHz clock */
330 return (0x80 | (180000UL / (val << 8)));
331}
332
Jean Delvare1c138102008-01-03 23:04:55 +0100333#define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff)
334#define BEEP_MASK_TO_REG(val) ((val) & 0xff7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
336#define DIV_FROM_REG(val) (1 << (val))
337
338static inline u8 DIV_TO_REG(long val)
339{
340 int i;
341 val = SENSORS_LIMIT(val, 1, 128) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000342 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 if (val == 0)
344 break;
345 val >>= 1;
346 }
347 return ((u8) i);
348}
349
Jean Delvareed6bafb2007-02-14 21:15:03 +0100350/* For each registered chip, we need to keep some data in memory.
351 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352struct w83627hf_data {
Jean Delvare787c72b2007-05-08 17:22:00 +0200353 unsigned short addr;
354 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700355 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100356 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 enum chips type;
358
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100359 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 char valid; /* !=0 if following fields are valid */
361 unsigned long last_updated; /* In jiffies */
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 u8 in[9]; /* Register value */
364 u8 in_max[9]; /* Register value */
365 u8 in_min[9]; /* Register value */
366 u8 fan[3]; /* Register value */
367 u8 fan_min[3]; /* Register value */
Jim Cromiedf48ed82007-10-14 17:10:52 -0600368 u16 temp[3]; /* Register value */
369 u16 temp_max[3]; /* Register value */
370 u16 temp_max_hyst[3]; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 u8 fan_div[3]; /* Register encoding, shifted right */
372 u8 vid; /* Register encoding, combined */
373 u32 alarms; /* Register encoding, combined */
374 u32 beep_mask; /* Register encoding, combined */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 u8 pwm[3]; /* Register value */
Dominik Geyera95a5ed2008-08-06 22:41:04 +0200376 u8 pwm_enable[3]; /* 1 = manual
377 2 = thermal cruise (also called SmartFan I)
378 3 = fan speed cruise */
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400379 u8 pwm_freq[3]; /* Register value */
Jean Delvareb26f9332007-08-16 14:30:01 +0200380 u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
381 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 u8 vrm;
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100383 u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384};
385
Jean Delvare787c72b2007-05-08 17:22:00 +0200386struct w83627hf_sio_data {
387 enum chips type;
388};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Jean Delvare787c72b2007-05-08 17:22:00 +0200391static int w83627hf_probe(struct platform_device *pdev);
Jean Delvared0546122007-07-22 12:09:48 +0200392static int __devexit w83627hf_remove(struct platform_device *pdev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200393
394static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
395static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
Jean Delvarec09c5182007-10-12 21:53:07 +0200396static void w83627hf_update_fan_div(struct w83627hf_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397static struct w83627hf_data *w83627hf_update_device(struct device *dev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200398static void w83627hf_init_device(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Jean Delvare787c72b2007-05-08 17:22:00 +0200400static struct platform_driver w83627hf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100401 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200402 .owner = THIS_MODULE,
Jean Delvared27c37c2007-05-08 17:21:59 +0200403 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100404 },
Jean Delvare787c72b2007-05-08 17:22:00 +0200405 .probe = w83627hf_probe,
406 .remove = __devexit_p(w83627hf_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407};
408
Jim Cromie07584c72007-10-12 21:08:00 +0200409static ssize_t
410show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
411{
412 int nr = to_sensor_dev_attr(devattr)->index;
413 struct w83627hf_data *data = w83627hf_update_device(dev);
414 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
Jim Cromie07584c72007-10-12 21:08:00 +0200416static ssize_t
417show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
418{
419 int nr = to_sensor_dev_attr(devattr)->index;
420 struct w83627hf_data *data = w83627hf_update_device(dev);
421 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
Jim Cromie07584c72007-10-12 21:08:00 +0200423static ssize_t
424show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
425{
426 int nr = to_sensor_dev_attr(devattr)->index;
427 struct w83627hf_data *data = w83627hf_update_device(dev);
428 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
429}
430static ssize_t
431store_in_min(struct device *dev, struct device_attribute *devattr,
432 const char *buf, size_t count)
433{
434 int nr = to_sensor_dev_attr(devattr)->index;
435 struct w83627hf_data *data = dev_get_drvdata(dev);
436 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Jim Cromie07584c72007-10-12 21:08:00 +0200438 mutex_lock(&data->update_lock);
439 data->in_min[nr] = IN_TO_REG(val);
440 w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
441 mutex_unlock(&data->update_lock);
442 return count;
443}
444static ssize_t
445store_in_max(struct device *dev, struct device_attribute *devattr,
446 const char *buf, size_t count)
447{
448 int nr = to_sensor_dev_attr(devattr)->index;
449 struct w83627hf_data *data = dev_get_drvdata(dev);
450 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Jim Cromie07584c72007-10-12 21:08:00 +0200452 mutex_lock(&data->update_lock);
453 data->in_max[nr] = IN_TO_REG(val);
454 w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
455 mutex_unlock(&data->update_lock);
456 return count;
457}
458#define sysfs_vin_decl(offset) \
459static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
460 show_in_input, NULL, offset); \
461static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
462 show_in_min, store_in_min, offset); \
463static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
464 show_in_max, store_in_max, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Jim Cromie07584c72007-10-12 21:08:00 +0200466sysfs_vin_decl(1);
467sysfs_vin_decl(2);
468sysfs_vin_decl(3);
469sysfs_vin_decl(4);
470sysfs_vin_decl(5);
471sysfs_vin_decl(6);
472sysfs_vin_decl(7);
473sysfs_vin_decl(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475/* use a different set of functions for in0 */
476static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
477{
478 long in0;
479
480 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100481 (w83627thf == data->type || w83637hf == data->type
482 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 /* use VRM9 calculation */
485 in0 = (long)((reg * 488 + 70000 + 50) / 100);
486 else
487 /* use VRM8 (standard) calculation */
488 in0 = (long)IN_FROM_REG(reg);
489
490 return sprintf(buf,"%ld\n", in0);
491}
492
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400493static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 struct w83627hf_data *data = w83627hf_update_device(dev);
496 return show_in_0(data, buf, data->in[0]);
497}
498
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400499static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct w83627hf_data *data = w83627hf_update_device(dev);
502 return show_in_0(data, buf, data->in_min[0]);
503}
504
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400505static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 struct w83627hf_data *data = w83627hf_update_device(dev);
508 return show_in_0(data, buf, data->in_max[0]);
509}
510
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400511static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 const char *buf, size_t count)
513{
Jean Delvare787c72b2007-05-08 17:22:00 +0200514 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 u32 val;
516
517 val = simple_strtoul(buf, NULL, 10);
518
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100519 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100522 (w83627thf == data->type || w83637hf == data->type
523 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800526 data->in_min[0] =
527 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
528 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 else
530 /* use VRM8 (standard) calculation */
531 data->in_min[0] = IN_TO_REG(val);
532
Jean Delvare787c72b2007-05-08 17:22:00 +0200533 w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100534 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return count;
536}
537
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400538static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 const char *buf, size_t count)
540{
Jean Delvare787c72b2007-05-08 17:22:00 +0200541 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 u32 val;
543
544 val = simple_strtoul(buf, NULL, 10);
545
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100546 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100549 (w83627thf == data->type || w83637hf == data->type
550 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800553 data->in_max[0] =
554 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
555 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 else
557 /* use VRM8 (standard) calculation */
558 data->in_max[0] = IN_TO_REG(val);
559
Jean Delvare787c72b2007-05-08 17:22:00 +0200560 w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100561 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return count;
563}
564
565static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
566static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
567 show_regs_in_min0, store_regs_in_min0);
568static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
569 show_regs_in_max0, store_regs_in_max0);
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200572show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
Jim Cromie07584c72007-10-12 21:08:00 +0200574 int nr = to_sensor_dev_attr(devattr)->index;
575 struct w83627hf_data *data = w83627hf_update_device(dev);
576 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
577 (long)DIV_FROM_REG(data->fan_div[nr])));
578}
579static ssize_t
580show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
581{
582 int nr = to_sensor_dev_attr(devattr)->index;
583 struct w83627hf_data *data = w83627hf_update_device(dev);
584 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
585 (long)DIV_FROM_REG(data->fan_div[nr])));
586}
587static ssize_t
588store_fan_min(struct device *dev, struct device_attribute *devattr,
589 const char *buf, size_t count)
590{
591 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200592 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200593 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100595 mutex_lock(&data->update_lock);
Jim Cromie07584c72007-10-12 21:08:00 +0200596 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600597 w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200598 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100600 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return count;
602}
Jim Cromie07584c72007-10-12 21:08:00 +0200603#define sysfs_fan_decl(offset) \
604static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
605 show_fan_input, NULL, offset - 1); \
606static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
607 show_fan_min, store_fan_min, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Jim Cromie07584c72007-10-12 21:08:00 +0200609sysfs_fan_decl(1);
610sysfs_fan_decl(2);
611sysfs_fan_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Jim Cromie07584c72007-10-12 21:08:00 +0200613static ssize_t
614show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
615{
616 int nr = to_sensor_dev_attr(devattr)->index;
617 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600618
619 u16 tmp = data->temp[nr];
620 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
621 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Jim Cromie07584c72007-10-12 21:08:00 +0200624static ssize_t
625show_temp_max(struct device *dev, struct device_attribute *devattr,
626 char *buf)
627{
628 int nr = to_sensor_dev_attr(devattr)->index;
629 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600630
631 u16 tmp = data->temp_max[nr];
632 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
633 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Jim Cromie07584c72007-10-12 21:08:00 +0200636static ssize_t
637show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
638 char *buf)
639{
640 int nr = to_sensor_dev_attr(devattr)->index;
641 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600642
643 u16 tmp = data->temp_max_hyst[nr];
644 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
645 : (long) TEMP_FROM_REG(tmp));
Jim Cromie07584c72007-10-12 21:08:00 +0200646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Jim Cromie07584c72007-10-12 21:08:00 +0200648static ssize_t
649store_temp_max(struct device *dev, struct device_attribute *devattr,
650 const char *buf, size_t count)
651{
652 int nr = to_sensor_dev_attr(devattr)->index;
653 struct w83627hf_data *data = dev_get_drvdata(dev);
654 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600655 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Jim Cromie07584c72007-10-12 21:08:00 +0200657 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600658 data->temp_max[nr] = tmp;
659 w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200660 mutex_unlock(&data->update_lock);
661 return count;
662}
663
664static ssize_t
665store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
666 const char *buf, size_t count)
667{
668 int nr = to_sensor_dev_attr(devattr)->index;
669 struct w83627hf_data *data = dev_get_drvdata(dev);
670 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600671 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Jim Cromie07584c72007-10-12 21:08:00 +0200672
673 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600674 data->temp_max_hyst[nr] = tmp;
675 w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200676 mutex_unlock(&data->update_lock);
677 return count;
678}
679
680#define sysfs_temp_decl(offset) \
681static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600682 show_temp, NULL, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200683static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600684 show_temp_max, store_temp_max, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200685static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600686 show_temp_max_hyst, store_temp_max_hyst, offset - 1);
Jim Cromie07584c72007-10-12 21:08:00 +0200687
688sysfs_temp_decl(1);
689sysfs_temp_decl(2);
690sysfs_temp_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400693show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 struct w83627hf_data *data = w83627hf_update_device(dev);
696 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
697}
698static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400701show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Jean Delvare90d66192007-10-08 18:24:35 +0200703 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return sprintf(buf, "%ld\n", (long) data->vrm);
705}
706static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400707store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
Jean Delvare787c72b2007-05-08 17:22:00 +0200709 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 u32 val;
711
712 val = simple_strtoul(buf, NULL, 10);
713 data->vrm = val;
714
715 return count;
716}
717static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400720show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 struct w83627hf_data *data = w83627hf_update_device(dev);
723 return sprintf(buf, "%ld\n", (long) data->alarms);
724}
725static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Jean Delvaree3604c62008-01-03 23:00:30 +0100727static ssize_t
728show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
729{
730 struct w83627hf_data *data = w83627hf_update_device(dev);
731 int bitnr = to_sensor_dev_attr(attr)->index;
732 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
733}
734static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
735static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
736static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
737static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
738static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
739static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
740static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
741static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
742static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
743static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
744static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
745static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
746static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
747static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
748static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
749
Jean Delvare1c138102008-01-03 23:04:55 +0100750static ssize_t
751show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf)
752{
753 struct w83627hf_data *data = w83627hf_update_device(dev);
754 return sprintf(buf, "%ld\n",
755 (long)BEEP_MASK_FROM_REG(data->beep_mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758static ssize_t
Jean Delvare1c138102008-01-03 23:04:55 +0100759store_beep_mask(struct device *dev, struct device_attribute *attr,
760 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Jean Delvare787c72b2007-05-08 17:22:00 +0200762 struct w83627hf_data *data = dev_get_drvdata(dev);
Jean Delvare1c138102008-01-03 23:04:55 +0100763 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 val = simple_strtoul(buf, NULL, 10);
766
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100767 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Jean Delvare1c138102008-01-03 23:04:55 +0100769 /* preserve beep enable */
770 data->beep_mask = (data->beep_mask & 0x8000)
771 | BEEP_MASK_TO_REG(val);
772 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
773 data->beep_mask & 0xff);
774 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
775 ((data->beep_mask) >> 16) & 0xff);
Jean Delvare787c72b2007-05-08 17:22:00 +0200776 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
Jean Delvare1c138102008-01-03 23:04:55 +0100777 (data->beep_mask >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100779 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return count;
781}
782
Jean Delvare1c138102008-01-03 23:04:55 +0100783static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
784 show_beep_mask, store_beep_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786static ssize_t
Jean Delvaree3604c62008-01-03 23:00:30 +0100787show_beep(struct device *dev, struct device_attribute *attr, char *buf)
788{
789 struct w83627hf_data *data = w83627hf_update_device(dev);
790 int bitnr = to_sensor_dev_attr(attr)->index;
791 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
792}
793
794static ssize_t
795store_beep(struct device *dev, struct device_attribute *attr,
796 const char *buf, size_t count)
797{
798 struct w83627hf_data *data = dev_get_drvdata(dev);
799 int bitnr = to_sensor_dev_attr(attr)->index;
800 unsigned long bit;
801 u8 reg;
802
803 bit = simple_strtoul(buf, NULL, 10);
804 if (bit & ~1)
805 return -EINVAL;
806
807 mutex_lock(&data->update_lock);
808 if (bit)
809 data->beep_mask |= (1 << bitnr);
810 else
811 data->beep_mask &= ~(1 << bitnr);
812
813 if (bitnr < 8) {
814 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1);
815 if (bit)
816 reg |= (1 << bitnr);
817 else
818 reg &= ~(1 << bitnr);
819 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg);
820 } else if (bitnr < 16) {
821 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
822 if (bit)
823 reg |= (1 << (bitnr - 8));
824 else
825 reg &= ~(1 << (bitnr - 8));
826 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg);
827 } else {
828 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3);
829 if (bit)
830 reg |= (1 << (bitnr - 16));
831 else
832 reg &= ~(1 << (bitnr - 16));
833 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg);
834 }
835 mutex_unlock(&data->update_lock);
836
837 return count;
838}
839
840static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
841 show_beep, store_beep, 0);
842static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
843 show_beep, store_beep, 1);
844static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
845 show_beep, store_beep, 2);
846static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
847 show_beep, store_beep, 3);
848static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
849 show_beep, store_beep, 8);
850static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
851 show_beep, store_beep, 9);
852static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
853 show_beep, store_beep, 10);
854static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
855 show_beep, store_beep, 16);
856static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
857 show_beep, store_beep, 17);
858static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
859 show_beep, store_beep, 6);
860static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
861 show_beep, store_beep, 7);
862static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
863 show_beep, store_beep, 11);
864static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
865 show_beep, store_beep, 4);
866static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
867 show_beep, store_beep, 5);
868static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR,
869 show_beep, store_beep, 13);
Jean Delvare1c138102008-01-03 23:04:55 +0100870static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
871 show_beep, store_beep, 15);
Jean Delvaree3604c62008-01-03 23:00:30 +0100872
873static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200874show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Jim Cromie07584c72007-10-12 21:08:00 +0200876 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 struct w83627hf_data *data = w83627hf_update_device(dev);
878 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200879 (long) DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881/* Note: we save and restore the fan minimum here, because its value is
882 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200883 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 because the divisor changed. */
885static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200886store_fan_div(struct device *dev, struct device_attribute *devattr,
887 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Jim Cromie07584c72007-10-12 21:08:00 +0200889 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200890 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 unsigned long min;
892 u8 reg;
893 unsigned long val = simple_strtoul(buf, NULL, 10);
894
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100895 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897 /* Save fan_min */
898 min = FAN_FROM_REG(data->fan_min[nr],
899 DIV_FROM_REG(data->fan_div[nr]));
900
901 data->fan_div[nr] = DIV_TO_REG(val);
902
Jean Delvare787c72b2007-05-08 17:22:00 +0200903 reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 & (nr==0 ? 0xcf : 0x3f))
905 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare787c72b2007-05-08 17:22:00 +0200906 w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Jean Delvare787c72b2007-05-08 17:22:00 +0200908 reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 & ~(1 << (5 + nr)))
910 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare787c72b2007-05-08 17:22:00 +0200911 w83627hf_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 /* Restore fan_min */
914 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600915 w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100917 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 return count;
919}
920
Jim Cromie07584c72007-10-12 21:08:00 +0200921static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
922 show_fan_div, store_fan_div, 0);
923static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
924 show_fan_div, store_fan_div, 1);
925static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
926 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200929show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930{
Jim Cromie07584c72007-10-12 21:08:00 +0200931 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200933 return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
936static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200937store_pwm(struct device *dev, struct device_attribute *devattr,
938 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939{
Jim Cromie07584c72007-10-12 21:08:00 +0200940 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200941 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200942 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100944 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 if (data->type == w83627thf) {
947 /* bits 0-3 are reserved in 627THF */
Jim Cromie07584c72007-10-12 21:08:00 +0200948 data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
Jean Delvare787c72b2007-05-08 17:22:00 +0200949 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200951 data->pwm[nr] |
Jean Delvare787c72b2007-05-08 17:22:00 +0200952 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
954 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200955 data->pwm[nr] = PWM_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200956 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200958 data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100961 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return count;
963}
964
Jim Cromie07584c72007-10-12 21:08:00 +0200965static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
966static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
967static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969static ssize_t
Dominik Geyera95a5ed2008-08-06 22:41:04 +0200970show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf)
971{
972 int nr = to_sensor_dev_attr(devattr)->index;
973 struct w83627hf_data *data = w83627hf_update_device(dev);
974 return sprintf(buf, "%d\n", data->pwm_enable[nr]);
975}
976
977static ssize_t
978store_pwm_enable(struct device *dev, struct device_attribute *devattr,
979 const char *buf, size_t count)
980{
981 int nr = to_sensor_dev_attr(devattr)->index;
982 struct w83627hf_data *data = dev_get_drvdata(dev);
983 unsigned long val = simple_strtoul(buf, NULL, 10);
984 u8 reg;
985
986 if (!val || (val > 3)) /* modes 1, 2 and 3 are supported */
987 return -EINVAL;
988 mutex_lock(&data->update_lock);
989 data->pwm_enable[nr] = val;
990 reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]);
991 reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]);
992 reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr];
993 w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg);
994 mutex_unlock(&data->update_lock);
995 return count;
996}
997
998static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
999 store_pwm_enable, 0);
1000static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
1001 store_pwm_enable, 1);
1002static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
1003 store_pwm_enable, 2);
1004
1005static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001006show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001007{
Jim Cromie07584c72007-10-12 21:08:00 +02001008 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001009 struct w83627hf_data *data = w83627hf_update_device(dev);
1010 if (data->type == w83627hf)
1011 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +02001012 pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001013 else
1014 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +02001015 pwm_freq_from_reg(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001016}
1017
1018static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001019store_pwm_freq(struct device *dev, struct device_attribute *devattr,
1020 const char *buf, size_t count)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001021{
Jim Cromie07584c72007-10-12 21:08:00 +02001022 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001023 struct w83627hf_data *data = dev_get_drvdata(dev);
1024 static const u8 mask[]={0xF8, 0x8F};
1025 u32 val;
1026
1027 val = simple_strtoul(buf, NULL, 10);
1028
1029 mutex_lock(&data->update_lock);
1030
1031 if (data->type == w83627hf) {
Jim Cromie07584c72007-10-12 21:08:00 +02001032 data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001033 w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
Jim Cromie07584c72007-10-12 21:08:00 +02001034 (data->pwm_freq[nr] << (nr*4)) |
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001035 (w83627hf_read_value(data,
Jim Cromie07584c72007-10-12 21:08:00 +02001036 W83627HF_REG_PWM_FREQ) & mask[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001037 } else {
Jim Cromie07584c72007-10-12 21:08:00 +02001038 data->pwm_freq[nr] = pwm_freq_to_reg(val);
1039 w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
1040 data->pwm_freq[nr]);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001041 }
1042
1043 mutex_unlock(&data->update_lock);
1044 return count;
1045}
1046
Jim Cromie07584c72007-10-12 21:08:00 +02001047static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
1048 show_pwm_freq, store_pwm_freq, 0);
1049static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
1050 show_pwm_freq, store_pwm_freq, 1);
1051static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
1052 show_pwm_freq, store_pwm_freq, 2);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001053
1054static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001055show_temp_type(struct device *dev, struct device_attribute *devattr,
1056 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
Jim Cromie07584c72007-10-12 21:08:00 +02001058 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +02001060 return sprintf(buf, "%ld\n", (long) data->sens[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
1063static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001064store_temp_type(struct device *dev, struct device_attribute *devattr,
1065 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
Jim Cromie07584c72007-10-12 21:08:00 +02001067 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +02001068 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 u32 val, tmp;
1070
1071 val = simple_strtoul(buf, NULL, 10);
1072
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001073 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 switch (val) {
1076 case 1: /* PII/Celeron diode */
Jean Delvare787c72b2007-05-08 17:22:00 +02001077 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1078 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001079 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +02001080 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
1081 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +02001082 tmp | BIT_SCFG2[nr]);
1083 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 break;
1085 case 2: /* 3904 */
Jean Delvare787c72b2007-05-08 17:22:00 +02001086 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1087 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001088 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +02001089 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
1090 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +02001091 tmp & ~BIT_SCFG2[nr]);
1092 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
Jean Delvareb26f9332007-08-16 14:30:01 +02001094 case W83781D_DEFAULT_BETA:
1095 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
1096 "instead\n", W83781D_DEFAULT_BETA);
1097 /* fall through */
1098 case 4: /* thermistor */
Jean Delvare787c72b2007-05-08 17:22:00 +02001099 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1100 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001101 tmp & ~BIT_SCFG1[nr]);
1102 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 break;
1104 default:
Jean Delvare787c72b2007-05-08 17:22:00 +02001105 dev_err(dev,
Jean Delvareb26f9332007-08-16 14:30:01 +02001106 "Invalid sensor type %ld; must be 1, 2, or 4\n",
1107 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 break;
1109 }
1110
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001111 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return count;
1113}
1114
Jim Cromie07584c72007-10-12 21:08:00 +02001115#define sysfs_temp_type(offset) \
1116static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
1117 show_temp_type, store_temp_type, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Jim Cromie07584c72007-10-12 21:08:00 +02001119sysfs_temp_type(1);
1120sysfs_temp_type(2);
1121sysfs_temp_type(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
Jim Cromie07584c72007-10-12 21:08:00 +02001123static ssize_t
1124show_name(struct device *dev, struct device_attribute *devattr, char *buf)
Jean Delvare787c72b2007-05-08 17:22:00 +02001125{
1126 struct w83627hf_data *data = dev_get_drvdata(dev);
1127
1128 return sprintf(buf, "%s\n", data->name);
1129}
1130static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1131
1132static int __init w83627hf_find(int sioaddr, unsigned short *addr,
1133 struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Jean Delvared27c37c2007-05-08 17:21:59 +02001135 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 u16 val;
1137
Jean Delvare787c72b2007-05-08 17:22:00 +02001138 static const __initdata char *names[] = {
1139 "W83627HF",
1140 "W83627THF",
1141 "W83697HF",
1142 "W83637HF",
1143 "W83687THF",
1144 };
1145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 REG = sioaddr;
1147 VAL = sioaddr + 1;
1148
1149 superio_enter();
Jean Delvare67b671b2007-12-06 23:13:42 +01001150 val = force_id ? force_id : superio_inb(DEVID);
Jean Delvare787c72b2007-05-08 17:22:00 +02001151 switch (val) {
1152 case W627_DEVID:
1153 sio_data->type = w83627hf;
1154 break;
1155 case W627THF_DEVID:
1156 sio_data->type = w83627thf;
1157 break;
1158 case W697_DEVID:
1159 sio_data->type = w83697hf;
1160 break;
1161 case W637_DEVID:
1162 sio_data->type = w83637hf;
1163 break;
1164 case W687THF_DEVID:
1165 sio_data->type = w83687thf;
1166 break;
Jean Delvaree142e2a2007-05-27 22:17:43 +02001167 case 0xff: /* No device at all */
1168 goto exit;
Jean Delvare787c72b2007-05-08 17:22:00 +02001169 default:
Jean Delvaree142e2a2007-05-27 22:17:43 +02001170 pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
Jean Delvared27c37c2007-05-08 17:21:59 +02001171 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
1174 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +02001175 force_addr &= WINB_ALIGNMENT;
1176 if (force_addr) {
1177 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1178 force_addr);
1179 superio_outb(WINB_BASE_REG, force_addr >> 8);
1180 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 val = (superio_inb(WINB_BASE_REG) << 8) |
1183 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001184 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +02001185 if (*addr == 0) {
1186 printk(KERN_WARNING DRVNAME ": Base address not set, "
1187 "skipping\n");
1188 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
Jean Delvared27c37c2007-05-08 17:21:59 +02001191 val = superio_inb(WINB_ACT_REG);
1192 if (!(val & 0x01)) {
1193 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1194 superio_outb(WINB_ACT_REG, val | 0x01);
1195 }
1196
1197 err = 0;
Jean Delvare787c72b2007-05-08 17:22:00 +02001198 pr_info(DRVNAME ": Found %s chip at %#x\n",
1199 names[sio_data->type], *addr);
Jean Delvared27c37c2007-05-08 17:21:59 +02001200
1201 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +02001203 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204}
1205
Jim Cromie07584c72007-10-12 21:08:00 +02001206#define VIN_UNIT_ATTRS(_X_) \
1207 &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
1208 &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001209 &sensor_dev_attr_in##_X_##_max.dev_attr.attr, \
1210 &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr, \
1211 &sensor_dev_attr_in##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001212
1213#define FAN_UNIT_ATTRS(_X_) \
1214 &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
1215 &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001216 &sensor_dev_attr_fan##_X_##_div.dev_attr.attr, \
1217 &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr, \
1218 &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001219
1220#define TEMP_UNIT_ATTRS(_X_) \
1221 &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
1222 &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
1223 &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001224 &sensor_dev_attr_temp##_X_##_type.dev_attr.attr, \
1225 &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \
1226 &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001227
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001228static struct attribute *w83627hf_attributes[] = {
1229 &dev_attr_in0_input.attr,
1230 &dev_attr_in0_min.attr,
1231 &dev_attr_in0_max.attr,
Jean Delvaree3604c62008-01-03 23:00:30 +01001232 &sensor_dev_attr_in0_alarm.dev_attr.attr,
1233 &sensor_dev_attr_in0_beep.dev_attr.attr,
Jim Cromie07584c72007-10-12 21:08:00 +02001234 VIN_UNIT_ATTRS(2),
1235 VIN_UNIT_ATTRS(3),
1236 VIN_UNIT_ATTRS(4),
1237 VIN_UNIT_ATTRS(7),
1238 VIN_UNIT_ATTRS(8),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001239
Jim Cromie07584c72007-10-12 21:08:00 +02001240 FAN_UNIT_ATTRS(1),
1241 FAN_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001242
Jim Cromie07584c72007-10-12 21:08:00 +02001243 TEMP_UNIT_ATTRS(1),
1244 TEMP_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001245
1246 &dev_attr_alarms.attr,
Jean Delvare1c138102008-01-03 23:04:55 +01001247 &sensor_dev_attr_beep_enable.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001248 &dev_attr_beep_mask.attr,
1249
Jim Cromie07584c72007-10-12 21:08:00 +02001250 &sensor_dev_attr_pwm1.dev_attr.attr,
1251 &sensor_dev_attr_pwm2.dev_attr.attr,
Jean Delvare787c72b2007-05-08 17:22:00 +02001252 &dev_attr_name.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001253 NULL
1254};
1255
1256static const struct attribute_group w83627hf_group = {
1257 .attrs = w83627hf_attributes,
1258};
1259
1260static struct attribute *w83627hf_attributes_opt[] = {
Jim Cromie07584c72007-10-12 21:08:00 +02001261 VIN_UNIT_ATTRS(1),
1262 VIN_UNIT_ATTRS(5),
1263 VIN_UNIT_ATTRS(6),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001264
Jim Cromie07584c72007-10-12 21:08:00 +02001265 FAN_UNIT_ATTRS(3),
1266 TEMP_UNIT_ATTRS(3),
1267 &sensor_dev_attr_pwm3.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001268
Jim Cromie07584c72007-10-12 21:08:00 +02001269 &sensor_dev_attr_pwm1_freq.dev_attr.attr,
1270 &sensor_dev_attr_pwm2_freq.dev_attr.attr,
1271 &sensor_dev_attr_pwm3_freq.dev_attr.attr,
Dominik Geyera95a5ed2008-08-06 22:41:04 +02001272
1273 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
1274 &sensor_dev_attr_pwm2_enable.dev_attr.attr,
1275 &sensor_dev_attr_pwm3_enable.dev_attr.attr,
1276
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001277 NULL
1278};
1279
1280static const struct attribute_group w83627hf_group_opt = {
1281 .attrs = w83627hf_attributes_opt,
1282};
1283
Jean Delvare787c72b2007-05-08 17:22:00 +02001284static int __devinit w83627hf_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
Jean Delvare787c72b2007-05-08 17:22:00 +02001286 struct device *dev = &pdev->dev;
1287 struct w83627hf_sio_data *sio_data = dev->platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 struct w83627hf_data *data;
Jean Delvare787c72b2007-05-08 17:22:00 +02001289 struct resource *res;
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001290 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
Jean Delvare787c72b2007-05-08 17:22:00 +02001292 static const char *names[] = {
1293 "w83627hf",
1294 "w83627thf",
1295 "w83697hf",
1296 "w83637hf",
1297 "w83687thf",
1298 };
1299
1300 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1301 if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1302 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1303 (unsigned long)res->start,
1304 (unsigned long)(res->start + WINB_REGION_SIZE - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 err = -EBUSY;
1306 goto ERROR0;
1307 }
1308
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001309 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 err = -ENOMEM;
1311 goto ERROR1;
1312 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001313 data->addr = res->start;
1314 data->type = sio_data->type;
1315 data->name = names[sio_data->type];
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001316 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001317 mutex_init(&data->update_lock);
Jean Delvare787c72b2007-05-08 17:22:00 +02001318 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 /* Initialize the chip */
Jean Delvare787c72b2007-05-08 17:22:00 +02001321 w83627hf_init_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323 /* A few vars need to be filled upon startup */
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001324 for (i = 0; i <= 2; i++)
1325 data->fan_min[i] = w83627hf_read_value(
1326 data, W83627HF_REG_FAN_MIN(i));
Jean Delvarec09c5182007-10-12 21:53:07 +02001327 w83627hf_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001329 /* Register common device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001330 if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001331 goto ERROR3;
1332
1333 /* Register chip-specific device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001334 if (data->type == w83627hf || data->type == w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001335 if ((err = device_create_file(dev,
1336 &sensor_dev_attr_in5_input.dev_attr))
1337 || (err = device_create_file(dev,
1338 &sensor_dev_attr_in5_min.dev_attr))
1339 || (err = device_create_file(dev,
1340 &sensor_dev_attr_in5_max.dev_attr))
1341 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001342 &sensor_dev_attr_in5_alarm.dev_attr))
1343 || (err = device_create_file(dev,
1344 &sensor_dev_attr_in5_beep.dev_attr))
1345 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001346 &sensor_dev_attr_in6_input.dev_attr))
1347 || (err = device_create_file(dev,
1348 &sensor_dev_attr_in6_min.dev_attr))
1349 || (err = device_create_file(dev,
1350 &sensor_dev_attr_in6_max.dev_attr))
1351 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001352 &sensor_dev_attr_in6_alarm.dev_attr))
1353 || (err = device_create_file(dev,
1354 &sensor_dev_attr_in6_beep.dev_attr))
1355 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001356 &sensor_dev_attr_pwm1_freq.dev_attr))
1357 || (err = device_create_file(dev,
1358 &sensor_dev_attr_pwm2_freq.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001359 goto ERROR4;
1360
Jean Delvare787c72b2007-05-08 17:22:00 +02001361 if (data->type != w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001362 if ((err = device_create_file(dev,
1363 &sensor_dev_attr_in1_input.dev_attr))
1364 || (err = device_create_file(dev,
1365 &sensor_dev_attr_in1_min.dev_attr))
1366 || (err = device_create_file(dev,
1367 &sensor_dev_attr_in1_max.dev_attr))
1368 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001369 &sensor_dev_attr_in1_alarm.dev_attr))
1370 || (err = device_create_file(dev,
1371 &sensor_dev_attr_in1_beep.dev_attr))
1372 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001373 &sensor_dev_attr_fan3_input.dev_attr))
1374 || (err = device_create_file(dev,
1375 &sensor_dev_attr_fan3_min.dev_attr))
1376 || (err = device_create_file(dev,
1377 &sensor_dev_attr_fan3_div.dev_attr))
1378 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001379 &sensor_dev_attr_fan3_alarm.dev_attr))
1380 || (err = device_create_file(dev,
1381 &sensor_dev_attr_fan3_beep.dev_attr))
1382 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001383 &sensor_dev_attr_temp3_input.dev_attr))
1384 || (err = device_create_file(dev,
1385 &sensor_dev_attr_temp3_max.dev_attr))
1386 || (err = device_create_file(dev,
1387 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1388 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001389 &sensor_dev_attr_temp3_alarm.dev_attr))
1390 || (err = device_create_file(dev,
1391 &sensor_dev_attr_temp3_beep.dev_attr))
1392 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001393 &sensor_dev_attr_temp3_type.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001394 goto ERROR4;
1395
Jean Delvare787c72b2007-05-08 17:22:00 +02001396 if (data->type != w83697hf && data->vid != 0xff) {
Jean Delvare8a665a02007-05-08 17:21:59 +02001397 /* Convert VID to voltage based on VRM */
1398 data->vrm = vid_which_vrm();
1399
Jean Delvare787c72b2007-05-08 17:22:00 +02001400 if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1401 || (err = device_create_file(dev, &dev_attr_vrm)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001402 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001403 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001404
Jean Delvare787c72b2007-05-08 17:22:00 +02001405 if (data->type == w83627thf || data->type == w83637hf
1406 || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001407 if ((err = device_create_file(dev,
1408 &sensor_dev_attr_pwm3.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001409 goto ERROR4;
1410
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001411 if (data->type == w83637hf || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001412 if ((err = device_create_file(dev,
1413 &sensor_dev_attr_pwm1_freq.dev_attr))
1414 || (err = device_create_file(dev,
1415 &sensor_dev_attr_pwm2_freq.dev_attr))
1416 || (err = device_create_file(dev,
1417 &sensor_dev_attr_pwm3_freq.dev_attr)))
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001418 goto ERROR4;
1419
Dominik Geyera95a5ed2008-08-06 22:41:04 +02001420 if (data->type != w83627hf)
1421 if ((err = device_create_file(dev,
1422 &sensor_dev_attr_pwm1_enable.dev_attr))
1423 || (err = device_create_file(dev,
1424 &sensor_dev_attr_pwm2_enable.dev_attr)))
1425 goto ERROR4;
1426
1427 if (data->type == w83627thf || data->type == w83637hf
1428 || data->type == w83687thf)
1429 if ((err = device_create_file(dev,
1430 &sensor_dev_attr_pwm3_enable.dev_attr)))
1431 goto ERROR4;
1432
Tony Jones1beeffe2007-08-20 13:46:20 -07001433 data->hwmon_dev = hwmon_device_register(dev);
1434 if (IS_ERR(data->hwmon_dev)) {
1435 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001436 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001437 }
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 return 0;
1440
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001441 ERROR4:
Jean Delvare787c72b2007-05-08 17:22:00 +02001442 sysfs_remove_group(&dev->kobj, &w83627hf_group);
1443 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001444 ERROR3:
Jean Delvare04a62172007-06-12 13:57:19 +02001445 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 kfree(data);
1447 ERROR1:
Jean Delvare787c72b2007-05-08 17:22:00 +02001448 release_region(res->start, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 ERROR0:
1450 return err;
1451}
1452
Jean Delvare787c72b2007-05-08 17:22:00 +02001453static int __devexit w83627hf_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
Jean Delvare787c72b2007-05-08 17:22:00 +02001455 struct w83627hf_data *data = platform_get_drvdata(pdev);
1456 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Tony Jones1beeffe2007-08-20 13:46:20 -07001458 hwmon_device_unregister(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001459
Jean Delvare787c72b2007-05-08 17:22:00 +02001460 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1461 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
Jean Delvare04a62172007-06-12 13:57:19 +02001462 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001463 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Jean Delvare787c72b2007-05-08 17:22:00 +02001465 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1466 release_region(res->start, WINB_REGION_SIZE);
1467
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 return 0;
1469}
1470
1471
Jean Delvared58df9c2007-10-10 16:30:23 +02001472/* Registers 0x50-0x5f are banked */
1473static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
1474{
1475 if ((reg & 0x00f0) == 0x50) {
1476 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1477 outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
1478 }
1479}
1480
1481/* Not strictly necessary, but play it safe for now */
1482static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
1483{
1484 if (reg & 0xff00) {
1485 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1486 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
1487 }
1488}
1489
Jean Delvare787c72b2007-05-08 17:22:00 +02001490static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 int res, word_sized;
1493
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001494 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 word_sized = (((reg & 0xff00) == 0x100)
1496 || ((reg & 0xff00) == 0x200))
1497 && (((reg & 0x00ff) == 0x50)
1498 || ((reg & 0x00ff) == 0x53)
1499 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001500 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001501 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1502 res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (word_sized) {
1504 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001505 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 res =
Jean Delvare787c72b2007-05-08 17:22:00 +02001507 (res << 8) + inb_p(data->addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 W83781D_DATA_REG_OFFSET);
1509 }
Jean Delvared58df9c2007-10-10 16:30:23 +02001510 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001511 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return res;
1513}
1514
Jean Delvare787c72b2007-05-08 17:22:00 +02001515static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 int res = 0xff, sel;
1518
1519 superio_enter();
1520 superio_select(W83627HF_LD_GPIO5);
1521
1522 /* Make sure these GPIO pins are enabled */
1523 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001524 dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 goto exit;
1526 }
1527
1528 /* Make sure the pins are configured for input
1529 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001530 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if ((sel & 0x1f) != 0x1f) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001532 dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 "function\n");
1534 goto exit;
1535 }
1536
Jean Delvare787c72b2007-05-08 17:22:00 +02001537 dev_info(&pdev->dev, "Reading VID from GPIO5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1539
1540exit:
1541 superio_exit();
1542 return res;
1543}
1544
Jean Delvare787c72b2007-05-08 17:22:00 +02001545static int __devinit w83687thf_read_vid(struct platform_device *pdev)
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001546{
1547 int res = 0xff;
1548
1549 superio_enter();
1550 superio_select(W83627HF_LD_HWM);
1551
1552 /* Make sure these GPIO pins are enabled */
1553 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001554 dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001555 goto exit;
1556 }
1557
1558 /* Make sure the pins are configured for input */
1559 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001560 dev_dbg(&pdev->dev, "VID configured as output, "
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001561 "no VID function\n");
1562 goto exit;
1563 }
1564
1565 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1566
1567exit:
1568 superio_exit();
1569 return res;
1570}
1571
Jean Delvare787c72b2007-05-08 17:22:00 +02001572static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 int word_sized;
1575
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001576 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 word_sized = (((reg & 0xff00) == 0x100)
1578 || ((reg & 0xff00) == 0x200))
1579 && (((reg & 0x00ff) == 0x53)
1580 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001581 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001582 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 if (word_sized) {
1584 outb_p(value >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001585 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001587 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 }
1589 outb_p(value & 0xff,
Jean Delvare787c72b2007-05-08 17:22:00 +02001590 data->addr + W83781D_DATA_REG_OFFSET);
Jean Delvared58df9c2007-10-10 16:30:23 +02001591 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001592 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 return 0;
1594}
1595
Jean Delvare787c72b2007-05-08 17:22:00 +02001596static void __devinit w83627hf_init_device(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
Jean Delvare787c72b2007-05-08 17:22:00 +02001598 struct w83627hf_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001600 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 u8 tmp;
1602
Jean Delvare2251cf12005-09-04 22:52:17 +02001603 if (reset) {
1604 /* Resetting the chip has been the default for a long time,
1605 but repeatedly caused problems (fans going to full
1606 speed...) so it is now optional. It might even go away if
1607 nobody reports it as being useful, as I see very little
1608 reason why this would be needed at all. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001609 dev_info(&pdev->dev, "If reset=1 solved a problem you were "
Jean Delvare2251cf12005-09-04 22:52:17 +02001610 "having, please report!\n");
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 /* save this register */
Jean Delvare787c72b2007-05-08 17:22:00 +02001613 i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 /* Reset all except Watchdog values and last conversion values
1615 This sets fan-divs to 2, among others */
Jean Delvare787c72b2007-05-08 17:22:00 +02001616 w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 /* Restore the register and disable power-on abnormal beep.
1618 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001619 w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 /* Disable master beep-enable (reset turns it on).
1621 Individual beeps should be reset to off but for some reason
1622 disabling this bit helps some people not get beeped */
Jean Delvare787c72b2007-05-08 17:22:00 +02001623 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 }
1625
1626 /* Minimize conflicts with other winbond i2c-only clients... */
1627 /* disable i2c subclients... how to disable main i2c client?? */
1628 /* force i2c address to relatively uncommon address */
Jean Delvare787c72b2007-05-08 17:22:00 +02001629 w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1630 w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001633 if (type == w83627hf || type == w83637hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001634 int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1635 int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001637 } else if (type == w83627thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001638 data->vid = w83627thf_read_gpio5(pdev);
Jean Delvared27c37c2007-05-08 17:21:59 +02001639 } else if (type == w83687thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001640 data->vid = w83687thf_read_vid(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 }
1642
1643 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001644 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 data->vrm_ovt =
Jean Delvare787c72b2007-05-08 17:22:00 +02001646 w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 }
1648
Jean Delvare787c72b2007-05-08 17:22:00 +02001649 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 for (i = 1; i <= 3; i++) {
1651 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001652 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 } else {
1654 if (w83627hf_read_value
Jean Delvare787c72b2007-05-08 17:22:00 +02001655 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1657 data->sens[i - 1] = 1;
1658 else
1659 data->sens[i - 1] = 2;
1660 }
1661 if ((type == w83697hf) && (i == 2))
1662 break;
1663 }
1664
1665 if(init) {
1666 /* Enable temp2 */
Jim Cromiedf48ed82007-10-14 17:10:52 -06001667 tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001669 dev_warn(&pdev->dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 "might not make sense\n");
Jim Cromiedf48ed82007-10-14 17:10:52 -06001671 w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 tmp & 0xfe);
1673 }
1674
1675 /* Enable temp3 */
1676 if (type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001677 tmp = w83627hf_read_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001678 W83627HF_REG_TEMP3_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001680 dev_warn(&pdev->dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 "readings might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001682 w83627hf_write_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001683 W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
1685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
1687
1688 /* Start monitoring */
Jean Delvare787c72b2007-05-08 17:22:00 +02001689 w83627hf_write_value(data, W83781D_REG_CONFIG,
1690 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 W83781D_REG_CONFIG) & 0xf7)
1692 | 0x01);
Jean Delvareef878b12008-01-03 22:54:13 +01001693
1694 /* Enable VBAT monitoring if needed */
1695 tmp = w83627hf_read_value(data, W83781D_REG_VBAT);
1696 if (!(tmp & 0x01))
1697 w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698}
1699
Jean Delvarec09c5182007-10-12 21:53:07 +02001700static void w83627hf_update_fan_div(struct w83627hf_data *data)
1701{
1702 int reg;
1703
1704 reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1705 data->fan_div[0] = (reg >> 4) & 0x03;
1706 data->fan_div[1] = (reg >> 6) & 0x03;
1707 if (data->type != w83697hf) {
1708 data->fan_div[2] = (w83627hf_read_value(data,
1709 W83781D_REG_PIN) >> 6) & 0x03;
1710 }
1711 reg = w83627hf_read_value(data, W83781D_REG_VBAT);
1712 data->fan_div[0] |= (reg >> 3) & 0x04;
1713 data->fan_div[1] |= (reg >> 4) & 0x04;
1714 if (data->type != w83697hf)
1715 data->fan_div[2] |= (reg >> 5) & 0x04;
1716}
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1719{
Jean Delvare787c72b2007-05-08 17:22:00 +02001720 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -06001721 int i, num_temps = (data->type == w83697hf) ? 2 : 3;
Dominik Geyera95a5ed2008-08-06 22:41:04 +02001722 int num_pwms = (data->type == w83697hf) ? 2 : 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001724 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1727 || !data->valid) {
1728 for (i = 0; i <= 8; i++) {
1729 /* skip missing sensors */
1730 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001731 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001732 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 continue;
1734 data->in[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001735 w83627hf_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 data->in_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001737 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 W83781D_REG_IN_MIN(i));
1739 data->in_max[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001740 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 W83781D_REG_IN_MAX(i));
1742 }
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001743 for (i = 0; i <= 2; i++) {
1744 data->fan[i] =
1745 w83627hf_read_value(data, W83627HF_REG_FAN(i));
1746 data->fan_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001747 w83627hf_read_value(data,
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001748 W83627HF_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
Jim Cromie07584c72007-10-12 21:08:00 +02001750 for (i = 0; i <= 2; i++) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001751 u8 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 W836X7HF_REG_PWM(data->type, i));
1753 /* bits 0-3 are reserved in 627THF */
1754 if (data->type == w83627thf)
1755 tmp &= 0xf0;
Jim Cromie07584c72007-10-12 21:08:00 +02001756 data->pwm[i] = tmp;
1757 if (i == 1 &&
1758 (data->type == w83627hf || data->type == w83697hf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 break;
1760 }
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001761 if (data->type == w83627hf) {
1762 u8 tmp = w83627hf_read_value(data,
1763 W83627HF_REG_PWM_FREQ);
1764 data->pwm_freq[0] = tmp & 0x07;
1765 data->pwm_freq[1] = (tmp >> 4) & 0x07;
1766 } else if (data->type != w83627thf) {
1767 for (i = 1; i <= 3; i++) {
1768 data->pwm_freq[i - 1] =
1769 w83627hf_read_value(data,
1770 W83637HF_REG_PWM_FREQ[i - 1]);
1771 if (i == 2 && (data->type == w83697hf))
1772 break;
1773 }
1774 }
Dominik Geyera95a5ed2008-08-06 22:41:04 +02001775 if (data->type != w83627hf) {
1776 for (i = 0; i < num_pwms; i++) {
1777 u8 tmp = w83627hf_read_value(data,
1778 W83627THF_REG_PWM_ENABLE[i]);
1779 data->pwm_enable[i] =
1780 ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i])
1781 & 0x03) + 1;
1782 }
1783 }
Jim Cromiedf48ed82007-10-14 17:10:52 -06001784 for (i = 0; i < num_temps; i++) {
1785 data->temp[i] = w83627hf_read_value(
1786 data, w83627hf_reg_temp[i]);
1787 data->temp_max[i] = w83627hf_read_value(
1788 data, w83627hf_reg_temp_over[i]);
1789 data->temp_max_hyst[i] = w83627hf_read_value(
1790 data, w83627hf_reg_temp_hyst[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
1792
Jean Delvarec09c5182007-10-12 21:53:07 +02001793 w83627hf_update_fan_div(data);
1794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 data->alarms =
Jean Delvare787c72b2007-05-08 17:22:00 +02001796 w83627hf_read_value(data, W83781D_REG_ALARM1) |
1797 (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1798 (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1799 i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
Jean Delvare1c138102008-01-03 23:04:55 +01001800 data->beep_mask = (i << 8) |
Jean Delvare787c72b2007-05-08 17:22:00 +02001801 w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1802 w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 data->last_updated = jiffies;
1804 data->valid = 1;
1805 }
1806
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001807 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809 return data;
1810}
1811
Jean Delvare787c72b2007-05-08 17:22:00 +02001812static int __init w83627hf_device_add(unsigned short address,
1813 const struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
Jean Delvare787c72b2007-05-08 17:22:00 +02001815 struct resource res = {
1816 .start = address + WINB_REGION_OFFSET,
1817 .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1818 .name = DRVNAME,
1819 .flags = IORESOURCE_IO,
1820 };
1821 int err;
1822
1823 pdev = platform_device_alloc(DRVNAME, address);
1824 if (!pdev) {
1825 err = -ENOMEM;
1826 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1827 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Jean Delvare787c72b2007-05-08 17:22:00 +02001830 err = platform_device_add_resources(pdev, &res, 1);
1831 if (err) {
1832 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1833 "(%d)\n", err);
1834 goto exit_device_put;
1835 }
1836
Jean Delvare2df6d812007-06-09 10:11:16 -04001837 err = platform_device_add_data(pdev, sio_data,
1838 sizeof(struct w83627hf_sio_data));
1839 if (err) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001840 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1841 goto exit_device_put;
1842 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001843
1844 err = platform_device_add(pdev);
1845 if (err) {
1846 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1847 err);
1848 goto exit_device_put;
1849 }
1850
1851 return 0;
1852
1853exit_device_put:
1854 platform_device_put(pdev);
1855exit:
1856 return err;
1857}
1858
1859static int __init sensors_w83627hf_init(void)
1860{
1861 int err;
1862 unsigned short address;
1863 struct w83627hf_sio_data sio_data;
1864
1865 if (w83627hf_find(0x2e, &address, &sio_data)
1866 && w83627hf_find(0x4e, &address, &sio_data))
1867 return -ENODEV;
1868
1869 err = platform_driver_register(&w83627hf_driver);
1870 if (err)
1871 goto exit;
1872
1873 /* Sets global pdev as a side effect */
1874 err = w83627hf_device_add(address, &sio_data);
1875 if (err)
1876 goto exit_driver;
1877
1878 return 0;
1879
1880exit_driver:
1881 platform_driver_unregister(&w83627hf_driver);
1882exit:
1883 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884}
1885
1886static void __exit sensors_w83627hf_exit(void)
1887{
Jean Delvare787c72b2007-05-08 17:22:00 +02001888 platform_device_unregister(pdev);
1889 platform_driver_unregister(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890}
1891
1892MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1893 "Philip Edelbrock <phil@netroedge.com>, "
1894 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1895MODULE_DESCRIPTION("W83627HF driver");
1896MODULE_LICENSE("GPL");
1897
1898module_init(sensors_w83627hf_init);
1899module_exit(sensors_w83627hf_exit);