blob: 181f4e8590b1cc3eaf5a21dd01fa1b9e9bfa87ae [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
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) ? \
Jim Cromie07584c72007-10-12 21:08:00 +0200222 regpwm_627hf[nr] : regpwm[nr])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400224#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
225
226#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
227#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
228#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
229
230static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
231 W83637HF_REG_PWM_FREQ2,
232 W83637HF_REG_PWM_FREQ3 };
233
234#define W83627HF_BASE_PWM_FREQ 46870
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#define W83781D_REG_I2C_ADDR 0x48
237#define W83781D_REG_I2C_SUBADDR 0x4A
238
239/* Sensor selection */
240#define W83781D_REG_SCFG1 0x5D
241static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
242#define W83781D_REG_SCFG2 0x59
243static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
244#define W83781D_DEFAULT_BETA 3435
245
246/* Conversions. Limit checking is only done on the TO_REG
247 variants. Note that you should be a bit careful with which arguments
248 these macros are called: arguments may be evaluated more than once.
249 Fixing this is just not worth it. */
250#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
251#define IN_FROM_REG(val) ((val) * 16)
252
253static inline u8 FAN_TO_REG(long rpm, int div)
254{
255 if (rpm == 0)
256 return 255;
257 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
258 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
259 254);
260}
261
262#define TEMP_MIN (-128000)
263#define TEMP_MAX ( 127000)
264
265/* TEMP: 0.001C/bit (-128C to +127C)
266 REG: 1C/bit, two's complement */
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200267static u8 TEMP_TO_REG(long temp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
269 int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
270 ntemp += (ntemp<0 ? -500 : 500);
271 return (u8)(ntemp / 1000);
272}
273
274static int TEMP_FROM_REG(u8 reg)
275{
276 return (s8)reg * 1000;
277}
278
279#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
280
281#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
282
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400283static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
284{
285 unsigned long freq;
286 freq = W83627HF_BASE_PWM_FREQ >> reg;
287 return freq;
288}
289static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
290{
291 u8 i;
292 /* Only 5 dividers (1 2 4 8 16)
293 Search for the nearest available frequency */
294 for (i = 0; i < 4; i++) {
295 if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
296 (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
297 break;
298 }
299 return i;
300}
301
302static inline unsigned long pwm_freq_from_reg(u8 reg)
303{
304 /* Clock bit 8 -> 180 kHz or 24 MHz */
305 unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
306
307 reg &= 0x7f;
308 /* This should not happen but anyway... */
309 if (reg == 0)
310 reg++;
311 return (clock / (reg << 8));
312}
313static inline u8 pwm_freq_to_reg(unsigned long val)
314{
315 /* Minimum divider value is 0x01 and maximum is 0x7F */
316 if (val >= 93750) /* The highest we can do */
317 return 0x01;
318 if (val >= 720) /* Use 24 MHz clock */
319 return (24000000UL / (val << 8));
320 if (val < 6) /* The lowest we can do */
321 return 0xFF;
322 else /* Use 180 kHz clock */
323 return (0x80 | (180000UL / (val << 8)));
324}
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define BEEP_MASK_FROM_REG(val) (val)
327#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
328#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
329#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
330
331#define DIV_FROM_REG(val) (1 << (val))
332
333static inline u8 DIV_TO_REG(long val)
334{
335 int i;
336 val = SENSORS_LIMIT(val, 1, 128) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000337 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (val == 0)
339 break;
340 val >>= 1;
341 }
342 return ((u8) i);
343}
344
Jean Delvareed6bafb2007-02-14 21:15:03 +0100345/* For each registered chip, we need to keep some data in memory.
346 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347struct w83627hf_data {
Jean Delvare787c72b2007-05-08 17:22:00 +0200348 unsigned short addr;
349 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700350 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100351 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 enum chips type;
353
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100354 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 char valid; /* !=0 if following fields are valid */
356 unsigned long last_updated; /* In jiffies */
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 u8 in[9]; /* Register value */
359 u8 in_max[9]; /* Register value */
360 u8 in_min[9]; /* Register value */
361 u8 fan[3]; /* Register value */
362 u8 fan_min[3]; /* Register value */
Jim Cromiedf48ed82007-10-14 17:10:52 -0600363 u16 temp[3]; /* Register value */
364 u16 temp_max[3]; /* Register value */
365 u16 temp_max_hyst[3]; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 u8 fan_div[3]; /* Register encoding, shifted right */
367 u8 vid; /* Register encoding, combined */
368 u32 alarms; /* Register encoding, combined */
369 u32 beep_mask; /* Register encoding, combined */
370 u8 beep_enable; /* Boolean */
371 u8 pwm[3]; /* Register value */
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400372 u8 pwm_freq[3]; /* Register value */
Jean Delvareb26f9332007-08-16 14:30:01 +0200373 u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
374 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 u8 vrm;
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100376 u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377};
378
Jean Delvare787c72b2007-05-08 17:22:00 +0200379struct w83627hf_sio_data {
380 enum chips type;
381};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Jean Delvare787c72b2007-05-08 17:22:00 +0200384static int w83627hf_probe(struct platform_device *pdev);
Jean Delvared0546122007-07-22 12:09:48 +0200385static int __devexit w83627hf_remove(struct platform_device *pdev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200386
387static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
388static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
Jean Delvarec09c5182007-10-12 21:53:07 +0200389static void w83627hf_update_fan_div(struct w83627hf_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390static struct w83627hf_data *w83627hf_update_device(struct device *dev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200391static void w83627hf_init_device(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Jean Delvare787c72b2007-05-08 17:22:00 +0200393static struct platform_driver w83627hf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100394 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200395 .owner = THIS_MODULE,
Jean Delvared27c37c2007-05-08 17:21:59 +0200396 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100397 },
Jean Delvare787c72b2007-05-08 17:22:00 +0200398 .probe = w83627hf_probe,
399 .remove = __devexit_p(w83627hf_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400};
401
Jim Cromie07584c72007-10-12 21:08:00 +0200402static ssize_t
403show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
404{
405 int nr = to_sensor_dev_attr(devattr)->index;
406 struct w83627hf_data *data = w83627hf_update_device(dev);
407 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408}
Jim Cromie07584c72007-10-12 21:08:00 +0200409static ssize_t
410show_in_min(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_min[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
Jim Cromie07584c72007-10-12 21:08:00 +0200416static ssize_t
417show_in_max(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_max[nr]));
422}
423static ssize_t
424store_in_min(struct device *dev, struct device_attribute *devattr,
425 const char *buf, size_t count)
426{
427 int nr = to_sensor_dev_attr(devattr)->index;
428 struct w83627hf_data *data = dev_get_drvdata(dev);
429 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Jim Cromie07584c72007-10-12 21:08:00 +0200431 mutex_lock(&data->update_lock);
432 data->in_min[nr] = IN_TO_REG(val);
433 w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
434 mutex_unlock(&data->update_lock);
435 return count;
436}
437static ssize_t
438store_in_max(struct device *dev, struct device_attribute *devattr,
439 const char *buf, size_t count)
440{
441 int nr = to_sensor_dev_attr(devattr)->index;
442 struct w83627hf_data *data = dev_get_drvdata(dev);
443 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Jim Cromie07584c72007-10-12 21:08:00 +0200445 mutex_lock(&data->update_lock);
446 data->in_max[nr] = IN_TO_REG(val);
447 w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
448 mutex_unlock(&data->update_lock);
449 return count;
450}
451#define sysfs_vin_decl(offset) \
452static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
453 show_in_input, NULL, offset); \
454static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
455 show_in_min, store_in_min, offset); \
456static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
457 show_in_max, store_in_max, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Jim Cromie07584c72007-10-12 21:08:00 +0200459sysfs_vin_decl(1);
460sysfs_vin_decl(2);
461sysfs_vin_decl(3);
462sysfs_vin_decl(4);
463sysfs_vin_decl(5);
464sysfs_vin_decl(6);
465sysfs_vin_decl(7);
466sysfs_vin_decl(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468/* use a different set of functions for in0 */
469static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
470{
471 long in0;
472
473 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100474 (w83627thf == data->type || w83637hf == data->type
475 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 /* use VRM9 calculation */
478 in0 = (long)((reg * 488 + 70000 + 50) / 100);
479 else
480 /* use VRM8 (standard) calculation */
481 in0 = (long)IN_FROM_REG(reg);
482
483 return sprintf(buf,"%ld\n", in0);
484}
485
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400486static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct w83627hf_data *data = w83627hf_update_device(dev);
489 return show_in_0(data, buf, data->in[0]);
490}
491
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400492static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct w83627hf_data *data = w83627hf_update_device(dev);
495 return show_in_0(data, buf, data->in_min[0]);
496}
497
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400498static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct w83627hf_data *data = w83627hf_update_device(dev);
501 return show_in_0(data, buf, data->in_max[0]);
502}
503
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400504static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 const char *buf, size_t count)
506{
Jean Delvare787c72b2007-05-08 17:22:00 +0200507 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 u32 val;
509
510 val = simple_strtoul(buf, NULL, 10);
511
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100512 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100515 (w83627thf == data->type || w83637hf == data->type
516 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800519 data->in_min[0] =
520 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
521 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 else
523 /* use VRM8 (standard) calculation */
524 data->in_min[0] = IN_TO_REG(val);
525
Jean Delvare787c72b2007-05-08 17:22:00 +0200526 w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100527 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 return count;
529}
530
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400531static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 const char *buf, size_t count)
533{
Jean Delvare787c72b2007-05-08 17:22:00 +0200534 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 u32 val;
536
537 val = simple_strtoul(buf, NULL, 10);
538
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100539 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100542 (w83627thf == data->type || w83637hf == data->type
543 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800546 data->in_max[0] =
547 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
548 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 else
550 /* use VRM8 (standard) calculation */
551 data->in_max[0] = IN_TO_REG(val);
552
Jean Delvare787c72b2007-05-08 17:22:00 +0200553 w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100554 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return count;
556}
557
558static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
559static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
560 show_regs_in_min0, store_regs_in_min0);
561static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
562 show_regs_in_max0, store_regs_in_max0);
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200565show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Jim Cromie07584c72007-10-12 21:08:00 +0200567 int nr = to_sensor_dev_attr(devattr)->index;
568 struct w83627hf_data *data = w83627hf_update_device(dev);
569 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
570 (long)DIV_FROM_REG(data->fan_div[nr])));
571}
572static ssize_t
573show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
574{
575 int nr = to_sensor_dev_attr(devattr)->index;
576 struct w83627hf_data *data = w83627hf_update_device(dev);
577 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
578 (long)DIV_FROM_REG(data->fan_div[nr])));
579}
580static ssize_t
581store_fan_min(struct device *dev, struct device_attribute *devattr,
582 const char *buf, size_t count)
583{
584 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200585 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200586 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100588 mutex_lock(&data->update_lock);
Jim Cromie07584c72007-10-12 21:08:00 +0200589 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600590 w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200591 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100593 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return count;
595}
Jim Cromie07584c72007-10-12 21:08:00 +0200596#define sysfs_fan_decl(offset) \
597static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
598 show_fan_input, NULL, offset - 1); \
599static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
600 show_fan_min, store_fan_min, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Jim Cromie07584c72007-10-12 21:08:00 +0200602sysfs_fan_decl(1);
603sysfs_fan_decl(2);
604sysfs_fan_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Jim Cromie07584c72007-10-12 21:08:00 +0200606static ssize_t
607show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
608{
609 int nr = to_sensor_dev_attr(devattr)->index;
610 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600611
612 u16 tmp = data->temp[nr];
613 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
614 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Jim Cromie07584c72007-10-12 21:08:00 +0200617static ssize_t
618show_temp_max(struct device *dev, struct device_attribute *devattr,
619 char *buf)
620{
621 int nr = to_sensor_dev_attr(devattr)->index;
622 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600623
624 u16 tmp = data->temp_max[nr];
625 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
626 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Jim Cromie07584c72007-10-12 21:08:00 +0200629static ssize_t
630show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
631 char *buf)
632{
633 int nr = to_sensor_dev_attr(devattr)->index;
634 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600635
636 u16 tmp = data->temp_max_hyst[nr];
637 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
638 : (long) TEMP_FROM_REG(tmp));
Jim Cromie07584c72007-10-12 21:08:00 +0200639}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Jim Cromie07584c72007-10-12 21:08:00 +0200641static ssize_t
642store_temp_max(struct device *dev, struct device_attribute *devattr,
643 const char *buf, size_t count)
644{
645 int nr = to_sensor_dev_attr(devattr)->index;
646 struct w83627hf_data *data = dev_get_drvdata(dev);
647 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600648 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Jim Cromie07584c72007-10-12 21:08:00 +0200650 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600651 data->temp_max[nr] = tmp;
652 w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200653 mutex_unlock(&data->update_lock);
654 return count;
655}
656
657static ssize_t
658store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
659 const char *buf, size_t count)
660{
661 int nr = to_sensor_dev_attr(devattr)->index;
662 struct w83627hf_data *data = dev_get_drvdata(dev);
663 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600664 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Jim Cromie07584c72007-10-12 21:08:00 +0200665
666 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600667 data->temp_max_hyst[nr] = tmp;
668 w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200669 mutex_unlock(&data->update_lock);
670 return count;
671}
672
673#define sysfs_temp_decl(offset) \
674static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600675 show_temp, NULL, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200676static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600677 show_temp_max, store_temp_max, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200678static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600679 show_temp_max_hyst, store_temp_max_hyst, offset - 1);
Jim Cromie07584c72007-10-12 21:08:00 +0200680
681sysfs_temp_decl(1);
682sysfs_temp_decl(2);
683sysfs_temp_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400686show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
688 struct w83627hf_data *data = w83627hf_update_device(dev);
689 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
690}
691static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400694show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Jean Delvare90d66192007-10-08 18:24:35 +0200696 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return sprintf(buf, "%ld\n", (long) data->vrm);
698}
699static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400700store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Jean Delvare787c72b2007-05-08 17:22:00 +0200702 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 u32 val;
704
705 val = simple_strtoul(buf, NULL, 10);
706 data->vrm = val;
707
708 return count;
709}
710static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400713show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 struct w83627hf_data *data = w83627hf_update_device(dev);
716 return sprintf(buf, "%ld\n", (long) data->alarms);
717}
718static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720#define show_beep_reg(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400721static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{ \
723 struct w83627hf_data *data = w83627hf_update_device(dev); \
724 return sprintf(buf,"%ld\n", \
725 (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
726}
727show_beep_reg(ENABLE, enable)
728show_beep_reg(MASK, mask)
729
730#define BEEP_ENABLE 0 /* Store beep_enable */
731#define BEEP_MASK 1 /* Store beep_mask */
732
733static ssize_t
734store_beep_reg(struct device *dev, const char *buf, size_t count,
735 int update_mask)
736{
Jean Delvare787c72b2007-05-08 17:22:00 +0200737 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 u32 val, val2;
739
740 val = simple_strtoul(buf, NULL, 10);
741
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100742 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
745 data->beep_mask = BEEP_MASK_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200746 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 data->beep_mask & 0xff);
Jean Delvare787c72b2007-05-08 17:22:00 +0200748 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 ((data->beep_mask) >> 16) & 0xff);
750 val2 = (data->beep_mask >> 8) & 0x7f;
751 } else { /* We are storing beep_enable */
752 val2 =
Jean Delvare787c72b2007-05-08 17:22:00 +0200753 w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 data->beep_enable = BEEP_ENABLE_TO_REG(val);
755 }
756
Jean Delvare787c72b2007-05-08 17:22:00 +0200757 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 val2 | data->beep_enable << 7);
759
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100760 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return count;
762}
763
764#define sysfs_beep(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400765static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{ \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400767 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768} \
769static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400770store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{ \
772 return store_beep_reg(dev, buf, count, BEEP_##REG); \
773} \
774static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
775 show_regs_beep_##reg, store_regs_beep_##reg);
776
777sysfs_beep(ENABLE, enable);
778sysfs_beep(MASK, mask);
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200781show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
Jim Cromie07584c72007-10-12 21:08:00 +0200783 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 struct w83627hf_data *data = w83627hf_update_device(dev);
785 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200786 (long) DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788/* Note: we save and restore the fan minimum here, because its value is
789 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200790 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 because the divisor changed. */
792static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200793store_fan_div(struct device *dev, struct device_attribute *devattr,
794 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Jim Cromie07584c72007-10-12 21:08:00 +0200796 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200797 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 unsigned long min;
799 u8 reg;
800 unsigned long val = simple_strtoul(buf, NULL, 10);
801
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100802 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 /* Save fan_min */
805 min = FAN_FROM_REG(data->fan_min[nr],
806 DIV_FROM_REG(data->fan_div[nr]));
807
808 data->fan_div[nr] = DIV_TO_REG(val);
809
Jean Delvare787c72b2007-05-08 17:22:00 +0200810 reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 & (nr==0 ? 0xcf : 0x3f))
812 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare787c72b2007-05-08 17:22:00 +0200813 w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Jean Delvare787c72b2007-05-08 17:22:00 +0200815 reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 & ~(1 << (5 + nr)))
817 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare787c72b2007-05-08 17:22:00 +0200818 w83627hf_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 /* Restore fan_min */
821 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600822 w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100824 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return count;
826}
827
Jim Cromie07584c72007-10-12 21:08:00 +0200828static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
829 show_fan_div, store_fan_div, 0);
830static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
831 show_fan_div, store_fan_div, 1);
832static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
833 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200836show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
Jim Cromie07584c72007-10-12 21:08:00 +0200838 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200840 return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841}
842
843static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200844store_pwm(struct device *dev, struct device_attribute *devattr,
845 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846{
Jim Cromie07584c72007-10-12 21:08:00 +0200847 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200848 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200849 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100851 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853 if (data->type == w83627thf) {
854 /* bits 0-3 are reserved in 627THF */
Jim Cromie07584c72007-10-12 21:08:00 +0200855 data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
Jean Delvare787c72b2007-05-08 17:22:00 +0200856 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200858 data->pwm[nr] |
Jean Delvare787c72b2007-05-08 17:22:00 +0200859 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
861 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200862 data->pwm[nr] = PWM_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200863 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200865 data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100868 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 return count;
870}
871
Jim Cromie07584c72007-10-12 21:08:00 +0200872static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
873static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
874static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200877show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400878{
Jim Cromie07584c72007-10-12 21:08:00 +0200879 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400880 struct w83627hf_data *data = w83627hf_update_device(dev);
881 if (data->type == w83627hf)
882 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200883 pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400884 else
885 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200886 pwm_freq_from_reg(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400887}
888
889static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200890store_pwm_freq(struct device *dev, struct device_attribute *devattr,
891 const char *buf, size_t count)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400892{
Jim Cromie07584c72007-10-12 21:08:00 +0200893 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400894 struct w83627hf_data *data = dev_get_drvdata(dev);
895 static const u8 mask[]={0xF8, 0x8F};
896 u32 val;
897
898 val = simple_strtoul(buf, NULL, 10);
899
900 mutex_lock(&data->update_lock);
901
902 if (data->type == w83627hf) {
Jim Cromie07584c72007-10-12 21:08:00 +0200903 data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400904 w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
Jim Cromie07584c72007-10-12 21:08:00 +0200905 (data->pwm_freq[nr] << (nr*4)) |
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400906 (w83627hf_read_value(data,
Jim Cromie07584c72007-10-12 21:08:00 +0200907 W83627HF_REG_PWM_FREQ) & mask[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400908 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200909 data->pwm_freq[nr] = pwm_freq_to_reg(val);
910 w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
911 data->pwm_freq[nr]);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400912 }
913
914 mutex_unlock(&data->update_lock);
915 return count;
916}
917
Jim Cromie07584c72007-10-12 21:08:00 +0200918static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
919 show_pwm_freq, store_pwm_freq, 0);
920static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
921 show_pwm_freq, store_pwm_freq, 1);
922static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
923 show_pwm_freq, store_pwm_freq, 2);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400924
925static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200926show_temp_type(struct device *dev, struct device_attribute *devattr,
927 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Jim Cromie07584c72007-10-12 21:08:00 +0200929 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200931 return sprintf(buf, "%ld\n", (long) data->sens[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
934static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200935store_temp_type(struct device *dev, struct device_attribute *devattr,
936 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Jim Cromie07584c72007-10-12 21:08:00 +0200938 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200939 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 u32 val, tmp;
941
942 val = simple_strtoul(buf, NULL, 10);
943
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100944 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 switch (val) {
947 case 1: /* PII/Celeron diode */
Jean Delvare787c72b2007-05-08 17:22:00 +0200948 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
949 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200950 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200951 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
952 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200953 tmp | BIT_SCFG2[nr]);
954 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 break;
956 case 2: /* 3904 */
Jean Delvare787c72b2007-05-08 17:22:00 +0200957 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
958 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200959 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200960 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
961 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200962 tmp & ~BIT_SCFG2[nr]);
963 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200965 case W83781D_DEFAULT_BETA:
966 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
967 "instead\n", W83781D_DEFAULT_BETA);
968 /* fall through */
969 case 4: /* thermistor */
Jean Delvare787c72b2007-05-08 17:22:00 +0200970 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
971 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200972 tmp & ~BIT_SCFG1[nr]);
973 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 break;
975 default:
Jean Delvare787c72b2007-05-08 17:22:00 +0200976 dev_err(dev,
Jean Delvareb26f9332007-08-16 14:30:01 +0200977 "Invalid sensor type %ld; must be 1, 2, or 4\n",
978 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 break;
980 }
981
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100982 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return count;
984}
985
Jim Cromie07584c72007-10-12 21:08:00 +0200986#define sysfs_temp_type(offset) \
987static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
988 show_temp_type, store_temp_type, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Jim Cromie07584c72007-10-12 21:08:00 +0200990sysfs_temp_type(1);
991sysfs_temp_type(2);
992sysfs_temp_type(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Jim Cromie07584c72007-10-12 21:08:00 +0200994static ssize_t
995show_name(struct device *dev, struct device_attribute *devattr, char *buf)
Jean Delvare787c72b2007-05-08 17:22:00 +0200996{
997 struct w83627hf_data *data = dev_get_drvdata(dev);
998
999 return sprintf(buf, "%s\n", data->name);
1000}
1001static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1002
1003static int __init w83627hf_find(int sioaddr, unsigned short *addr,
1004 struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
Jean Delvared27c37c2007-05-08 17:21:59 +02001006 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 u16 val;
1008
Jean Delvare787c72b2007-05-08 17:22:00 +02001009 static const __initdata char *names[] = {
1010 "W83627HF",
1011 "W83627THF",
1012 "W83697HF",
1013 "W83637HF",
1014 "W83687THF",
1015 };
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 REG = sioaddr;
1018 VAL = sioaddr + 1;
1019
1020 superio_enter();
Jean Delvare67b671b2007-12-06 23:13:42 +01001021 val = force_id ? force_id : superio_inb(DEVID);
Jean Delvare787c72b2007-05-08 17:22:00 +02001022 switch (val) {
1023 case W627_DEVID:
1024 sio_data->type = w83627hf;
1025 break;
1026 case W627THF_DEVID:
1027 sio_data->type = w83627thf;
1028 break;
1029 case W697_DEVID:
1030 sio_data->type = w83697hf;
1031 break;
1032 case W637_DEVID:
1033 sio_data->type = w83637hf;
1034 break;
1035 case W687THF_DEVID:
1036 sio_data->type = w83687thf;
1037 break;
Jean Delvaree142e2a2007-05-27 22:17:43 +02001038 case 0xff: /* No device at all */
1039 goto exit;
Jean Delvare787c72b2007-05-08 17:22:00 +02001040 default:
Jean Delvaree142e2a2007-05-27 22:17:43 +02001041 pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
Jean Delvared27c37c2007-05-08 17:21:59 +02001042 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044
1045 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +02001046 force_addr &= WINB_ALIGNMENT;
1047 if (force_addr) {
1048 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1049 force_addr);
1050 superio_outb(WINB_BASE_REG, force_addr >> 8);
1051 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 val = (superio_inb(WINB_BASE_REG) << 8) |
1054 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001055 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +02001056 if (*addr == 0) {
1057 printk(KERN_WARNING DRVNAME ": Base address not set, "
1058 "skipping\n");
1059 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Jean Delvared27c37c2007-05-08 17:21:59 +02001062 val = superio_inb(WINB_ACT_REG);
1063 if (!(val & 0x01)) {
1064 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1065 superio_outb(WINB_ACT_REG, val | 0x01);
1066 }
1067
1068 err = 0;
Jean Delvare787c72b2007-05-08 17:22:00 +02001069 pr_info(DRVNAME ": Found %s chip at %#x\n",
1070 names[sio_data->type], *addr);
Jean Delvared27c37c2007-05-08 17:21:59 +02001071
1072 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +02001074 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075}
1076
Jim Cromie07584c72007-10-12 21:08:00 +02001077#define VIN_UNIT_ATTRS(_X_) \
1078 &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
1079 &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
1080 &sensor_dev_attr_in##_X_##_max.dev_attr.attr
1081
1082#define FAN_UNIT_ATTRS(_X_) \
1083 &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
1084 &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
1085 &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
1086
1087#define TEMP_UNIT_ATTRS(_X_) \
1088 &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
1089 &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
1090 &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
1091 &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
1092
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001093static struct attribute *w83627hf_attributes[] = {
1094 &dev_attr_in0_input.attr,
1095 &dev_attr_in0_min.attr,
1096 &dev_attr_in0_max.attr,
Jim Cromie07584c72007-10-12 21:08:00 +02001097 VIN_UNIT_ATTRS(2),
1098 VIN_UNIT_ATTRS(3),
1099 VIN_UNIT_ATTRS(4),
1100 VIN_UNIT_ATTRS(7),
1101 VIN_UNIT_ATTRS(8),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001102
Jim Cromie07584c72007-10-12 21:08:00 +02001103 FAN_UNIT_ATTRS(1),
1104 FAN_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001105
Jim Cromie07584c72007-10-12 21:08:00 +02001106 TEMP_UNIT_ATTRS(1),
1107 TEMP_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001108
1109 &dev_attr_alarms.attr,
1110 &dev_attr_beep_enable.attr,
1111 &dev_attr_beep_mask.attr,
1112
Jim Cromie07584c72007-10-12 21:08:00 +02001113 &sensor_dev_attr_pwm1.dev_attr.attr,
1114 &sensor_dev_attr_pwm2.dev_attr.attr,
Jean Delvare787c72b2007-05-08 17:22:00 +02001115 &dev_attr_name.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001116 NULL
1117};
1118
1119static const struct attribute_group w83627hf_group = {
1120 .attrs = w83627hf_attributes,
1121};
1122
1123static struct attribute *w83627hf_attributes_opt[] = {
Jim Cromie07584c72007-10-12 21:08:00 +02001124 VIN_UNIT_ATTRS(1),
1125 VIN_UNIT_ATTRS(5),
1126 VIN_UNIT_ATTRS(6),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001127
Jim Cromie07584c72007-10-12 21:08:00 +02001128 FAN_UNIT_ATTRS(3),
1129 TEMP_UNIT_ATTRS(3),
1130 &sensor_dev_attr_pwm3.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001131
Jim Cromie07584c72007-10-12 21:08:00 +02001132 &sensor_dev_attr_pwm1_freq.dev_attr.attr,
1133 &sensor_dev_attr_pwm2_freq.dev_attr.attr,
1134 &sensor_dev_attr_pwm3_freq.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001135 NULL
1136};
1137
1138static const struct attribute_group w83627hf_group_opt = {
1139 .attrs = w83627hf_attributes_opt,
1140};
1141
Jean Delvare787c72b2007-05-08 17:22:00 +02001142static int __devinit w83627hf_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Jean Delvare787c72b2007-05-08 17:22:00 +02001144 struct device *dev = &pdev->dev;
1145 struct w83627hf_sio_data *sio_data = dev->platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 struct w83627hf_data *data;
Jean Delvare787c72b2007-05-08 17:22:00 +02001147 struct resource *res;
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001148 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Jean Delvare787c72b2007-05-08 17:22:00 +02001150 static const char *names[] = {
1151 "w83627hf",
1152 "w83627thf",
1153 "w83697hf",
1154 "w83637hf",
1155 "w83687thf",
1156 };
1157
1158 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1159 if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1160 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1161 (unsigned long)res->start,
1162 (unsigned long)(res->start + WINB_REGION_SIZE - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 err = -EBUSY;
1164 goto ERROR0;
1165 }
1166
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001167 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 err = -ENOMEM;
1169 goto ERROR1;
1170 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001171 data->addr = res->start;
1172 data->type = sio_data->type;
1173 data->name = names[sio_data->type];
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001174 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001175 mutex_init(&data->update_lock);
Jean Delvare787c72b2007-05-08 17:22:00 +02001176 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 /* Initialize the chip */
Jean Delvare787c72b2007-05-08 17:22:00 +02001179 w83627hf_init_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 /* A few vars need to be filled upon startup */
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001182 for (i = 0; i <= 2; i++)
1183 data->fan_min[i] = w83627hf_read_value(
1184 data, W83627HF_REG_FAN_MIN(i));
Jean Delvarec09c5182007-10-12 21:53:07 +02001185 w83627hf_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001187 /* Register common device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001188 if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001189 goto ERROR3;
1190
1191 /* Register chip-specific device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001192 if (data->type == w83627hf || data->type == w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001193 if ((err = device_create_file(dev,
1194 &sensor_dev_attr_in5_input.dev_attr))
1195 || (err = device_create_file(dev,
1196 &sensor_dev_attr_in5_min.dev_attr))
1197 || (err = device_create_file(dev,
1198 &sensor_dev_attr_in5_max.dev_attr))
1199 || (err = device_create_file(dev,
1200 &sensor_dev_attr_in6_input.dev_attr))
1201 || (err = device_create_file(dev,
1202 &sensor_dev_attr_in6_min.dev_attr))
1203 || (err = device_create_file(dev,
1204 &sensor_dev_attr_in6_max.dev_attr))
1205 || (err = device_create_file(dev,
1206 &sensor_dev_attr_pwm1_freq.dev_attr))
1207 || (err = device_create_file(dev,
1208 &sensor_dev_attr_pwm2_freq.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001209 goto ERROR4;
1210
Jean Delvare787c72b2007-05-08 17:22:00 +02001211 if (data->type != w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001212 if ((err = device_create_file(dev,
1213 &sensor_dev_attr_in1_input.dev_attr))
1214 || (err = device_create_file(dev,
1215 &sensor_dev_attr_in1_min.dev_attr))
1216 || (err = device_create_file(dev,
1217 &sensor_dev_attr_in1_max.dev_attr))
1218 || (err = device_create_file(dev,
1219 &sensor_dev_attr_fan3_input.dev_attr))
1220 || (err = device_create_file(dev,
1221 &sensor_dev_attr_fan3_min.dev_attr))
1222 || (err = device_create_file(dev,
1223 &sensor_dev_attr_fan3_div.dev_attr))
1224 || (err = device_create_file(dev,
1225 &sensor_dev_attr_temp3_input.dev_attr))
1226 || (err = device_create_file(dev,
1227 &sensor_dev_attr_temp3_max.dev_attr))
1228 || (err = device_create_file(dev,
1229 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1230 || (err = device_create_file(dev,
1231 &sensor_dev_attr_temp3_type.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001232 goto ERROR4;
1233
Jean Delvare787c72b2007-05-08 17:22:00 +02001234 if (data->type != w83697hf && data->vid != 0xff) {
Jean Delvare8a665a02007-05-08 17:21:59 +02001235 /* Convert VID to voltage based on VRM */
1236 data->vrm = vid_which_vrm();
1237
Jean Delvare787c72b2007-05-08 17:22:00 +02001238 if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1239 || (err = device_create_file(dev, &dev_attr_vrm)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001240 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001241 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001242
Jean Delvare787c72b2007-05-08 17:22:00 +02001243 if (data->type == w83627thf || data->type == w83637hf
1244 || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001245 if ((err = device_create_file(dev,
1246 &sensor_dev_attr_pwm3.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001247 goto ERROR4;
1248
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001249 if (data->type == w83637hf || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001250 if ((err = device_create_file(dev,
1251 &sensor_dev_attr_pwm1_freq.dev_attr))
1252 || (err = device_create_file(dev,
1253 &sensor_dev_attr_pwm2_freq.dev_attr))
1254 || (err = device_create_file(dev,
1255 &sensor_dev_attr_pwm3_freq.dev_attr)))
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001256 goto ERROR4;
1257
Tony Jones1beeffe2007-08-20 13:46:20 -07001258 data->hwmon_dev = hwmon_device_register(dev);
1259 if (IS_ERR(data->hwmon_dev)) {
1260 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001261 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001262 }
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return 0;
1265
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001266 ERROR4:
Jean Delvare787c72b2007-05-08 17:22:00 +02001267 sysfs_remove_group(&dev->kobj, &w83627hf_group);
1268 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001269 ERROR3:
Jean Delvare04a62172007-06-12 13:57:19 +02001270 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 kfree(data);
1272 ERROR1:
Jean Delvare787c72b2007-05-08 17:22:00 +02001273 release_region(res->start, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 ERROR0:
1275 return err;
1276}
1277
Jean Delvare787c72b2007-05-08 17:22:00 +02001278static int __devexit w83627hf_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
Jean Delvare787c72b2007-05-08 17:22:00 +02001280 struct w83627hf_data *data = platform_get_drvdata(pdev);
1281 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Tony Jones1beeffe2007-08-20 13:46:20 -07001283 hwmon_device_unregister(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001284
Jean Delvare787c72b2007-05-08 17:22:00 +02001285 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1286 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
Jean Delvare04a62172007-06-12 13:57:19 +02001287 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001288 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Jean Delvare787c72b2007-05-08 17:22:00 +02001290 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1291 release_region(res->start, WINB_REGION_SIZE);
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 return 0;
1294}
1295
1296
Jean Delvared58df9c2007-10-10 16:30:23 +02001297/* Registers 0x50-0x5f are banked */
1298static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
1299{
1300 if ((reg & 0x00f0) == 0x50) {
1301 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1302 outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
1303 }
1304}
1305
1306/* Not strictly necessary, but play it safe for now */
1307static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
1308{
1309 if (reg & 0xff00) {
1310 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1311 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
1312 }
1313}
1314
Jean Delvare787c72b2007-05-08 17:22:00 +02001315static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 int res, word_sized;
1318
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001319 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 word_sized = (((reg & 0xff00) == 0x100)
1321 || ((reg & 0xff00) == 0x200))
1322 && (((reg & 0x00ff) == 0x50)
1323 || ((reg & 0x00ff) == 0x53)
1324 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001325 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001326 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1327 res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (word_sized) {
1329 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001330 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 res =
Jean Delvare787c72b2007-05-08 17:22:00 +02001332 (res << 8) + inb_p(data->addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 W83781D_DATA_REG_OFFSET);
1334 }
Jean Delvared58df9c2007-10-10 16:30:23 +02001335 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001336 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 return res;
1338}
1339
Jean Delvare787c72b2007-05-08 17:22:00 +02001340static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341{
1342 int res = 0xff, sel;
1343
1344 superio_enter();
1345 superio_select(W83627HF_LD_GPIO5);
1346
1347 /* Make sure these GPIO pins are enabled */
1348 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001349 dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 goto exit;
1351 }
1352
1353 /* Make sure the pins are configured for input
1354 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001355 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if ((sel & 0x1f) != 0x1f) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001357 dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 "function\n");
1359 goto exit;
1360 }
1361
Jean Delvare787c72b2007-05-08 17:22:00 +02001362 dev_info(&pdev->dev, "Reading VID from GPIO5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1364
1365exit:
1366 superio_exit();
1367 return res;
1368}
1369
Jean Delvare787c72b2007-05-08 17:22:00 +02001370static int __devinit w83687thf_read_vid(struct platform_device *pdev)
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001371{
1372 int res = 0xff;
1373
1374 superio_enter();
1375 superio_select(W83627HF_LD_HWM);
1376
1377 /* Make sure these GPIO pins are enabled */
1378 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001379 dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001380 goto exit;
1381 }
1382
1383 /* Make sure the pins are configured for input */
1384 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001385 dev_dbg(&pdev->dev, "VID configured as output, "
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001386 "no VID function\n");
1387 goto exit;
1388 }
1389
1390 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1391
1392exit:
1393 superio_exit();
1394 return res;
1395}
1396
Jean Delvare787c72b2007-05-08 17:22:00 +02001397static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 int word_sized;
1400
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001401 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 word_sized = (((reg & 0xff00) == 0x100)
1403 || ((reg & 0xff00) == 0x200))
1404 && (((reg & 0x00ff) == 0x53)
1405 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001406 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001407 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (word_sized) {
1409 outb_p(value >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001410 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001412 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
1414 outb_p(value & 0xff,
Jean Delvare787c72b2007-05-08 17:22:00 +02001415 data->addr + W83781D_DATA_REG_OFFSET);
Jean Delvared58df9c2007-10-10 16:30:23 +02001416 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001417 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 return 0;
1419}
1420
Jean Delvare787c72b2007-05-08 17:22:00 +02001421static void __devinit w83627hf_init_device(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422{
Jean Delvare787c72b2007-05-08 17:22:00 +02001423 struct w83627hf_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001425 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 u8 tmp;
1427
Jean Delvare2251cf12005-09-04 22:52:17 +02001428 if (reset) {
1429 /* Resetting the chip has been the default for a long time,
1430 but repeatedly caused problems (fans going to full
1431 speed...) so it is now optional. It might even go away if
1432 nobody reports it as being useful, as I see very little
1433 reason why this would be needed at all. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001434 dev_info(&pdev->dev, "If reset=1 solved a problem you were "
Jean Delvare2251cf12005-09-04 22:52:17 +02001435 "having, please report!\n");
1436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* save this register */
Jean Delvare787c72b2007-05-08 17:22:00 +02001438 i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 /* Reset all except Watchdog values and last conversion values
1440 This sets fan-divs to 2, among others */
Jean Delvare787c72b2007-05-08 17:22:00 +02001441 w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 /* Restore the register and disable power-on abnormal beep.
1443 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001444 w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 /* Disable master beep-enable (reset turns it on).
1446 Individual beeps should be reset to off but for some reason
1447 disabling this bit helps some people not get beeped */
Jean Delvare787c72b2007-05-08 17:22:00 +02001448 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
1450
1451 /* Minimize conflicts with other winbond i2c-only clients... */
1452 /* disable i2c subclients... how to disable main i2c client?? */
1453 /* force i2c address to relatively uncommon address */
Jean Delvare787c72b2007-05-08 17:22:00 +02001454 w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1455 w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
1457 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001458 if (type == w83627hf || type == w83637hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001459 int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1460 int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001462 } else if (type == w83627thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001463 data->vid = w83627thf_read_gpio5(pdev);
Jean Delvared27c37c2007-05-08 17:21:59 +02001464 } else if (type == w83687thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001465 data->vid = w83687thf_read_vid(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 }
1467
1468 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001469 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 data->vrm_ovt =
Jean Delvare787c72b2007-05-08 17:22:00 +02001471 w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473
Jean Delvare787c72b2007-05-08 17:22:00 +02001474 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 for (i = 1; i <= 3; i++) {
1476 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001477 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 } else {
1479 if (w83627hf_read_value
Jean Delvare787c72b2007-05-08 17:22:00 +02001480 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1482 data->sens[i - 1] = 1;
1483 else
1484 data->sens[i - 1] = 2;
1485 }
1486 if ((type == w83697hf) && (i == 2))
1487 break;
1488 }
1489
1490 if(init) {
1491 /* Enable temp2 */
Jim Cromiedf48ed82007-10-14 17:10:52 -06001492 tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001494 dev_warn(&pdev->dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 "might not make sense\n");
Jim Cromiedf48ed82007-10-14 17:10:52 -06001496 w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 tmp & 0xfe);
1498 }
1499
1500 /* Enable temp3 */
1501 if (type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001502 tmp = w83627hf_read_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001503 W83627HF_REG_TEMP3_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001505 dev_warn(&pdev->dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 "readings might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001507 w83627hf_write_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001508 W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 }
1510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
1512
1513 /* Start monitoring */
Jean Delvare787c72b2007-05-08 17:22:00 +02001514 w83627hf_write_value(data, W83781D_REG_CONFIG,
1515 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 W83781D_REG_CONFIG) & 0xf7)
1517 | 0x01);
1518}
1519
Jean Delvarec09c5182007-10-12 21:53:07 +02001520static void w83627hf_update_fan_div(struct w83627hf_data *data)
1521{
1522 int reg;
1523
1524 reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1525 data->fan_div[0] = (reg >> 4) & 0x03;
1526 data->fan_div[1] = (reg >> 6) & 0x03;
1527 if (data->type != w83697hf) {
1528 data->fan_div[2] = (w83627hf_read_value(data,
1529 W83781D_REG_PIN) >> 6) & 0x03;
1530 }
1531 reg = w83627hf_read_value(data, W83781D_REG_VBAT);
1532 data->fan_div[0] |= (reg >> 3) & 0x04;
1533 data->fan_div[1] |= (reg >> 4) & 0x04;
1534 if (data->type != w83697hf)
1535 data->fan_div[2] |= (reg >> 5) & 0x04;
1536}
1537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1539{
Jean Delvare787c72b2007-05-08 17:22:00 +02001540 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -06001541 int i, num_temps = (data->type == w83697hf) ? 2 : 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001543 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1546 || !data->valid) {
1547 for (i = 0; i <= 8; i++) {
1548 /* skip missing sensors */
1549 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001550 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001551 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 continue;
1553 data->in[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001554 w83627hf_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 data->in_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001556 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 W83781D_REG_IN_MIN(i));
1558 data->in_max[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001559 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 W83781D_REG_IN_MAX(i));
1561 }
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001562 for (i = 0; i <= 2; i++) {
1563 data->fan[i] =
1564 w83627hf_read_value(data, W83627HF_REG_FAN(i));
1565 data->fan_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001566 w83627hf_read_value(data,
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001567 W83627HF_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 }
Jim Cromie07584c72007-10-12 21:08:00 +02001569 for (i = 0; i <= 2; i++) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001570 u8 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 W836X7HF_REG_PWM(data->type, i));
1572 /* bits 0-3 are reserved in 627THF */
1573 if (data->type == w83627thf)
1574 tmp &= 0xf0;
Jim Cromie07584c72007-10-12 21:08:00 +02001575 data->pwm[i] = tmp;
1576 if (i == 1 &&
1577 (data->type == w83627hf || data->type == w83697hf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 break;
1579 }
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001580 if (data->type == w83627hf) {
1581 u8 tmp = w83627hf_read_value(data,
1582 W83627HF_REG_PWM_FREQ);
1583 data->pwm_freq[0] = tmp & 0x07;
1584 data->pwm_freq[1] = (tmp >> 4) & 0x07;
1585 } else if (data->type != w83627thf) {
1586 for (i = 1; i <= 3; i++) {
1587 data->pwm_freq[i - 1] =
1588 w83627hf_read_value(data,
1589 W83637HF_REG_PWM_FREQ[i - 1]);
1590 if (i == 2 && (data->type == w83697hf))
1591 break;
1592 }
1593 }
Jim Cromiedf48ed82007-10-14 17:10:52 -06001594 for (i = 0; i < num_temps; i++) {
1595 data->temp[i] = w83627hf_read_value(
1596 data, w83627hf_reg_temp[i]);
1597 data->temp_max[i] = w83627hf_read_value(
1598 data, w83627hf_reg_temp_over[i]);
1599 data->temp_max_hyst[i] = w83627hf_read_value(
1600 data, w83627hf_reg_temp_hyst[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 }
1602
Jean Delvarec09c5182007-10-12 21:53:07 +02001603 w83627hf_update_fan_div(data);
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 data->alarms =
Jean Delvare787c72b2007-05-08 17:22:00 +02001606 w83627hf_read_value(data, W83781D_REG_ALARM1) |
1607 (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1608 (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1609 i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 data->beep_enable = i >> 7;
1611 data->beep_mask = ((i & 0x7f) << 8) |
Jean Delvare787c72b2007-05-08 17:22:00 +02001612 w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1613 w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 data->last_updated = jiffies;
1615 data->valid = 1;
1616 }
1617
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001618 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 return data;
1621}
1622
Jean Delvare787c72b2007-05-08 17:22:00 +02001623static int __init w83627hf_device_add(unsigned short address,
1624 const struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625{
Jean Delvare787c72b2007-05-08 17:22:00 +02001626 struct resource res = {
1627 .start = address + WINB_REGION_OFFSET,
1628 .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1629 .name = DRVNAME,
1630 .flags = IORESOURCE_IO,
1631 };
1632 int err;
1633
1634 pdev = platform_device_alloc(DRVNAME, address);
1635 if (!pdev) {
1636 err = -ENOMEM;
1637 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1638 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Jean Delvare787c72b2007-05-08 17:22:00 +02001641 err = platform_device_add_resources(pdev, &res, 1);
1642 if (err) {
1643 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1644 "(%d)\n", err);
1645 goto exit_device_put;
1646 }
1647
Jean Delvare2df6d812007-06-09 10:11:16 -04001648 err = platform_device_add_data(pdev, sio_data,
1649 sizeof(struct w83627hf_sio_data));
1650 if (err) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001651 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1652 goto exit_device_put;
1653 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001654
1655 err = platform_device_add(pdev);
1656 if (err) {
1657 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1658 err);
1659 goto exit_device_put;
1660 }
1661
1662 return 0;
1663
1664exit_device_put:
1665 platform_device_put(pdev);
1666exit:
1667 return err;
1668}
1669
1670static int __init sensors_w83627hf_init(void)
1671{
1672 int err;
1673 unsigned short address;
1674 struct w83627hf_sio_data sio_data;
1675
1676 if (w83627hf_find(0x2e, &address, &sio_data)
1677 && w83627hf_find(0x4e, &address, &sio_data))
1678 return -ENODEV;
1679
1680 err = platform_driver_register(&w83627hf_driver);
1681 if (err)
1682 goto exit;
1683
1684 /* Sets global pdev as a side effect */
1685 err = w83627hf_device_add(address, &sio_data);
1686 if (err)
1687 goto exit_driver;
1688
1689 return 0;
1690
1691exit_driver:
1692 platform_driver_unregister(&w83627hf_driver);
1693exit:
1694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695}
1696
1697static void __exit sensors_w83627hf_exit(void)
1698{
Jean Delvare787c72b2007-05-08 17:22:00 +02001699 platform_device_unregister(pdev);
1700 platform_driver_unregister(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701}
1702
1703MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1704 "Philip Edelbrock <phil@netroedge.com>, "
1705 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1706MODULE_DESCRIPTION("W83627HF driver");
1707MODULE_LICENSE("GPL");
1708
1709module_init(sensors_w83627hf_init);
1710module_exit(sensors_w83627hf_exit);