blob: 1128eac7023b6f6cbecf7e60ba23ea89f18eb79e [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
Guenter Roecke7e1ca62011-02-04 13:24:30 -08003 the Winbond W83627EHF Super-I/O chip
Jean Delvare08e7e272005-04-25 22:43:25 +02004 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Guenter Roecke7e1ca62011-02-04 13:24:30 -08006 Rudolf Marek <r.marek@assembler.cz>
7 David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman41e9a062009-12-14 18:01:37 -08008 Daniel J Blueman <daniel.blueman@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02009
10 Shamelessly ripped from the w83627hf driver
11 Copyright (C) 2003 Mark Studebaker
12
13 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
14 in testing and debugging this driver.
15
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020016 This driver also supports the W83627EHG, which is the lead-free
17 version of the W83627EHF.
18
Jean Delvare08e7e272005-04-25 22:43:25 +020019 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
33
34 Supports the following chips:
35
David Hubbard657c93b2007-02-14 21:15:04 +010036 Chip #vin #fan #pwm #temp chip IDs man ID
37 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
Guenter Roecke7e1ca62011-02-04 13:24:30 -080038 0x8860 0xa1
David Hubbard657c93b2007-02-14 21:15:04 +010039 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020040 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d2f2009-03-30 21:46:42 +020041 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckc39aeda2010-08-14 21:08:55 +020042 w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020043*/
44
Joe Perchesabdc6fd2010-10-20 06:51:54 +000045#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
46
Jean Delvare08e7e272005-04-25 22:43:25 +020047#include <linux/module.h>
48#include <linux/init.h>
49#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020050#include <linux/jiffies.h>
51#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040052#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010053#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020054#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040055#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010056#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010057#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020058#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020059#include "lm75.h"
60
Guenter Roeckc39aeda2010-08-14 21:08:55 +020061enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
David Hubbard1ea6dd32007-06-24 11:16:15 +020062
63/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
Guenter Roecke7e1ca62011-02-04 13:24:30 -080064static const char * const w83627ehf_device_names[] = {
David Hubbard1ea6dd32007-06-24 11:16:15 +020065 "w83627ehf",
66 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020067 "w83627dhg",
Gong Jun237c8d2f2009-03-30 21:46:42 +020068 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020069 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020070};
71
Jean Delvare67b671b2007-12-06 23:13:42 +010072static unsigned short force_id;
73module_param(force_id, ushort, 0);
74MODULE_PARM_DESC(force_id, "Override the detected device ID");
75
David Hubbard1ea6dd32007-06-24 11:16:15 +020076#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020077
78/*
79 * Super-I/O constants and functions
80 */
81
Jean Delvare08e7e272005-04-25 22:43:25 +020082#define W83627EHF_LD_HWM 0x0b
Guenter Roecke7e1ca62011-02-04 13:24:30 -080083#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020084
85#define SIO_REG_LDSEL 0x07 /* Logical device select */
86#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020087#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020088#define SIO_REG_ENABLE 0x30 /* Logical device enable */
89#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020090#define SIO_REG_VID_CTRL 0xF0 /* VID control */
91#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020092
David Hubbard657c93b2007-02-14 21:15:04 +010093#define SIO_W83627EHF_ID 0x8850
94#define SIO_W83627EHG_ID 0x8860
95#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020096#define SIO_W83627DHG_P_ID 0xb070
Guenter Roecke7e1ca62011-02-04 13:24:30 -080097#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +020098#define SIO_W83667HG_B_ID 0xb350
David Hubbard657c93b2007-02-14 21:15:04 +010099#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +0200100
101static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200103{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200104 outb(reg, ioreg);
105 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200106}
107
108static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200110{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200111 outb(reg, ioreg);
112 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200113}
114
115static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200117{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200118 outb(SIO_REG_LDSEL, ioreg);
119 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200120}
121
122static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200124{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200125 outb(0x87, ioreg);
126 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200127}
128
129static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200130superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200131{
Jonas Jonsson022b75a2010-09-17 17:24:13 +0200132 outb(0xaa, ioreg);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200133 outb(0x02, ioreg);
134 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200135}
136
137/*
138 * ISA constants
139 */
140
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800141#define IOREGION_ALIGNMENT (~7)
Jean Delvare1a641fc2007-04-23 14:41:16 -0700142#define IOREGION_OFFSET 5
143#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200144#define ADDR_REG_OFFSET 0
145#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200146
147#define W83627EHF_REG_BANK 0x4E
148#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100149
150/* Not currently used:
151 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
152 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
153 * REG_MAN_ID is at port 0x4f
154 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200155
156static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
157static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
158
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100159/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
160#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
161 (0x554 + (((nr) - 7) * 2)))
162#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
163 (0x555 + (((nr) - 7) * 2)))
164#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
165 (0x550 + (nr) - 7))
166
Guenter Roeckbce26c52011-02-04 12:54:14 -0800167static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
168static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
169static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
170static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
Jean Delvare08e7e272005-04-25 22:43:25 +0200171
172/* Fan clock dividers are spread over the following five registers */
173#define W83627EHF_REG_FANDIV1 0x47
174#define W83627EHF_REG_FANDIV2 0x4B
175#define W83627EHF_REG_VBAT 0x5D
176#define W83627EHF_REG_DIODE 0x59
177#define W83627EHF_REG_SMI_OVT 0x4C
178
Jean Delvarea4589db2006-03-23 16:30:29 +0100179#define W83627EHF_REG_ALARM1 0x459
180#define W83627EHF_REG_ALARM2 0x45A
181#define W83627EHF_REG_ALARM3 0x45B
182
Rudolf Marek08c79952006-07-05 18:14:31 +0200183/* SmartFan registers */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800184#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
185#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
186
Rudolf Marek08c79952006-07-05 18:14:31 +0200187/* DC or PWM output fan configuration */
188static const u8 W83627EHF_REG_PWM_ENABLE[] = {
189 0x04, /* SYS FAN0 output mode and PWM mode */
190 0x04, /* CPU FAN0 output mode and PWM mode */
191 0x12, /* AUX FAN mode */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800192 0x62, /* CPU FAN1 mode */
Rudolf Marek08c79952006-07-05 18:14:31 +0200193};
194
195static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
196static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
197
198/* FAN Duty Cycle, be used to control */
199static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
200static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
201static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
202
Rudolf Marek08c79952006-07-05 18:14:31 +0200203/* Advanced Fan control, some values are common for all fans */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800204static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
205static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
206static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200207
208static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
209 = { 0xff, 0x67, 0xff, 0x69 };
210static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
211 = { 0xff, 0x68, 0xff, 0x6a };
212
213static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
214static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
Rudolf Marek08c79952006-07-05 18:14:31 +0200215
Guenter Roeckbce26c52011-02-04 12:54:14 -0800216static inline int is_word_sized(u16 reg)
217{
218 return (((reg & 0xff00) == 0x100
219 || (reg & 0xff00) == 0x200)
220 && ((reg & 0x00ff) == 0x50
221 || (reg & 0x00ff) == 0x53
222 || (reg & 0x00ff) == 0x55));
223}
224
Jean Delvare08e7e272005-04-25 22:43:25 +0200225/*
226 * Conversions
227 */
228
Rudolf Marek08c79952006-07-05 18:14:31 +0200229/* 1 is PWM mode, output in ms */
230static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
231{
232 return mode ? 100 * reg : 400 * reg;
233}
234
235static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
236{
237 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
238 (msec + 200) / 400), 1, 255);
239}
240
Jean Delvare08e7e272005-04-25 22:43:25 +0200241static inline unsigned int
242fan_from_reg(u8 reg, unsigned int div)
243{
244 if (reg == 0 || reg == 255)
245 return 0;
246 return 1350000U / (reg * div);
247}
248
249static inline unsigned int
250div_from_reg(u8 reg)
251{
252 return 1 << reg;
253}
254
255static inline int
Guenter Roeckbce26c52011-02-04 12:54:14 -0800256temp_from_reg(u16 reg, s16 regval)
Jean Delvare08e7e272005-04-25 22:43:25 +0200257{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800258 if (is_word_sized(reg))
259 return LM75_TEMP_FROM_REG(regval);
260 return regval * 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200261}
262
Guenter Roeckbce26c52011-02-04 12:54:14 -0800263static inline s16
264temp_to_reg(u16 reg, long temp)
Jean Delvare08e7e272005-04-25 22:43:25 +0200265{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800266 if (is_word_sized(reg))
267 return LM75_TEMP_TO_REG(temp);
268 return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
Jean Delvare08e7e272005-04-25 22:43:25 +0200269}
270
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100271/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
272
273static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
274
275static inline long in_from_reg(u8 reg, u8 nr)
276{
277 return reg * scale_in[nr];
278}
279
280static inline u8 in_to_reg(u32 val, u8 nr)
281{
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800282 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
283 255);
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100284}
285
Jean Delvare08e7e272005-04-25 22:43:25 +0200286/*
287 * Data structures and manipulation thereof
288 */
289
290struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200291 int addr; /* IO base of hw monitor block */
292 const char *name;
293
Tony Jones1beeffe2007-08-20 13:46:20 -0700294 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100295 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200296
Guenter Roeckda2e0252010-08-14 21:08:55 +0200297 const u8 *REG_FAN_START_OUTPUT;
298 const u8 *REG_FAN_STOP_OUTPUT;
299 const u8 *REG_FAN_MAX_OUTPUT;
300 const u8 *REG_FAN_STEP_OUTPUT;
301
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100302 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200303 char valid; /* !=0 if following fields are valid */
304 unsigned long last_updated; /* In jiffies */
305
306 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200307 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100308 u8 in[10]; /* Register value */
309 u8 in_max[10]; /* Register value */
310 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200311 u8 fan[5];
312 u8 fan_min[5];
313 u8 fan_div[5];
314 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200315 u8 temp_type[3];
Guenter Roeckbce26c52011-02-04 12:54:14 -0800316 s16 temp[3];
317 s16 temp_max[3];
318 s16 temp_max_hyst[3];
Jean Delvarea4589db2006-03-23 16:30:29 +0100319 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200320
321 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
322 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800323 2->thermal cruise mode (also called SmartFan I)
324 3->fan speed cruise mode
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800325 4->variable thermal cruise (also called
326 SmartFan III) */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200327 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200328 u8 pwm[4];
329 u8 target_temp[4];
330 u8 tolerance[4];
331
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800332 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
333 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
334 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
335 u8 fan_max_output[4]; /* maximum fan speed */
336 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200337
338 u8 vid;
339 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200340
341 u8 temp3_disable;
342 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200343};
344
David Hubbard1ea6dd32007-06-24 11:16:15 +0200345struct w83627ehf_sio_data {
346 int sioreg;
347 enum kinds kind;
348};
349
Jean Delvare09568952007-08-11 13:57:05 +0200350/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200351static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200352{
Jean Delvare09568952007-08-11 13:57:05 +0200353 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200354 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
355 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200356 }
357}
358
Jean Delvare09568952007-08-11 13:57:05 +0200359/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200360static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200361{
362 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200363 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
364 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200365 }
366}
367
David Hubbard1ea6dd32007-06-24 11:16:15 +0200368static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200369{
Jean Delvare08e7e272005-04-25 22:43:25 +0200370 int res, word_sized = is_word_sized(reg);
371
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100372 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200373
David Hubbard1ea6dd32007-06-24 11:16:15 +0200374 w83627ehf_set_bank(data, reg);
375 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
376 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200377 if (word_sized) {
378 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200379 data->addr + ADDR_REG_OFFSET);
380 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200381 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200382 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200383
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100384 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200385
386 return res;
387}
388
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800389static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
390 u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200391{
Jean Delvare08e7e272005-04-25 22:43:25 +0200392 int word_sized = is_word_sized(reg);
393
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100394 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200395
David Hubbard1ea6dd32007-06-24 11:16:15 +0200396 w83627ehf_set_bank(data, reg);
397 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200398 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200399 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200400 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200401 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200402 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200403 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
404 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200405
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100406 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200407 return 0;
408}
409
410/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200411static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200412{
Jean Delvare08e7e272005-04-25 22:43:25 +0200413 u8 reg;
414
415 switch (nr) {
416 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200417 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200418 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200419 /* fan5 input control bit is write only, compute the value */
420 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200421 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
422 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200423 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200424 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200425 break;
426 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200427 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200428 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200429 /* fan5 input control bit is write only, compute the value */
430 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200431 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
432 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200433 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200434 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200435 break;
436 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200437 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200438 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200439 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
440 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200441 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200442 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200443 break;
444 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200445 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200446 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200447 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
448 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200449 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200450 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200451 break;
452 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200453 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700454 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200455 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200456 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200457 break;
458 }
459}
460
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400461static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
462{
463 int i;
464
465 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
466 data->fan_div[0] = (i >> 4) & 0x03;
467 data->fan_div[1] = (i >> 6) & 0x03;
468 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
469 data->fan_div[2] = (i >> 6) & 0x03;
470 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
471 data->fan_div[0] |= (i >> 3) & 0x04;
472 data->fan_div[1] |= (i >> 4) & 0x04;
473 data->fan_div[2] |= (i >> 5) & 0x04;
474 if (data->has_fan & ((1 << 3) | (1 << 4))) {
475 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
476 data->fan_div[3] = i & 0x03;
477 data->fan_div[4] = ((i >> 2) & 0x03)
478 | ((i >> 5) & 0x04);
479 }
480 if (data->has_fan & (1 << 3)) {
481 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
482 data->fan_div[3] |= (i >> 5) & 0x04;
483 }
484}
485
Jean Delvare08e7e272005-04-25 22:43:25 +0200486static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
487{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200488 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200489 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200490 int i;
491
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100492 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200493
Jean Delvare6b3e4642007-06-24 11:19:01 +0200494 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200495 || !data->valid) {
496 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400497 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200498
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100499 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200500 for (i = 0; i < data->in_num; i++) {
501 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100502 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200503 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100504 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200505 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100506 W83627EHF_REG_IN_MAX(i));
507 }
508
Jean Delvare08e7e272005-04-25 22:43:25 +0200509 /* Measured fan speeds and limits */
510 for (i = 0; i < 5; i++) {
511 if (!(data->has_fan & (1 << i)))
512 continue;
513
David Hubbard1ea6dd32007-06-24 11:16:15 +0200514 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200515 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200516 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200517 W83627EHF_REG_FAN_MIN[i]);
518
519 /* If we failed to measure the fan speed and clock
520 divider can be increased, let's try that for next
521 time */
522 if (data->fan[i] == 0xff
523 && data->fan_div[i] < 0x07) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800524 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200525 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700526 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200527 div_from_reg(data->fan_div[i] + 1));
528 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200529 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200530 /* Preserve min limit if possible */
531 if (data->fan_min[i] >= 2
532 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200533 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200534 W83627EHF_REG_FAN_MIN[i],
535 (data->fan_min[i] /= 2));
536 }
537 }
538
Guenter Roeckda2e0252010-08-14 21:08:55 +0200539 for (i = 0; i < data->pwm_num; i++) {
540 if (!(data->has_fan & (1 << i)))
541 continue;
542
Jean Delvare77fa49d2009-01-07 16:37:35 +0100543 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200544 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200545 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200546 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200547 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200548 W83627EHF_REG_TOLERANCE[i]);
549 }
550 data->pwm_mode[i] =
551 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
552 ? 0 : 1;
553 data->pwm_enable[i] =
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800554 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
555 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200556 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200557 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800558 data->fan_start_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800559 W83627EHF_REG_FAN_START_OUTPUT[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800560 data->fan_stop_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800561 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200562 data->fan_stop_time[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800563 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200564
565 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
566 data->fan_max_output[i] =
567 w83627ehf_read_value(data,
568 data->REG_FAN_MAX_OUTPUT[i]);
569
570 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
571 data->fan_step_output[i] =
572 w83627ehf_read_value(data,
573 data->REG_FAN_STEP_OUTPUT[i]);
574
Rudolf Marek08c79952006-07-05 18:14:31 +0200575 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200576 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200577 W83627EHF_REG_TARGET[i]) &
578 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
579 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
580 & 0x0f;
581 }
582
Jean Delvare08e7e272005-04-25 22:43:25 +0200583 /* Measured temperatures and limits */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800584 for (i = 0; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200585 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200586 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200587 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200588 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200589 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200590 W83627EHF_REG_TEMP_HYST[i]);
591 }
592
David Hubbard1ea6dd32007-06-24 11:16:15 +0200593 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100594 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200595 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100596 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200597 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100598 W83627EHF_REG_ALARM3) << 16);
599
Jean Delvare08e7e272005-04-25 22:43:25 +0200600 data->last_updated = jiffies;
601 data->valid = 1;
602 }
603
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100604 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200605 return data;
606}
607
608/*
609 * Sysfs callback functions
610 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100611#define show_in_reg(reg) \
612static ssize_t \
613show_##reg(struct device *dev, struct device_attribute *attr, \
614 char *buf) \
615{ \
616 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800617 struct sensor_device_attribute *sensor_attr = \
618 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100619 int nr = sensor_attr->index; \
620 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
621}
622show_in_reg(in)
623show_in_reg(in_min)
624show_in_reg(in_max)
625
626#define store_in_reg(REG, reg) \
627static ssize_t \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800628store_in_##reg(struct device *dev, struct device_attribute *attr, \
629 const char *buf, size_t count) \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100630{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200631 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800632 struct sensor_device_attribute *sensor_attr = \
633 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100634 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800635 unsigned long val; \
636 int err; \
637 err = strict_strtoul(buf, 10, &val); \
638 if (err < 0) \
639 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100640 mutex_lock(&data->update_lock); \
641 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200642 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100643 data->in_##reg[nr]); \
644 mutex_unlock(&data->update_lock); \
645 return count; \
646}
647
648store_in_reg(MIN, min)
649store_in_reg(MAX, max)
650
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800651static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
652 char *buf)
Jean Delvarea4589db2006-03-23 16:30:29 +0100653{
654 struct w83627ehf_data *data = w83627ehf_update_device(dev);
655 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
656 int nr = sensor_attr->index;
657 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
658}
659
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100660static struct sensor_device_attribute sda_in_input[] = {
661 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
662 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
663 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
664 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
665 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
666 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
667 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
668 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
669 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
670 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
671};
672
Jean Delvarea4589db2006-03-23 16:30:29 +0100673static struct sensor_device_attribute sda_in_alarm[] = {
674 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
675 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
676 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
677 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
678 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
679 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
680 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
681 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
682 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
683 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
684};
685
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100686static struct sensor_device_attribute sda_in_min[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800687 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
688 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
689 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
690 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
691 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
692 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
693 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
694 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
695 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
696 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100697};
698
699static struct sensor_device_attribute sda_in_max[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800700 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
701 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
702 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
703 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
704 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
705 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
706 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
707 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
708 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
709 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100710};
711
Jean Delvare08e7e272005-04-25 22:43:25 +0200712#define show_fan_reg(reg) \
713static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100714show_##reg(struct device *dev, struct device_attribute *attr, \
715 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200716{ \
717 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800718 struct sensor_device_attribute *sensor_attr = \
719 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100720 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200721 return sprintf(buf, "%d\n", \
722 fan_from_reg(data->reg[nr], \
723 div_from_reg(data->fan_div[nr]))); \
724}
725show_fan_reg(fan);
726show_fan_reg(fan_min);
727
728static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100729show_fan_div(struct device *dev, struct device_attribute *attr,
730 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200731{
732 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100733 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
734 int nr = sensor_attr->index;
735 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200736}
737
738static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100739store_fan_min(struct device *dev, struct device_attribute *attr,
740 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200741{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200742 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100743 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
744 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800745 unsigned long val;
746 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +0200747 unsigned int reg;
748 u8 new_div;
749
Guenter Roeckbce26c52011-02-04 12:54:14 -0800750 err = strict_strtoul(buf, 10, &val);
751 if (err < 0)
752 return err;
753
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100754 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200755 if (!val) {
756 /* No min limit, alarm disabled */
757 data->fan_min[nr] = 255;
758 new_div = data->fan_div[nr]; /* No change */
759 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
760 } else if ((reg = 1350000U / val) >= 128 * 255) {
761 /* Speed below this value cannot possibly be represented,
762 even with the highest divider (128) */
763 data->fan_min[nr] = 254;
764 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800765 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Jean Delvare08e7e272005-04-25 22:43:25 +0200766 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
767 } else if (!reg) {
768 /* Speed above this value cannot possibly be represented,
769 even with the lowest divider (1) */
770 data->fan_min[nr] = 1;
771 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800772 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200773 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200774 } else {
775 /* Automatically pick the best divider, i.e. the one such
776 that the min limit will correspond to a register value
777 in the 96..192 range */
778 new_div = 0;
779 while (reg > 192 && new_div < 7) {
780 reg >>= 1;
781 new_div++;
782 }
783 data->fan_min[nr] = reg;
784 }
785
786 /* Write both the fan clock divider (if it changed) and the new
787 fan min (unconditionally) */
788 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200789 /* Preserve the fan speed reading */
790 if (data->fan[nr] != 0xff) {
791 if (new_div > data->fan_div[nr])
792 data->fan[nr] >>= new_div - data->fan_div[nr];
793 else if (data->fan[nr] & 0x80)
794 data->fan[nr] = 0xff;
795 else
796 data->fan[nr] <<= data->fan_div[nr] - new_div;
797 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200798
799 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
800 nr + 1, div_from_reg(data->fan_div[nr]),
801 div_from_reg(new_div));
802 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200803 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200804 /* Give the chip time to sample a new speed value */
805 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200806 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200807 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200808 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100809 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200810
811 return count;
812}
813
Yuan Mu412fec82006-02-05 23:24:16 +0100814static struct sensor_device_attribute sda_fan_input[] = {
815 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
816 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
817 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
818 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
819 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
820};
Jean Delvare08e7e272005-04-25 22:43:25 +0200821
Jean Delvarea4589db2006-03-23 16:30:29 +0100822static struct sensor_device_attribute sda_fan_alarm[] = {
823 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
824 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
825 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
826 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
827 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
828};
829
Yuan Mu412fec82006-02-05 23:24:16 +0100830static struct sensor_device_attribute sda_fan_min[] = {
831 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
832 store_fan_min, 0),
833 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
834 store_fan_min, 1),
835 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
836 store_fan_min, 2),
837 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
838 store_fan_min, 3),
839 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
840 store_fan_min, 4),
841};
Jean Delvare08e7e272005-04-25 22:43:25 +0200842
Yuan Mu412fec82006-02-05 23:24:16 +0100843static struct sensor_device_attribute sda_fan_div[] = {
844 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
845 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
846 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
847 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
848 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
849};
Jean Delvare08e7e272005-04-25 22:43:25 +0200850
Guenter Roeckbce26c52011-02-04 12:54:14 -0800851#define show_temp_reg(REG, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200852static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100853show_##reg(struct device *dev, struct device_attribute *attr, \
854 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200855{ \
856 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800857 struct sensor_device_attribute *sensor_attr = \
858 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100859 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200860 return sprintf(buf, "%d\n", \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800861 temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200862}
Guenter Roeckbce26c52011-02-04 12:54:14 -0800863show_temp_reg(TEMP, temp);
864show_temp_reg(TEMP_OVER, temp_max);
865show_temp_reg(TEMP_HYST, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +0200866
867#define store_temp_reg(REG, reg) \
868static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100869store_##reg(struct device *dev, struct device_attribute *attr, \
870 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200871{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200872 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800873 struct sensor_device_attribute *sensor_attr = \
874 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100875 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800876 int err; \
877 long val; \
878 err = strict_strtol(buf, 10, &val); \
879 if (err < 0) \
880 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100881 mutex_lock(&data->update_lock); \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800882 data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200883 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200884 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100885 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200886 return count; \
887}
888store_temp_reg(OVER, temp_max);
889store_temp_reg(HYST, temp_max_hyst);
890
Jean Delvareda667362007-06-24 11:21:02 +0200891static ssize_t
892show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
893{
894 struct w83627ehf_data *data = w83627ehf_update_device(dev);
895 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
896 int nr = sensor_attr->index;
897 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
898}
899
Gong Juna157d062009-03-30 21:46:43 +0200900static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800901 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
902 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
903 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Gong Juna157d062009-03-30 21:46:43 +0200904};
905
906static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800907 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100908 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800909 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100910 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800911 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
912 store_temp_max, 2),
Gong Juna157d062009-03-30 21:46:43 +0200913};
914
915static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800916 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100917 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800918 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100919 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800920 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
921 store_temp_max_hyst, 2),
Gong Juna157d062009-03-30 21:46:43 +0200922};
923
924static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100925 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
926 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
927 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200928};
929
930static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200931 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
932 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
933 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100934};
Jean Delvare08e7e272005-04-25 22:43:25 +0200935
Rudolf Marek08c79952006-07-05 18:14:31 +0200936#define show_pwm_reg(reg) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800937static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
938 char *buf) \
Rudolf Marek08c79952006-07-05 18:14:31 +0200939{ \
940 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800941 struct sensor_device_attribute *sensor_attr = \
942 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200943 int nr = sensor_attr->index; \
944 return sprintf(buf, "%d\n", data->reg[nr]); \
945}
946
947show_pwm_reg(pwm_mode)
948show_pwm_reg(pwm_enable)
949show_pwm_reg(pwm)
950
951static ssize_t
952store_pwm_mode(struct device *dev, struct device_attribute *attr,
953 const char *buf, size_t count)
954{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200955 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200956 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
957 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800958 unsigned long val;
959 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +0200960 u16 reg;
961
Guenter Roeckbce26c52011-02-04 12:54:14 -0800962 err = strict_strtoul(buf, 10, &val);
963 if (err < 0)
964 return err;
965
Rudolf Marek08c79952006-07-05 18:14:31 +0200966 if (val > 1)
967 return -EINVAL;
968 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200969 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200970 data->pwm_mode[nr] = val;
971 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
972 if (!val)
973 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200974 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200975 mutex_unlock(&data->update_lock);
976 return count;
977}
978
979static ssize_t
980store_pwm(struct device *dev, struct device_attribute *attr,
981 const char *buf, size_t count)
982{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200983 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200984 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
985 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800986 unsigned long val;
987 int err;
988
989 err = strict_strtoul(buf, 10, &val);
990 if (err < 0)
991 return err;
992
993 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +0200994
995 mutex_lock(&data->update_lock);
996 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200997 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200998 mutex_unlock(&data->update_lock);
999 return count;
1000}
1001
1002static ssize_t
1003store_pwm_enable(struct device *dev, struct device_attribute *attr,
1004 const char *buf, size_t count)
1005{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001006 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001007 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1008 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001009 unsigned long val;
1010 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001011 u16 reg;
1012
Guenter Roeckbce26c52011-02-04 12:54:14 -08001013 err = strict_strtoul(buf, 10, &val);
1014 if (err < 0)
1015 return err;
1016
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001017 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001018 return -EINVAL;
1019 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001020 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001021 data->pwm_enable[nr] = val;
1022 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1023 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001024 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001025 mutex_unlock(&data->update_lock);
1026 return count;
1027}
1028
1029
1030#define show_tol_temp(reg) \
1031static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1032 char *buf) \
1033{ \
1034 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001035 struct sensor_device_attribute *sensor_attr = \
1036 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001037 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001038 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001039}
1040
1041show_tol_temp(tolerance)
1042show_tol_temp(target_temp)
1043
1044static ssize_t
1045store_target_temp(struct device *dev, struct device_attribute *attr,
1046 const char *buf, size_t count)
1047{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001048 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001049 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1050 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001051 long val;
1052 int err;
1053
1054 err = strict_strtol(buf, 10, &val);
1055 if (err < 0)
1056 return err;
1057
1058 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001059
1060 mutex_lock(&data->update_lock);
1061 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001062 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001063 mutex_unlock(&data->update_lock);
1064 return count;
1065}
1066
1067static ssize_t
1068store_tolerance(struct device *dev, struct device_attribute *attr,
1069 const char *buf, size_t count)
1070{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001071 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001072 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1073 int nr = sensor_attr->index;
1074 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001075 long val;
1076 int err;
1077
1078 err = strict_strtol(buf, 10, &val);
1079 if (err < 0)
1080 return err;
1081
Rudolf Marek08c79952006-07-05 18:14:31 +02001082 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001083 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001084
1085 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001086 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001087 data->tolerance[nr] = val;
1088 if (nr == 1)
1089 reg = (reg & 0x0f) | (val << 4);
1090 else
1091 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001092 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001093 mutex_unlock(&data->update_lock);
1094 return count;
1095}
1096
1097static struct sensor_device_attribute sda_pwm[] = {
1098 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1099 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1100 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1101 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1102};
1103
1104static struct sensor_device_attribute sda_pwm_mode[] = {
1105 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1106 store_pwm_mode, 0),
1107 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1108 store_pwm_mode, 1),
1109 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1110 store_pwm_mode, 2),
1111 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1112 store_pwm_mode, 3),
1113};
1114
1115static struct sensor_device_attribute sda_pwm_enable[] = {
1116 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1117 store_pwm_enable, 0),
1118 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1119 store_pwm_enable, 1),
1120 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1121 store_pwm_enable, 2),
1122 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1123 store_pwm_enable, 3),
1124};
1125
1126static struct sensor_device_attribute sda_target_temp[] = {
1127 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1128 store_target_temp, 0),
1129 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1130 store_target_temp, 1),
1131 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1132 store_target_temp, 2),
1133 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1134 store_target_temp, 3),
1135};
1136
1137static struct sensor_device_attribute sda_tolerance[] = {
1138 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1139 store_tolerance, 0),
1140 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1141 store_tolerance, 1),
1142 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1143 store_tolerance, 2),
1144 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1145 store_tolerance, 3),
1146};
1147
Rudolf Marek08c79952006-07-05 18:14:31 +02001148/* Smart Fan registers */
1149
1150#define fan_functions(reg, REG) \
1151static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1152 char *buf) \
1153{ \
1154 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001155 struct sensor_device_attribute *sensor_attr = \
1156 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001157 int nr = sensor_attr->index; \
1158 return sprintf(buf, "%d\n", data->reg[nr]); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001159} \
Rudolf Marek08c79952006-07-05 18:14:31 +02001160static ssize_t \
1161store_##reg(struct device *dev, struct device_attribute *attr, \
1162 const char *buf, size_t count) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001163{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001164 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001165 struct sensor_device_attribute *sensor_attr = \
1166 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001167 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001168 unsigned long val; \
1169 int err; \
1170 err = strict_strtoul(buf, 10, &val); \
1171 if (err < 0) \
1172 return err; \
1173 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001174 mutex_lock(&data->update_lock); \
1175 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001176 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001177 mutex_unlock(&data->update_lock); \
1178 return count; \
1179}
1180
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001181fan_functions(fan_start_output, FAN_START_OUTPUT)
1182fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1183fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1184fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001185
1186#define fan_time_functions(reg, REG) \
1187static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1188 char *buf) \
1189{ \
1190 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001191 struct sensor_device_attribute *sensor_attr = \
1192 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001193 int nr = sensor_attr->index; \
1194 return sprintf(buf, "%d\n", \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001195 step_time_from_reg(data->reg[nr], \
1196 data->pwm_mode[nr])); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001197} \
1198\
1199static ssize_t \
1200store_##reg(struct device *dev, struct device_attribute *attr, \
1201 const char *buf, size_t count) \
1202{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001203 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001204 struct sensor_device_attribute *sensor_attr = \
1205 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001206 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001207 unsigned long val; \
1208 int err; \
1209 err = strict_strtoul(buf, 10, &val); \
1210 if (err < 0) \
1211 return err; \
1212 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001213 mutex_lock(&data->update_lock); \
1214 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001215 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001216 mutex_unlock(&data->update_lock); \
1217 return count; \
1218} \
1219
1220fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1221
David Hubbard1ea6dd32007-06-24 11:16:15 +02001222static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1223 char *buf)
1224{
1225 struct w83627ehf_data *data = dev_get_drvdata(dev);
1226
1227 return sprintf(buf, "%s\n", data->name);
1228}
1229static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001230
1231static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1232 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1233 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001234 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1235 store_fan_start_output, 3),
1236 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1237 store_fan_stop_output, 3),
1238 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1239 store_fan_max_output, 3),
1240 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1241 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001242};
1243
1244static struct sensor_device_attribute sda_sf3_arrays[] = {
1245 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1246 store_fan_stop_time, 0),
1247 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1248 store_fan_stop_time, 1),
1249 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1250 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001251 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1252 store_fan_start_output, 0),
1253 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1254 store_fan_start_output, 1),
1255 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1256 store_fan_start_output, 2),
1257 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1258 store_fan_stop_output, 0),
1259 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1260 store_fan_stop_output, 1),
1261 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1262 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001263};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001264
Guenter Roeckda2e0252010-08-14 21:08:55 +02001265
1266/*
1267 * pwm1 and pwm3 don't support max and step settings on all chips.
1268 * Need to check support while generating/removing attribute files.
1269 */
1270static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1271 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1272 store_fan_max_output, 0),
1273 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1274 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001275 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1276 store_fan_max_output, 1),
1277 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1278 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001279 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1280 store_fan_max_output, 2),
1281 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1282 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001283};
1284
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001285static ssize_t
1286show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1287{
1288 struct w83627ehf_data *data = dev_get_drvdata(dev);
1289 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1290}
1291static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1292
Jean Delvare08e7e272005-04-25 22:43:25 +02001293/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001294 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001295 */
1296
David Hubbardc18beb52006-09-24 21:04:38 +02001297static void w83627ehf_device_remove_files(struct device *dev)
1298{
1299 /* some entries in the following arrays may not have been used in
1300 * device_create_file(), but device_remove_file() will ignore them */
1301 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001302 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001303
1304 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1305 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001306 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1307 struct sensor_device_attribute *attr =
1308 &sda_sf3_max_step_arrays[i];
1309 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1310 device_remove_file(dev, &attr->dev_attr);
1311 }
David Hubbardc18beb52006-09-24 21:04:38 +02001312 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1313 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001314 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001315 if ((i == 6) && data->in6_skip)
1316 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001317 device_remove_file(dev, &sda_in_input[i].dev_attr);
1318 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1319 device_remove_file(dev, &sda_in_min[i].dev_attr);
1320 device_remove_file(dev, &sda_in_max[i].dev_attr);
1321 }
1322 for (i = 0; i < 5; i++) {
1323 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1324 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1325 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1326 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1327 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001328 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001329 device_remove_file(dev, &sda_pwm[i].dev_attr);
1330 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1331 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1332 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1333 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1334 }
Gong Juna157d062009-03-30 21:46:43 +02001335 for (i = 0; i < 3; i++) {
1336 if ((i == 2) && data->temp3_disable)
1337 continue;
1338 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1339 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1340 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1341 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1342 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1343 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001344
1345 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001346 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001347}
1348
David Hubbard1ea6dd32007-06-24 11:16:15 +02001349/* Get the monitoring functions started */
1350static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001351{
1352 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001353 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001354
1355 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001356 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001357 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001358 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001359 tmp | 0x01);
1360
1361 /* Enable temp2 and temp3 if needed */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001362 for (i = 1; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001363 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001364 W83627EHF_REG_TEMP_CONFIG[i]);
Guenter Roeckbce26c52011-02-04 12:54:14 -08001365 if ((i == 2) && data->temp3_disable)
Gong Juna157d062009-03-30 21:46:43 +02001366 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001367 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001368 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001369 W83627EHF_REG_TEMP_CONFIG[i],
1370 tmp & 0xfe);
1371 }
Jean Delvared3130f02007-06-24 11:20:13 +02001372
1373 /* Enable VBAT monitoring if needed */
1374 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1375 if (!(tmp & 0x01))
1376 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001377
1378 /* Get thermal sensor types */
1379 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1380 for (i = 0; i < 3; i++) {
1381 if ((tmp & (0x02 << i)))
1382 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1383 else
1384 data->temp_type[i] = 4; /* thermistor */
1385 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001386}
1387
David Hubbard1ea6dd32007-06-24 11:16:15 +02001388static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001389{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001390 struct device *dev = &pdev->dev;
1391 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001392 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001393 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001394 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001395 int i, err = 0;
1396
David Hubbard1ea6dd32007-06-24 11:16:15 +02001397 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1398 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001399 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001400 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1401 (unsigned long)res->start,
1402 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001403 goto exit;
1404 }
1405
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001406 data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1407 if (!data) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001408 err = -ENOMEM;
1409 goto exit_release;
1410 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001411
David Hubbard1ea6dd32007-06-24 11:16:15 +02001412 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001413 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001414 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001415 data->name = w83627ehf_device_names[sio_data->kind];
1416 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001417
Gong Jun237c8d2f2009-03-30 21:46:42 +02001418 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1419 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1420 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001421 data->pwm_num = (sio_data->kind == w83667hg
1422 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001423
Gong Juna157d062009-03-30 21:46:43 +02001424 /* Check temp3 configuration bit for 667HG */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001425 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Juna157d062009-03-30 21:46:43 +02001426 data->temp3_disable = w83627ehf_read_value(data,
Guenter Roeckbce26c52011-02-04 12:54:14 -08001427 W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
Gong Juna157d062009-03-30 21:46:43 +02001428 data->in6_skip = !data->temp3_disable;
1429 }
1430
Guenter Roeckda2e0252010-08-14 21:08:55 +02001431 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1432 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001433 if (sio_data->kind == w83667hg_b) {
1434 data->REG_FAN_MAX_OUTPUT =
1435 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1436 data->REG_FAN_STEP_OUTPUT =
1437 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1438 } else {
1439 data->REG_FAN_MAX_OUTPUT =
1440 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1441 data->REG_FAN_STEP_OUTPUT =
1442 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1443 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001444
Jean Delvare08e7e272005-04-25 22:43:25 +02001445 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001446 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001447
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001448 data->vrm = vid_which_vrm();
1449 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001450 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001451 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001452 /* W83667HG has different pins for VID input and output, so
1453 we can get the VID input values directly at logical device D
1454 0xe3. */
1455 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1456 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001457 err = device_create_file(dev, &dev_attr_cpu0_vid);
1458 if (err)
1459 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001460 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001461 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1462 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1463 /* Set VID input sensibility if needed. In theory the
1464 BIOS should have set it, but in practice it's not
1465 always the case. We only do it for the W83627EHF/EHG
1466 because the W83627DHG is more complex in this
1467 respect. */
1468 if (sio_data->kind == w83627ehf) {
1469 en_vrm10 = superio_inb(sio_data->sioreg,
1470 SIO_REG_EN_VRM10);
1471 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1472 dev_warn(dev, "Setting VID input "
1473 "voltage to TTL\n");
1474 superio_outb(sio_data->sioreg,
1475 SIO_REG_EN_VRM10,
1476 en_vrm10 & ~0x08);
1477 } else if (!(en_vrm10 & 0x08)
1478 && data->vrm == 100) {
1479 dev_warn(dev, "Setting VID input "
1480 "voltage to VRM10\n");
1481 superio_outb(sio_data->sioreg,
1482 SIO_REG_EN_VRM10,
1483 en_vrm10 | 0x08);
1484 }
1485 }
1486
1487 data->vid = superio_inb(sio_data->sioreg,
1488 SIO_REG_VID_DATA);
1489 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1490 data->vid &= 0x3f;
1491
1492 err = device_create_file(dev, &dev_attr_cpu0_vid);
1493 if (err)
1494 goto exit_release;
1495 } else {
1496 dev_info(dev, "VID pins in output mode, CPU VID not "
1497 "available\n");
1498 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001499 }
1500
Rudolf Marek08c79952006-07-05 18:14:31 +02001501 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001502 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001503 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1504 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1505 } else {
1506 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1507 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1508 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001509 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001510
Jean Delvare08e7e272005-04-25 22:43:25 +02001511 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001512 as fan on/off switches, but fan5 control is write only :/
1513 We assume that if the serial interface is disabled, designers
1514 connected fan5 as input unless they are emitting log 1, which
1515 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001516
Jean Delvare08e7e272005-04-25 22:43:25 +02001517 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001518 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001519 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001520 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001521 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001522 data->has_fan |= (1 << 4);
1523
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001524 /* Read fan clock dividers immediately */
1525 w83627ehf_update_fan_div(data);
1526
Jean Delvare08e7e272005-04-25 22:43:25 +02001527 /* Register sysfs hooks */
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001528 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
1529 err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
1530 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001531 goto exit_remove;
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001532 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001533
Guenter Roeckda2e0252010-08-14 21:08:55 +02001534 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1535 struct sensor_device_attribute *attr =
1536 &sda_sf3_max_step_arrays[i];
1537 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1538 err = device_create_file(dev, &attr->dev_attr);
1539 if (err)
1540 goto exit_remove;
1541 }
1542 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001543 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001544 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001545 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001546 err = device_create_file(dev,
1547 &sda_sf3_arrays_fan4[i].dev_attr);
1548 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001549 goto exit_remove;
1550 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001551
Gong Juna157d062009-03-30 21:46:43 +02001552 for (i = 0; i < data->in_num; i++) {
1553 if ((i == 6) && data->in6_skip)
1554 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001555 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1556 || (err = device_create_file(dev,
1557 &sda_in_alarm[i].dev_attr))
1558 || (err = device_create_file(dev,
1559 &sda_in_min[i].dev_attr))
1560 || (err = device_create_file(dev,
1561 &sda_in_max[i].dev_attr)))
1562 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001563 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001564
Yuan Mu412fec82006-02-05 23:24:16 +01001565 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001566 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001567 if ((err = device_create_file(dev,
1568 &sda_fan_input[i].dev_attr))
1569 || (err = device_create_file(dev,
1570 &sda_fan_alarm[i].dev_attr))
1571 || (err = device_create_file(dev,
1572 &sda_fan_div[i].dev_attr))
1573 || (err = device_create_file(dev,
1574 &sda_fan_min[i].dev_attr)))
1575 goto exit_remove;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001576 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001577 ((err = device_create_file(dev,
1578 &sda_pwm[i].dev_attr))
1579 || (err = device_create_file(dev,
1580 &sda_pwm_mode[i].dev_attr))
1581 || (err = device_create_file(dev,
1582 &sda_pwm_enable[i].dev_attr))
1583 || (err = device_create_file(dev,
1584 &sda_target_temp[i].dev_attr))
1585 || (err = device_create_file(dev,
1586 &sda_tolerance[i].dev_attr))))
1587 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001588 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001589 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001590
Gong Juna157d062009-03-30 21:46:43 +02001591 for (i = 0; i < 3; i++) {
1592 if ((i == 2) && data->temp3_disable)
1593 continue;
1594 if ((err = device_create_file(dev,
1595 &sda_temp_input[i].dev_attr))
1596 || (err = device_create_file(dev,
1597 &sda_temp_max[i].dev_attr))
1598 || (err = device_create_file(dev,
1599 &sda_temp_max_hyst[i].dev_attr))
1600 || (err = device_create_file(dev,
1601 &sda_temp_alarm[i].dev_attr))
1602 || (err = device_create_file(dev,
1603 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001604 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001605 }
David Hubbardc18beb52006-09-24 21:04:38 +02001606
David Hubbard1ea6dd32007-06-24 11:16:15 +02001607 err = device_create_file(dev, &dev_attr_name);
1608 if (err)
1609 goto exit_remove;
1610
Tony Jones1beeffe2007-08-20 13:46:20 -07001611 data->hwmon_dev = hwmon_device_register(dev);
1612 if (IS_ERR(data->hwmon_dev)) {
1613 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001614 goto exit_remove;
1615 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001616
1617 return 0;
1618
David Hubbardc18beb52006-09-24 21:04:38 +02001619exit_remove:
1620 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001621 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001622 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001623exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001624 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001625exit:
1626 return err;
1627}
1628
David Hubbard1ea6dd32007-06-24 11:16:15 +02001629static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001630{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001631 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001632
Tony Jones1beeffe2007-08-20 13:46:20 -07001633 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001634 w83627ehf_device_remove_files(&pdev->dev);
1635 release_region(data->addr, IOREGION_LENGTH);
1636 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001637 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001638
1639 return 0;
1640}
1641
David Hubbard1ea6dd32007-06-24 11:16:15 +02001642static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001643 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001644 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001645 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001646 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001647 .probe = w83627ehf_probe,
1648 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001649};
1650
David Hubbard1ea6dd32007-06-24 11:16:15 +02001651/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1652static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1653 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001654{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001655 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1656 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1657 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001658 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02001659 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001660 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001661
Jean Delvare08e7e272005-04-25 22:43:25 +02001662 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001663 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001664
David Hubbard1ea6dd32007-06-24 11:16:15 +02001665 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001666
Jean Delvare67b671b2007-12-06 23:13:42 +01001667 if (force_id)
1668 val = force_id;
1669 else
1670 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1671 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001672 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001673 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001674 sio_data->kind = w83627ehf;
1675 sio_name = sio_name_W83627EHF;
1676 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001677 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001678 sio_data->kind = w83627ehf;
1679 sio_name = sio_name_W83627EHG;
1680 break;
1681 case SIO_W83627DHG_ID:
1682 sio_data->kind = w83627dhg;
1683 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001684 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001685 case SIO_W83627DHG_P_ID:
1686 sio_data->kind = w83627dhg_p;
1687 sio_name = sio_name_W83627DHG_P;
1688 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001689 case SIO_W83667HG_ID:
1690 sio_data->kind = w83667hg;
1691 sio_name = sio_name_W83667HG;
1692 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001693 case SIO_W83667HG_B_ID:
1694 sio_data->kind = w83667hg_b;
1695 sio_name = sio_name_W83667HG_B;
1696 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001697 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001698 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001699 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001700 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001701 return -ENODEV;
1702 }
1703
David Hubbard1ea6dd32007-06-24 11:16:15 +02001704 /* We have a known chip, find the HWM I/O address */
1705 superio_select(sioaddr, W83627EHF_LD_HWM);
1706 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1707 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001708 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001709 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001710 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001711 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001712 return -ENODEV;
1713 }
1714
1715 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001716 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001717 if (!(val & 0x01)) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001718 pr_warn("Forcibly enabling Super-I/O. "
1719 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001720 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001721 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001722
David Hubbard1ea6dd32007-06-24 11:16:15 +02001723 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001724 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001725 sio_data->sioreg = sioaddr;
1726
Jean Delvare08e7e272005-04-25 22:43:25 +02001727 return 0;
1728}
1729
David Hubbard1ea6dd32007-06-24 11:16:15 +02001730/* when Super-I/O functions move to a separate file, the Super-I/O
1731 * bus will manage the lifetime of the device and this module will only keep
1732 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1733 * must keep track of the device */
1734static struct platform_device *pdev;
1735
Jean Delvare08e7e272005-04-25 22:43:25 +02001736static int __init sensors_w83627ehf_init(void)
1737{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001738 int err;
1739 unsigned short address;
1740 struct resource res;
1741 struct w83627ehf_sio_data sio_data;
1742
1743 /* initialize sio_data->kind and sio_data->sioreg.
1744 *
1745 * when Super-I/O functions move to a separate file, the Super-I/O
1746 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1747 * w83627ehf hardware monitor, and call probe() */
1748 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1749 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001750 return -ENODEV;
1751
David Hubbard1ea6dd32007-06-24 11:16:15 +02001752 err = platform_driver_register(&w83627ehf_driver);
1753 if (err)
1754 goto exit;
1755
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001756 pdev = platform_device_alloc(DRVNAME, address);
1757 if (!pdev) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001758 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001759 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001760 goto exit_unregister;
1761 }
1762
1763 err = platform_device_add_data(pdev, &sio_data,
1764 sizeof(struct w83627ehf_sio_data));
1765 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001766 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001767 goto exit_device_put;
1768 }
1769
1770 memset(&res, 0, sizeof(res));
1771 res.name = DRVNAME;
1772 res.start = address + IOREGION_OFFSET;
1773 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1774 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001775
1776 err = acpi_check_resource_conflict(&res);
1777 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001778 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001779
David Hubbard1ea6dd32007-06-24 11:16:15 +02001780 err = platform_device_add_resources(pdev, &res, 1);
1781 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001782 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001783 goto exit_device_put;
1784 }
1785
1786 /* platform_device_add calls probe() */
1787 err = platform_device_add(pdev);
1788 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001789 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001790 goto exit_device_put;
1791 }
1792
1793 return 0;
1794
1795exit_device_put:
1796 platform_device_put(pdev);
1797exit_unregister:
1798 platform_driver_unregister(&w83627ehf_driver);
1799exit:
1800 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001801}
1802
1803static void __exit sensors_w83627ehf_exit(void)
1804{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001805 platform_device_unregister(pdev);
1806 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001807}
1808
1809MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1810MODULE_DESCRIPTION("W83627EHF driver");
1811MODULE_LICENSE("GPL");
1812
1813module_init(sensors_w83627ehf_init);
1814module_exit(sensors_w83627ehf_exit);