blob: 5a627b9db3e83096cde5f2c82bf8f58cd4b3e860 [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 */
Guenter Roeck83cc8982011-02-06 08:10:15 -0800307 u8 bank; /* current register bank */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200308 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100309 u8 in[10]; /* Register value */
310 u8 in_max[10]; /* Register value */
311 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200312 u8 fan[5];
313 u8 fan_min[5];
314 u8 fan_div[5];
315 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200316 u8 temp_type[3];
Guenter Roeckbce26c52011-02-04 12:54:14 -0800317 s16 temp[3];
318 s16 temp_max[3];
319 s16 temp_max_hyst[3];
Jean Delvarea4589db2006-03-23 16:30:29 +0100320 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200321
322 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
323 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800324 2->thermal cruise mode (also called SmartFan I)
325 3->fan speed cruise mode
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800326 4->variable thermal cruise (also called
327 SmartFan III) */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200328 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200329 u8 pwm[4];
330 u8 target_temp[4];
331 u8 tolerance[4];
332
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800333 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
334 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
335 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
336 u8 fan_max_output[4]; /* maximum fan speed */
337 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200338
339 u8 vid;
340 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200341
342 u8 temp3_disable;
343 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200344};
345
David Hubbard1ea6dd32007-06-24 11:16:15 +0200346struct w83627ehf_sio_data {
347 int sioreg;
348 enum kinds kind;
349};
350
Guenter Roeck83cc8982011-02-06 08:10:15 -0800351/*
352 * On older chips, only registers 0x50-0x5f are banked.
353 * On more recent chips, all registers are banked.
354 * Assume that is the case and set the bank number for each access.
355 * Cache the bank number so it only needs to be set if it changes.
356 */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200357static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200358{
Guenter Roeck83cc8982011-02-06 08:10:15 -0800359 u8 bank = reg >> 8;
360 if (data->bank != bank) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200361 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
Guenter Roeck83cc8982011-02-06 08:10:15 -0800362 outb_p(bank, data->addr + DATA_REG_OFFSET);
363 data->bank = bank;
Jean Delvare08e7e272005-04-25 22:43:25 +0200364 }
365}
366
David Hubbard1ea6dd32007-06-24 11:16:15 +0200367static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200368{
Jean Delvare08e7e272005-04-25 22:43:25 +0200369 int res, 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);
375 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200376 if (word_sized) {
377 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200378 data->addr + ADDR_REG_OFFSET);
379 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200380 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200381
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100382 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200383 return res;
384}
385
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800386static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
387 u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200388{
Jean Delvare08e7e272005-04-25 22:43:25 +0200389 int word_sized = is_word_sized(reg);
390
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100391 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200392
David Hubbard1ea6dd32007-06-24 11:16:15 +0200393 w83627ehf_set_bank(data, reg);
394 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200395 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200396 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200397 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200398 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200399 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200400 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200401
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100402 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200403 return 0;
404}
405
406/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200407static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200408{
Jean Delvare08e7e272005-04-25 22:43:25 +0200409 u8 reg;
410
411 switch (nr) {
412 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200413 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200414 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200415 /* fan5 input control bit is write only, compute the value */
416 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200417 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
418 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200419 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200420 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200421 break;
422 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200423 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200424 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200425 /* fan5 input control bit is write only, compute the value */
426 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200427 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
428 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200429 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200430 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200431 break;
432 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200433 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200434 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200435 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
436 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200437 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200438 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200439 break;
440 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200441 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200442 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200443 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
444 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200445 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200446 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200447 break;
448 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200449 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700450 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200451 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200452 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200453 break;
454 }
455}
456
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400457static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
458{
459 int i;
460
461 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
462 data->fan_div[0] = (i >> 4) & 0x03;
463 data->fan_div[1] = (i >> 6) & 0x03;
464 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
465 data->fan_div[2] = (i >> 6) & 0x03;
466 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
467 data->fan_div[0] |= (i >> 3) & 0x04;
468 data->fan_div[1] |= (i >> 4) & 0x04;
469 data->fan_div[2] |= (i >> 5) & 0x04;
470 if (data->has_fan & ((1 << 3) | (1 << 4))) {
471 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
472 data->fan_div[3] = i & 0x03;
473 data->fan_div[4] = ((i >> 2) & 0x03)
474 | ((i >> 5) & 0x04);
475 }
476 if (data->has_fan & (1 << 3)) {
477 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
478 data->fan_div[3] |= (i >> 5) & 0x04;
479 }
480}
481
Jean Delvare08e7e272005-04-25 22:43:25 +0200482static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
483{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200484 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200485 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200486 int i;
487
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100488 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200489
Jean Delvare6b3e4642007-06-24 11:19:01 +0200490 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200491 || !data->valid) {
492 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400493 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200494
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100495 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200496 for (i = 0; i < data->in_num; i++) {
497 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100498 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200499 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100500 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200501 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100502 W83627EHF_REG_IN_MAX(i));
503 }
504
Jean Delvare08e7e272005-04-25 22:43:25 +0200505 /* Measured fan speeds and limits */
506 for (i = 0; i < 5; i++) {
507 if (!(data->has_fan & (1 << i)))
508 continue;
509
David Hubbard1ea6dd32007-06-24 11:16:15 +0200510 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200511 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200512 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200513 W83627EHF_REG_FAN_MIN[i]);
514
515 /* If we failed to measure the fan speed and clock
516 divider can be increased, let's try that for next
517 time */
518 if (data->fan[i] == 0xff
519 && data->fan_div[i] < 0x07) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800520 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200521 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700522 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200523 div_from_reg(data->fan_div[i] + 1));
524 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200525 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200526 /* Preserve min limit if possible */
527 if (data->fan_min[i] >= 2
528 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200529 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200530 W83627EHF_REG_FAN_MIN[i],
531 (data->fan_min[i] /= 2));
532 }
533 }
534
Guenter Roeckda2e0252010-08-14 21:08:55 +0200535 for (i = 0; i < data->pwm_num; i++) {
536 if (!(data->has_fan & (1 << i)))
537 continue;
538
Jean Delvare77fa49d2009-01-07 16:37:35 +0100539 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200540 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200541 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200542 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200543 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200544 W83627EHF_REG_TOLERANCE[i]);
545 }
546 data->pwm_mode[i] =
547 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
548 ? 0 : 1;
549 data->pwm_enable[i] =
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800550 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
551 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200552 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200553 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800554 data->fan_start_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800555 W83627EHF_REG_FAN_START_OUTPUT[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800556 data->fan_stop_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800557 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200558 data->fan_stop_time[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800559 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200560
561 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
562 data->fan_max_output[i] =
563 w83627ehf_read_value(data,
564 data->REG_FAN_MAX_OUTPUT[i]);
565
566 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
567 data->fan_step_output[i] =
568 w83627ehf_read_value(data,
569 data->REG_FAN_STEP_OUTPUT[i]);
570
Rudolf Marek08c79952006-07-05 18:14:31 +0200571 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200572 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200573 W83627EHF_REG_TARGET[i]) &
574 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
575 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
576 & 0x0f;
577 }
578
Jean Delvare08e7e272005-04-25 22:43:25 +0200579 /* Measured temperatures and limits */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800580 for (i = 0; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200581 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200582 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200583 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200584 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200585 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200586 W83627EHF_REG_TEMP_HYST[i]);
587 }
588
David Hubbard1ea6dd32007-06-24 11:16:15 +0200589 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100590 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200591 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100592 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200593 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100594 W83627EHF_REG_ALARM3) << 16);
595
Jean Delvare08e7e272005-04-25 22:43:25 +0200596 data->last_updated = jiffies;
597 data->valid = 1;
598 }
599
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100600 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200601 return data;
602}
603
604/*
605 * Sysfs callback functions
606 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100607#define show_in_reg(reg) \
608static ssize_t \
609show_##reg(struct device *dev, struct device_attribute *attr, \
610 char *buf) \
611{ \
612 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800613 struct sensor_device_attribute *sensor_attr = \
614 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100615 int nr = sensor_attr->index; \
616 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
617}
618show_in_reg(in)
619show_in_reg(in_min)
620show_in_reg(in_max)
621
622#define store_in_reg(REG, reg) \
623static ssize_t \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800624store_in_##reg(struct device *dev, struct device_attribute *attr, \
625 const char *buf, size_t count) \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100626{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200627 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800628 struct sensor_device_attribute *sensor_attr = \
629 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100630 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800631 unsigned long val; \
632 int err; \
633 err = strict_strtoul(buf, 10, &val); \
634 if (err < 0) \
635 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100636 mutex_lock(&data->update_lock); \
637 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200638 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100639 data->in_##reg[nr]); \
640 mutex_unlock(&data->update_lock); \
641 return count; \
642}
643
644store_in_reg(MIN, min)
645store_in_reg(MAX, max)
646
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800647static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
648 char *buf)
Jean Delvarea4589db2006-03-23 16:30:29 +0100649{
650 struct w83627ehf_data *data = w83627ehf_update_device(dev);
651 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
652 int nr = sensor_attr->index;
653 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
654}
655
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100656static struct sensor_device_attribute sda_in_input[] = {
657 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
658 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
659 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
660 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
661 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
662 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
663 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
664 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
665 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
666 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
667};
668
Jean Delvarea4589db2006-03-23 16:30:29 +0100669static struct sensor_device_attribute sda_in_alarm[] = {
670 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
671 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
672 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
673 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
674 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
675 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
676 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
677 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
678 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
679 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
680};
681
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100682static struct sensor_device_attribute sda_in_min[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800683 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
684 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
685 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
686 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
687 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
688 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
689 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
690 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
691 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
692 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100693};
694
695static struct sensor_device_attribute sda_in_max[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800696 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
697 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
698 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
699 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
700 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
701 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
702 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
703 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
704 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
705 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100706};
707
Jean Delvare08e7e272005-04-25 22:43:25 +0200708#define show_fan_reg(reg) \
709static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100710show_##reg(struct device *dev, struct device_attribute *attr, \
711 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200712{ \
713 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800714 struct sensor_device_attribute *sensor_attr = \
715 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100716 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200717 return sprintf(buf, "%d\n", \
718 fan_from_reg(data->reg[nr], \
719 div_from_reg(data->fan_div[nr]))); \
720}
721show_fan_reg(fan);
722show_fan_reg(fan_min);
723
724static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100725show_fan_div(struct device *dev, struct device_attribute *attr,
726 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200727{
728 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100729 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
730 int nr = sensor_attr->index;
731 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200732}
733
734static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100735store_fan_min(struct device *dev, struct device_attribute *attr,
736 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200737{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200738 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100739 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
740 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800741 unsigned long val;
742 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +0200743 unsigned int reg;
744 u8 new_div;
745
Guenter Roeckbce26c52011-02-04 12:54:14 -0800746 err = strict_strtoul(buf, 10, &val);
747 if (err < 0)
748 return err;
749
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100750 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200751 if (!val) {
752 /* No min limit, alarm disabled */
753 data->fan_min[nr] = 255;
754 new_div = data->fan_div[nr]; /* No change */
755 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
756 } else if ((reg = 1350000U / val) >= 128 * 255) {
757 /* Speed below this value cannot possibly be represented,
758 even with the highest divider (128) */
759 data->fan_min[nr] = 254;
760 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800761 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Jean Delvare08e7e272005-04-25 22:43:25 +0200762 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
763 } else if (!reg) {
764 /* Speed above this value cannot possibly be represented,
765 even with the lowest divider (1) */
766 data->fan_min[nr] = 1;
767 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800768 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200769 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200770 } else {
771 /* Automatically pick the best divider, i.e. the one such
772 that the min limit will correspond to a register value
773 in the 96..192 range */
774 new_div = 0;
775 while (reg > 192 && new_div < 7) {
776 reg >>= 1;
777 new_div++;
778 }
779 data->fan_min[nr] = reg;
780 }
781
782 /* Write both the fan clock divider (if it changed) and the new
783 fan min (unconditionally) */
784 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200785 /* Preserve the fan speed reading */
786 if (data->fan[nr] != 0xff) {
787 if (new_div > data->fan_div[nr])
788 data->fan[nr] >>= new_div - data->fan_div[nr];
789 else if (data->fan[nr] & 0x80)
790 data->fan[nr] = 0xff;
791 else
792 data->fan[nr] <<= data->fan_div[nr] - new_div;
793 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200794
795 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
796 nr + 1, div_from_reg(data->fan_div[nr]),
797 div_from_reg(new_div));
798 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200799 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200800 /* Give the chip time to sample a new speed value */
801 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200802 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200803 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200804 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100805 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200806
807 return count;
808}
809
Yuan Mu412fec82006-02-05 23:24:16 +0100810static struct sensor_device_attribute sda_fan_input[] = {
811 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
812 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
813 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
814 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
815 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
816};
Jean Delvare08e7e272005-04-25 22:43:25 +0200817
Jean Delvarea4589db2006-03-23 16:30:29 +0100818static struct sensor_device_attribute sda_fan_alarm[] = {
819 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
820 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
821 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
822 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
823 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
824};
825
Yuan Mu412fec82006-02-05 23:24:16 +0100826static struct sensor_device_attribute sda_fan_min[] = {
827 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
828 store_fan_min, 0),
829 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
830 store_fan_min, 1),
831 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
832 store_fan_min, 2),
833 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
834 store_fan_min, 3),
835 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
836 store_fan_min, 4),
837};
Jean Delvare08e7e272005-04-25 22:43:25 +0200838
Yuan Mu412fec82006-02-05 23:24:16 +0100839static struct sensor_device_attribute sda_fan_div[] = {
840 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
841 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
842 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
843 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
844 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
845};
Jean Delvare08e7e272005-04-25 22:43:25 +0200846
Guenter Roeckbce26c52011-02-04 12:54:14 -0800847#define show_temp_reg(REG, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200848static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100849show_##reg(struct device *dev, struct device_attribute *attr, \
850 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200851{ \
852 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800853 struct sensor_device_attribute *sensor_attr = \
854 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100855 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200856 return sprintf(buf, "%d\n", \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800857 temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200858}
Guenter Roeckbce26c52011-02-04 12:54:14 -0800859show_temp_reg(TEMP, temp);
860show_temp_reg(TEMP_OVER, temp_max);
861show_temp_reg(TEMP_HYST, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +0200862
863#define store_temp_reg(REG, reg) \
864static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100865store_##reg(struct device *dev, struct device_attribute *attr, \
866 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200867{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200868 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800869 struct sensor_device_attribute *sensor_attr = \
870 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100871 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800872 int err; \
873 long val; \
874 err = strict_strtol(buf, 10, &val); \
875 if (err < 0) \
876 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100877 mutex_lock(&data->update_lock); \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800878 data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200879 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200880 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100881 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200882 return count; \
883}
884store_temp_reg(OVER, temp_max);
885store_temp_reg(HYST, temp_max_hyst);
886
Jean Delvareda667362007-06-24 11:21:02 +0200887static ssize_t
888show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
889{
890 struct w83627ehf_data *data = w83627ehf_update_device(dev);
891 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
892 int nr = sensor_attr->index;
893 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
894}
895
Gong Juna157d062009-03-30 21:46:43 +0200896static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800897 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
898 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
899 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Gong Juna157d062009-03-30 21:46:43 +0200900};
901
902static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800903 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100904 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800905 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100906 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800907 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
908 store_temp_max, 2),
Gong Juna157d062009-03-30 21:46:43 +0200909};
910
911static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800912 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100913 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800914 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100915 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800916 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
917 store_temp_max_hyst, 2),
Gong Juna157d062009-03-30 21:46:43 +0200918};
919
920static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100921 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
922 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
923 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200924};
925
926static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200927 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
928 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
929 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100930};
Jean Delvare08e7e272005-04-25 22:43:25 +0200931
Rudolf Marek08c79952006-07-05 18:14:31 +0200932#define show_pwm_reg(reg) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800933static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
934 char *buf) \
Rudolf Marek08c79952006-07-05 18:14:31 +0200935{ \
936 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800937 struct sensor_device_attribute *sensor_attr = \
938 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200939 int nr = sensor_attr->index; \
940 return sprintf(buf, "%d\n", data->reg[nr]); \
941}
942
943show_pwm_reg(pwm_mode)
944show_pwm_reg(pwm_enable)
945show_pwm_reg(pwm)
946
947static ssize_t
948store_pwm_mode(struct device *dev, struct device_attribute *attr,
949 const char *buf, size_t count)
950{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200951 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200952 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
953 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800954 unsigned long val;
955 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +0200956 u16 reg;
957
Guenter Roeckbce26c52011-02-04 12:54:14 -0800958 err = strict_strtoul(buf, 10, &val);
959 if (err < 0)
960 return err;
961
Rudolf Marek08c79952006-07-05 18:14:31 +0200962 if (val > 1)
963 return -EINVAL;
964 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200965 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200966 data->pwm_mode[nr] = val;
967 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
968 if (!val)
969 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200970 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200971 mutex_unlock(&data->update_lock);
972 return count;
973}
974
975static ssize_t
976store_pwm(struct device *dev, struct device_attribute *attr,
977 const char *buf, size_t count)
978{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200979 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200980 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
981 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800982 unsigned long val;
983 int err;
984
985 err = strict_strtoul(buf, 10, &val);
986 if (err < 0)
987 return err;
988
989 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +0200990
991 mutex_lock(&data->update_lock);
992 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200993 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200994 mutex_unlock(&data->update_lock);
995 return count;
996}
997
998static ssize_t
999store_pwm_enable(struct device *dev, struct device_attribute *attr,
1000 const char *buf, size_t count)
1001{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001002 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001003 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1004 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001005 unsigned long val;
1006 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001007 u16 reg;
1008
Guenter Roeckbce26c52011-02-04 12:54:14 -08001009 err = strict_strtoul(buf, 10, &val);
1010 if (err < 0)
1011 return err;
1012
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001013 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001014 return -EINVAL;
1015 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001016 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001017 data->pwm_enable[nr] = val;
1018 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1019 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001020 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001021 mutex_unlock(&data->update_lock);
1022 return count;
1023}
1024
1025
1026#define show_tol_temp(reg) \
1027static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1028 char *buf) \
1029{ \
1030 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001031 struct sensor_device_attribute *sensor_attr = \
1032 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001033 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001034 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001035}
1036
1037show_tol_temp(tolerance)
1038show_tol_temp(target_temp)
1039
1040static ssize_t
1041store_target_temp(struct device *dev, struct device_attribute *attr,
1042 const char *buf, size_t count)
1043{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001044 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001045 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1046 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001047 long val;
1048 int err;
1049
1050 err = strict_strtol(buf, 10, &val);
1051 if (err < 0)
1052 return err;
1053
1054 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001055
1056 mutex_lock(&data->update_lock);
1057 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001058 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001059 mutex_unlock(&data->update_lock);
1060 return count;
1061}
1062
1063static ssize_t
1064store_tolerance(struct device *dev, struct device_attribute *attr,
1065 const char *buf, size_t count)
1066{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001067 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001068 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1069 int nr = sensor_attr->index;
1070 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001071 long val;
1072 int err;
1073
1074 err = strict_strtol(buf, 10, &val);
1075 if (err < 0)
1076 return err;
1077
Rudolf Marek08c79952006-07-05 18:14:31 +02001078 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001079 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001080
1081 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001082 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001083 data->tolerance[nr] = val;
1084 if (nr == 1)
1085 reg = (reg & 0x0f) | (val << 4);
1086 else
1087 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001088 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001089 mutex_unlock(&data->update_lock);
1090 return count;
1091}
1092
1093static struct sensor_device_attribute sda_pwm[] = {
1094 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1095 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1096 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1097 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1098};
1099
1100static struct sensor_device_attribute sda_pwm_mode[] = {
1101 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1102 store_pwm_mode, 0),
1103 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1104 store_pwm_mode, 1),
1105 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1106 store_pwm_mode, 2),
1107 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1108 store_pwm_mode, 3),
1109};
1110
1111static struct sensor_device_attribute sda_pwm_enable[] = {
1112 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1113 store_pwm_enable, 0),
1114 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1115 store_pwm_enable, 1),
1116 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1117 store_pwm_enable, 2),
1118 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1119 store_pwm_enable, 3),
1120};
1121
1122static struct sensor_device_attribute sda_target_temp[] = {
1123 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1124 store_target_temp, 0),
1125 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1126 store_target_temp, 1),
1127 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1128 store_target_temp, 2),
1129 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1130 store_target_temp, 3),
1131};
1132
1133static struct sensor_device_attribute sda_tolerance[] = {
1134 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1135 store_tolerance, 0),
1136 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1137 store_tolerance, 1),
1138 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1139 store_tolerance, 2),
1140 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1141 store_tolerance, 3),
1142};
1143
Rudolf Marek08c79952006-07-05 18:14:31 +02001144/* Smart Fan registers */
1145
1146#define fan_functions(reg, REG) \
1147static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1148 char *buf) \
1149{ \
1150 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001151 struct sensor_device_attribute *sensor_attr = \
1152 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001153 int nr = sensor_attr->index; \
1154 return sprintf(buf, "%d\n", data->reg[nr]); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001155} \
Rudolf Marek08c79952006-07-05 18:14:31 +02001156static ssize_t \
1157store_##reg(struct device *dev, struct device_attribute *attr, \
1158 const char *buf, size_t count) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001159{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001160 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001161 struct sensor_device_attribute *sensor_attr = \
1162 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001163 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001164 unsigned long val; \
1165 int err; \
1166 err = strict_strtoul(buf, 10, &val); \
1167 if (err < 0) \
1168 return err; \
1169 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001170 mutex_lock(&data->update_lock); \
1171 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001172 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001173 mutex_unlock(&data->update_lock); \
1174 return count; \
1175}
1176
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001177fan_functions(fan_start_output, FAN_START_OUTPUT)
1178fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1179fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1180fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001181
1182#define fan_time_functions(reg, REG) \
1183static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1184 char *buf) \
1185{ \
1186 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001187 struct sensor_device_attribute *sensor_attr = \
1188 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001189 int nr = sensor_attr->index; \
1190 return sprintf(buf, "%d\n", \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001191 step_time_from_reg(data->reg[nr], \
1192 data->pwm_mode[nr])); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001193} \
1194\
1195static ssize_t \
1196store_##reg(struct device *dev, struct device_attribute *attr, \
1197 const char *buf, size_t count) \
1198{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001199 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001200 struct sensor_device_attribute *sensor_attr = \
1201 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001202 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001203 unsigned long val; \
1204 int err; \
1205 err = strict_strtoul(buf, 10, &val); \
1206 if (err < 0) \
1207 return err; \
1208 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001209 mutex_lock(&data->update_lock); \
1210 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001211 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001212 mutex_unlock(&data->update_lock); \
1213 return count; \
1214} \
1215
1216fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1217
David Hubbard1ea6dd32007-06-24 11:16:15 +02001218static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1219 char *buf)
1220{
1221 struct w83627ehf_data *data = dev_get_drvdata(dev);
1222
1223 return sprintf(buf, "%s\n", data->name);
1224}
1225static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001226
1227static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1228 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1229 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001230 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1231 store_fan_start_output, 3),
1232 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1233 store_fan_stop_output, 3),
1234 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1235 store_fan_max_output, 3),
1236 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1237 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001238};
1239
1240static struct sensor_device_attribute sda_sf3_arrays[] = {
1241 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1242 store_fan_stop_time, 0),
1243 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1244 store_fan_stop_time, 1),
1245 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1246 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001247 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1248 store_fan_start_output, 0),
1249 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1250 store_fan_start_output, 1),
1251 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1252 store_fan_start_output, 2),
1253 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1254 store_fan_stop_output, 0),
1255 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1256 store_fan_stop_output, 1),
1257 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1258 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001259};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001260
Guenter Roeckda2e0252010-08-14 21:08:55 +02001261
1262/*
1263 * pwm1 and pwm3 don't support max and step settings on all chips.
1264 * Need to check support while generating/removing attribute files.
1265 */
1266static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1267 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1268 store_fan_max_output, 0),
1269 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1270 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001271 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1272 store_fan_max_output, 1),
1273 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1274 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001275 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1276 store_fan_max_output, 2),
1277 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1278 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001279};
1280
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001281static ssize_t
1282show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1283{
1284 struct w83627ehf_data *data = dev_get_drvdata(dev);
1285 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1286}
1287static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1288
Jean Delvare08e7e272005-04-25 22:43:25 +02001289/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001290 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001291 */
1292
David Hubbardc18beb52006-09-24 21:04:38 +02001293static void w83627ehf_device_remove_files(struct device *dev)
1294{
1295 /* some entries in the following arrays may not have been used in
1296 * device_create_file(), but device_remove_file() will ignore them */
1297 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001298 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001299
1300 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1301 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001302 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1303 struct sensor_device_attribute *attr =
1304 &sda_sf3_max_step_arrays[i];
1305 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1306 device_remove_file(dev, &attr->dev_attr);
1307 }
David Hubbardc18beb52006-09-24 21:04:38 +02001308 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1309 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001310 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001311 if ((i == 6) && data->in6_skip)
1312 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001313 device_remove_file(dev, &sda_in_input[i].dev_attr);
1314 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1315 device_remove_file(dev, &sda_in_min[i].dev_attr);
1316 device_remove_file(dev, &sda_in_max[i].dev_attr);
1317 }
1318 for (i = 0; i < 5; i++) {
1319 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1320 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1321 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1322 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1323 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001324 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001325 device_remove_file(dev, &sda_pwm[i].dev_attr);
1326 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1327 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1328 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1329 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1330 }
Gong Juna157d062009-03-30 21:46:43 +02001331 for (i = 0; i < 3; i++) {
1332 if ((i == 2) && data->temp3_disable)
1333 continue;
1334 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1335 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1336 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1337 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1338 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1339 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001340
1341 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001342 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001343}
1344
David Hubbard1ea6dd32007-06-24 11:16:15 +02001345/* Get the monitoring functions started */
1346static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001347{
1348 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001349 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001350
1351 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001352 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001353 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001354 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001355 tmp | 0x01);
1356
1357 /* Enable temp2 and temp3 if needed */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001358 for (i = 1; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001359 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001360 W83627EHF_REG_TEMP_CONFIG[i]);
Guenter Roeckbce26c52011-02-04 12:54:14 -08001361 if ((i == 2) && data->temp3_disable)
Gong Juna157d062009-03-30 21:46:43 +02001362 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001363 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001364 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001365 W83627EHF_REG_TEMP_CONFIG[i],
1366 tmp & 0xfe);
1367 }
Jean Delvared3130f02007-06-24 11:20:13 +02001368
1369 /* Enable VBAT monitoring if needed */
1370 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1371 if (!(tmp & 0x01))
1372 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001373
1374 /* Get thermal sensor types */
1375 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1376 for (i = 0; i < 3; i++) {
1377 if ((tmp & (0x02 << i)))
1378 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1379 else
1380 data->temp_type[i] = 4; /* thermistor */
1381 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001382}
1383
David Hubbard1ea6dd32007-06-24 11:16:15 +02001384static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001385{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001386 struct device *dev = &pdev->dev;
1387 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001388 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001389 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001390 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001391 int i, err = 0;
1392
David Hubbard1ea6dd32007-06-24 11:16:15 +02001393 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1394 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001395 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001396 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1397 (unsigned long)res->start,
1398 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001399 goto exit;
1400 }
1401
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001402 data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1403 if (!data) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001404 err = -ENOMEM;
1405 goto exit_release;
1406 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001407
David Hubbard1ea6dd32007-06-24 11:16:15 +02001408 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001409 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001410 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001411 data->name = w83627ehf_device_names[sio_data->kind];
1412 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001413
Gong Jun237c8d2f2009-03-30 21:46:42 +02001414 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1415 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1416 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001417 data->pwm_num = (sio_data->kind == w83667hg
1418 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001419
Gong Juna157d062009-03-30 21:46:43 +02001420 /* Check temp3 configuration bit for 667HG */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001421 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Juna157d062009-03-30 21:46:43 +02001422 data->temp3_disable = w83627ehf_read_value(data,
Guenter Roeckbce26c52011-02-04 12:54:14 -08001423 W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
Gong Juna157d062009-03-30 21:46:43 +02001424 data->in6_skip = !data->temp3_disable;
1425 }
1426
Guenter Roeckda2e0252010-08-14 21:08:55 +02001427 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1428 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001429 if (sio_data->kind == w83667hg_b) {
1430 data->REG_FAN_MAX_OUTPUT =
1431 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1432 data->REG_FAN_STEP_OUTPUT =
1433 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1434 } else {
1435 data->REG_FAN_MAX_OUTPUT =
1436 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1437 data->REG_FAN_STEP_OUTPUT =
1438 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1439 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001440
Jean Delvare08e7e272005-04-25 22:43:25 +02001441 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001442 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001443
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001444 data->vrm = vid_which_vrm();
1445 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001446 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001447 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001448 /* W83667HG has different pins for VID input and output, so
1449 we can get the VID input values directly at logical device D
1450 0xe3. */
1451 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1452 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001453 err = device_create_file(dev, &dev_attr_cpu0_vid);
1454 if (err)
1455 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001456 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001457 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1458 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1459 /* Set VID input sensibility if needed. In theory the
1460 BIOS should have set it, but in practice it's not
1461 always the case. We only do it for the W83627EHF/EHG
1462 because the W83627DHG is more complex in this
1463 respect. */
1464 if (sio_data->kind == w83627ehf) {
1465 en_vrm10 = superio_inb(sio_data->sioreg,
1466 SIO_REG_EN_VRM10);
1467 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1468 dev_warn(dev, "Setting VID input "
1469 "voltage to TTL\n");
1470 superio_outb(sio_data->sioreg,
1471 SIO_REG_EN_VRM10,
1472 en_vrm10 & ~0x08);
1473 } else if (!(en_vrm10 & 0x08)
1474 && data->vrm == 100) {
1475 dev_warn(dev, "Setting VID input "
1476 "voltage to VRM10\n");
1477 superio_outb(sio_data->sioreg,
1478 SIO_REG_EN_VRM10,
1479 en_vrm10 | 0x08);
1480 }
1481 }
1482
1483 data->vid = superio_inb(sio_data->sioreg,
1484 SIO_REG_VID_DATA);
1485 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1486 data->vid &= 0x3f;
1487
1488 err = device_create_file(dev, &dev_attr_cpu0_vid);
1489 if (err)
1490 goto exit_release;
1491 } else {
1492 dev_info(dev, "VID pins in output mode, CPU VID not "
1493 "available\n");
1494 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001495 }
1496
Rudolf Marek08c79952006-07-05 18:14:31 +02001497 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001498 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001499 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1500 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1501 } else {
1502 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1503 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1504 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001505 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001506
Jean Delvare08e7e272005-04-25 22:43:25 +02001507 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001508 as fan on/off switches, but fan5 control is write only :/
1509 We assume that if the serial interface is disabled, designers
1510 connected fan5 as input unless they are emitting log 1, which
1511 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001512
Jean Delvare08e7e272005-04-25 22:43:25 +02001513 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001514 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001515 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001516 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001517 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001518 data->has_fan |= (1 << 4);
1519
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001520 /* Read fan clock dividers immediately */
1521 w83627ehf_update_fan_div(data);
1522
Jean Delvare08e7e272005-04-25 22:43:25 +02001523 /* Register sysfs hooks */
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001524 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
1525 err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
1526 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001527 goto exit_remove;
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001528 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001529
Guenter Roeckda2e0252010-08-14 21:08:55 +02001530 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1531 struct sensor_device_attribute *attr =
1532 &sda_sf3_max_step_arrays[i];
1533 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1534 err = device_create_file(dev, &attr->dev_attr);
1535 if (err)
1536 goto exit_remove;
1537 }
1538 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001539 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001540 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001541 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001542 err = device_create_file(dev,
1543 &sda_sf3_arrays_fan4[i].dev_attr);
1544 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001545 goto exit_remove;
1546 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001547
Gong Juna157d062009-03-30 21:46:43 +02001548 for (i = 0; i < data->in_num; i++) {
1549 if ((i == 6) && data->in6_skip)
1550 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001551 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1552 || (err = device_create_file(dev,
1553 &sda_in_alarm[i].dev_attr))
1554 || (err = device_create_file(dev,
1555 &sda_in_min[i].dev_attr))
1556 || (err = device_create_file(dev,
1557 &sda_in_max[i].dev_attr)))
1558 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001559 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001560
Yuan Mu412fec82006-02-05 23:24:16 +01001561 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001562 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001563 if ((err = device_create_file(dev,
1564 &sda_fan_input[i].dev_attr))
1565 || (err = device_create_file(dev,
1566 &sda_fan_alarm[i].dev_attr))
1567 || (err = device_create_file(dev,
1568 &sda_fan_div[i].dev_attr))
1569 || (err = device_create_file(dev,
1570 &sda_fan_min[i].dev_attr)))
1571 goto exit_remove;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001572 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001573 ((err = device_create_file(dev,
1574 &sda_pwm[i].dev_attr))
1575 || (err = device_create_file(dev,
1576 &sda_pwm_mode[i].dev_attr))
1577 || (err = device_create_file(dev,
1578 &sda_pwm_enable[i].dev_attr))
1579 || (err = device_create_file(dev,
1580 &sda_target_temp[i].dev_attr))
1581 || (err = device_create_file(dev,
1582 &sda_tolerance[i].dev_attr))))
1583 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001584 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001585 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001586
Gong Juna157d062009-03-30 21:46:43 +02001587 for (i = 0; i < 3; i++) {
1588 if ((i == 2) && data->temp3_disable)
1589 continue;
1590 if ((err = device_create_file(dev,
1591 &sda_temp_input[i].dev_attr))
1592 || (err = device_create_file(dev,
1593 &sda_temp_max[i].dev_attr))
1594 || (err = device_create_file(dev,
1595 &sda_temp_max_hyst[i].dev_attr))
1596 || (err = device_create_file(dev,
1597 &sda_temp_alarm[i].dev_attr))
1598 || (err = device_create_file(dev,
1599 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001600 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001601 }
David Hubbardc18beb52006-09-24 21:04:38 +02001602
David Hubbard1ea6dd32007-06-24 11:16:15 +02001603 err = device_create_file(dev, &dev_attr_name);
1604 if (err)
1605 goto exit_remove;
1606
Tony Jones1beeffe2007-08-20 13:46:20 -07001607 data->hwmon_dev = hwmon_device_register(dev);
1608 if (IS_ERR(data->hwmon_dev)) {
1609 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001610 goto exit_remove;
1611 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001612
1613 return 0;
1614
David Hubbardc18beb52006-09-24 21:04:38 +02001615exit_remove:
1616 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001617 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001618 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001619exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001620 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001621exit:
1622 return err;
1623}
1624
David Hubbard1ea6dd32007-06-24 11:16:15 +02001625static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001626{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001627 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001628
Tony Jones1beeffe2007-08-20 13:46:20 -07001629 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001630 w83627ehf_device_remove_files(&pdev->dev);
1631 release_region(data->addr, IOREGION_LENGTH);
1632 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001633 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001634
1635 return 0;
1636}
1637
David Hubbard1ea6dd32007-06-24 11:16:15 +02001638static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001639 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001640 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001641 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001642 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001643 .probe = w83627ehf_probe,
1644 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001645};
1646
David Hubbard1ea6dd32007-06-24 11:16:15 +02001647/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1648static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1649 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001650{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001651 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1652 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1653 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001654 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02001655 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001656 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001657
Jean Delvare08e7e272005-04-25 22:43:25 +02001658 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001659 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001660
David Hubbard1ea6dd32007-06-24 11:16:15 +02001661 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001662
Jean Delvare67b671b2007-12-06 23:13:42 +01001663 if (force_id)
1664 val = force_id;
1665 else
1666 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1667 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001668 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001669 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001670 sio_data->kind = w83627ehf;
1671 sio_name = sio_name_W83627EHF;
1672 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001673 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001674 sio_data->kind = w83627ehf;
1675 sio_name = sio_name_W83627EHG;
1676 break;
1677 case SIO_W83627DHG_ID:
1678 sio_data->kind = w83627dhg;
1679 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001680 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001681 case SIO_W83627DHG_P_ID:
1682 sio_data->kind = w83627dhg_p;
1683 sio_name = sio_name_W83627DHG_P;
1684 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001685 case SIO_W83667HG_ID:
1686 sio_data->kind = w83667hg;
1687 sio_name = sio_name_W83667HG;
1688 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001689 case SIO_W83667HG_B_ID:
1690 sio_data->kind = w83667hg_b;
1691 sio_name = sio_name_W83667HG_B;
1692 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001693 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001694 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001695 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001696 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001697 return -ENODEV;
1698 }
1699
David Hubbard1ea6dd32007-06-24 11:16:15 +02001700 /* We have a known chip, find the HWM I/O address */
1701 superio_select(sioaddr, W83627EHF_LD_HWM);
1702 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1703 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001704 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001705 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001706 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 +02001707 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001708 return -ENODEV;
1709 }
1710
1711 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001712 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001713 if (!(val & 0x01)) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001714 pr_warn("Forcibly enabling Super-I/O. "
1715 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001716 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001717 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001718
David Hubbard1ea6dd32007-06-24 11:16:15 +02001719 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001720 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001721 sio_data->sioreg = sioaddr;
1722
Jean Delvare08e7e272005-04-25 22:43:25 +02001723 return 0;
1724}
1725
David Hubbard1ea6dd32007-06-24 11:16:15 +02001726/* when Super-I/O functions move to a separate file, the Super-I/O
1727 * bus will manage the lifetime of the device and this module will only keep
1728 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1729 * must keep track of the device */
1730static struct platform_device *pdev;
1731
Jean Delvare08e7e272005-04-25 22:43:25 +02001732static int __init sensors_w83627ehf_init(void)
1733{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001734 int err;
1735 unsigned short address;
1736 struct resource res;
1737 struct w83627ehf_sio_data sio_data;
1738
1739 /* initialize sio_data->kind and sio_data->sioreg.
1740 *
1741 * when Super-I/O functions move to a separate file, the Super-I/O
1742 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1743 * w83627ehf hardware monitor, and call probe() */
1744 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1745 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001746 return -ENODEV;
1747
David Hubbard1ea6dd32007-06-24 11:16:15 +02001748 err = platform_driver_register(&w83627ehf_driver);
1749 if (err)
1750 goto exit;
1751
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001752 pdev = platform_device_alloc(DRVNAME, address);
1753 if (!pdev) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001754 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001755 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001756 goto exit_unregister;
1757 }
1758
1759 err = platform_device_add_data(pdev, &sio_data,
1760 sizeof(struct w83627ehf_sio_data));
1761 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001762 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001763 goto exit_device_put;
1764 }
1765
1766 memset(&res, 0, sizeof(res));
1767 res.name = DRVNAME;
1768 res.start = address + IOREGION_OFFSET;
1769 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1770 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001771
1772 err = acpi_check_resource_conflict(&res);
1773 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001774 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001775
David Hubbard1ea6dd32007-06-24 11:16:15 +02001776 err = platform_device_add_resources(pdev, &res, 1);
1777 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001778 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001779 goto exit_device_put;
1780 }
1781
1782 /* platform_device_add calls probe() */
1783 err = platform_device_add(pdev);
1784 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001785 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001786 goto exit_device_put;
1787 }
1788
1789 return 0;
1790
1791exit_device_put:
1792 platform_device_put(pdev);
1793exit_unregister:
1794 platform_driver_unregister(&w83627ehf_driver);
1795exit:
1796 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001797}
1798
1799static void __exit sensors_w83627ehf_exit(void)
1800{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001801 platform_device_unregister(pdev);
1802 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001803}
1804
1805MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1806MODULE_DESCRIPTION("W83627EHF driver");
1807MODULE_LICENSE("GPL");
1808
1809module_init(sensors_w83627ehf_init);
1810module_exit(sensors_w83627ehf_exit);