blob: c02c3bbde19f3266c075a6a2aa32cb09d1484c33 [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
Jean Delvaree3604c62008-01-03 23:00:30 +0100720static ssize_t
721show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
722{
723 struct w83627hf_data *data = w83627hf_update_device(dev);
724 int bitnr = to_sensor_dev_attr(attr)->index;
725 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
726}
727static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
728static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
729static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
730static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
731static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
732static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
733static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
734static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
735static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
736static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
737static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
738static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
739static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
740static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
741static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743#define show_beep_reg(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400744static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{ \
746 struct w83627hf_data *data = w83627hf_update_device(dev); \
747 return sprintf(buf,"%ld\n", \
748 (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
749}
750show_beep_reg(ENABLE, enable)
751show_beep_reg(MASK, mask)
752
753#define BEEP_ENABLE 0 /* Store beep_enable */
754#define BEEP_MASK 1 /* Store beep_mask */
755
756static ssize_t
757store_beep_reg(struct device *dev, const char *buf, size_t count,
758 int update_mask)
759{
Jean Delvare787c72b2007-05-08 17:22:00 +0200760 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 u32 val, val2;
762
763 val = simple_strtoul(buf, NULL, 10);
764
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100765 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
768 data->beep_mask = BEEP_MASK_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200769 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 data->beep_mask & 0xff);
Jean Delvare787c72b2007-05-08 17:22:00 +0200771 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 ((data->beep_mask) >> 16) & 0xff);
773 val2 = (data->beep_mask >> 8) & 0x7f;
774 } else { /* We are storing beep_enable */
775 val2 =
Jean Delvare787c72b2007-05-08 17:22:00 +0200776 w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 data->beep_enable = BEEP_ENABLE_TO_REG(val);
778 }
779
Jean Delvare787c72b2007-05-08 17:22:00 +0200780 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 val2 | data->beep_enable << 7);
782
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100783 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return count;
785}
786
787#define sysfs_beep(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400788static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{ \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400790 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791} \
792static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400793store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{ \
795 return store_beep_reg(dev, buf, count, BEEP_##REG); \
796} \
797static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
798 show_regs_beep_##reg, store_regs_beep_##reg);
799
800sysfs_beep(ENABLE, enable);
801sysfs_beep(MASK, mask);
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803static ssize_t
Jean Delvaree3604c62008-01-03 23:00:30 +0100804show_beep(struct device *dev, struct device_attribute *attr, char *buf)
805{
806 struct w83627hf_data *data = w83627hf_update_device(dev);
807 int bitnr = to_sensor_dev_attr(attr)->index;
808 return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
809}
810
811static ssize_t
812store_beep(struct device *dev, struct device_attribute *attr,
813 const char *buf, size_t count)
814{
815 struct w83627hf_data *data = dev_get_drvdata(dev);
816 int bitnr = to_sensor_dev_attr(attr)->index;
817 unsigned long bit;
818 u8 reg;
819
820 bit = simple_strtoul(buf, NULL, 10);
821 if (bit & ~1)
822 return -EINVAL;
823
824 mutex_lock(&data->update_lock);
825 if (bit)
826 data->beep_mask |= (1 << bitnr);
827 else
828 data->beep_mask &= ~(1 << bitnr);
829
830 if (bitnr < 8) {
831 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1);
832 if (bit)
833 reg |= (1 << bitnr);
834 else
835 reg &= ~(1 << bitnr);
836 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg);
837 } else if (bitnr < 16) {
838 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
839 if (bit)
840 reg |= (1 << (bitnr - 8));
841 else
842 reg &= ~(1 << (bitnr - 8));
843 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg);
844 } else {
845 reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3);
846 if (bit)
847 reg |= (1 << (bitnr - 16));
848 else
849 reg &= ~(1 << (bitnr - 16));
850 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg);
851 }
852 mutex_unlock(&data->update_lock);
853
854 return count;
855}
856
857static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
858 show_beep, store_beep, 0);
859static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
860 show_beep, store_beep, 1);
861static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
862 show_beep, store_beep, 2);
863static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
864 show_beep, store_beep, 3);
865static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
866 show_beep, store_beep, 8);
867static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
868 show_beep, store_beep, 9);
869static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
870 show_beep, store_beep, 10);
871static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
872 show_beep, store_beep, 16);
873static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
874 show_beep, store_beep, 17);
875static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
876 show_beep, store_beep, 6);
877static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
878 show_beep, store_beep, 7);
879static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
880 show_beep, store_beep, 11);
881static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
882 show_beep, store_beep, 4);
883static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
884 show_beep, store_beep, 5);
885static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR,
886 show_beep, store_beep, 13);
887
888static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200889show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Jim Cromie07584c72007-10-12 21:08:00 +0200891 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 struct w83627hf_data *data = w83627hf_update_device(dev);
893 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200894 (long) DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896/* Note: we save and restore the fan minimum here, because its value is
897 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200898 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 because the divisor changed. */
900static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200901store_fan_div(struct device *dev, struct device_attribute *devattr,
902 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
Jim Cromie07584c72007-10-12 21:08:00 +0200904 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200905 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 unsigned long min;
907 u8 reg;
908 unsigned long val = simple_strtoul(buf, NULL, 10);
909
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100910 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 /* Save fan_min */
913 min = FAN_FROM_REG(data->fan_min[nr],
914 DIV_FROM_REG(data->fan_div[nr]));
915
916 data->fan_div[nr] = DIV_TO_REG(val);
917
Jean Delvare787c72b2007-05-08 17:22:00 +0200918 reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 & (nr==0 ? 0xcf : 0x3f))
920 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare787c72b2007-05-08 17:22:00 +0200921 w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Jean Delvare787c72b2007-05-08 17:22:00 +0200923 reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 & ~(1 << (5 + nr)))
925 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare787c72b2007-05-08 17:22:00 +0200926 w83627hf_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 /* Restore fan_min */
929 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jim Cromie2ca2fcd2007-10-14 17:20:50 -0600930 w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100932 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return count;
934}
935
Jim Cromie07584c72007-10-12 21:08:00 +0200936static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
937 show_fan_div, store_fan_div, 0);
938static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
939 show_fan_div, store_fan_div, 1);
940static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
941 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200944show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
Jim Cromie07584c72007-10-12 21:08:00 +0200946 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200948 return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200952store_pwm(struct device *dev, struct device_attribute *devattr,
953 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
Jim Cromie07584c72007-10-12 21:08:00 +0200955 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200956 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200957 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100959 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 if (data->type == w83627thf) {
962 /* bits 0-3 are reserved in 627THF */
Jim Cromie07584c72007-10-12 21:08:00 +0200963 data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
Jean Delvare787c72b2007-05-08 17:22:00 +0200964 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200966 data->pwm[nr] |
Jean Delvare787c72b2007-05-08 17:22:00 +0200967 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
969 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200970 data->pwm[nr] = PWM_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200971 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200973 data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 }
975
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100976 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return count;
978}
979
Jim Cromie07584c72007-10-12 21:08:00 +0200980static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
981static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
982static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200985show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400986{
Jim Cromie07584c72007-10-12 21:08:00 +0200987 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400988 struct w83627hf_data *data = w83627hf_update_device(dev);
989 if (data->type == w83627hf)
990 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200991 pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400992 else
993 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200994 pwm_freq_from_reg(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400995}
996
997static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200998store_pwm_freq(struct device *dev, struct device_attribute *devattr,
999 const char *buf, size_t count)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001000{
Jim Cromie07584c72007-10-12 21:08:00 +02001001 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001002 struct w83627hf_data *data = dev_get_drvdata(dev);
1003 static const u8 mask[]={0xF8, 0x8F};
1004 u32 val;
1005
1006 val = simple_strtoul(buf, NULL, 10);
1007
1008 mutex_lock(&data->update_lock);
1009
1010 if (data->type == w83627hf) {
Jim Cromie07584c72007-10-12 21:08:00 +02001011 data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001012 w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
Jim Cromie07584c72007-10-12 21:08:00 +02001013 (data->pwm_freq[nr] << (nr*4)) |
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001014 (w83627hf_read_value(data,
Jim Cromie07584c72007-10-12 21:08:00 +02001015 W83627HF_REG_PWM_FREQ) & mask[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001016 } else {
Jim Cromie07584c72007-10-12 21:08:00 +02001017 data->pwm_freq[nr] = pwm_freq_to_reg(val);
1018 w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
1019 data->pwm_freq[nr]);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001020 }
1021
1022 mutex_unlock(&data->update_lock);
1023 return count;
1024}
1025
Jim Cromie07584c72007-10-12 21:08:00 +02001026static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
1027 show_pwm_freq, store_pwm_freq, 0);
1028static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
1029 show_pwm_freq, store_pwm_freq, 1);
1030static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
1031 show_pwm_freq, store_pwm_freq, 2);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001032
1033static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001034show_temp_type(struct device *dev, struct device_attribute *devattr,
1035 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
Jim Cromie07584c72007-10-12 21:08:00 +02001037 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +02001039 return sprintf(buf, "%ld\n", (long) data->sens[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040}
1041
1042static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +02001043store_temp_type(struct device *dev, struct device_attribute *devattr,
1044 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045{
Jim Cromie07584c72007-10-12 21:08:00 +02001046 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +02001047 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 u32 val, tmp;
1049
1050 val = simple_strtoul(buf, NULL, 10);
1051
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001052 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 switch (val) {
1055 case 1: /* PII/Celeron diode */
Jean Delvare787c72b2007-05-08 17:22:00 +02001056 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1057 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001058 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +02001059 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
1060 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +02001061 tmp | BIT_SCFG2[nr]);
1062 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 break;
1064 case 2: /* 3904 */
Jean Delvare787c72b2007-05-08 17:22:00 +02001065 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1066 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001067 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +02001068 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
1069 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +02001070 tmp & ~BIT_SCFG2[nr]);
1071 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 break;
Jean Delvareb26f9332007-08-16 14:30:01 +02001073 case W83781D_DEFAULT_BETA:
1074 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
1075 "instead\n", W83781D_DEFAULT_BETA);
1076 /* fall through */
1077 case 4: /* thermistor */
Jean Delvare787c72b2007-05-08 17:22:00 +02001078 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1079 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +02001080 tmp & ~BIT_SCFG1[nr]);
1081 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 break;
1083 default:
Jean Delvare787c72b2007-05-08 17:22:00 +02001084 dev_err(dev,
Jean Delvareb26f9332007-08-16 14:30:01 +02001085 "Invalid sensor type %ld; must be 1, 2, or 4\n",
1086 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 break;
1088 }
1089
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001090 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return count;
1092}
1093
Jim Cromie07584c72007-10-12 21:08:00 +02001094#define sysfs_temp_type(offset) \
1095static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
1096 show_temp_type, store_temp_type, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Jim Cromie07584c72007-10-12 21:08:00 +02001098sysfs_temp_type(1);
1099sysfs_temp_type(2);
1100sysfs_temp_type(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Jim Cromie07584c72007-10-12 21:08:00 +02001102static ssize_t
1103show_name(struct device *dev, struct device_attribute *devattr, char *buf)
Jean Delvare787c72b2007-05-08 17:22:00 +02001104{
1105 struct w83627hf_data *data = dev_get_drvdata(dev);
1106
1107 return sprintf(buf, "%s\n", data->name);
1108}
1109static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1110
1111static int __init w83627hf_find(int sioaddr, unsigned short *addr,
1112 struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Jean Delvared27c37c2007-05-08 17:21:59 +02001114 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 u16 val;
1116
Jean Delvare787c72b2007-05-08 17:22:00 +02001117 static const __initdata char *names[] = {
1118 "W83627HF",
1119 "W83627THF",
1120 "W83697HF",
1121 "W83637HF",
1122 "W83687THF",
1123 };
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 REG = sioaddr;
1126 VAL = sioaddr + 1;
1127
1128 superio_enter();
Jean Delvare67b671b2007-12-06 23:13:42 +01001129 val = force_id ? force_id : superio_inb(DEVID);
Jean Delvare787c72b2007-05-08 17:22:00 +02001130 switch (val) {
1131 case W627_DEVID:
1132 sio_data->type = w83627hf;
1133 break;
1134 case W627THF_DEVID:
1135 sio_data->type = w83627thf;
1136 break;
1137 case W697_DEVID:
1138 sio_data->type = w83697hf;
1139 break;
1140 case W637_DEVID:
1141 sio_data->type = w83637hf;
1142 break;
1143 case W687THF_DEVID:
1144 sio_data->type = w83687thf;
1145 break;
Jean Delvaree142e2a2007-05-27 22:17:43 +02001146 case 0xff: /* No device at all */
1147 goto exit;
Jean Delvare787c72b2007-05-08 17:22:00 +02001148 default:
Jean Delvaree142e2a2007-05-27 22:17:43 +02001149 pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
Jean Delvared27c37c2007-05-08 17:21:59 +02001150 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152
1153 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +02001154 force_addr &= WINB_ALIGNMENT;
1155 if (force_addr) {
1156 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1157 force_addr);
1158 superio_outb(WINB_BASE_REG, force_addr >> 8);
1159 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 val = (superio_inb(WINB_BASE_REG) << 8) |
1162 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001163 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +02001164 if (*addr == 0) {
1165 printk(KERN_WARNING DRVNAME ": Base address not set, "
1166 "skipping\n");
1167 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Jean Delvared27c37c2007-05-08 17:21:59 +02001170 val = superio_inb(WINB_ACT_REG);
1171 if (!(val & 0x01)) {
1172 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1173 superio_outb(WINB_ACT_REG, val | 0x01);
1174 }
1175
1176 err = 0;
Jean Delvare787c72b2007-05-08 17:22:00 +02001177 pr_info(DRVNAME ": Found %s chip at %#x\n",
1178 names[sio_data->type], *addr);
Jean Delvared27c37c2007-05-08 17:21:59 +02001179
1180 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +02001182 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183}
1184
Jim Cromie07584c72007-10-12 21:08:00 +02001185#define VIN_UNIT_ATTRS(_X_) \
1186 &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
1187 &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001188 &sensor_dev_attr_in##_X_##_max.dev_attr.attr, \
1189 &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr, \
1190 &sensor_dev_attr_in##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001191
1192#define FAN_UNIT_ATTRS(_X_) \
1193 &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
1194 &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001195 &sensor_dev_attr_fan##_X_##_div.dev_attr.attr, \
1196 &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr, \
1197 &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001198
1199#define TEMP_UNIT_ATTRS(_X_) \
1200 &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
1201 &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
1202 &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
Jean Delvaree3604c62008-01-03 23:00:30 +01001203 &sensor_dev_attr_temp##_X_##_type.dev_attr.attr, \
1204 &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \
1205 &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr
Jim Cromie07584c72007-10-12 21:08:00 +02001206
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001207static struct attribute *w83627hf_attributes[] = {
1208 &dev_attr_in0_input.attr,
1209 &dev_attr_in0_min.attr,
1210 &dev_attr_in0_max.attr,
Jean Delvaree3604c62008-01-03 23:00:30 +01001211 &sensor_dev_attr_in0_alarm.dev_attr.attr,
1212 &sensor_dev_attr_in0_beep.dev_attr.attr,
Jim Cromie07584c72007-10-12 21:08:00 +02001213 VIN_UNIT_ATTRS(2),
1214 VIN_UNIT_ATTRS(3),
1215 VIN_UNIT_ATTRS(4),
1216 VIN_UNIT_ATTRS(7),
1217 VIN_UNIT_ATTRS(8),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001218
Jim Cromie07584c72007-10-12 21:08:00 +02001219 FAN_UNIT_ATTRS(1),
1220 FAN_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001221
Jim Cromie07584c72007-10-12 21:08:00 +02001222 TEMP_UNIT_ATTRS(1),
1223 TEMP_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001224
1225 &dev_attr_alarms.attr,
1226 &dev_attr_beep_enable.attr,
1227 &dev_attr_beep_mask.attr,
1228
Jim Cromie07584c72007-10-12 21:08:00 +02001229 &sensor_dev_attr_pwm1.dev_attr.attr,
1230 &sensor_dev_attr_pwm2.dev_attr.attr,
Jean Delvare787c72b2007-05-08 17:22:00 +02001231 &dev_attr_name.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001232 NULL
1233};
1234
1235static const struct attribute_group w83627hf_group = {
1236 .attrs = w83627hf_attributes,
1237};
1238
1239static struct attribute *w83627hf_attributes_opt[] = {
Jim Cromie07584c72007-10-12 21:08:00 +02001240 VIN_UNIT_ATTRS(1),
1241 VIN_UNIT_ATTRS(5),
1242 VIN_UNIT_ATTRS(6),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001243
Jim Cromie07584c72007-10-12 21:08:00 +02001244 FAN_UNIT_ATTRS(3),
1245 TEMP_UNIT_ATTRS(3),
1246 &sensor_dev_attr_pwm3.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001247
Jim Cromie07584c72007-10-12 21:08:00 +02001248 &sensor_dev_attr_pwm1_freq.dev_attr.attr,
1249 &sensor_dev_attr_pwm2_freq.dev_attr.attr,
1250 &sensor_dev_attr_pwm3_freq.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001251 NULL
1252};
1253
1254static const struct attribute_group w83627hf_group_opt = {
1255 .attrs = w83627hf_attributes_opt,
1256};
1257
Jean Delvare787c72b2007-05-08 17:22:00 +02001258static int __devinit w83627hf_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
Jean Delvare787c72b2007-05-08 17:22:00 +02001260 struct device *dev = &pdev->dev;
1261 struct w83627hf_sio_data *sio_data = dev->platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 struct w83627hf_data *data;
Jean Delvare787c72b2007-05-08 17:22:00 +02001263 struct resource *res;
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001264 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Jean Delvare787c72b2007-05-08 17:22:00 +02001266 static const char *names[] = {
1267 "w83627hf",
1268 "w83627thf",
1269 "w83697hf",
1270 "w83637hf",
1271 "w83687thf",
1272 };
1273
1274 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1275 if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1276 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1277 (unsigned long)res->start,
1278 (unsigned long)(res->start + WINB_REGION_SIZE - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 err = -EBUSY;
1280 goto ERROR0;
1281 }
1282
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001283 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 err = -ENOMEM;
1285 goto ERROR1;
1286 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001287 data->addr = res->start;
1288 data->type = sio_data->type;
1289 data->name = names[sio_data->type];
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001290 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001291 mutex_init(&data->update_lock);
Jean Delvare787c72b2007-05-08 17:22:00 +02001292 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 /* Initialize the chip */
Jean Delvare787c72b2007-05-08 17:22:00 +02001295 w83627hf_init_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 /* A few vars need to be filled upon startup */
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001298 for (i = 0; i <= 2; i++)
1299 data->fan_min[i] = w83627hf_read_value(
1300 data, W83627HF_REG_FAN_MIN(i));
Jean Delvarec09c5182007-10-12 21:53:07 +02001301 w83627hf_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001303 /* Register common device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001304 if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001305 goto ERROR3;
1306
1307 /* Register chip-specific device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001308 if (data->type == w83627hf || data->type == w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001309 if ((err = device_create_file(dev,
1310 &sensor_dev_attr_in5_input.dev_attr))
1311 || (err = device_create_file(dev,
1312 &sensor_dev_attr_in5_min.dev_attr))
1313 || (err = device_create_file(dev,
1314 &sensor_dev_attr_in5_max.dev_attr))
1315 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001316 &sensor_dev_attr_in5_alarm.dev_attr))
1317 || (err = device_create_file(dev,
1318 &sensor_dev_attr_in5_beep.dev_attr))
1319 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001320 &sensor_dev_attr_in6_input.dev_attr))
1321 || (err = device_create_file(dev,
1322 &sensor_dev_attr_in6_min.dev_attr))
1323 || (err = device_create_file(dev,
1324 &sensor_dev_attr_in6_max.dev_attr))
1325 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001326 &sensor_dev_attr_in6_alarm.dev_attr))
1327 || (err = device_create_file(dev,
1328 &sensor_dev_attr_in6_beep.dev_attr))
1329 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001330 &sensor_dev_attr_pwm1_freq.dev_attr))
1331 || (err = device_create_file(dev,
1332 &sensor_dev_attr_pwm2_freq.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001333 goto ERROR4;
1334
Jean Delvare787c72b2007-05-08 17:22:00 +02001335 if (data->type != w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001336 if ((err = device_create_file(dev,
1337 &sensor_dev_attr_in1_input.dev_attr))
1338 || (err = device_create_file(dev,
1339 &sensor_dev_attr_in1_min.dev_attr))
1340 || (err = device_create_file(dev,
1341 &sensor_dev_attr_in1_max.dev_attr))
1342 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001343 &sensor_dev_attr_in1_alarm.dev_attr))
1344 || (err = device_create_file(dev,
1345 &sensor_dev_attr_in1_beep.dev_attr))
1346 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001347 &sensor_dev_attr_fan3_input.dev_attr))
1348 || (err = device_create_file(dev,
1349 &sensor_dev_attr_fan3_min.dev_attr))
1350 || (err = device_create_file(dev,
1351 &sensor_dev_attr_fan3_div.dev_attr))
1352 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001353 &sensor_dev_attr_fan3_alarm.dev_attr))
1354 || (err = device_create_file(dev,
1355 &sensor_dev_attr_fan3_beep.dev_attr))
1356 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001357 &sensor_dev_attr_temp3_input.dev_attr))
1358 || (err = device_create_file(dev,
1359 &sensor_dev_attr_temp3_max.dev_attr))
1360 || (err = device_create_file(dev,
1361 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1362 || (err = device_create_file(dev,
Jean Delvaree3604c62008-01-03 23:00:30 +01001363 &sensor_dev_attr_temp3_alarm.dev_attr))
1364 || (err = device_create_file(dev,
1365 &sensor_dev_attr_temp3_beep.dev_attr))
1366 || (err = device_create_file(dev,
Jim Cromie07584c72007-10-12 21:08:00 +02001367 &sensor_dev_attr_temp3_type.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001368 goto ERROR4;
1369
Jean Delvare787c72b2007-05-08 17:22:00 +02001370 if (data->type != w83697hf && data->vid != 0xff) {
Jean Delvare8a665a02007-05-08 17:21:59 +02001371 /* Convert VID to voltage based on VRM */
1372 data->vrm = vid_which_vrm();
1373
Jean Delvare787c72b2007-05-08 17:22:00 +02001374 if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1375 || (err = device_create_file(dev, &dev_attr_vrm)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001376 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001377 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001378
Jean Delvare787c72b2007-05-08 17:22:00 +02001379 if (data->type == w83627thf || data->type == w83637hf
1380 || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001381 if ((err = device_create_file(dev,
1382 &sensor_dev_attr_pwm3.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001383 goto ERROR4;
1384
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001385 if (data->type == w83637hf || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001386 if ((err = device_create_file(dev,
1387 &sensor_dev_attr_pwm1_freq.dev_attr))
1388 || (err = device_create_file(dev,
1389 &sensor_dev_attr_pwm2_freq.dev_attr))
1390 || (err = device_create_file(dev,
1391 &sensor_dev_attr_pwm3_freq.dev_attr)))
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001392 goto ERROR4;
1393
Tony Jones1beeffe2007-08-20 13:46:20 -07001394 data->hwmon_dev = hwmon_device_register(dev);
1395 if (IS_ERR(data->hwmon_dev)) {
1396 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001397 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001398 }
1399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 return 0;
1401
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001402 ERROR4:
Jean Delvare787c72b2007-05-08 17:22:00 +02001403 sysfs_remove_group(&dev->kobj, &w83627hf_group);
1404 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001405 ERROR3:
Jean Delvare04a62172007-06-12 13:57:19 +02001406 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 kfree(data);
1408 ERROR1:
Jean Delvare787c72b2007-05-08 17:22:00 +02001409 release_region(res->start, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 ERROR0:
1411 return err;
1412}
1413
Jean Delvare787c72b2007-05-08 17:22:00 +02001414static int __devexit w83627hf_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415{
Jean Delvare787c72b2007-05-08 17:22:00 +02001416 struct w83627hf_data *data = platform_get_drvdata(pdev);
1417 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Tony Jones1beeffe2007-08-20 13:46:20 -07001419 hwmon_device_unregister(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001420
Jean Delvare787c72b2007-05-08 17:22:00 +02001421 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1422 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
Jean Delvare04a62172007-06-12 13:57:19 +02001423 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001424 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Jean Delvare787c72b2007-05-08 17:22:00 +02001426 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1427 release_region(res->start, WINB_REGION_SIZE);
1428
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 return 0;
1430}
1431
1432
Jean Delvared58df9c2007-10-10 16:30:23 +02001433/* Registers 0x50-0x5f are banked */
1434static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
1435{
1436 if ((reg & 0x00f0) == 0x50) {
1437 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1438 outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
1439 }
1440}
1441
1442/* Not strictly necessary, but play it safe for now */
1443static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
1444{
1445 if (reg & 0xff00) {
1446 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1447 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
1448 }
1449}
1450
Jean Delvare787c72b2007-05-08 17:22:00 +02001451static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 int res, word_sized;
1454
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001455 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 word_sized = (((reg & 0xff00) == 0x100)
1457 || ((reg & 0xff00) == 0x200))
1458 && (((reg & 0x00ff) == 0x50)
1459 || ((reg & 0x00ff) == 0x53)
1460 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001461 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001462 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1463 res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if (word_sized) {
1465 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001466 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 res =
Jean Delvare787c72b2007-05-08 17:22:00 +02001468 (res << 8) + inb_p(data->addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 W83781D_DATA_REG_OFFSET);
1470 }
Jean Delvared58df9c2007-10-10 16:30:23 +02001471 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001472 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 return res;
1474}
1475
Jean Delvare787c72b2007-05-08 17:22:00 +02001476static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
1478 int res = 0xff, sel;
1479
1480 superio_enter();
1481 superio_select(W83627HF_LD_GPIO5);
1482
1483 /* Make sure these GPIO pins are enabled */
1484 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001485 dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 goto exit;
1487 }
1488
1489 /* Make sure the pins are configured for input
1490 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001491 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if ((sel & 0x1f) != 0x1f) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001493 dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 "function\n");
1495 goto exit;
1496 }
1497
Jean Delvare787c72b2007-05-08 17:22:00 +02001498 dev_info(&pdev->dev, "Reading VID from GPIO5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1500
1501exit:
1502 superio_exit();
1503 return res;
1504}
1505
Jean Delvare787c72b2007-05-08 17:22:00 +02001506static int __devinit w83687thf_read_vid(struct platform_device *pdev)
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001507{
1508 int res = 0xff;
1509
1510 superio_enter();
1511 superio_select(W83627HF_LD_HWM);
1512
1513 /* Make sure these GPIO pins are enabled */
1514 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001515 dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001516 goto exit;
1517 }
1518
1519 /* Make sure the pins are configured for input */
1520 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001521 dev_dbg(&pdev->dev, "VID configured as output, "
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001522 "no VID function\n");
1523 goto exit;
1524 }
1525
1526 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1527
1528exit:
1529 superio_exit();
1530 return res;
1531}
1532
Jean Delvare787c72b2007-05-08 17:22:00 +02001533static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 int word_sized;
1536
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001537 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 word_sized = (((reg & 0xff00) == 0x100)
1539 || ((reg & 0xff00) == 0x200))
1540 && (((reg & 0x00ff) == 0x53)
1541 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001542 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001543 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (word_sized) {
1545 outb_p(value >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001546 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001548 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 }
1550 outb_p(value & 0xff,
Jean Delvare787c72b2007-05-08 17:22:00 +02001551 data->addr + W83781D_DATA_REG_OFFSET);
Jean Delvared58df9c2007-10-10 16:30:23 +02001552 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001553 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 return 0;
1555}
1556
Jean Delvare787c72b2007-05-08 17:22:00 +02001557static void __devinit w83627hf_init_device(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
Jean Delvare787c72b2007-05-08 17:22:00 +02001559 struct w83627hf_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001561 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 u8 tmp;
1563
Jean Delvare2251cf12005-09-04 22:52:17 +02001564 if (reset) {
1565 /* Resetting the chip has been the default for a long time,
1566 but repeatedly caused problems (fans going to full
1567 speed...) so it is now optional. It might even go away if
1568 nobody reports it as being useful, as I see very little
1569 reason why this would be needed at all. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001570 dev_info(&pdev->dev, "If reset=1 solved a problem you were "
Jean Delvare2251cf12005-09-04 22:52:17 +02001571 "having, please report!\n");
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 /* save this register */
Jean Delvare787c72b2007-05-08 17:22:00 +02001574 i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 /* Reset all except Watchdog values and last conversion values
1576 This sets fan-divs to 2, among others */
Jean Delvare787c72b2007-05-08 17:22:00 +02001577 w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 /* Restore the register and disable power-on abnormal beep.
1579 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001580 w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 /* Disable master beep-enable (reset turns it on).
1582 Individual beeps should be reset to off but for some reason
1583 disabling this bit helps some people not get beeped */
Jean Delvare787c72b2007-05-08 17:22:00 +02001584 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 }
1586
1587 /* Minimize conflicts with other winbond i2c-only clients... */
1588 /* disable i2c subclients... how to disable main i2c client?? */
1589 /* force i2c address to relatively uncommon address */
Jean Delvare787c72b2007-05-08 17:22:00 +02001590 w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1591 w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001594 if (type == w83627hf || type == w83637hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001595 int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1596 int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001598 } else if (type == w83627thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001599 data->vid = w83627thf_read_gpio5(pdev);
Jean Delvared27c37c2007-05-08 17:21:59 +02001600 } else if (type == w83687thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001601 data->vid = w83687thf_read_vid(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
1603
1604 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001605 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 data->vrm_ovt =
Jean Delvare787c72b2007-05-08 17:22:00 +02001607 w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
1609
Jean Delvare787c72b2007-05-08 17:22:00 +02001610 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 for (i = 1; i <= 3; i++) {
1612 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001613 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 } else {
1615 if (w83627hf_read_value
Jean Delvare787c72b2007-05-08 17:22:00 +02001616 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1618 data->sens[i - 1] = 1;
1619 else
1620 data->sens[i - 1] = 2;
1621 }
1622 if ((type == w83697hf) && (i == 2))
1623 break;
1624 }
1625
1626 if(init) {
1627 /* Enable temp2 */
Jim Cromiedf48ed82007-10-14 17:10:52 -06001628 tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001630 dev_warn(&pdev->dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 "might not make sense\n");
Jim Cromiedf48ed82007-10-14 17:10:52 -06001632 w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 tmp & 0xfe);
1634 }
1635
1636 /* Enable temp3 */
1637 if (type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001638 tmp = w83627hf_read_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001639 W83627HF_REG_TEMP3_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001641 dev_warn(&pdev->dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 "readings might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001643 w83627hf_write_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001644 W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 }
1646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 }
1648
1649 /* Start monitoring */
Jean Delvare787c72b2007-05-08 17:22:00 +02001650 w83627hf_write_value(data, W83781D_REG_CONFIG,
1651 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 W83781D_REG_CONFIG) & 0xf7)
1653 | 0x01);
Jean Delvareef878b12008-01-03 22:54:13 +01001654
1655 /* Enable VBAT monitoring if needed */
1656 tmp = w83627hf_read_value(data, W83781D_REG_VBAT);
1657 if (!(tmp & 0x01))
1658 w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659}
1660
Jean Delvarec09c5182007-10-12 21:53:07 +02001661static void w83627hf_update_fan_div(struct w83627hf_data *data)
1662{
1663 int reg;
1664
1665 reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1666 data->fan_div[0] = (reg >> 4) & 0x03;
1667 data->fan_div[1] = (reg >> 6) & 0x03;
1668 if (data->type != w83697hf) {
1669 data->fan_div[2] = (w83627hf_read_value(data,
1670 W83781D_REG_PIN) >> 6) & 0x03;
1671 }
1672 reg = w83627hf_read_value(data, W83781D_REG_VBAT);
1673 data->fan_div[0] |= (reg >> 3) & 0x04;
1674 data->fan_div[1] |= (reg >> 4) & 0x04;
1675 if (data->type != w83697hf)
1676 data->fan_div[2] |= (reg >> 5) & 0x04;
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1680{
Jean Delvare787c72b2007-05-08 17:22:00 +02001681 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -06001682 int i, num_temps = (data->type == w83697hf) ? 2 : 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001684 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
1686 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1687 || !data->valid) {
1688 for (i = 0; i <= 8; i++) {
1689 /* skip missing sensors */
1690 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001691 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001692 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 continue;
1694 data->in[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001695 w83627hf_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 data->in_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001697 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 W83781D_REG_IN_MIN(i));
1699 data->in_max[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001700 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 W83781D_REG_IN_MAX(i));
1702 }
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001703 for (i = 0; i <= 2; i++) {
1704 data->fan[i] =
1705 w83627hf_read_value(data, W83627HF_REG_FAN(i));
1706 data->fan_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001707 w83627hf_read_value(data,
Jim Cromie2ca2fcd2007-10-14 17:20:50 -06001708 W83627HF_REG_FAN_MIN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 }
Jim Cromie07584c72007-10-12 21:08:00 +02001710 for (i = 0; i <= 2; i++) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001711 u8 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 W836X7HF_REG_PWM(data->type, i));
1713 /* bits 0-3 are reserved in 627THF */
1714 if (data->type == w83627thf)
1715 tmp &= 0xf0;
Jim Cromie07584c72007-10-12 21:08:00 +02001716 data->pwm[i] = tmp;
1717 if (i == 1 &&
1718 (data->type == w83627hf || data->type == w83697hf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 break;
1720 }
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001721 if (data->type == w83627hf) {
1722 u8 tmp = w83627hf_read_value(data,
1723 W83627HF_REG_PWM_FREQ);
1724 data->pwm_freq[0] = tmp & 0x07;
1725 data->pwm_freq[1] = (tmp >> 4) & 0x07;
1726 } else if (data->type != w83627thf) {
1727 for (i = 1; i <= 3; i++) {
1728 data->pwm_freq[i - 1] =
1729 w83627hf_read_value(data,
1730 W83637HF_REG_PWM_FREQ[i - 1]);
1731 if (i == 2 && (data->type == w83697hf))
1732 break;
1733 }
1734 }
Jim Cromiedf48ed82007-10-14 17:10:52 -06001735 for (i = 0; i < num_temps; i++) {
1736 data->temp[i] = w83627hf_read_value(
1737 data, w83627hf_reg_temp[i]);
1738 data->temp_max[i] = w83627hf_read_value(
1739 data, w83627hf_reg_temp_over[i]);
1740 data->temp_max_hyst[i] = w83627hf_read_value(
1741 data, w83627hf_reg_temp_hyst[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743
Jean Delvarec09c5182007-10-12 21:53:07 +02001744 w83627hf_update_fan_div(data);
1745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 data->alarms =
Jean Delvare787c72b2007-05-08 17:22:00 +02001747 w83627hf_read_value(data, W83781D_REG_ALARM1) |
1748 (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1749 (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1750 i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 data->beep_enable = i >> 7;
1752 data->beep_mask = ((i & 0x7f) << 8) |
Jean Delvare787c72b2007-05-08 17:22:00 +02001753 w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1754 w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 data->last_updated = jiffies;
1756 data->valid = 1;
1757 }
1758
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001759 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 return data;
1762}
1763
Jean Delvare787c72b2007-05-08 17:22:00 +02001764static int __init w83627hf_device_add(unsigned short address,
1765 const struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766{
Jean Delvare787c72b2007-05-08 17:22:00 +02001767 struct resource res = {
1768 .start = address + WINB_REGION_OFFSET,
1769 .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1770 .name = DRVNAME,
1771 .flags = IORESOURCE_IO,
1772 };
1773 int err;
1774
1775 pdev = platform_device_alloc(DRVNAME, address);
1776 if (!pdev) {
1777 err = -ENOMEM;
1778 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1779 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Jean Delvare787c72b2007-05-08 17:22:00 +02001782 err = platform_device_add_resources(pdev, &res, 1);
1783 if (err) {
1784 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1785 "(%d)\n", err);
1786 goto exit_device_put;
1787 }
1788
Jean Delvare2df6d812007-06-09 10:11:16 -04001789 err = platform_device_add_data(pdev, sio_data,
1790 sizeof(struct w83627hf_sio_data));
1791 if (err) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001792 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1793 goto exit_device_put;
1794 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001795
1796 err = platform_device_add(pdev);
1797 if (err) {
1798 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1799 err);
1800 goto exit_device_put;
1801 }
1802
1803 return 0;
1804
1805exit_device_put:
1806 platform_device_put(pdev);
1807exit:
1808 return err;
1809}
1810
1811static int __init sensors_w83627hf_init(void)
1812{
1813 int err;
1814 unsigned short address;
1815 struct w83627hf_sio_data sio_data;
1816
1817 if (w83627hf_find(0x2e, &address, &sio_data)
1818 && w83627hf_find(0x4e, &address, &sio_data))
1819 return -ENODEV;
1820
1821 err = platform_driver_register(&w83627hf_driver);
1822 if (err)
1823 goto exit;
1824
1825 /* Sets global pdev as a side effect */
1826 err = w83627hf_device_add(address, &sio_data);
1827 if (err)
1828 goto exit_driver;
1829
1830 return 0;
1831
1832exit_driver:
1833 platform_driver_unregister(&w83627hf_driver);
1834exit:
1835 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836}
1837
1838static void __exit sensors_w83627hf_exit(void)
1839{
Jean Delvare787c72b2007-05-08 17:22:00 +02001840 platform_device_unregister(pdev);
1841 platform_driver_unregister(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842}
1843
1844MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1845 "Philip Edelbrock <phil@netroedge.com>, "
1846 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1847MODULE_DESCRIPTION("W83627HF driver");
1848MODULE_LICENSE("GPL");
1849
1850module_init(sensors_w83627hf_init);
1851module_exit(sensors_w83627hf_exit);