blob: 0e9746913d2b718bafdd43dc38be46c8a931ab38 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
3 the Winbond W83627EHF Super-I/O chip
4 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Jean Delvare7188cc62006-12-12 18:18:30 +01006 Rudolf Marek <r.marek@assembler.cz>
David Hubbardc18beb52006-09-24 21:04:38 +02007 David Hubbard <david.c.hubbard@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02008
9 Shamelessly ripped from the w83627hf driver
10 Copyright (C) 2003 Mark Studebaker
11
12 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
13 in testing and debugging this driver.
14
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020015 This driver also supports the W83627EHG, which is the lead-free
16 version of the W83627EHF.
17
Jean Delvare08e7e272005-04-25 22:43:25 +020018 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
32
33 Supports the following chips:
34
David Hubbard657c93b2007-02-14 21:15:04 +010035 Chip #vin #fan #pwm #temp chip IDs man ID
36 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
37 0x8860 0xa1
38 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020039 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d2f2009-03-30 21:46:42 +020040 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020041*/
42
43#include <linux/module.h>
44#include <linux/init.h>
45#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020046#include <linux/jiffies.h>
47#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040048#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010049#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020050#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040051#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010052#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010053#include <linux/acpi.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020054#include <asm/io.h>
55#include "lm75.h"
56
Jean Delvarec1e48dc2009-06-15 18:39:50 +020057enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg };
David Hubbard1ea6dd32007-06-24 11:16:15 +020058
59/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
60static const char * w83627ehf_device_names[] = {
61 "w83627ehf",
62 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020063 "w83627dhg",
Gong Jun237c8d2f2009-03-30 21:46:42 +020064 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020065};
66
Jean Delvare67b671b2007-12-06 23:13:42 +010067static unsigned short force_id;
68module_param(force_id, ushort, 0);
69MODULE_PARM_DESC(force_id, "Override the detected device ID");
70
David Hubbard1ea6dd32007-06-24 11:16:15 +020071#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020072
73/*
74 * Super-I/O constants and functions
75 */
76
Jean Delvare08e7e272005-04-25 22:43:25 +020077#define W83627EHF_LD_HWM 0x0b
Gong Jun237c8d2f2009-03-30 21:46:42 +020078#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020079
80#define SIO_REG_LDSEL 0x07 /* Logical device select */
81#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020082#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020083#define SIO_REG_ENABLE 0x30 /* Logical device enable */
84#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020085#define SIO_REG_VID_CTRL 0xF0 /* VID control */
86#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020087
David Hubbard657c93b2007-02-14 21:15:04 +010088#define SIO_W83627EHF_ID 0x8850
89#define SIO_W83627EHG_ID 0x8860
90#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020091#define SIO_W83627DHG_P_ID 0xb070
Gong Jun237c8d2f2009-03-30 21:46:42 +020092#define SIO_W83667HG_ID 0xa510
David Hubbard657c93b2007-02-14 21:15:04 +010093#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020094
95static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +020096superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +020097{
David Hubbard1ea6dd32007-06-24 11:16:15 +020098 outb(reg, ioreg);
99 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200100}
101
102static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200103superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200104{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200105 outb(reg, ioreg);
106 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200107}
108
109static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200110superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200111{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200112 outb(SIO_REG_LDSEL, ioreg);
113 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200114}
115
116static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200117superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200118{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200119 outb(0x87, ioreg);
120 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200121}
122
123static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200124superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200125{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200126 outb(0x02, ioreg);
127 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200128}
129
130/*
131 * ISA constants
132 */
133
Jean Delvare1a641fc2007-04-23 14:41:16 -0700134#define IOREGION_ALIGNMENT ~7
135#define IOREGION_OFFSET 5
136#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200137#define ADDR_REG_OFFSET 0
138#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200139
140#define W83627EHF_REG_BANK 0x4E
141#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100142
143/* Not currently used:
144 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
145 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
146 * REG_MAN_ID is at port 0x4f
147 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200148
149static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
150static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
151
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100152/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
153#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
154 (0x554 + (((nr) - 7) * 2)))
155#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
156 (0x555 + (((nr) - 7) * 2)))
157#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
158 (0x550 + (nr) - 7))
159
Jean Delvare08e7e272005-04-25 22:43:25 +0200160#define W83627EHF_REG_TEMP1 0x27
161#define W83627EHF_REG_TEMP1_HYST 0x3a
162#define W83627EHF_REG_TEMP1_OVER 0x39
163static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
164static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
165static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
166static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
167
168/* Fan clock dividers are spread over the following five registers */
169#define W83627EHF_REG_FANDIV1 0x47
170#define W83627EHF_REG_FANDIV2 0x4B
171#define W83627EHF_REG_VBAT 0x5D
172#define W83627EHF_REG_DIODE 0x59
173#define W83627EHF_REG_SMI_OVT 0x4C
174
Jean Delvarea4589db2006-03-23 16:30:29 +0100175#define W83627EHF_REG_ALARM1 0x459
176#define W83627EHF_REG_ALARM2 0x45A
177#define W83627EHF_REG_ALARM3 0x45B
178
Rudolf Marek08c79952006-07-05 18:14:31 +0200179/* SmartFan registers */
180/* DC or PWM output fan configuration */
181static const u8 W83627EHF_REG_PWM_ENABLE[] = {
182 0x04, /* SYS FAN0 output mode and PWM mode */
183 0x04, /* CPU FAN0 output mode and PWM mode */
184 0x12, /* AUX FAN mode */
185 0x62, /* CPU fan1 mode */
186};
187
188static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
189static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
190
191/* FAN Duty Cycle, be used to control */
192static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
193static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
194static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
195
196
197/* Advanced Fan control, some values are common for all fans */
198static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
199static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
200
Jean Delvare08e7e272005-04-25 22:43:25 +0200201/*
202 * Conversions
203 */
204
Rudolf Marek08c79952006-07-05 18:14:31 +0200205/* 1 is PWM mode, output in ms */
206static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
207{
208 return mode ? 100 * reg : 400 * reg;
209}
210
211static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
212{
213 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
214 (msec + 200) / 400), 1, 255);
215}
216
Jean Delvare08e7e272005-04-25 22:43:25 +0200217static inline unsigned int
218fan_from_reg(u8 reg, unsigned int div)
219{
220 if (reg == 0 || reg == 255)
221 return 0;
222 return 1350000U / (reg * div);
223}
224
225static inline unsigned int
226div_from_reg(u8 reg)
227{
228 return 1 << reg;
229}
230
231static inline int
232temp1_from_reg(s8 reg)
233{
234 return reg * 1000;
235}
236
237static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200238temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200239{
Rudolf Marek08c79952006-07-05 18:14:31 +0200240 if (temp <= min)
241 return min / 1000;
242 if (temp >= max)
243 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200244 if (temp < 0)
245 return (temp - 500) / 1000;
246 return (temp + 500) / 1000;
247}
248
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100249/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
250
251static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
252
253static inline long in_from_reg(u8 reg, u8 nr)
254{
255 return reg * scale_in[nr];
256}
257
258static inline u8 in_to_reg(u32 val, u8 nr)
259{
260 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
261}
262
Jean Delvare08e7e272005-04-25 22:43:25 +0200263/*
264 * Data structures and manipulation thereof
265 */
266
267struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200268 int addr; /* IO base of hw monitor block */
269 const char *name;
270
Tony Jones1beeffe2007-08-20 13:46:20 -0700271 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100272 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200273
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100274 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200275 char valid; /* !=0 if following fields are valid */
276 unsigned long last_updated; /* In jiffies */
277
278 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200279 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100280 u8 in[10]; /* Register value */
281 u8 in_max[10]; /* Register value */
282 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200283 u8 fan[5];
284 u8 fan_min[5];
285 u8 fan_div[5];
286 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200287 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200288 s8 temp1;
289 s8 temp1_max;
290 s8 temp1_max_hyst;
291 s16 temp[2];
292 s16 temp_max[2];
293 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100294 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200295
296 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
297 u8 pwm_enable[4]; /* 1->manual
298 2->thermal cruise (also called SmartFan I) */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200299 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200300 u8 pwm[4];
301 u8 target_temp[4];
302 u8 tolerance[4];
303
304 u8 fan_min_output[4]; /* minimum fan speed */
305 u8 fan_stop_time[4];
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200306
307 u8 vid;
308 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200309
310 u8 temp3_disable;
311 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200312};
313
David Hubbard1ea6dd32007-06-24 11:16:15 +0200314struct w83627ehf_sio_data {
315 int sioreg;
316 enum kinds kind;
317};
318
Jean Delvare08e7e272005-04-25 22:43:25 +0200319static inline int is_word_sized(u16 reg)
320{
321 return (((reg & 0xff00) == 0x100
322 || (reg & 0xff00) == 0x200)
323 && ((reg & 0x00ff) == 0x50
324 || (reg & 0x00ff) == 0x53
325 || (reg & 0x00ff) == 0x55));
326}
327
Jean Delvare09568952007-08-11 13:57:05 +0200328/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200329static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200330{
Jean Delvare09568952007-08-11 13:57:05 +0200331 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200332 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
333 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200334 }
335}
336
Jean Delvare09568952007-08-11 13:57:05 +0200337/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200338static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200339{
340 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200341 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
342 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200343 }
344}
345
David Hubbard1ea6dd32007-06-24 11:16:15 +0200346static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200347{
Jean Delvare08e7e272005-04-25 22:43:25 +0200348 int res, word_sized = is_word_sized(reg);
349
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100350 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200351
David Hubbard1ea6dd32007-06-24 11:16:15 +0200352 w83627ehf_set_bank(data, reg);
353 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
354 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200355 if (word_sized) {
356 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200357 data->addr + ADDR_REG_OFFSET);
358 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200359 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200360 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200361
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100362 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200363
364 return res;
365}
366
David Hubbard1ea6dd32007-06-24 11:16:15 +0200367static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200368{
Jean Delvare08e7e272005-04-25 22:43:25 +0200369 int word_sized = is_word_sized(reg);
370
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100371 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200372
David Hubbard1ea6dd32007-06-24 11:16:15 +0200373 w83627ehf_set_bank(data, reg);
374 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200375 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200376 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200377 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200378 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200379 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200380 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
381 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200382
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100383 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200384 return 0;
385}
386
387/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200388static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200389{
Jean Delvare08e7e272005-04-25 22:43:25 +0200390 u8 reg;
391
392 switch (nr) {
393 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200394 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200395 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200396 /* fan5 input control bit is write only, compute the value */
397 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200398 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
399 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200400 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200401 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200402 break;
403 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200404 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200405 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200406 /* fan5 input control bit is write only, compute the value */
407 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200408 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
409 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200410 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200411 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200412 break;
413 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200414 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200415 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200416 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
417 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200418 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200419 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200420 break;
421 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200422 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200423 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200424 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
425 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200426 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200427 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200428 break;
429 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200430 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700431 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200432 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200433 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200434 break;
435 }
436}
437
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400438static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
439{
440 int i;
441
442 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
443 data->fan_div[0] = (i >> 4) & 0x03;
444 data->fan_div[1] = (i >> 6) & 0x03;
445 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
446 data->fan_div[2] = (i >> 6) & 0x03;
447 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
448 data->fan_div[0] |= (i >> 3) & 0x04;
449 data->fan_div[1] |= (i >> 4) & 0x04;
450 data->fan_div[2] |= (i >> 5) & 0x04;
451 if (data->has_fan & ((1 << 3) | (1 << 4))) {
452 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
453 data->fan_div[3] = i & 0x03;
454 data->fan_div[4] = ((i >> 2) & 0x03)
455 | ((i >> 5) & 0x04);
456 }
457 if (data->has_fan & (1 << 3)) {
458 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
459 data->fan_div[3] |= (i >> 5) & 0x04;
460 }
461}
462
Jean Delvare08e7e272005-04-25 22:43:25 +0200463static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
464{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200465 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200466 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200467 int i;
468
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100469 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200470
Jean Delvare6b3e4642007-06-24 11:19:01 +0200471 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200472 || !data->valid) {
473 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400474 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200475
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100476 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200477 for (i = 0; i < data->in_num; i++) {
478 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100479 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200480 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100481 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200482 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100483 W83627EHF_REG_IN_MAX(i));
484 }
485
Jean Delvare08e7e272005-04-25 22:43:25 +0200486 /* Measured fan speeds and limits */
487 for (i = 0; i < 5; i++) {
488 if (!(data->has_fan & (1 << i)))
489 continue;
490
David Hubbard1ea6dd32007-06-24 11:16:15 +0200491 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200492 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200493 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200494 W83627EHF_REG_FAN_MIN[i]);
495
496 /* If we failed to measure the fan speed and clock
497 divider can be increased, let's try that for next
498 time */
499 if (data->fan[i] == 0xff
500 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200501 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200502 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700503 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200504 div_from_reg(data->fan_div[i] + 1));
505 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200506 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200507 /* Preserve min limit if possible */
508 if (data->fan_min[i] >= 2
509 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200510 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200511 W83627EHF_REG_FAN_MIN[i],
512 (data->fan_min[i] /= 2));
513 }
514 }
515
Rudolf Marek08c79952006-07-05 18:14:31 +0200516 for (i = 0; i < 4; i++) {
Jean Delvare77fa49d2009-01-07 16:37:35 +0100517 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200518 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200519 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200520 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200521 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200522 W83627EHF_REG_TOLERANCE[i]);
523 }
524 data->pwm_mode[i] =
525 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
526 ? 0 : 1;
527 data->pwm_enable[i] =
528 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
529 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200530 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200531 W83627EHF_REG_PWM[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200532 data->fan_min_output[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200533 W83627EHF_REG_FAN_MIN_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200534 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200535 W83627EHF_REG_FAN_STOP_TIME[i]);
536 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200537 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200538 W83627EHF_REG_TARGET[i]) &
539 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
540 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
541 & 0x0f;
542 }
543
Jean Delvare08e7e272005-04-25 22:43:25 +0200544 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200545 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200546 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200547 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200548 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200549 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200550 W83627EHF_REG_TEMP1_HYST);
551 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200552 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200553 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200554 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200555 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200556 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200557 W83627EHF_REG_TEMP_HYST[i]);
558 }
559
David Hubbard1ea6dd32007-06-24 11:16:15 +0200560 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100561 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200562 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100563 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200564 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100565 W83627EHF_REG_ALARM3) << 16);
566
Jean Delvare08e7e272005-04-25 22:43:25 +0200567 data->last_updated = jiffies;
568 data->valid = 1;
569 }
570
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100571 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200572 return data;
573}
574
575/*
576 * Sysfs callback functions
577 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100578#define show_in_reg(reg) \
579static ssize_t \
580show_##reg(struct device *dev, struct device_attribute *attr, \
581 char *buf) \
582{ \
583 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
584 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
585 int nr = sensor_attr->index; \
586 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
587}
588show_in_reg(in)
589show_in_reg(in_min)
590show_in_reg(in_max)
591
592#define store_in_reg(REG, reg) \
593static ssize_t \
594store_in_##reg (struct device *dev, struct device_attribute *attr, \
595 const char *buf, size_t count) \
596{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200597 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100598 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
599 int nr = sensor_attr->index; \
600 u32 val = simple_strtoul(buf, NULL, 10); \
601 \
602 mutex_lock(&data->update_lock); \
603 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200604 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100605 data->in_##reg[nr]); \
606 mutex_unlock(&data->update_lock); \
607 return count; \
608}
609
610store_in_reg(MIN, min)
611store_in_reg(MAX, max)
612
Jean Delvarea4589db2006-03-23 16:30:29 +0100613static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
614{
615 struct w83627ehf_data *data = w83627ehf_update_device(dev);
616 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
617 int nr = sensor_attr->index;
618 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
619}
620
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100621static struct sensor_device_attribute sda_in_input[] = {
622 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
623 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
624 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
625 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
626 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
627 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
628 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
629 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
630 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
631 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
632};
633
Jean Delvarea4589db2006-03-23 16:30:29 +0100634static struct sensor_device_attribute sda_in_alarm[] = {
635 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
636 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
637 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
638 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
639 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
640 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
641 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
642 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
643 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
644 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
645};
646
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100647static struct sensor_device_attribute sda_in_min[] = {
648 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
649 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
650 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
651 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
652 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
653 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
654 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
655 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
656 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
657 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
658};
659
660static struct sensor_device_attribute sda_in_max[] = {
661 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
662 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
663 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
664 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
665 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
666 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
667 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
668 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
669 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
670 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
671};
672
Jean Delvare08e7e272005-04-25 22:43:25 +0200673#define show_fan_reg(reg) \
674static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100675show_##reg(struct device *dev, struct device_attribute *attr, \
676 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200677{ \
678 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100679 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
680 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200681 return sprintf(buf, "%d\n", \
682 fan_from_reg(data->reg[nr], \
683 div_from_reg(data->fan_div[nr]))); \
684}
685show_fan_reg(fan);
686show_fan_reg(fan_min);
687
688static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100689show_fan_div(struct device *dev, struct device_attribute *attr,
690 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200691{
692 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100693 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
694 int nr = sensor_attr->index;
695 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200696}
697
698static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100699store_fan_min(struct device *dev, struct device_attribute *attr,
700 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200701{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200702 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100703 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
704 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200705 unsigned int val = simple_strtoul(buf, NULL, 10);
706 unsigned int reg;
707 u8 new_div;
708
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100709 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200710 if (!val) {
711 /* No min limit, alarm disabled */
712 data->fan_min[nr] = 255;
713 new_div = data->fan_div[nr]; /* No change */
714 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
715 } else if ((reg = 1350000U / val) >= 128 * 255) {
716 /* Speed below this value cannot possibly be represented,
717 even with the highest divider (128) */
718 data->fan_min[nr] = 254;
719 new_div = 7; /* 128 == (1 << 7) */
720 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
721 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
722 } else if (!reg) {
723 /* Speed above this value cannot possibly be represented,
724 even with the lowest divider (1) */
725 data->fan_min[nr] = 1;
726 new_div = 0; /* 1 == (1 << 0) */
727 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200728 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200729 } else {
730 /* Automatically pick the best divider, i.e. the one such
731 that the min limit will correspond to a register value
732 in the 96..192 range */
733 new_div = 0;
734 while (reg > 192 && new_div < 7) {
735 reg >>= 1;
736 new_div++;
737 }
738 data->fan_min[nr] = reg;
739 }
740
741 /* Write both the fan clock divider (if it changed) and the new
742 fan min (unconditionally) */
743 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200744 /* Preserve the fan speed reading */
745 if (data->fan[nr] != 0xff) {
746 if (new_div > data->fan_div[nr])
747 data->fan[nr] >>= new_div - data->fan_div[nr];
748 else if (data->fan[nr] & 0x80)
749 data->fan[nr] = 0xff;
750 else
751 data->fan[nr] <<= data->fan_div[nr] - new_div;
752 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200753
754 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
755 nr + 1, div_from_reg(data->fan_div[nr]),
756 div_from_reg(new_div));
757 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200758 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200759 /* Give the chip time to sample a new speed value */
760 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200761 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200762 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200763 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100764 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200765
766 return count;
767}
768
Yuan Mu412fec82006-02-05 23:24:16 +0100769static struct sensor_device_attribute sda_fan_input[] = {
770 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
771 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
772 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
773 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
774 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
775};
Jean Delvare08e7e272005-04-25 22:43:25 +0200776
Jean Delvarea4589db2006-03-23 16:30:29 +0100777static struct sensor_device_attribute sda_fan_alarm[] = {
778 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
779 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
780 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
781 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
782 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
783};
784
Yuan Mu412fec82006-02-05 23:24:16 +0100785static struct sensor_device_attribute sda_fan_min[] = {
786 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
787 store_fan_min, 0),
788 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
789 store_fan_min, 1),
790 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
791 store_fan_min, 2),
792 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
793 store_fan_min, 3),
794 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
795 store_fan_min, 4),
796};
Jean Delvare08e7e272005-04-25 22:43:25 +0200797
Yuan Mu412fec82006-02-05 23:24:16 +0100798static struct sensor_device_attribute sda_fan_div[] = {
799 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
800 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
801 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
802 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
803 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
804};
Jean Delvare08e7e272005-04-25 22:43:25 +0200805
Jean Delvare08e7e272005-04-25 22:43:25 +0200806#define show_temp1_reg(reg) \
807static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700808show_##reg(struct device *dev, struct device_attribute *attr, \
809 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200810{ \
811 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
812 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
813}
814show_temp1_reg(temp1);
815show_temp1_reg(temp1_max);
816show_temp1_reg(temp1_max_hyst);
817
818#define store_temp1_reg(REG, reg) \
819static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700820store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
821 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200822{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200823 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200824 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200825 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100826 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200827 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200828 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200829 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100830 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200831 return count; \
832}
833store_temp1_reg(OVER, max);
834store_temp1_reg(HYST, max_hyst);
835
Jean Delvare08e7e272005-04-25 22:43:25 +0200836#define show_temp_reg(reg) \
837static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100838show_##reg(struct device *dev, struct device_attribute *attr, \
839 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200840{ \
841 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100842 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
843 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200844 return sprintf(buf, "%d\n", \
845 LM75_TEMP_FROM_REG(data->reg[nr])); \
846}
847show_temp_reg(temp);
848show_temp_reg(temp_max);
849show_temp_reg(temp_max_hyst);
850
851#define store_temp_reg(REG, reg) \
852static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100853store_##reg(struct device *dev, struct device_attribute *attr, \
854 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200855{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200856 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100857 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
858 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200859 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200860 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100861 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200862 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200863 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200864 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100865 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200866 return count; \
867}
868store_temp_reg(OVER, temp_max);
869store_temp_reg(HYST, temp_max_hyst);
870
Jean Delvareda667362007-06-24 11:21:02 +0200871static ssize_t
872show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
873{
874 struct w83627ehf_data *data = w83627ehf_update_device(dev);
875 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
876 int nr = sensor_attr->index;
877 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
878}
879
Gong Juna157d062009-03-30 21:46:43 +0200880static struct sensor_device_attribute sda_temp_input[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100881 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
882 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
883 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
Gong Juna157d062009-03-30 21:46:43 +0200884};
885
886static struct sensor_device_attribute sda_temp_max[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100887 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
888 store_temp1_max, 0),
889 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
890 store_temp_max, 0),
891 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
892 store_temp_max, 1),
Gong Juna157d062009-03-30 21:46:43 +0200893};
894
895static struct sensor_device_attribute sda_temp_max_hyst[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100896 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
897 store_temp1_max_hyst, 0),
898 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
899 store_temp_max_hyst, 0),
900 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
901 store_temp_max_hyst, 1),
Gong Juna157d062009-03-30 21:46:43 +0200902};
903
904static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100905 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
906 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
907 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200908};
909
910static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200911 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
912 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
913 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100914};
Jean Delvare08e7e272005-04-25 22:43:25 +0200915
Rudolf Marek08c79952006-07-05 18:14:31 +0200916#define show_pwm_reg(reg) \
917static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
918 char *buf) \
919{ \
920 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
921 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
922 int nr = sensor_attr->index; \
923 return sprintf(buf, "%d\n", data->reg[nr]); \
924}
925
926show_pwm_reg(pwm_mode)
927show_pwm_reg(pwm_enable)
928show_pwm_reg(pwm)
929
930static ssize_t
931store_pwm_mode(struct device *dev, struct device_attribute *attr,
932 const char *buf, size_t count)
933{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200934 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200935 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
936 int nr = sensor_attr->index;
937 u32 val = simple_strtoul(buf, NULL, 10);
938 u16 reg;
939
940 if (val > 1)
941 return -EINVAL;
942 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200943 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200944 data->pwm_mode[nr] = val;
945 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
946 if (!val)
947 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200948 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200949 mutex_unlock(&data->update_lock);
950 return count;
951}
952
953static ssize_t
954store_pwm(struct device *dev, struct device_attribute *attr,
955 const char *buf, size_t count)
956{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200957 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200958 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
959 int nr = sensor_attr->index;
960 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
961
962 mutex_lock(&data->update_lock);
963 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200964 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200965 mutex_unlock(&data->update_lock);
966 return count;
967}
968
969static ssize_t
970store_pwm_enable(struct device *dev, struct device_attribute *attr,
971 const char *buf, size_t count)
972{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200973 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200974 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
975 int nr = sensor_attr->index;
976 u32 val = simple_strtoul(buf, NULL, 10);
977 u16 reg;
978
979 if (!val || (val > 2)) /* only modes 1 and 2 are supported */
980 return -EINVAL;
981 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200982 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200983 data->pwm_enable[nr] = val;
984 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
985 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200986 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200987 mutex_unlock(&data->update_lock);
988 return count;
989}
990
991
992#define show_tol_temp(reg) \
993static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
994 char *buf) \
995{ \
996 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
997 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
998 int nr = sensor_attr->index; \
999 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
1000}
1001
1002show_tol_temp(tolerance)
1003show_tol_temp(target_temp)
1004
1005static ssize_t
1006store_target_temp(struct device *dev, struct device_attribute *attr,
1007 const char *buf, size_t count)
1008{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001009 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001010 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1011 int nr = sensor_attr->index;
1012 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
1013
1014 mutex_lock(&data->update_lock);
1015 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001016 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001017 mutex_unlock(&data->update_lock);
1018 return count;
1019}
1020
1021static ssize_t
1022store_tolerance(struct device *dev, struct device_attribute *attr,
1023 const char *buf, size_t count)
1024{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001025 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001026 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1027 int nr = sensor_attr->index;
1028 u16 reg;
1029 /* Limit the temp to 0C - 15C */
1030 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1031
1032 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001033 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001034 data->tolerance[nr] = val;
1035 if (nr == 1)
1036 reg = (reg & 0x0f) | (val << 4);
1037 else
1038 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001039 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001040 mutex_unlock(&data->update_lock);
1041 return count;
1042}
1043
1044static struct sensor_device_attribute sda_pwm[] = {
1045 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1046 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1047 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1048 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1049};
1050
1051static struct sensor_device_attribute sda_pwm_mode[] = {
1052 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1053 store_pwm_mode, 0),
1054 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1055 store_pwm_mode, 1),
1056 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1057 store_pwm_mode, 2),
1058 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1059 store_pwm_mode, 3),
1060};
1061
1062static struct sensor_device_attribute sda_pwm_enable[] = {
1063 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1064 store_pwm_enable, 0),
1065 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1066 store_pwm_enable, 1),
1067 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1068 store_pwm_enable, 2),
1069 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1070 store_pwm_enable, 3),
1071};
1072
1073static struct sensor_device_attribute sda_target_temp[] = {
1074 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1075 store_target_temp, 0),
1076 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1077 store_target_temp, 1),
1078 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1079 store_target_temp, 2),
1080 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1081 store_target_temp, 3),
1082};
1083
1084static struct sensor_device_attribute sda_tolerance[] = {
1085 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1086 store_tolerance, 0),
1087 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1088 store_tolerance, 1),
1089 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1090 store_tolerance, 2),
1091 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1092 store_tolerance, 3),
1093};
1094
Rudolf Marek08c79952006-07-05 18:14:31 +02001095/* Smart Fan registers */
1096
1097#define fan_functions(reg, REG) \
1098static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1099 char *buf) \
1100{ \
1101 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1102 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1103 int nr = sensor_attr->index; \
1104 return sprintf(buf, "%d\n", data->reg[nr]); \
1105}\
1106static ssize_t \
1107store_##reg(struct device *dev, struct device_attribute *attr, \
1108 const char *buf, size_t count) \
1109{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001110 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001111 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1112 int nr = sensor_attr->index; \
1113 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1114 mutex_lock(&data->update_lock); \
1115 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001116 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001117 mutex_unlock(&data->update_lock); \
1118 return count; \
1119}
1120
1121fan_functions(fan_min_output, FAN_MIN_OUTPUT)
1122
1123#define fan_time_functions(reg, REG) \
1124static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1125 char *buf) \
1126{ \
1127 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1128 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1129 int nr = sensor_attr->index; \
1130 return sprintf(buf, "%d\n", \
1131 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1132} \
1133\
1134static ssize_t \
1135store_##reg(struct device *dev, struct device_attribute *attr, \
1136 const char *buf, size_t count) \
1137{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001138 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001139 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1140 int nr = sensor_attr->index; \
1141 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1142 data->pwm_mode[nr]); \
1143 mutex_lock(&data->update_lock); \
1144 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001145 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001146 mutex_unlock(&data->update_lock); \
1147 return count; \
1148} \
1149
1150fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1151
David Hubbard1ea6dd32007-06-24 11:16:15 +02001152static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1153 char *buf)
1154{
1155 struct w83627ehf_data *data = dev_get_drvdata(dev);
1156
1157 return sprintf(buf, "%s\n", data->name);
1158}
1159static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001160
1161static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1162 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1163 store_fan_stop_time, 3),
1164 SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1165 store_fan_min_output, 3),
1166};
1167
1168static struct sensor_device_attribute sda_sf3_arrays[] = {
1169 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1170 store_fan_stop_time, 0),
1171 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1172 store_fan_stop_time, 1),
1173 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1174 store_fan_stop_time, 2),
1175 SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1176 store_fan_min_output, 0),
1177 SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1178 store_fan_min_output, 1),
1179 SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1180 store_fan_min_output, 2),
1181};
1182
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001183static ssize_t
1184show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1185{
1186 struct w83627ehf_data *data = dev_get_drvdata(dev);
1187 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1188}
1189static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1190
Jean Delvare08e7e272005-04-25 22:43:25 +02001191/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001192 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001193 */
1194
David Hubbardc18beb52006-09-24 21:04:38 +02001195static void w83627ehf_device_remove_files(struct device *dev)
1196{
1197 /* some entries in the following arrays may not have been used in
1198 * device_create_file(), but device_remove_file() will ignore them */
1199 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001200 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001201
1202 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1203 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1204 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1205 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001206 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001207 if ((i == 6) && data->in6_skip)
1208 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001209 device_remove_file(dev, &sda_in_input[i].dev_attr);
1210 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1211 device_remove_file(dev, &sda_in_min[i].dev_attr);
1212 device_remove_file(dev, &sda_in_max[i].dev_attr);
1213 }
1214 for (i = 0; i < 5; i++) {
1215 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1216 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1217 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1218 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1219 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001220 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001221 device_remove_file(dev, &sda_pwm[i].dev_attr);
1222 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1223 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1224 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1225 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1226 }
Gong Juna157d062009-03-30 21:46:43 +02001227 for (i = 0; i < 3; i++) {
1228 if ((i == 2) && data->temp3_disable)
1229 continue;
1230 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1231 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1232 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1233 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1234 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1235 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001236
1237 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001238 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001239}
1240
David Hubbard1ea6dd32007-06-24 11:16:15 +02001241/* Get the monitoring functions started */
1242static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001243{
1244 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001245 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001246
1247 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001248 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001249 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001250 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001251 tmp | 0x01);
1252
1253 /* Enable temp2 and temp3 if needed */
1254 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001255 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001256 W83627EHF_REG_TEMP_CONFIG[i]);
Gong Juna157d062009-03-30 21:46:43 +02001257 if ((i == 1) && data->temp3_disable)
1258 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001259 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001260 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001261 W83627EHF_REG_TEMP_CONFIG[i],
1262 tmp & 0xfe);
1263 }
Jean Delvared3130f02007-06-24 11:20:13 +02001264
1265 /* Enable VBAT monitoring if needed */
1266 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1267 if (!(tmp & 0x01))
1268 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001269
1270 /* Get thermal sensor types */
1271 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1272 for (i = 0; i < 3; i++) {
1273 if ((tmp & (0x02 << i)))
1274 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1275 else
1276 data->temp_type[i] = 4; /* thermistor */
1277 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001278}
1279
David Hubbard1ea6dd32007-06-24 11:16:15 +02001280static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001281{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001282 struct device *dev = &pdev->dev;
1283 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001284 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001285 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001286 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001287 int i, err = 0;
1288
David Hubbard1ea6dd32007-06-24 11:16:15 +02001289 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1290 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001291 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001292 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1293 (unsigned long)res->start,
1294 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001295 goto exit;
1296 }
1297
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001298 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001299 err = -ENOMEM;
1300 goto exit_release;
1301 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001302
David Hubbard1ea6dd32007-06-24 11:16:15 +02001303 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001304 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001305 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001306 data->name = w83627ehf_device_names[sio_data->kind];
1307 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001308
Gong Jun237c8d2f2009-03-30 21:46:42 +02001309 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1310 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1311 /* 667HG has 3 pwms */
1312 data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001313
Gong Juna157d062009-03-30 21:46:43 +02001314 /* Check temp3 configuration bit for 667HG */
1315 if (sio_data->kind == w83667hg) {
1316 data->temp3_disable = w83627ehf_read_value(data,
1317 W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
1318 data->in6_skip = !data->temp3_disable;
1319 }
1320
Jean Delvare08e7e272005-04-25 22:43:25 +02001321 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001322 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001323
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001324 data->vrm = vid_which_vrm();
1325 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001326 /* Read VID value */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001327 if (sio_data->kind == w83667hg) {
1328 /* W83667HG has different pins for VID input and output, so
1329 we can get the VID input values directly at logical device D
1330 0xe3. */
1331 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1332 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001333 err = device_create_file(dev, &dev_attr_cpu0_vid);
1334 if (err)
1335 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001336 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001337 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1338 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1339 /* Set VID input sensibility if needed. In theory the
1340 BIOS should have set it, but in practice it's not
1341 always the case. We only do it for the W83627EHF/EHG
1342 because the W83627DHG is more complex in this
1343 respect. */
1344 if (sio_data->kind == w83627ehf) {
1345 en_vrm10 = superio_inb(sio_data->sioreg,
1346 SIO_REG_EN_VRM10);
1347 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1348 dev_warn(dev, "Setting VID input "
1349 "voltage to TTL\n");
1350 superio_outb(sio_data->sioreg,
1351 SIO_REG_EN_VRM10,
1352 en_vrm10 & ~0x08);
1353 } else if (!(en_vrm10 & 0x08)
1354 && data->vrm == 100) {
1355 dev_warn(dev, "Setting VID input "
1356 "voltage to VRM10\n");
1357 superio_outb(sio_data->sioreg,
1358 SIO_REG_EN_VRM10,
1359 en_vrm10 | 0x08);
1360 }
1361 }
1362
1363 data->vid = superio_inb(sio_data->sioreg,
1364 SIO_REG_VID_DATA);
1365 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1366 data->vid &= 0x3f;
1367
1368 err = device_create_file(dev, &dev_attr_cpu0_vid);
1369 if (err)
1370 goto exit_release;
1371 } else {
1372 dev_info(dev, "VID pins in output mode, CPU VID not "
1373 "available\n");
1374 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001375 }
1376
Rudolf Marek08c79952006-07-05 18:14:31 +02001377 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001378 if (sio_data->kind == w83667hg) {
1379 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1380 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1381 } else {
1382 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1383 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1384 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001385 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001386
Jean Delvare08e7e272005-04-25 22:43:25 +02001387 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001388 as fan on/off switches, but fan5 control is write only :/
1389 We assume that if the serial interface is disabled, designers
1390 connected fan5 as input unless they are emitting log 1, which
1391 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001392
Jean Delvare08e7e272005-04-25 22:43:25 +02001393 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001394 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001395 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001396 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001397 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001398 data->has_fan |= (1 << 4);
1399
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001400 /* Read fan clock dividers immediately */
1401 w83627ehf_update_fan_div(data);
1402
Jean Delvare08e7e272005-04-25 22:43:25 +02001403 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001404 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001405 if ((err = device_create_file(dev,
1406 &sda_sf3_arrays[i].dev_attr)))
1407 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001408
1409 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001410 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001411 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1412 if ((err = device_create_file(dev,
1413 &sda_sf3_arrays_fan4[i].dev_attr)))
1414 goto exit_remove;
1415 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001416
Gong Juna157d062009-03-30 21:46:43 +02001417 for (i = 0; i < data->in_num; i++) {
1418 if ((i == 6) && data->in6_skip)
1419 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001420 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1421 || (err = device_create_file(dev,
1422 &sda_in_alarm[i].dev_attr))
1423 || (err = device_create_file(dev,
1424 &sda_in_min[i].dev_attr))
1425 || (err = device_create_file(dev,
1426 &sda_in_max[i].dev_attr)))
1427 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001428 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001429
Yuan Mu412fec82006-02-05 23:24:16 +01001430 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001431 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001432 if ((err = device_create_file(dev,
1433 &sda_fan_input[i].dev_attr))
1434 || (err = device_create_file(dev,
1435 &sda_fan_alarm[i].dev_attr))
1436 || (err = device_create_file(dev,
1437 &sda_fan_div[i].dev_attr))
1438 || (err = device_create_file(dev,
1439 &sda_fan_min[i].dev_attr)))
1440 goto exit_remove;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001441 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001442 ((err = device_create_file(dev,
1443 &sda_pwm[i].dev_attr))
1444 || (err = device_create_file(dev,
1445 &sda_pwm_mode[i].dev_attr))
1446 || (err = device_create_file(dev,
1447 &sda_pwm_enable[i].dev_attr))
1448 || (err = device_create_file(dev,
1449 &sda_target_temp[i].dev_attr))
1450 || (err = device_create_file(dev,
1451 &sda_tolerance[i].dev_attr))))
1452 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001453 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001454 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001455
Gong Juna157d062009-03-30 21:46:43 +02001456 for (i = 0; i < 3; i++) {
1457 if ((i == 2) && data->temp3_disable)
1458 continue;
1459 if ((err = device_create_file(dev,
1460 &sda_temp_input[i].dev_attr))
1461 || (err = device_create_file(dev,
1462 &sda_temp_max[i].dev_attr))
1463 || (err = device_create_file(dev,
1464 &sda_temp_max_hyst[i].dev_attr))
1465 || (err = device_create_file(dev,
1466 &sda_temp_alarm[i].dev_attr))
1467 || (err = device_create_file(dev,
1468 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001469 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001470 }
David Hubbardc18beb52006-09-24 21:04:38 +02001471
David Hubbard1ea6dd32007-06-24 11:16:15 +02001472 err = device_create_file(dev, &dev_attr_name);
1473 if (err)
1474 goto exit_remove;
1475
Tony Jones1beeffe2007-08-20 13:46:20 -07001476 data->hwmon_dev = hwmon_device_register(dev);
1477 if (IS_ERR(data->hwmon_dev)) {
1478 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001479 goto exit_remove;
1480 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001481
1482 return 0;
1483
David Hubbardc18beb52006-09-24 21:04:38 +02001484exit_remove:
1485 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001486 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001487 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001488exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001489 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001490exit:
1491 return err;
1492}
1493
David Hubbard1ea6dd32007-06-24 11:16:15 +02001494static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001495{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001496 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001497
Tony Jones1beeffe2007-08-20 13:46:20 -07001498 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001499 w83627ehf_device_remove_files(&pdev->dev);
1500 release_region(data->addr, IOREGION_LENGTH);
1501 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001502 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001503
1504 return 0;
1505}
1506
David Hubbard1ea6dd32007-06-24 11:16:15 +02001507static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001508 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001509 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001510 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001511 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001512 .probe = w83627ehf_probe,
1513 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001514};
1515
David Hubbard1ea6dd32007-06-24 11:16:15 +02001516/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1517static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1518 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001519{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001520 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1521 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1522 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001523 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02001524 static const char __initdata sio_name_W83667HG[] = "W83667HG";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001525
Jean Delvare08e7e272005-04-25 22:43:25 +02001526 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001527 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001528
David Hubbard1ea6dd32007-06-24 11:16:15 +02001529 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001530
Jean Delvare67b671b2007-12-06 23:13:42 +01001531 if (force_id)
1532 val = force_id;
1533 else
1534 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1535 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001536 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001537 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001538 sio_data->kind = w83627ehf;
1539 sio_name = sio_name_W83627EHF;
1540 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001541 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001542 sio_data->kind = w83627ehf;
1543 sio_name = sio_name_W83627EHG;
1544 break;
1545 case SIO_W83627DHG_ID:
1546 sio_data->kind = w83627dhg;
1547 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001548 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001549 case SIO_W83627DHG_P_ID:
1550 sio_data->kind = w83627dhg_p;
1551 sio_name = sio_name_W83627DHG_P;
1552 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001553 case SIO_W83667HG_ID:
1554 sio_data->kind = w83667hg;
1555 sio_name = sio_name_W83667HG;
1556 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001557 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001558 if (val != 0xffff)
1559 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1560 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001561 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001562 return -ENODEV;
1563 }
1564
David Hubbard1ea6dd32007-06-24 11:16:15 +02001565 /* We have a known chip, find the HWM I/O address */
1566 superio_select(sioaddr, W83627EHF_LD_HWM);
1567 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1568 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001569 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001570 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001571 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1572 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001573 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001574 return -ENODEV;
1575 }
1576
1577 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001578 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001579 if (!(val & 0x01)) {
1580 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1581 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001582 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001583 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001584
David Hubbard1ea6dd32007-06-24 11:16:15 +02001585 superio_exit(sioaddr);
1586 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1587 sio_data->sioreg = sioaddr;
1588
Jean Delvare08e7e272005-04-25 22:43:25 +02001589 return 0;
1590}
1591
David Hubbard1ea6dd32007-06-24 11:16:15 +02001592/* when Super-I/O functions move to a separate file, the Super-I/O
1593 * bus will manage the lifetime of the device and this module will only keep
1594 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1595 * must keep track of the device */
1596static struct platform_device *pdev;
1597
Jean Delvare08e7e272005-04-25 22:43:25 +02001598static int __init sensors_w83627ehf_init(void)
1599{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001600 int err;
1601 unsigned short address;
1602 struct resource res;
1603 struct w83627ehf_sio_data sio_data;
1604
1605 /* initialize sio_data->kind and sio_data->sioreg.
1606 *
1607 * when Super-I/O functions move to a separate file, the Super-I/O
1608 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1609 * w83627ehf hardware monitor, and call probe() */
1610 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1611 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001612 return -ENODEV;
1613
David Hubbard1ea6dd32007-06-24 11:16:15 +02001614 err = platform_driver_register(&w83627ehf_driver);
1615 if (err)
1616 goto exit;
1617
1618 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1619 err = -ENOMEM;
1620 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1621 goto exit_unregister;
1622 }
1623
1624 err = platform_device_add_data(pdev, &sio_data,
1625 sizeof(struct w83627ehf_sio_data));
1626 if (err) {
1627 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1628 goto exit_device_put;
1629 }
1630
1631 memset(&res, 0, sizeof(res));
1632 res.name = DRVNAME;
1633 res.start = address + IOREGION_OFFSET;
1634 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1635 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001636
1637 err = acpi_check_resource_conflict(&res);
1638 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001639 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001640
David Hubbard1ea6dd32007-06-24 11:16:15 +02001641 err = platform_device_add_resources(pdev, &res, 1);
1642 if (err) {
1643 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1644 "(%d)\n", err);
1645 goto exit_device_put;
1646 }
1647
1648 /* platform_device_add calls probe() */
1649 err = platform_device_add(pdev);
1650 if (err) {
1651 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1652 err);
1653 goto exit_device_put;
1654 }
1655
1656 return 0;
1657
1658exit_device_put:
1659 platform_device_put(pdev);
1660exit_unregister:
1661 platform_driver_unregister(&w83627ehf_driver);
1662exit:
1663 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001664}
1665
1666static void __exit sensors_w83627ehf_exit(void)
1667{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001668 platform_device_unregister(pdev);
1669 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001670}
1671
1672MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1673MODULE_DESCRIPTION("W83627EHF driver");
1674MODULE_LICENSE("GPL");
1675
1676module_init(sensors_w83627ehf_init);
1677module_exit(sensors_w83627ehf_exit);