blob: 410f10687cc4554dc616cc2320d34a63d14b0bfb [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
78/* modified from kernel/include/traps.c */
79static int REG; /* The register to read/write */
80#define DEV 0x07 /* Register: Logical device select */
81static int VAL; /* The value to read/write */
82
83/* logical device numbers for superio_select (below) */
84#define W83627HF_LD_FDC 0x00
85#define W83627HF_LD_PRT 0x01
86#define W83627HF_LD_UART1 0x02
87#define W83627HF_LD_UART2 0x03
88#define W83627HF_LD_KBC 0x05
89#define W83627HF_LD_CIR 0x06 /* w83627hf only */
90#define W83627HF_LD_GAME 0x07
91#define W83627HF_LD_MIDI 0x07
92#define W83627HF_LD_GPIO1 0x07
93#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
94#define W83627HF_LD_GPIO2 0x08
95#define W83627HF_LD_GPIO3 0x09
96#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
97#define W83627HF_LD_ACPI 0x0a
98#define W83627HF_LD_HWM 0x0b
99
100#define DEVID 0x20 /* Register: Device ID */
101
102#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
103#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
104#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
105
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100106#define W83687THF_VID_EN 0x29 /* w83687thf only */
107#define W83687THF_VID_CFG 0xF0 /* w83687thf only */
108#define W83687THF_VID_DATA 0xF1 /* w83687thf only */
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110static inline void
111superio_outb(int reg, int val)
112{
113 outb(reg, REG);
114 outb(val, VAL);
115}
116
117static inline int
118superio_inb(int reg)
119{
120 outb(reg, REG);
121 return inb(VAL);
122}
123
124static inline void
125superio_select(int ld)
126{
127 outb(DEV, REG);
128 outb(ld, VAL);
129}
130
131static inline void
132superio_enter(void)
133{
134 outb(0x87, REG);
135 outb(0x87, REG);
136}
137
138static inline void
139superio_exit(void)
140{
141 outb(0xAA, REG);
142}
143
144#define W627_DEVID 0x52
145#define W627THF_DEVID 0x82
146#define W697_DEVID 0x60
147#define W637_DEVID 0x70
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100148#define W687THF_DEVID 0x85
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#define WINB_ACT_REG 0x30
150#define WINB_BASE_REG 0x60
151/* Constants specified below */
152
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200153/* Alignment of the base address */
154#define WINB_ALIGNMENT ~7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200156/* Offset & size of I/O region we are interested in */
157#define WINB_REGION_OFFSET 5
158#define WINB_REGION_SIZE 2
159
Jean Delvare787c72b2007-05-08 17:22:00 +0200160/* Where are the sensors address/data registers relative to the region offset */
161#define W83781D_ADDR_REG_OFFSET 0
162#define W83781D_DATA_REG_OFFSET 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164/* The W83781D registers */
165/* The W83782D registers for nr=7,8 are in bank 5 */
166#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
167 (0x554 + (((nr) - 7) * 2)))
168#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
169 (0x555 + (((nr) - 7) * 2)))
170#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
171 (0x550 + (nr) - 7))
172
173#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
174#define W83781D_REG_FAN(nr) (0x27 + (nr))
175
Jim Cromiedf48ed82007-10-14 17:10:52 -0600176#define W83627HF_REG_TEMP2_CONFIG 0x152
177#define W83627HF_REG_TEMP3_CONFIG 0x252
178/* these are zero-based, unlike config constants above */
179static const u16 w83627hf_reg_temp[] = { 0x27, 0x150, 0x250 };
180static const u16 w83627hf_reg_temp_hyst[] = { 0x3A, 0x153, 0x253 };
181static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183#define W83781D_REG_BANK 0x4E
184
185#define W83781D_REG_CONFIG 0x40
Yuan Mu4a1c44472005-11-07 22:19:04 +0100186#define W83781D_REG_ALARM1 0x459
187#define W83781D_REG_ALARM2 0x45A
188#define W83781D_REG_ALARM3 0x45B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define W83781D_REG_BEEP_CONFIG 0x4D
191#define W83781D_REG_BEEP_INTS1 0x56
192#define W83781D_REG_BEEP_INTS2 0x57
193#define W83781D_REG_BEEP_INTS3 0x453
194
195#define W83781D_REG_VID_FANDIV 0x47
196
197#define W83781D_REG_CHIPID 0x49
198#define W83781D_REG_WCHIPID 0x58
199#define W83781D_REG_CHIPMAN 0x4F
200#define W83781D_REG_PIN 0x4B
201
202#define W83781D_REG_VBAT 0x5D
203
204#define W83627HF_REG_PWM1 0x5A
205#define W83627HF_REG_PWM2 0x5B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100207#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
208#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
209#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100211#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
214static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
215 W83627THF_REG_PWM3 };
216#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
Jim Cromie07584c72007-10-12 21:08:00 +0200217 regpwm_627hf[nr] : regpwm[nr])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400219#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
220
221#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
222#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
223#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
224
225static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
226 W83637HF_REG_PWM_FREQ2,
227 W83637HF_REG_PWM_FREQ3 };
228
229#define W83627HF_BASE_PWM_FREQ 46870
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231#define W83781D_REG_I2C_ADDR 0x48
232#define W83781D_REG_I2C_SUBADDR 0x4A
233
234/* Sensor selection */
235#define W83781D_REG_SCFG1 0x5D
236static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
237#define W83781D_REG_SCFG2 0x59
238static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
239#define W83781D_DEFAULT_BETA 3435
240
241/* Conversions. Limit checking is only done on the TO_REG
242 variants. Note that you should be a bit careful with which arguments
243 these macros are called: arguments may be evaluated more than once.
244 Fixing this is just not worth it. */
245#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
246#define IN_FROM_REG(val) ((val) * 16)
247
248static inline u8 FAN_TO_REG(long rpm, int div)
249{
250 if (rpm == 0)
251 return 255;
252 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
253 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
254 254);
255}
256
257#define TEMP_MIN (-128000)
258#define TEMP_MAX ( 127000)
259
260/* TEMP: 0.001C/bit (-128C to +127C)
261 REG: 1C/bit, two's complement */
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200262static u8 TEMP_TO_REG(long temp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
265 ntemp += (ntemp<0 ? -500 : 500);
266 return (u8)(ntemp / 1000);
267}
268
269static int TEMP_FROM_REG(u8 reg)
270{
271 return (s8)reg * 1000;
272}
273
274#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
275
276#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
277
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400278static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
279{
280 unsigned long freq;
281 freq = W83627HF_BASE_PWM_FREQ >> reg;
282 return freq;
283}
284static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
285{
286 u8 i;
287 /* Only 5 dividers (1 2 4 8 16)
288 Search for the nearest available frequency */
289 for (i = 0; i < 4; i++) {
290 if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
291 (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
292 break;
293 }
294 return i;
295}
296
297static inline unsigned long pwm_freq_from_reg(u8 reg)
298{
299 /* Clock bit 8 -> 180 kHz or 24 MHz */
300 unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
301
302 reg &= 0x7f;
303 /* This should not happen but anyway... */
304 if (reg == 0)
305 reg++;
306 return (clock / (reg << 8));
307}
308static inline u8 pwm_freq_to_reg(unsigned long val)
309{
310 /* Minimum divider value is 0x01 and maximum is 0x7F */
311 if (val >= 93750) /* The highest we can do */
312 return 0x01;
313 if (val >= 720) /* Use 24 MHz clock */
314 return (24000000UL / (val << 8));
315 if (val < 6) /* The lowest we can do */
316 return 0xFF;
317 else /* Use 180 kHz clock */
318 return (0x80 | (180000UL / (val << 8)));
319}
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321#define BEEP_MASK_FROM_REG(val) (val)
322#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
323#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
324#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
325
326#define DIV_FROM_REG(val) (1 << (val))
327
328static inline u8 DIV_TO_REG(long val)
329{
330 int i;
331 val = SENSORS_LIMIT(val, 1, 128) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000332 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (val == 0)
334 break;
335 val >>= 1;
336 }
337 return ((u8) i);
338}
339
Jean Delvareed6bafb2007-02-14 21:15:03 +0100340/* For each registered chip, we need to keep some data in memory.
341 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342struct w83627hf_data {
Jean Delvare787c72b2007-05-08 17:22:00 +0200343 unsigned short addr;
344 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700345 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100346 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 enum chips type;
348
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100349 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 char valid; /* !=0 if following fields are valid */
351 unsigned long last_updated; /* In jiffies */
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 u8 in[9]; /* Register value */
354 u8 in_max[9]; /* Register value */
355 u8 in_min[9]; /* Register value */
356 u8 fan[3]; /* Register value */
357 u8 fan_min[3]; /* Register value */
Jim Cromiedf48ed82007-10-14 17:10:52 -0600358 u16 temp[3]; /* Register value */
359 u16 temp_max[3]; /* Register value */
360 u16 temp_max_hyst[3]; /* Register value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 u8 fan_div[3]; /* Register encoding, shifted right */
362 u8 vid; /* Register encoding, combined */
363 u32 alarms; /* Register encoding, combined */
364 u32 beep_mask; /* Register encoding, combined */
365 u8 beep_enable; /* Boolean */
366 u8 pwm[3]; /* Register value */
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400367 u8 pwm_freq[3]; /* Register value */
Jean Delvareb26f9332007-08-16 14:30:01 +0200368 u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
369 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 u8 vrm;
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100371 u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372};
373
Jean Delvare787c72b2007-05-08 17:22:00 +0200374struct w83627hf_sio_data {
375 enum chips type;
376};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Jean Delvare787c72b2007-05-08 17:22:00 +0200379static int w83627hf_probe(struct platform_device *pdev);
Jean Delvared0546122007-07-22 12:09:48 +0200380static int __devexit w83627hf_remove(struct platform_device *pdev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200381
382static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
383static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
Jean Delvarec09c5182007-10-12 21:53:07 +0200384static void w83627hf_update_fan_div(struct w83627hf_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385static struct w83627hf_data *w83627hf_update_device(struct device *dev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200386static void w83627hf_init_device(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Jean Delvare787c72b2007-05-08 17:22:00 +0200388static struct platform_driver w83627hf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100389 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200390 .owner = THIS_MODULE,
Jean Delvared27c37c2007-05-08 17:21:59 +0200391 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100392 },
Jean Delvare787c72b2007-05-08 17:22:00 +0200393 .probe = w83627hf_probe,
394 .remove = __devexit_p(w83627hf_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395};
396
Jim Cromie07584c72007-10-12 21:08:00 +0200397static ssize_t
398show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
399{
400 int nr = to_sensor_dev_attr(devattr)->index;
401 struct w83627hf_data *data = w83627hf_update_device(dev);
402 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
Jim Cromie07584c72007-10-12 21:08:00 +0200404static ssize_t
405show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
406{
407 int nr = to_sensor_dev_attr(devattr)->index;
408 struct w83627hf_data *data = w83627hf_update_device(dev);
409 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
Jim Cromie07584c72007-10-12 21:08:00 +0200411static ssize_t
412show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
413{
414 int nr = to_sensor_dev_attr(devattr)->index;
415 struct w83627hf_data *data = w83627hf_update_device(dev);
416 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
417}
418static ssize_t
419store_in_min(struct device *dev, struct device_attribute *devattr,
420 const char *buf, size_t count)
421{
422 int nr = to_sensor_dev_attr(devattr)->index;
423 struct w83627hf_data *data = dev_get_drvdata(dev);
424 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Jim Cromie07584c72007-10-12 21:08:00 +0200426 mutex_lock(&data->update_lock);
427 data->in_min[nr] = IN_TO_REG(val);
428 w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
429 mutex_unlock(&data->update_lock);
430 return count;
431}
432static ssize_t
433store_in_max(struct device *dev, struct device_attribute *devattr,
434 const char *buf, size_t count)
435{
436 int nr = to_sensor_dev_attr(devattr)->index;
437 struct w83627hf_data *data = dev_get_drvdata(dev);
438 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Jim Cromie07584c72007-10-12 21:08:00 +0200440 mutex_lock(&data->update_lock);
441 data->in_max[nr] = IN_TO_REG(val);
442 w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
443 mutex_unlock(&data->update_lock);
444 return count;
445}
446#define sysfs_vin_decl(offset) \
447static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
448 show_in_input, NULL, offset); \
449static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
450 show_in_min, store_in_min, offset); \
451static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
452 show_in_max, store_in_max, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Jim Cromie07584c72007-10-12 21:08:00 +0200454sysfs_vin_decl(1);
455sysfs_vin_decl(2);
456sysfs_vin_decl(3);
457sysfs_vin_decl(4);
458sysfs_vin_decl(5);
459sysfs_vin_decl(6);
460sysfs_vin_decl(7);
461sysfs_vin_decl(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463/* use a different set of functions for in0 */
464static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
465{
466 long in0;
467
468 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100469 (w83627thf == data->type || w83637hf == data->type
470 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 /* use VRM9 calculation */
473 in0 = (long)((reg * 488 + 70000 + 50) / 100);
474 else
475 /* use VRM8 (standard) calculation */
476 in0 = (long)IN_FROM_REG(reg);
477
478 return sprintf(buf,"%ld\n", in0);
479}
480
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400481static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct w83627hf_data *data = w83627hf_update_device(dev);
484 return show_in_0(data, buf, data->in[0]);
485}
486
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400487static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 struct w83627hf_data *data = w83627hf_update_device(dev);
490 return show_in_0(data, buf, data->in_min[0]);
491}
492
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400493static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 struct w83627hf_data *data = w83627hf_update_device(dev);
496 return show_in_0(data, buf, data->in_max[0]);
497}
498
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400499static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 const char *buf, size_t count)
501{
Jean Delvare787c72b2007-05-08 17:22:00 +0200502 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 u32 val;
504
505 val = simple_strtoul(buf, NULL, 10);
506
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100507 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100510 (w83627thf == data->type || w83637hf == data->type
511 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800514 data->in_min[0] =
515 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
516 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 else
518 /* use VRM8 (standard) calculation */
519 data->in_min[0] = IN_TO_REG(val);
520
Jean Delvare787c72b2007-05-08 17:22:00 +0200521 w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100522 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 return count;
524}
525
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400526static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 const char *buf, size_t count)
528{
Jean Delvare787c72b2007-05-08 17:22:00 +0200529 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 u32 val;
531
532 val = simple_strtoul(buf, NULL, 10);
533
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100534 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100537 (w83627thf == data->type || w83637hf == data->type
538 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
540 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800541 data->in_max[0] =
542 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
543 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 else
545 /* use VRM8 (standard) calculation */
546 data->in_max[0] = IN_TO_REG(val);
547
Jean Delvare787c72b2007-05-08 17:22:00 +0200548 w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100549 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 return count;
551}
552
553static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
554static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
555 show_regs_in_min0, store_regs_in_min0);
556static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
557 show_regs_in_max0, store_regs_in_max0);
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200560show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
Jim Cromie07584c72007-10-12 21:08:00 +0200562 int nr = to_sensor_dev_attr(devattr)->index;
563 struct w83627hf_data *data = w83627hf_update_device(dev);
564 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
565 (long)DIV_FROM_REG(data->fan_div[nr])));
566}
567static ssize_t
568show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
569{
570 int nr = to_sensor_dev_attr(devattr)->index;
571 struct w83627hf_data *data = w83627hf_update_device(dev);
572 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
573 (long)DIV_FROM_REG(data->fan_div[nr])));
574}
575static ssize_t
576store_fan_min(struct device *dev, struct device_attribute *devattr,
577 const char *buf, size_t count)
578{
579 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200580 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200581 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100583 mutex_lock(&data->update_lock);
Jim Cromie07584c72007-10-12 21:08:00 +0200584 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
585 w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
586 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100588 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return count;
590}
Jim Cromie07584c72007-10-12 21:08:00 +0200591#define sysfs_fan_decl(offset) \
592static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
593 show_fan_input, NULL, offset - 1); \
594static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
595 show_fan_min, store_fan_min, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Jim Cromie07584c72007-10-12 21:08:00 +0200597sysfs_fan_decl(1);
598sysfs_fan_decl(2);
599sysfs_fan_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Jim Cromie07584c72007-10-12 21:08:00 +0200601static ssize_t
602show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
603{
604 int nr = to_sensor_dev_attr(devattr)->index;
605 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600606
607 u16 tmp = data->temp[nr];
608 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
609 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Jim Cromie07584c72007-10-12 21:08:00 +0200612static ssize_t
613show_temp_max(struct device *dev, struct device_attribute *devattr,
614 char *buf)
615{
616 int nr = to_sensor_dev_attr(devattr)->index;
617 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600618
619 u16 tmp = data->temp_max[nr];
620 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
621 : (long) TEMP_FROM_REG(tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Jim Cromie07584c72007-10-12 21:08:00 +0200624static ssize_t
625show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
626 char *buf)
627{
628 int nr = to_sensor_dev_attr(devattr)->index;
629 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600630
631 u16 tmp = data->temp_max_hyst[nr];
632 return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
633 : (long) TEMP_FROM_REG(tmp));
Jim Cromie07584c72007-10-12 21:08:00 +0200634}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Jim Cromie07584c72007-10-12 21:08:00 +0200636static ssize_t
637store_temp_max(struct device *dev, struct device_attribute *devattr,
638 const char *buf, size_t count)
639{
640 int nr = to_sensor_dev_attr(devattr)->index;
641 struct w83627hf_data *data = dev_get_drvdata(dev);
642 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600643 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Jim Cromie07584c72007-10-12 21:08:00 +0200645 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600646 data->temp_max[nr] = tmp;
647 w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200648 mutex_unlock(&data->update_lock);
649 return count;
650}
651
652static ssize_t
653store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
654 const char *buf, size_t count)
655{
656 int nr = to_sensor_dev_attr(devattr)->index;
657 struct w83627hf_data *data = dev_get_drvdata(dev);
658 long val = simple_strtol(buf, NULL, 10);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600659 u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
Jim Cromie07584c72007-10-12 21:08:00 +0200660
661 mutex_lock(&data->update_lock);
Jim Cromiedf48ed82007-10-14 17:10:52 -0600662 data->temp_max_hyst[nr] = tmp;
663 w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
Jim Cromie07584c72007-10-12 21:08:00 +0200664 mutex_unlock(&data->update_lock);
665 return count;
666}
667
668#define sysfs_temp_decl(offset) \
669static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600670 show_temp, NULL, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200671static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600672 show_temp_max, store_temp_max, offset - 1); \
Jim Cromie07584c72007-10-12 21:08:00 +0200673static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
Jim Cromiedf48ed82007-10-14 17:10:52 -0600674 show_temp_max_hyst, store_temp_max_hyst, offset - 1);
Jim Cromie07584c72007-10-12 21:08:00 +0200675
676sysfs_temp_decl(1);
677sysfs_temp_decl(2);
678sysfs_temp_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400681show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 struct w83627hf_data *data = w83627hf_update_device(dev);
684 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
685}
686static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400689show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Jean Delvare90d66192007-10-08 18:24:35 +0200691 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return sprintf(buf, "%ld\n", (long) data->vrm);
693}
694static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400695store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
Jean Delvare787c72b2007-05-08 17:22:00 +0200697 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 u32 val;
699
700 val = simple_strtoul(buf, NULL, 10);
701 data->vrm = val;
702
703 return count;
704}
705static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400708show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 struct w83627hf_data *data = w83627hf_update_device(dev);
711 return sprintf(buf, "%ld\n", (long) data->alarms);
712}
713static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715#define show_beep_reg(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400716static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{ \
718 struct w83627hf_data *data = w83627hf_update_device(dev); \
719 return sprintf(buf,"%ld\n", \
720 (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
721}
722show_beep_reg(ENABLE, enable)
723show_beep_reg(MASK, mask)
724
725#define BEEP_ENABLE 0 /* Store beep_enable */
726#define BEEP_MASK 1 /* Store beep_mask */
727
728static ssize_t
729store_beep_reg(struct device *dev, const char *buf, size_t count,
730 int update_mask)
731{
Jean Delvare787c72b2007-05-08 17:22:00 +0200732 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 u32 val, val2;
734
735 val = simple_strtoul(buf, NULL, 10);
736
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100737 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
740 data->beep_mask = BEEP_MASK_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200741 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 data->beep_mask & 0xff);
Jean Delvare787c72b2007-05-08 17:22:00 +0200743 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 ((data->beep_mask) >> 16) & 0xff);
745 val2 = (data->beep_mask >> 8) & 0x7f;
746 } else { /* We are storing beep_enable */
747 val2 =
Jean Delvare787c72b2007-05-08 17:22:00 +0200748 w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 data->beep_enable = BEEP_ENABLE_TO_REG(val);
750 }
751
Jean Delvare787c72b2007-05-08 17:22:00 +0200752 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 val2 | data->beep_enable << 7);
754
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100755 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return count;
757}
758
759#define sysfs_beep(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400760static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{ \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400762 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763} \
764static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400765store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{ \
767 return store_beep_reg(dev, buf, count, BEEP_##REG); \
768} \
769static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
770 show_regs_beep_##reg, store_regs_beep_##reg);
771
772sysfs_beep(ENABLE, enable);
773sysfs_beep(MASK, mask);
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200776show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Jim Cromie07584c72007-10-12 21:08:00 +0200778 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct w83627hf_data *data = w83627hf_update_device(dev);
780 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200781 (long) DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783/* Note: we save and restore the fan minimum here, because its value is
784 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200785 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 because the divisor changed. */
787static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200788store_fan_div(struct device *dev, struct device_attribute *devattr,
789 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Jim Cromie07584c72007-10-12 21:08:00 +0200791 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200792 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 unsigned long min;
794 u8 reg;
795 unsigned long val = simple_strtoul(buf, NULL, 10);
796
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100797 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 /* Save fan_min */
800 min = FAN_FROM_REG(data->fan_min[nr],
801 DIV_FROM_REG(data->fan_div[nr]));
802
803 data->fan_div[nr] = DIV_TO_REG(val);
804
Jean Delvare787c72b2007-05-08 17:22:00 +0200805 reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 & (nr==0 ? 0xcf : 0x3f))
807 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare787c72b2007-05-08 17:22:00 +0200808 w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Jean Delvare787c72b2007-05-08 17:22:00 +0200810 reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 & ~(1 << (5 + nr)))
812 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare787c72b2007-05-08 17:22:00 +0200813 w83627hf_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 /* Restore fan_min */
816 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare787c72b2007-05-08 17:22:00 +0200817 w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100819 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 return count;
821}
822
Jim Cromie07584c72007-10-12 21:08:00 +0200823static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
824 show_fan_div, store_fan_div, 0);
825static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
826 show_fan_div, store_fan_div, 1);
827static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
828 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200831show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Jim Cromie07584c72007-10-12 21:08:00 +0200833 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200835 return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
837
838static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200839store_pwm(struct device *dev, struct device_attribute *devattr,
840 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Jim Cromie07584c72007-10-12 21:08:00 +0200842 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200843 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200844 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100846 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 if (data->type == w83627thf) {
849 /* bits 0-3 are reserved in 627THF */
Jim Cromie07584c72007-10-12 21:08:00 +0200850 data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
Jean Delvare787c72b2007-05-08 17:22:00 +0200851 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200853 data->pwm[nr] |
Jean Delvare787c72b2007-05-08 17:22:00 +0200854 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
856 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200857 data->pwm[nr] = PWM_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200858 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200860 data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
862
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100863 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return count;
865}
866
Jim Cromie07584c72007-10-12 21:08:00 +0200867static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
868static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
869static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200872show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400873{
Jim Cromie07584c72007-10-12 21:08:00 +0200874 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400875 struct w83627hf_data *data = w83627hf_update_device(dev);
876 if (data->type == w83627hf)
877 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200878 pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400879 else
880 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200881 pwm_freq_from_reg(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400882}
883
884static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200885store_pwm_freq(struct device *dev, struct device_attribute *devattr,
886 const char *buf, size_t count)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400887{
Jim Cromie07584c72007-10-12 21:08:00 +0200888 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400889 struct w83627hf_data *data = dev_get_drvdata(dev);
890 static const u8 mask[]={0xF8, 0x8F};
891 u32 val;
892
893 val = simple_strtoul(buf, NULL, 10);
894
895 mutex_lock(&data->update_lock);
896
897 if (data->type == w83627hf) {
Jim Cromie07584c72007-10-12 21:08:00 +0200898 data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400899 w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
Jim Cromie07584c72007-10-12 21:08:00 +0200900 (data->pwm_freq[nr] << (nr*4)) |
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400901 (w83627hf_read_value(data,
Jim Cromie07584c72007-10-12 21:08:00 +0200902 W83627HF_REG_PWM_FREQ) & mask[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400903 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200904 data->pwm_freq[nr] = pwm_freq_to_reg(val);
905 w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
906 data->pwm_freq[nr]);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400907 }
908
909 mutex_unlock(&data->update_lock);
910 return count;
911}
912
Jim Cromie07584c72007-10-12 21:08:00 +0200913static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
914 show_pwm_freq, store_pwm_freq, 0);
915static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
916 show_pwm_freq, store_pwm_freq, 1);
917static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
918 show_pwm_freq, store_pwm_freq, 2);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400919
920static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200921show_temp_type(struct device *dev, struct device_attribute *devattr,
922 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
Jim Cromie07584c72007-10-12 21:08:00 +0200924 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200926 return sprintf(buf, "%ld\n", (long) data->sens[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927}
928
929static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200930store_temp_type(struct device *dev, struct device_attribute *devattr,
931 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Jim Cromie07584c72007-10-12 21:08:00 +0200933 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200934 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 u32 val, tmp;
936
937 val = simple_strtoul(buf, NULL, 10);
938
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100939 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 switch (val) {
942 case 1: /* PII/Celeron diode */
Jean Delvare787c72b2007-05-08 17:22:00 +0200943 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
944 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200945 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200946 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
947 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200948 tmp | BIT_SCFG2[nr]);
949 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
951 case 2: /* 3904 */
Jean Delvare787c72b2007-05-08 17:22:00 +0200952 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
953 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200954 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200955 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
956 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200957 tmp & ~BIT_SCFG2[nr]);
958 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200960 case W83781D_DEFAULT_BETA:
961 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
962 "instead\n", W83781D_DEFAULT_BETA);
963 /* fall through */
964 case 4: /* thermistor */
Jean Delvare787c72b2007-05-08 17:22:00 +0200965 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
966 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200967 tmp & ~BIT_SCFG1[nr]);
968 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 break;
970 default:
Jean Delvare787c72b2007-05-08 17:22:00 +0200971 dev_err(dev,
Jean Delvareb26f9332007-08-16 14:30:01 +0200972 "Invalid sensor type %ld; must be 1, 2, or 4\n",
973 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 break;
975 }
976
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100977 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return count;
979}
980
Jim Cromie07584c72007-10-12 21:08:00 +0200981#define sysfs_temp_type(offset) \
982static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
983 show_temp_type, store_temp_type, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Jim Cromie07584c72007-10-12 21:08:00 +0200985sysfs_temp_type(1);
986sysfs_temp_type(2);
987sysfs_temp_type(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Jim Cromie07584c72007-10-12 21:08:00 +0200989static ssize_t
990show_name(struct device *dev, struct device_attribute *devattr, char *buf)
Jean Delvare787c72b2007-05-08 17:22:00 +0200991{
992 struct w83627hf_data *data = dev_get_drvdata(dev);
993
994 return sprintf(buf, "%s\n", data->name);
995}
996static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
997
998static int __init w83627hf_find(int sioaddr, unsigned short *addr,
999 struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
Jean Delvared27c37c2007-05-08 17:21:59 +02001001 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 u16 val;
1003
Jean Delvare787c72b2007-05-08 17:22:00 +02001004 static const __initdata char *names[] = {
1005 "W83627HF",
1006 "W83627THF",
1007 "W83697HF",
1008 "W83637HF",
1009 "W83687THF",
1010 };
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 REG = sioaddr;
1013 VAL = sioaddr + 1;
1014
1015 superio_enter();
1016 val= superio_inb(DEVID);
Jean Delvare787c72b2007-05-08 17:22:00 +02001017 switch (val) {
1018 case W627_DEVID:
1019 sio_data->type = w83627hf;
1020 break;
1021 case W627THF_DEVID:
1022 sio_data->type = w83627thf;
1023 break;
1024 case W697_DEVID:
1025 sio_data->type = w83697hf;
1026 break;
1027 case W637_DEVID:
1028 sio_data->type = w83637hf;
1029 break;
1030 case W687THF_DEVID:
1031 sio_data->type = w83687thf;
1032 break;
Jean Delvaree142e2a2007-05-27 22:17:43 +02001033 case 0xff: /* No device at all */
1034 goto exit;
Jean Delvare787c72b2007-05-08 17:22:00 +02001035 default:
Jean Delvaree142e2a2007-05-27 22:17:43 +02001036 pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
Jean Delvared27c37c2007-05-08 17:21:59 +02001037 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039
1040 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +02001041 force_addr &= WINB_ALIGNMENT;
1042 if (force_addr) {
1043 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1044 force_addr);
1045 superio_outb(WINB_BASE_REG, force_addr >> 8);
1046 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 val = (superio_inb(WINB_BASE_REG) << 8) |
1049 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001050 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +02001051 if (*addr == 0) {
1052 printk(KERN_WARNING DRVNAME ": Base address not set, "
1053 "skipping\n");
1054 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Jean Delvared27c37c2007-05-08 17:21:59 +02001057 val = superio_inb(WINB_ACT_REG);
1058 if (!(val & 0x01)) {
1059 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1060 superio_outb(WINB_ACT_REG, val | 0x01);
1061 }
1062
1063 err = 0;
Jean Delvare787c72b2007-05-08 17:22:00 +02001064 pr_info(DRVNAME ": Found %s chip at %#x\n",
1065 names[sio_data->type], *addr);
Jean Delvared27c37c2007-05-08 17:21:59 +02001066
1067 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +02001069 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070}
1071
Jim Cromie07584c72007-10-12 21:08:00 +02001072#define VIN_UNIT_ATTRS(_X_) \
1073 &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
1074 &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
1075 &sensor_dev_attr_in##_X_##_max.dev_attr.attr
1076
1077#define FAN_UNIT_ATTRS(_X_) \
1078 &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
1079 &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
1080 &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
1081
1082#define TEMP_UNIT_ATTRS(_X_) \
1083 &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
1084 &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
1085 &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
1086 &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
1087
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001088static struct attribute *w83627hf_attributes[] = {
1089 &dev_attr_in0_input.attr,
1090 &dev_attr_in0_min.attr,
1091 &dev_attr_in0_max.attr,
Jim Cromie07584c72007-10-12 21:08:00 +02001092 VIN_UNIT_ATTRS(2),
1093 VIN_UNIT_ATTRS(3),
1094 VIN_UNIT_ATTRS(4),
1095 VIN_UNIT_ATTRS(7),
1096 VIN_UNIT_ATTRS(8),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001097
Jim Cromie07584c72007-10-12 21:08:00 +02001098 FAN_UNIT_ATTRS(1),
1099 FAN_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001100
Jim Cromie07584c72007-10-12 21:08:00 +02001101 TEMP_UNIT_ATTRS(1),
1102 TEMP_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001103
1104 &dev_attr_alarms.attr,
1105 &dev_attr_beep_enable.attr,
1106 &dev_attr_beep_mask.attr,
1107
Jim Cromie07584c72007-10-12 21:08:00 +02001108 &sensor_dev_attr_pwm1.dev_attr.attr,
1109 &sensor_dev_attr_pwm2.dev_attr.attr,
Jean Delvare787c72b2007-05-08 17:22:00 +02001110 &dev_attr_name.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001111 NULL
1112};
1113
1114static const struct attribute_group w83627hf_group = {
1115 .attrs = w83627hf_attributes,
1116};
1117
1118static struct attribute *w83627hf_attributes_opt[] = {
Jim Cromie07584c72007-10-12 21:08:00 +02001119 VIN_UNIT_ATTRS(1),
1120 VIN_UNIT_ATTRS(5),
1121 VIN_UNIT_ATTRS(6),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001122
Jim Cromie07584c72007-10-12 21:08:00 +02001123 FAN_UNIT_ATTRS(3),
1124 TEMP_UNIT_ATTRS(3),
1125 &sensor_dev_attr_pwm3.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001126
Jim Cromie07584c72007-10-12 21:08:00 +02001127 &sensor_dev_attr_pwm1_freq.dev_attr.attr,
1128 &sensor_dev_attr_pwm2_freq.dev_attr.attr,
1129 &sensor_dev_attr_pwm3_freq.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001130 NULL
1131};
1132
1133static const struct attribute_group w83627hf_group_opt = {
1134 .attrs = w83627hf_attributes_opt,
1135};
1136
Jean Delvare787c72b2007-05-08 17:22:00 +02001137static int __devinit w83627hf_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Jean Delvare787c72b2007-05-08 17:22:00 +02001139 struct device *dev = &pdev->dev;
1140 struct w83627hf_sio_data *sio_data = dev->platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 struct w83627hf_data *data;
Jean Delvare787c72b2007-05-08 17:22:00 +02001142 struct resource *res;
1143 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Jean Delvare787c72b2007-05-08 17:22:00 +02001145 static const char *names[] = {
1146 "w83627hf",
1147 "w83627thf",
1148 "w83697hf",
1149 "w83637hf",
1150 "w83687thf",
1151 };
1152
1153 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1154 if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1155 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1156 (unsigned long)res->start,
1157 (unsigned long)(res->start + WINB_REGION_SIZE - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 err = -EBUSY;
1159 goto ERROR0;
1160 }
1161
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001162 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 err = -ENOMEM;
1164 goto ERROR1;
1165 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001166 data->addr = res->start;
1167 data->type = sio_data->type;
1168 data->name = names[sio_data->type];
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001169 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001170 mutex_init(&data->update_lock);
Jean Delvare787c72b2007-05-08 17:22:00 +02001171 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 /* Initialize the chip */
Jean Delvare787c72b2007-05-08 17:22:00 +02001174 w83627hf_init_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 /* A few vars need to be filled upon startup */
Jean Delvare787c72b2007-05-08 17:22:00 +02001177 data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
1178 data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
1179 data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
Jean Delvarec09c5182007-10-12 21:53:07 +02001180 w83627hf_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001182 /* Register common device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001183 if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001184 goto ERROR3;
1185
1186 /* Register chip-specific device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001187 if (data->type == w83627hf || data->type == w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001188 if ((err = device_create_file(dev,
1189 &sensor_dev_attr_in5_input.dev_attr))
1190 || (err = device_create_file(dev,
1191 &sensor_dev_attr_in5_min.dev_attr))
1192 || (err = device_create_file(dev,
1193 &sensor_dev_attr_in5_max.dev_attr))
1194 || (err = device_create_file(dev,
1195 &sensor_dev_attr_in6_input.dev_attr))
1196 || (err = device_create_file(dev,
1197 &sensor_dev_attr_in6_min.dev_attr))
1198 || (err = device_create_file(dev,
1199 &sensor_dev_attr_in6_max.dev_attr))
1200 || (err = device_create_file(dev,
1201 &sensor_dev_attr_pwm1_freq.dev_attr))
1202 || (err = device_create_file(dev,
1203 &sensor_dev_attr_pwm2_freq.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001204 goto ERROR4;
1205
Jean Delvare787c72b2007-05-08 17:22:00 +02001206 if (data->type != w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001207 if ((err = device_create_file(dev,
1208 &sensor_dev_attr_in1_input.dev_attr))
1209 || (err = device_create_file(dev,
1210 &sensor_dev_attr_in1_min.dev_attr))
1211 || (err = device_create_file(dev,
1212 &sensor_dev_attr_in1_max.dev_attr))
1213 || (err = device_create_file(dev,
1214 &sensor_dev_attr_fan3_input.dev_attr))
1215 || (err = device_create_file(dev,
1216 &sensor_dev_attr_fan3_min.dev_attr))
1217 || (err = device_create_file(dev,
1218 &sensor_dev_attr_fan3_div.dev_attr))
1219 || (err = device_create_file(dev,
1220 &sensor_dev_attr_temp3_input.dev_attr))
1221 || (err = device_create_file(dev,
1222 &sensor_dev_attr_temp3_max.dev_attr))
1223 || (err = device_create_file(dev,
1224 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1225 || (err = device_create_file(dev,
1226 &sensor_dev_attr_temp3_type.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001227 goto ERROR4;
1228
Jean Delvare787c72b2007-05-08 17:22:00 +02001229 if (data->type != w83697hf && data->vid != 0xff) {
Jean Delvare8a665a02007-05-08 17:21:59 +02001230 /* Convert VID to voltage based on VRM */
1231 data->vrm = vid_which_vrm();
1232
Jean Delvare787c72b2007-05-08 17:22:00 +02001233 if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1234 || (err = device_create_file(dev, &dev_attr_vrm)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001235 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001236 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001237
Jean Delvare787c72b2007-05-08 17:22:00 +02001238 if (data->type == w83627thf || data->type == w83637hf
1239 || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001240 if ((err = device_create_file(dev,
1241 &sensor_dev_attr_pwm3.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001242 goto ERROR4;
1243
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001244 if (data->type == w83637hf || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001245 if ((err = device_create_file(dev,
1246 &sensor_dev_attr_pwm1_freq.dev_attr))
1247 || (err = device_create_file(dev,
1248 &sensor_dev_attr_pwm2_freq.dev_attr))
1249 || (err = device_create_file(dev,
1250 &sensor_dev_attr_pwm3_freq.dev_attr)))
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001251 goto ERROR4;
1252
Tony Jones1beeffe2007-08-20 13:46:20 -07001253 data->hwmon_dev = hwmon_device_register(dev);
1254 if (IS_ERR(data->hwmon_dev)) {
1255 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001256 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001257 }
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 return 0;
1260
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001261 ERROR4:
Jean Delvare787c72b2007-05-08 17:22:00 +02001262 sysfs_remove_group(&dev->kobj, &w83627hf_group);
1263 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001264 ERROR3:
Jean Delvare04a62172007-06-12 13:57:19 +02001265 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 kfree(data);
1267 ERROR1:
Jean Delvare787c72b2007-05-08 17:22:00 +02001268 release_region(res->start, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 ERROR0:
1270 return err;
1271}
1272
Jean Delvare787c72b2007-05-08 17:22:00 +02001273static int __devexit w83627hf_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
Jean Delvare787c72b2007-05-08 17:22:00 +02001275 struct w83627hf_data *data = platform_get_drvdata(pdev);
1276 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Tony Jones1beeffe2007-08-20 13:46:20 -07001278 hwmon_device_unregister(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001279
Jean Delvare787c72b2007-05-08 17:22:00 +02001280 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1281 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
Jean Delvare04a62172007-06-12 13:57:19 +02001282 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001283 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Jean Delvare787c72b2007-05-08 17:22:00 +02001285 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1286 release_region(res->start, WINB_REGION_SIZE);
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 return 0;
1289}
1290
1291
Jean Delvared58df9c2007-10-10 16:30:23 +02001292/* Registers 0x50-0x5f are banked */
1293static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
1294{
1295 if ((reg & 0x00f0) == 0x50) {
1296 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1297 outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
1298 }
1299}
1300
1301/* Not strictly necessary, but play it safe for now */
1302static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
1303{
1304 if (reg & 0xff00) {
1305 outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1306 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
1307 }
1308}
1309
Jean Delvare787c72b2007-05-08 17:22:00 +02001310static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 int res, word_sized;
1313
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001314 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 word_sized = (((reg & 0xff00) == 0x100)
1316 || ((reg & 0xff00) == 0x200))
1317 && (((reg & 0x00ff) == 0x50)
1318 || ((reg & 0x00ff) == 0x53)
1319 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001320 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001321 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1322 res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (word_sized) {
1324 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001325 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 res =
Jean Delvare787c72b2007-05-08 17:22:00 +02001327 (res << 8) + inb_p(data->addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 W83781D_DATA_REG_OFFSET);
1329 }
Jean Delvared58df9c2007-10-10 16:30:23 +02001330 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001331 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 return res;
1333}
1334
Jean Delvare787c72b2007-05-08 17:22:00 +02001335static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
1337 int res = 0xff, sel;
1338
1339 superio_enter();
1340 superio_select(W83627HF_LD_GPIO5);
1341
1342 /* Make sure these GPIO pins are enabled */
1343 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001344 dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 goto exit;
1346 }
1347
1348 /* Make sure the pins are configured for input
1349 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001350 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if ((sel & 0x1f) != 0x1f) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001352 dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 "function\n");
1354 goto exit;
1355 }
1356
Jean Delvare787c72b2007-05-08 17:22:00 +02001357 dev_info(&pdev->dev, "Reading VID from GPIO5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1359
1360exit:
1361 superio_exit();
1362 return res;
1363}
1364
Jean Delvare787c72b2007-05-08 17:22:00 +02001365static int __devinit w83687thf_read_vid(struct platform_device *pdev)
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001366{
1367 int res = 0xff;
1368
1369 superio_enter();
1370 superio_select(W83627HF_LD_HWM);
1371
1372 /* Make sure these GPIO pins are enabled */
1373 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001374 dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001375 goto exit;
1376 }
1377
1378 /* Make sure the pins are configured for input */
1379 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001380 dev_dbg(&pdev->dev, "VID configured as output, "
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001381 "no VID function\n");
1382 goto exit;
1383 }
1384
1385 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1386
1387exit:
1388 superio_exit();
1389 return res;
1390}
1391
Jean Delvare787c72b2007-05-08 17:22:00 +02001392static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 int word_sized;
1395
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001396 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 word_sized = (((reg & 0xff00) == 0x100)
1398 || ((reg & 0xff00) == 0x200))
1399 && (((reg & 0x00ff) == 0x53)
1400 || ((reg & 0x00ff) == 0x55));
Jean Delvared58df9c2007-10-10 16:30:23 +02001401 w83627hf_set_bank(data, reg);
Jean Delvare787c72b2007-05-08 17:22:00 +02001402 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (word_sized) {
1404 outb_p(value >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001405 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001407 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
1409 outb_p(value & 0xff,
Jean Delvare787c72b2007-05-08 17:22:00 +02001410 data->addr + W83781D_DATA_REG_OFFSET);
Jean Delvared58df9c2007-10-10 16:30:23 +02001411 w83627hf_reset_bank(data, reg);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001412 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 return 0;
1414}
1415
Jean Delvare787c72b2007-05-08 17:22:00 +02001416static void __devinit w83627hf_init_device(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417{
Jean Delvare787c72b2007-05-08 17:22:00 +02001418 struct w83627hf_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001420 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 u8 tmp;
1422
Jean Delvare2251cf12005-09-04 22:52:17 +02001423 if (reset) {
1424 /* Resetting the chip has been the default for a long time,
1425 but repeatedly caused problems (fans going to full
1426 speed...) so it is now optional. It might even go away if
1427 nobody reports it as being useful, as I see very little
1428 reason why this would be needed at all. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001429 dev_info(&pdev->dev, "If reset=1 solved a problem you were "
Jean Delvare2251cf12005-09-04 22:52:17 +02001430 "having, please report!\n");
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 /* save this register */
Jean Delvare787c72b2007-05-08 17:22:00 +02001433 i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 /* Reset all except Watchdog values and last conversion values
1435 This sets fan-divs to 2, among others */
Jean Delvare787c72b2007-05-08 17:22:00 +02001436 w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* Restore the register and disable power-on abnormal beep.
1438 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001439 w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 /* Disable master beep-enable (reset turns it on).
1441 Individual beeps should be reset to off but for some reason
1442 disabling this bit helps some people not get beeped */
Jean Delvare787c72b2007-05-08 17:22:00 +02001443 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 }
1445
1446 /* Minimize conflicts with other winbond i2c-only clients... */
1447 /* disable i2c subclients... how to disable main i2c client?? */
1448 /* force i2c address to relatively uncommon address */
Jean Delvare787c72b2007-05-08 17:22:00 +02001449 w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1450 w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001453 if (type == w83627hf || type == w83637hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001454 int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1455 int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001457 } else if (type == w83627thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001458 data->vid = w83627thf_read_gpio5(pdev);
Jean Delvared27c37c2007-05-08 17:21:59 +02001459 } else if (type == w83687thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001460 data->vid = w83687thf_read_vid(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
1462
1463 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001464 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 data->vrm_ovt =
Jean Delvare787c72b2007-05-08 17:22:00 +02001466 w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 }
1468
Jean Delvare787c72b2007-05-08 17:22:00 +02001469 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 for (i = 1; i <= 3; i++) {
1471 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001472 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 } else {
1474 if (w83627hf_read_value
Jean Delvare787c72b2007-05-08 17:22:00 +02001475 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1477 data->sens[i - 1] = 1;
1478 else
1479 data->sens[i - 1] = 2;
1480 }
1481 if ((type == w83697hf) && (i == 2))
1482 break;
1483 }
1484
1485 if(init) {
1486 /* Enable temp2 */
Jim Cromiedf48ed82007-10-14 17:10:52 -06001487 tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001489 dev_warn(&pdev->dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 "might not make sense\n");
Jim Cromiedf48ed82007-10-14 17:10:52 -06001491 w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 tmp & 0xfe);
1493 }
1494
1495 /* Enable temp3 */
1496 if (type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001497 tmp = w83627hf_read_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001498 W83627HF_REG_TEMP3_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001500 dev_warn(&pdev->dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 "readings might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001502 w83627hf_write_value(data,
Jim Cromiedf48ed82007-10-14 17:10:52 -06001503 W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 }
1505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 }
1507
1508 /* Start monitoring */
Jean Delvare787c72b2007-05-08 17:22:00 +02001509 w83627hf_write_value(data, W83781D_REG_CONFIG,
1510 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 W83781D_REG_CONFIG) & 0xf7)
1512 | 0x01);
1513}
1514
Jean Delvarec09c5182007-10-12 21:53:07 +02001515static void w83627hf_update_fan_div(struct w83627hf_data *data)
1516{
1517 int reg;
1518
1519 reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1520 data->fan_div[0] = (reg >> 4) & 0x03;
1521 data->fan_div[1] = (reg >> 6) & 0x03;
1522 if (data->type != w83697hf) {
1523 data->fan_div[2] = (w83627hf_read_value(data,
1524 W83781D_REG_PIN) >> 6) & 0x03;
1525 }
1526 reg = w83627hf_read_value(data, W83781D_REG_VBAT);
1527 data->fan_div[0] |= (reg >> 3) & 0x04;
1528 data->fan_div[1] |= (reg >> 4) & 0x04;
1529 if (data->type != w83697hf)
1530 data->fan_div[2] |= (reg >> 5) & 0x04;
1531}
1532
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1534{
Jean Delvare787c72b2007-05-08 17:22:00 +02001535 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromiedf48ed82007-10-14 17:10:52 -06001536 int i, num_temps = (data->type == w83697hf) ? 2 : 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001538 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1541 || !data->valid) {
1542 for (i = 0; i <= 8; i++) {
1543 /* skip missing sensors */
1544 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001545 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001546 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 continue;
1548 data->in[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001549 w83627hf_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 data->in_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001551 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 W83781D_REG_IN_MIN(i));
1553 data->in_max[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001554 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 W83781D_REG_IN_MAX(i));
1556 }
1557 for (i = 1; i <= 3; i++) {
1558 data->fan[i - 1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001559 w83627hf_read_value(data, W83781D_REG_FAN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 data->fan_min[i - 1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001561 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 W83781D_REG_FAN_MIN(i));
1563 }
Jim Cromie07584c72007-10-12 21:08:00 +02001564 for (i = 0; i <= 2; i++) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001565 u8 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 W836X7HF_REG_PWM(data->type, i));
1567 /* bits 0-3 are reserved in 627THF */
1568 if (data->type == w83627thf)
1569 tmp &= 0xf0;
Jim Cromie07584c72007-10-12 21:08:00 +02001570 data->pwm[i] = tmp;
1571 if (i == 1 &&
1572 (data->type == w83627hf || data->type == w83697hf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 break;
1574 }
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001575 if (data->type == w83627hf) {
1576 u8 tmp = w83627hf_read_value(data,
1577 W83627HF_REG_PWM_FREQ);
1578 data->pwm_freq[0] = tmp & 0x07;
1579 data->pwm_freq[1] = (tmp >> 4) & 0x07;
1580 } else if (data->type != w83627thf) {
1581 for (i = 1; i <= 3; i++) {
1582 data->pwm_freq[i - 1] =
1583 w83627hf_read_value(data,
1584 W83637HF_REG_PWM_FREQ[i - 1]);
1585 if (i == 2 && (data->type == w83697hf))
1586 break;
1587 }
1588 }
Jim Cromiedf48ed82007-10-14 17:10:52 -06001589 for (i = 0; i < num_temps; i++) {
1590 data->temp[i] = w83627hf_read_value(
1591 data, w83627hf_reg_temp[i]);
1592 data->temp_max[i] = w83627hf_read_value(
1593 data, w83627hf_reg_temp_over[i]);
1594 data->temp_max_hyst[i] = w83627hf_read_value(
1595 data, w83627hf_reg_temp_hyst[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 }
1597
Jean Delvarec09c5182007-10-12 21:53:07 +02001598 w83627hf_update_fan_div(data);
1599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 data->alarms =
Jean Delvare787c72b2007-05-08 17:22:00 +02001601 w83627hf_read_value(data, W83781D_REG_ALARM1) |
1602 (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1603 (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1604 i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 data->beep_enable = i >> 7;
1606 data->beep_mask = ((i & 0x7f) << 8) |
Jean Delvare787c72b2007-05-08 17:22:00 +02001607 w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1608 w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 data->last_updated = jiffies;
1610 data->valid = 1;
1611 }
1612
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001613 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
1615 return data;
1616}
1617
Jean Delvare787c72b2007-05-08 17:22:00 +02001618static int __init w83627hf_device_add(unsigned short address,
1619 const struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
Jean Delvare787c72b2007-05-08 17:22:00 +02001621 struct resource res = {
1622 .start = address + WINB_REGION_OFFSET,
1623 .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1624 .name = DRVNAME,
1625 .flags = IORESOURCE_IO,
1626 };
1627 int err;
1628
1629 pdev = platform_device_alloc(DRVNAME, address);
1630 if (!pdev) {
1631 err = -ENOMEM;
1632 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1633 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Jean Delvare787c72b2007-05-08 17:22:00 +02001636 err = platform_device_add_resources(pdev, &res, 1);
1637 if (err) {
1638 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1639 "(%d)\n", err);
1640 goto exit_device_put;
1641 }
1642
Jean Delvare2df6d812007-06-09 10:11:16 -04001643 err = platform_device_add_data(pdev, sio_data,
1644 sizeof(struct w83627hf_sio_data));
1645 if (err) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001646 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1647 goto exit_device_put;
1648 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001649
1650 err = platform_device_add(pdev);
1651 if (err) {
1652 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1653 err);
1654 goto exit_device_put;
1655 }
1656
1657 return 0;
1658
1659exit_device_put:
1660 platform_device_put(pdev);
1661exit:
1662 return err;
1663}
1664
1665static int __init sensors_w83627hf_init(void)
1666{
1667 int err;
1668 unsigned short address;
1669 struct w83627hf_sio_data sio_data;
1670
1671 if (w83627hf_find(0x2e, &address, &sio_data)
1672 && w83627hf_find(0x4e, &address, &sio_data))
1673 return -ENODEV;
1674
1675 err = platform_driver_register(&w83627hf_driver);
1676 if (err)
1677 goto exit;
1678
1679 /* Sets global pdev as a side effect */
1680 err = w83627hf_device_add(address, &sio_data);
1681 if (err)
1682 goto exit_driver;
1683
1684 return 0;
1685
1686exit_driver:
1687 platform_driver_unregister(&w83627hf_driver);
1688exit:
1689 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
1691
1692static void __exit sensors_w83627hf_exit(void)
1693{
Jean Delvare787c72b2007-05-08 17:22:00 +02001694 platform_device_unregister(pdev);
1695 platform_driver_unregister(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696}
1697
1698MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1699 "Philip Edelbrock <phil@netroedge.com>, "
1700 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1701MODULE_DESCRIPTION("W83627HF driver");
1702MODULE_LICENSE("GPL");
1703
1704module_init(sensors_w83627hf_init);
1705module_exit(sensors_w83627hf_exit);