blob: cb808d0153619838378bd70f1ea5bfc3ca1c5ad2 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
3 the Winbond W83627EHF Super-I/O chip
4 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Jean Delvare7188cc62006-12-12 18:18:30 +01006 Rudolf Marek <r.marek@assembler.cz>
David Hubbardc18beb52006-09-24 21:04:38 +02007 David Hubbard <david.c.hubbard@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02008
9 Shamelessly ripped from the w83627hf driver
10 Copyright (C) 2003 Mark Studebaker
11
12 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
13 in testing and debugging this driver.
14
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020015 This driver also supports the W83627EHG, which is the lead-free
16 version of the W83627EHF.
17
Jean Delvare08e7e272005-04-25 22:43:25 +020018 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
32
33 Supports the following chips:
34
David Hubbard657c93b2007-02-14 21:15:04 +010035 Chip #vin #fan #pwm #temp chip IDs man ID
36 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
37 0x8860 0xa1
38 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020039*/
40
41#include <linux/module.h>
42#include <linux/init.h>
43#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020044#include <linux/jiffies.h>
45#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040046#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010047#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020048#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040049#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010050#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010051#include <linux/acpi.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020052#include <asm/io.h>
53#include "lm75.h"
54
David Hubbard1ea6dd32007-06-24 11:16:15 +020055enum kinds { w83627ehf, w83627dhg };
56
57/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
58static const char * w83627ehf_device_names[] = {
59 "w83627ehf",
60 "w83627dhg",
61};
62
Jean Delvare67b671b2007-12-06 23:13:42 +010063static unsigned short force_id;
64module_param(force_id, ushort, 0);
65MODULE_PARM_DESC(force_id, "Override the detected device ID");
66
David Hubbard1ea6dd32007-06-24 11:16:15 +020067#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020068
69/*
70 * Super-I/O constants and functions
71 */
72
Jean Delvare08e7e272005-04-25 22:43:25 +020073#define W83627EHF_LD_HWM 0x0b
74
75#define SIO_REG_LDSEL 0x07 /* Logical device select */
76#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020077#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020078#define SIO_REG_ENABLE 0x30 /* Logical device enable */
79#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020080#define SIO_REG_VID_CTRL 0xF0 /* VID control */
81#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020082
David Hubbard657c93b2007-02-14 21:15:04 +010083#define SIO_W83627EHF_ID 0x8850
84#define SIO_W83627EHG_ID 0x8860
85#define SIO_W83627DHG_ID 0xa020
86#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020087
88static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +020089superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +020090{
David Hubbard1ea6dd32007-06-24 11:16:15 +020091 outb(reg, ioreg);
92 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +020093}
94
95static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +020096superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +020097{
David Hubbard1ea6dd32007-06-24 11:16:15 +020098 outb(reg, ioreg);
99 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200100}
101
102static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200103superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200104{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200105 outb(SIO_REG_LDSEL, ioreg);
106 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200107}
108
109static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200110superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200111{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200112 outb(0x87, ioreg);
113 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200114}
115
116static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200117superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200118{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200119 outb(0x02, ioreg);
120 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200121}
122
123/*
124 * ISA constants
125 */
126
Jean Delvare1a641fc2007-04-23 14:41:16 -0700127#define IOREGION_ALIGNMENT ~7
128#define IOREGION_OFFSET 5
129#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200130#define ADDR_REG_OFFSET 0
131#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200132
133#define W83627EHF_REG_BANK 0x4E
134#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100135
136/* Not currently used:
137 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
138 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
139 * REG_MAN_ID is at port 0x4f
140 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200141
142static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
143static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
144
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100145/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
146#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
147 (0x554 + (((nr) - 7) * 2)))
148#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
149 (0x555 + (((nr) - 7) * 2)))
150#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
151 (0x550 + (nr) - 7))
152
Jean Delvare08e7e272005-04-25 22:43:25 +0200153#define W83627EHF_REG_TEMP1 0x27
154#define W83627EHF_REG_TEMP1_HYST 0x3a
155#define W83627EHF_REG_TEMP1_OVER 0x39
156static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
157static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
158static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
159static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
160
161/* Fan clock dividers are spread over the following five registers */
162#define W83627EHF_REG_FANDIV1 0x47
163#define W83627EHF_REG_FANDIV2 0x4B
164#define W83627EHF_REG_VBAT 0x5D
165#define W83627EHF_REG_DIODE 0x59
166#define W83627EHF_REG_SMI_OVT 0x4C
167
Jean Delvarea4589db2006-03-23 16:30:29 +0100168#define W83627EHF_REG_ALARM1 0x459
169#define W83627EHF_REG_ALARM2 0x45A
170#define W83627EHF_REG_ALARM3 0x45B
171
Rudolf Marek08c79952006-07-05 18:14:31 +0200172/* SmartFan registers */
173/* DC or PWM output fan configuration */
174static const u8 W83627EHF_REG_PWM_ENABLE[] = {
175 0x04, /* SYS FAN0 output mode and PWM mode */
176 0x04, /* CPU FAN0 output mode and PWM mode */
177 0x12, /* AUX FAN mode */
178 0x62, /* CPU fan1 mode */
179};
180
181static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
182static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
183
184/* FAN Duty Cycle, be used to control */
185static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
186static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
187static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
188
189
190/* Advanced Fan control, some values are common for all fans */
191static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
192static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
193
Jean Delvare08e7e272005-04-25 22:43:25 +0200194/*
195 * Conversions
196 */
197
Rudolf Marek08c79952006-07-05 18:14:31 +0200198/* 1 is PWM mode, output in ms */
199static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
200{
201 return mode ? 100 * reg : 400 * reg;
202}
203
204static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
205{
206 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
207 (msec + 200) / 400), 1, 255);
208}
209
Jean Delvare08e7e272005-04-25 22:43:25 +0200210static inline unsigned int
211fan_from_reg(u8 reg, unsigned int div)
212{
213 if (reg == 0 || reg == 255)
214 return 0;
215 return 1350000U / (reg * div);
216}
217
218static inline unsigned int
219div_from_reg(u8 reg)
220{
221 return 1 << reg;
222}
223
224static inline int
225temp1_from_reg(s8 reg)
226{
227 return reg * 1000;
228}
229
230static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200231temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200232{
Rudolf Marek08c79952006-07-05 18:14:31 +0200233 if (temp <= min)
234 return min / 1000;
235 if (temp >= max)
236 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200237 if (temp < 0)
238 return (temp - 500) / 1000;
239 return (temp + 500) / 1000;
240}
241
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100242/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
243
244static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
245
246static inline long in_from_reg(u8 reg, u8 nr)
247{
248 return reg * scale_in[nr];
249}
250
251static inline u8 in_to_reg(u32 val, u8 nr)
252{
253 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
254}
255
Jean Delvare08e7e272005-04-25 22:43:25 +0200256/*
257 * Data structures and manipulation thereof
258 */
259
260struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200261 int addr; /* IO base of hw monitor block */
262 const char *name;
263
Tony Jones1beeffe2007-08-20 13:46:20 -0700264 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100265 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200266
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100267 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200268 char valid; /* !=0 if following fields are valid */
269 unsigned long last_updated; /* In jiffies */
270
271 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200272 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100273 u8 in[10]; /* Register value */
274 u8 in_max[10]; /* Register value */
275 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200276 u8 fan[5];
277 u8 fan_min[5];
278 u8 fan_div[5];
279 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200280 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200281 s8 temp1;
282 s8 temp1_max;
283 s8 temp1_max_hyst;
284 s16 temp[2];
285 s16 temp_max[2];
286 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100287 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200288
289 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
290 u8 pwm_enable[4]; /* 1->manual
291 2->thermal cruise (also called SmartFan I) */
292 u8 pwm[4];
293 u8 target_temp[4];
294 u8 tolerance[4];
295
296 u8 fan_min_output[4]; /* minimum fan speed */
297 u8 fan_stop_time[4];
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200298
299 u8 vid;
300 u8 vrm;
Jean Delvare08e7e272005-04-25 22:43:25 +0200301};
302
David Hubbard1ea6dd32007-06-24 11:16:15 +0200303struct w83627ehf_sio_data {
304 int sioreg;
305 enum kinds kind;
306};
307
Jean Delvare08e7e272005-04-25 22:43:25 +0200308static inline int is_word_sized(u16 reg)
309{
310 return (((reg & 0xff00) == 0x100
311 || (reg & 0xff00) == 0x200)
312 && ((reg & 0x00ff) == 0x50
313 || (reg & 0x00ff) == 0x53
314 || (reg & 0x00ff) == 0x55));
315}
316
Jean Delvare09568952007-08-11 13:57:05 +0200317/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200318static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200319{
Jean Delvare09568952007-08-11 13:57:05 +0200320 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200321 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
322 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200323 }
324}
325
Jean Delvare09568952007-08-11 13:57:05 +0200326/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200327static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200328{
329 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200330 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
331 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200332 }
333}
334
David Hubbard1ea6dd32007-06-24 11:16:15 +0200335static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200336{
Jean Delvare08e7e272005-04-25 22:43:25 +0200337 int res, word_sized = is_word_sized(reg);
338
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100339 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200340
David Hubbard1ea6dd32007-06-24 11:16:15 +0200341 w83627ehf_set_bank(data, reg);
342 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
343 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200344 if (word_sized) {
345 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200346 data->addr + ADDR_REG_OFFSET);
347 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200348 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200349 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200350
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100351 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200352
353 return res;
354}
355
David Hubbard1ea6dd32007-06-24 11:16:15 +0200356static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200357{
Jean Delvare08e7e272005-04-25 22:43:25 +0200358 int word_sized = is_word_sized(reg);
359
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100360 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200361
David Hubbard1ea6dd32007-06-24 11:16:15 +0200362 w83627ehf_set_bank(data, reg);
363 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200364 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200365 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200366 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200367 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200368 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200369 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
370 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200371
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100372 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200373 return 0;
374}
375
376/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200377static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200378{
Jean Delvare08e7e272005-04-25 22:43:25 +0200379 u8 reg;
380
381 switch (nr) {
382 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200383 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200384 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200385 /* fan5 input control bit is write only, compute the value */
386 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200387 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
388 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200389 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200390 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200391 break;
392 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200393 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200394 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200395 /* fan5 input control bit is write only, compute the value */
396 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200397 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
398 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200399 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200400 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200401 break;
402 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200403 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200404 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200405 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
406 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200407 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200408 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200409 break;
410 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200411 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200412 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200413 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
414 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200415 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200416 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200417 break;
418 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200419 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700420 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200421 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200422 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200423 break;
424 }
425}
426
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400427static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
428{
429 int i;
430
431 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
432 data->fan_div[0] = (i >> 4) & 0x03;
433 data->fan_div[1] = (i >> 6) & 0x03;
434 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
435 data->fan_div[2] = (i >> 6) & 0x03;
436 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
437 data->fan_div[0] |= (i >> 3) & 0x04;
438 data->fan_div[1] |= (i >> 4) & 0x04;
439 data->fan_div[2] |= (i >> 5) & 0x04;
440 if (data->has_fan & ((1 << 3) | (1 << 4))) {
441 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
442 data->fan_div[3] = i & 0x03;
443 data->fan_div[4] = ((i >> 2) & 0x03)
444 | ((i >> 5) & 0x04);
445 }
446 if (data->has_fan & (1 << 3)) {
447 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
448 data->fan_div[3] |= (i >> 5) & 0x04;
449 }
450}
451
Jean Delvare08e7e272005-04-25 22:43:25 +0200452static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
453{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200454 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200455 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200456 int i;
457
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100458 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200459
Jean Delvare6b3e4642007-06-24 11:19:01 +0200460 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200461 || !data->valid) {
462 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400463 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200464
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100465 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200466 for (i = 0; i < data->in_num; i++) {
467 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100468 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200469 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100470 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200471 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100472 W83627EHF_REG_IN_MAX(i));
473 }
474
Jean Delvare08e7e272005-04-25 22:43:25 +0200475 /* Measured fan speeds and limits */
476 for (i = 0; i < 5; i++) {
477 if (!(data->has_fan & (1 << i)))
478 continue;
479
David Hubbard1ea6dd32007-06-24 11:16:15 +0200480 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200481 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200482 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200483 W83627EHF_REG_FAN_MIN[i]);
484
485 /* If we failed to measure the fan speed and clock
486 divider can be increased, let's try that for next
487 time */
488 if (data->fan[i] == 0xff
489 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200490 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200491 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700492 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200493 div_from_reg(data->fan_div[i] + 1));
494 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200495 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200496 /* Preserve min limit if possible */
497 if (data->fan_min[i] >= 2
498 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200499 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200500 W83627EHF_REG_FAN_MIN[i],
501 (data->fan_min[i] /= 2));
502 }
503 }
504
Rudolf Marek08c79952006-07-05 18:14:31 +0200505 for (i = 0; i < 4; i++) {
Jean Delvare77fa49d2009-01-07 16:37:35 +0100506 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200507 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200508 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200509 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200510 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200511 W83627EHF_REG_TOLERANCE[i]);
512 }
513 data->pwm_mode[i] =
514 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
515 ? 0 : 1;
516 data->pwm_enable[i] =
517 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
518 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200519 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200520 W83627EHF_REG_PWM[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200521 data->fan_min_output[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200522 W83627EHF_REG_FAN_MIN_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200523 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200524 W83627EHF_REG_FAN_STOP_TIME[i]);
525 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200527 W83627EHF_REG_TARGET[i]) &
528 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
529 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
530 & 0x0f;
531 }
532
Jean Delvare08e7e272005-04-25 22:43:25 +0200533 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200534 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200535 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200536 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200537 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200538 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200539 W83627EHF_REG_TEMP1_HYST);
540 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200541 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200542 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200543 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200544 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200545 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200546 W83627EHF_REG_TEMP_HYST[i]);
547 }
548
David Hubbard1ea6dd32007-06-24 11:16:15 +0200549 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100550 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200551 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100552 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200553 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100554 W83627EHF_REG_ALARM3) << 16);
555
Jean Delvare08e7e272005-04-25 22:43:25 +0200556 data->last_updated = jiffies;
557 data->valid = 1;
558 }
559
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100560 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200561 return data;
562}
563
564/*
565 * Sysfs callback functions
566 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100567#define show_in_reg(reg) \
568static ssize_t \
569show_##reg(struct device *dev, struct device_attribute *attr, \
570 char *buf) \
571{ \
572 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
573 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
574 int nr = sensor_attr->index; \
575 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
576}
577show_in_reg(in)
578show_in_reg(in_min)
579show_in_reg(in_max)
580
581#define store_in_reg(REG, reg) \
582static ssize_t \
583store_in_##reg (struct device *dev, struct device_attribute *attr, \
584 const char *buf, size_t count) \
585{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200586 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100587 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
588 int nr = sensor_attr->index; \
589 u32 val = simple_strtoul(buf, NULL, 10); \
590 \
591 mutex_lock(&data->update_lock); \
592 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200593 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100594 data->in_##reg[nr]); \
595 mutex_unlock(&data->update_lock); \
596 return count; \
597}
598
599store_in_reg(MIN, min)
600store_in_reg(MAX, max)
601
Jean Delvarea4589db2006-03-23 16:30:29 +0100602static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
603{
604 struct w83627ehf_data *data = w83627ehf_update_device(dev);
605 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
606 int nr = sensor_attr->index;
607 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
608}
609
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100610static struct sensor_device_attribute sda_in_input[] = {
611 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
612 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
613 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
614 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
615 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
616 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
617 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
618 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
619 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
620 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
621};
622
Jean Delvarea4589db2006-03-23 16:30:29 +0100623static struct sensor_device_attribute sda_in_alarm[] = {
624 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
625 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
626 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
627 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
628 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
629 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
630 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
631 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
632 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
633 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
634};
635
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100636static struct sensor_device_attribute sda_in_min[] = {
637 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
638 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
639 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
640 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
641 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
642 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
643 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
644 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
645 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
646 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
647};
648
649static struct sensor_device_attribute sda_in_max[] = {
650 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
651 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
652 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
653 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
654 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
655 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
656 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
657 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
658 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
659 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
660};
661
Jean Delvare08e7e272005-04-25 22:43:25 +0200662#define show_fan_reg(reg) \
663static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100664show_##reg(struct device *dev, struct device_attribute *attr, \
665 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200666{ \
667 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100668 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
669 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200670 return sprintf(buf, "%d\n", \
671 fan_from_reg(data->reg[nr], \
672 div_from_reg(data->fan_div[nr]))); \
673}
674show_fan_reg(fan);
675show_fan_reg(fan_min);
676
677static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100678show_fan_div(struct device *dev, struct device_attribute *attr,
679 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200680{
681 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100682 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
683 int nr = sensor_attr->index;
684 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200685}
686
687static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100688store_fan_min(struct device *dev, struct device_attribute *attr,
689 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200690{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200691 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100692 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
693 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200694 unsigned int val = simple_strtoul(buf, NULL, 10);
695 unsigned int reg;
696 u8 new_div;
697
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100698 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200699 if (!val) {
700 /* No min limit, alarm disabled */
701 data->fan_min[nr] = 255;
702 new_div = data->fan_div[nr]; /* No change */
703 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
704 } else if ((reg = 1350000U / val) >= 128 * 255) {
705 /* Speed below this value cannot possibly be represented,
706 even with the highest divider (128) */
707 data->fan_min[nr] = 254;
708 new_div = 7; /* 128 == (1 << 7) */
709 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
710 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
711 } else if (!reg) {
712 /* Speed above this value cannot possibly be represented,
713 even with the lowest divider (1) */
714 data->fan_min[nr] = 1;
715 new_div = 0; /* 1 == (1 << 0) */
716 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200717 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200718 } else {
719 /* Automatically pick the best divider, i.e. the one such
720 that the min limit will correspond to a register value
721 in the 96..192 range */
722 new_div = 0;
723 while (reg > 192 && new_div < 7) {
724 reg >>= 1;
725 new_div++;
726 }
727 data->fan_min[nr] = reg;
728 }
729
730 /* Write both the fan clock divider (if it changed) and the new
731 fan min (unconditionally) */
732 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200733 /* Preserve the fan speed reading */
734 if (data->fan[nr] != 0xff) {
735 if (new_div > data->fan_div[nr])
736 data->fan[nr] >>= new_div - data->fan_div[nr];
737 else if (data->fan[nr] & 0x80)
738 data->fan[nr] = 0xff;
739 else
740 data->fan[nr] <<= data->fan_div[nr] - new_div;
741 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200742
743 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
744 nr + 1, div_from_reg(data->fan_div[nr]),
745 div_from_reg(new_div));
746 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200747 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200748 /* Give the chip time to sample a new speed value */
749 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200750 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200751 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200752 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100753 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200754
755 return count;
756}
757
Yuan Mu412fec82006-02-05 23:24:16 +0100758static struct sensor_device_attribute sda_fan_input[] = {
759 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
760 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
761 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
762 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
763 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
764};
Jean Delvare08e7e272005-04-25 22:43:25 +0200765
Jean Delvarea4589db2006-03-23 16:30:29 +0100766static struct sensor_device_attribute sda_fan_alarm[] = {
767 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
768 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
769 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
770 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
771 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
772};
773
Yuan Mu412fec82006-02-05 23:24:16 +0100774static struct sensor_device_attribute sda_fan_min[] = {
775 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
776 store_fan_min, 0),
777 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
778 store_fan_min, 1),
779 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
780 store_fan_min, 2),
781 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
782 store_fan_min, 3),
783 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
784 store_fan_min, 4),
785};
Jean Delvare08e7e272005-04-25 22:43:25 +0200786
Yuan Mu412fec82006-02-05 23:24:16 +0100787static struct sensor_device_attribute sda_fan_div[] = {
788 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
789 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
790 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
791 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
792 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
793};
Jean Delvare08e7e272005-04-25 22:43:25 +0200794
Jean Delvare08e7e272005-04-25 22:43:25 +0200795#define show_temp1_reg(reg) \
796static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700797show_##reg(struct device *dev, struct device_attribute *attr, \
798 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200799{ \
800 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
801 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
802}
803show_temp1_reg(temp1);
804show_temp1_reg(temp1_max);
805show_temp1_reg(temp1_max_hyst);
806
807#define store_temp1_reg(REG, reg) \
808static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700809store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
810 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200811{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200812 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200813 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200814 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100815 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200816 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200817 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200818 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100819 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200820 return count; \
821}
822store_temp1_reg(OVER, max);
823store_temp1_reg(HYST, max_hyst);
824
Jean Delvare08e7e272005-04-25 22:43:25 +0200825#define show_temp_reg(reg) \
826static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100827show_##reg(struct device *dev, struct device_attribute *attr, \
828 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200829{ \
830 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100831 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
832 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200833 return sprintf(buf, "%d\n", \
834 LM75_TEMP_FROM_REG(data->reg[nr])); \
835}
836show_temp_reg(temp);
837show_temp_reg(temp_max);
838show_temp_reg(temp_max_hyst);
839
840#define store_temp_reg(REG, reg) \
841static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100842store_##reg(struct device *dev, struct device_attribute *attr, \
843 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200844{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200845 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100846 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
847 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200848 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200849 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100850 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200851 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200852 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200853 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100854 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200855 return count; \
856}
857store_temp_reg(OVER, temp_max);
858store_temp_reg(HYST, temp_max_hyst);
859
Jean Delvareda667362007-06-24 11:21:02 +0200860static ssize_t
861show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
862{
863 struct w83627ehf_data *data = w83627ehf_update_device(dev);
864 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
865 int nr = sensor_attr->index;
866 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
867}
868
Yuan Mu412fec82006-02-05 23:24:16 +0100869static struct sensor_device_attribute sda_temp[] = {
870 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
871 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
872 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
873 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
874 store_temp1_max, 0),
875 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
876 store_temp_max, 0),
877 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
878 store_temp_max, 1),
879 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
880 store_temp1_max_hyst, 0),
881 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
882 store_temp_max_hyst, 0),
883 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
884 store_temp_max_hyst, 1),
Jean Delvarea4589db2006-03-23 16:30:29 +0100885 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
886 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
887 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Jean Delvareda667362007-06-24 11:21:02 +0200888 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
889 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
890 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100891};
Jean Delvare08e7e272005-04-25 22:43:25 +0200892
Rudolf Marek08c79952006-07-05 18:14:31 +0200893#define show_pwm_reg(reg) \
894static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
895 char *buf) \
896{ \
897 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
898 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
899 int nr = sensor_attr->index; \
900 return sprintf(buf, "%d\n", data->reg[nr]); \
901}
902
903show_pwm_reg(pwm_mode)
904show_pwm_reg(pwm_enable)
905show_pwm_reg(pwm)
906
907static ssize_t
908store_pwm_mode(struct device *dev, struct device_attribute *attr,
909 const char *buf, size_t count)
910{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200911 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200912 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
913 int nr = sensor_attr->index;
914 u32 val = simple_strtoul(buf, NULL, 10);
915 u16 reg;
916
917 if (val > 1)
918 return -EINVAL;
919 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200920 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200921 data->pwm_mode[nr] = val;
922 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
923 if (!val)
924 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200925 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200926 mutex_unlock(&data->update_lock);
927 return count;
928}
929
930static ssize_t
931store_pwm(struct device *dev, struct device_attribute *attr,
932 const char *buf, size_t count)
933{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200934 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200935 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
936 int nr = sensor_attr->index;
937 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
938
939 mutex_lock(&data->update_lock);
940 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200941 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200942 mutex_unlock(&data->update_lock);
943 return count;
944}
945
946static ssize_t
947store_pwm_enable(struct device *dev, struct device_attribute *attr,
948 const char *buf, size_t count)
949{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200950 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200951 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
952 int nr = sensor_attr->index;
953 u32 val = simple_strtoul(buf, NULL, 10);
954 u16 reg;
955
956 if (!val || (val > 2)) /* only modes 1 and 2 are supported */
957 return -EINVAL;
958 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200959 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200960 data->pwm_enable[nr] = val;
961 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
962 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200963 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200964 mutex_unlock(&data->update_lock);
965 return count;
966}
967
968
969#define show_tol_temp(reg) \
970static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
971 char *buf) \
972{ \
973 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
974 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
975 int nr = sensor_attr->index; \
976 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
977}
978
979show_tol_temp(tolerance)
980show_tol_temp(target_temp)
981
982static ssize_t
983store_target_temp(struct device *dev, struct device_attribute *attr,
984 const char *buf, size_t count)
985{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200986 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200987 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
988 int nr = sensor_attr->index;
989 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
990
991 mutex_lock(&data->update_lock);
992 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200993 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200994 mutex_unlock(&data->update_lock);
995 return count;
996}
997
998static ssize_t
999store_tolerance(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;
1005 u16 reg;
1006 /* Limit the temp to 0C - 15C */
1007 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1008
1009 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001010 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001011 data->tolerance[nr] = val;
1012 if (nr == 1)
1013 reg = (reg & 0x0f) | (val << 4);
1014 else
1015 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001016 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001017 mutex_unlock(&data->update_lock);
1018 return count;
1019}
1020
1021static struct sensor_device_attribute sda_pwm[] = {
1022 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1023 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1024 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1025 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1026};
1027
1028static struct sensor_device_attribute sda_pwm_mode[] = {
1029 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1030 store_pwm_mode, 0),
1031 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1032 store_pwm_mode, 1),
1033 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1034 store_pwm_mode, 2),
1035 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1036 store_pwm_mode, 3),
1037};
1038
1039static struct sensor_device_attribute sda_pwm_enable[] = {
1040 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1041 store_pwm_enable, 0),
1042 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1043 store_pwm_enable, 1),
1044 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1045 store_pwm_enable, 2),
1046 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1047 store_pwm_enable, 3),
1048};
1049
1050static struct sensor_device_attribute sda_target_temp[] = {
1051 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1052 store_target_temp, 0),
1053 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1054 store_target_temp, 1),
1055 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1056 store_target_temp, 2),
1057 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1058 store_target_temp, 3),
1059};
1060
1061static struct sensor_device_attribute sda_tolerance[] = {
1062 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1063 store_tolerance, 0),
1064 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1065 store_tolerance, 1),
1066 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1067 store_tolerance, 2),
1068 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1069 store_tolerance, 3),
1070};
1071
Rudolf Marek08c79952006-07-05 18:14:31 +02001072/* Smart Fan registers */
1073
1074#define fan_functions(reg, REG) \
1075static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1076 char *buf) \
1077{ \
1078 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1079 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1080 int nr = sensor_attr->index; \
1081 return sprintf(buf, "%d\n", data->reg[nr]); \
1082}\
1083static ssize_t \
1084store_##reg(struct device *dev, struct device_attribute *attr, \
1085 const char *buf, size_t count) \
1086{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001087 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001088 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1089 int nr = sensor_attr->index; \
1090 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1091 mutex_lock(&data->update_lock); \
1092 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001093 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001094 mutex_unlock(&data->update_lock); \
1095 return count; \
1096}
1097
1098fan_functions(fan_min_output, FAN_MIN_OUTPUT)
1099
1100#define fan_time_functions(reg, REG) \
1101static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1102 char *buf) \
1103{ \
1104 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1105 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1106 int nr = sensor_attr->index; \
1107 return sprintf(buf, "%d\n", \
1108 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1109} \
1110\
1111static ssize_t \
1112store_##reg(struct device *dev, struct device_attribute *attr, \
1113 const char *buf, size_t count) \
1114{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001115 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001116 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1117 int nr = sensor_attr->index; \
1118 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1119 data->pwm_mode[nr]); \
1120 mutex_lock(&data->update_lock); \
1121 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001122 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001123 mutex_unlock(&data->update_lock); \
1124 return count; \
1125} \
1126
1127fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1128
David Hubbard1ea6dd32007-06-24 11:16:15 +02001129static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1130 char *buf)
1131{
1132 struct w83627ehf_data *data = dev_get_drvdata(dev);
1133
1134 return sprintf(buf, "%s\n", data->name);
1135}
1136static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001137
1138static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1139 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1140 store_fan_stop_time, 3),
1141 SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1142 store_fan_min_output, 3),
1143};
1144
1145static struct sensor_device_attribute sda_sf3_arrays[] = {
1146 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1147 store_fan_stop_time, 0),
1148 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1149 store_fan_stop_time, 1),
1150 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1151 store_fan_stop_time, 2),
1152 SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1153 store_fan_min_output, 0),
1154 SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1155 store_fan_min_output, 1),
1156 SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1157 store_fan_min_output, 2),
1158};
1159
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001160static ssize_t
1161show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1162{
1163 struct w83627ehf_data *data = dev_get_drvdata(dev);
1164 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1165}
1166static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1167
Jean Delvare08e7e272005-04-25 22:43:25 +02001168/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001169 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001170 */
1171
David Hubbardc18beb52006-09-24 21:04:38 +02001172static void w83627ehf_device_remove_files(struct device *dev)
1173{
1174 /* some entries in the following arrays may not have been used in
1175 * device_create_file(), but device_remove_file() will ignore them */
1176 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001177 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001178
1179 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1180 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1181 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1182 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001183 for (i = 0; i < data->in_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001184 device_remove_file(dev, &sda_in_input[i].dev_attr);
1185 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1186 device_remove_file(dev, &sda_in_min[i].dev_attr);
1187 device_remove_file(dev, &sda_in_max[i].dev_attr);
1188 }
1189 for (i = 0; i < 5; i++) {
1190 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1191 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1192 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1193 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1194 }
1195 for (i = 0; i < 4; i++) {
1196 device_remove_file(dev, &sda_pwm[i].dev_attr);
1197 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1198 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1199 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1200 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1201 }
1202 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
1203 device_remove_file(dev, &sda_temp[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001204
1205 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001206 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001207}
1208
David Hubbard1ea6dd32007-06-24 11:16:15 +02001209/* Get the monitoring functions started */
1210static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001211{
1212 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001213 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001214
1215 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001216 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001217 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001218 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001219 tmp | 0x01);
1220
1221 /* Enable temp2 and temp3 if needed */
1222 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001223 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001224 W83627EHF_REG_TEMP_CONFIG[i]);
1225 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001226 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001227 W83627EHF_REG_TEMP_CONFIG[i],
1228 tmp & 0xfe);
1229 }
Jean Delvared3130f02007-06-24 11:20:13 +02001230
1231 /* Enable VBAT monitoring if needed */
1232 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1233 if (!(tmp & 0x01))
1234 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001235
1236 /* Get thermal sensor types */
1237 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1238 for (i = 0; i < 3; i++) {
1239 if ((tmp & (0x02 << i)))
1240 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1241 else
1242 data->temp_type[i] = 4; /* thermistor */
1243 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001244}
1245
David Hubbard1ea6dd32007-06-24 11:16:15 +02001246static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001247{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001248 struct device *dev = &pdev->dev;
1249 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001250 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001251 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001252 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001253 int i, err = 0;
1254
David Hubbard1ea6dd32007-06-24 11:16:15 +02001255 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1256 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001257 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001258 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1259 (unsigned long)res->start,
1260 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001261 goto exit;
1262 }
1263
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001264 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001265 err = -ENOMEM;
1266 goto exit_release;
1267 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001268
David Hubbard1ea6dd32007-06-24 11:16:15 +02001269 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001270 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001271 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001272 data->name = w83627ehf_device_names[sio_data->kind];
1273 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001274
David Hubbard1ea6dd32007-06-24 11:16:15 +02001275 /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
1276 data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001277
1278 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001279 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001280
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001281 data->vrm = vid_which_vrm();
1282 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001283 /* Read VID value */
1284 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
Jean Delvare58e6e782008-01-03 07:33:31 -05001285 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1286 /* Set VID input sensibility if needed. In theory the BIOS
1287 should have set it, but in practice it's not always the
1288 case. We only do it for the W83627EHF/EHG because the
1289 W83627DHG is more complex in this respect. */
1290 if (sio_data->kind == w83627ehf) {
1291 en_vrm10 = superio_inb(sio_data->sioreg,
1292 SIO_REG_EN_VRM10);
1293 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1294 dev_warn(dev, "Setting VID input voltage to "
1295 "TTL\n");
1296 superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
1297 en_vrm10 & ~0x08);
1298 } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
1299 dev_warn(dev, "Setting VID input voltage to "
1300 "VRM10\n");
1301 superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
1302 en_vrm10 | 0x08);
1303 }
1304 }
1305
Jean Delvarecbe311f2008-01-03 21:22:44 +01001306 data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
1307 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1308 data->vid &= 0x3f;
1309
1310 err = device_create_file(dev, &dev_attr_cpu0_vid);
1311 if (err)
1312 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001313 } else {
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001314 dev_info(dev, "VID pins in output mode, CPU VID not "
1315 "available\n");
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001316 }
1317
Rudolf Marek08c79952006-07-05 18:14:31 +02001318 /* fan4 and fan5 share some pins with the GPIO and serial flash */
1319
David Hubbard1ea6dd32007-06-24 11:16:15 +02001320 fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
1321 fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
1322 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001323
Jean Delvare08e7e272005-04-25 22:43:25 +02001324 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001325 as fan on/off switches, but fan5 control is write only :/
1326 We assume that if the serial interface is disabled, designers
1327 connected fan5 as input unless they are emitting log 1, which
1328 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001329
Jean Delvare08e7e272005-04-25 22:43:25 +02001330 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001331 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Rudolf Marek08c79952006-07-05 18:14:31 +02001332 if ((i & (1 << 2)) && (!fan4pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001333 data->has_fan |= (1 << 3);
Rudolf Marek14992c72006-10-08 22:02:09 +02001334 if (!(i & (1 << 1)) && (!fan5pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001335 data->has_fan |= (1 << 4);
1336
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001337 /* Read fan clock dividers immediately */
1338 w83627ehf_update_fan_div(data);
1339
Jean Delvare08e7e272005-04-25 22:43:25 +02001340 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001341 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001342 if ((err = device_create_file(dev,
1343 &sda_sf3_arrays[i].dev_attr)))
1344 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001345
1346 /* if fan4 is enabled create the sf3 files for it */
1347 if (data->has_fan & (1 << 3))
David Hubbardc18beb52006-09-24 21:04:38 +02001348 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1349 if ((err = device_create_file(dev,
1350 &sda_sf3_arrays_fan4[i].dev_attr)))
1351 goto exit_remove;
1352 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001353
David Hubbard1ea6dd32007-06-24 11:16:15 +02001354 for (i = 0; i < data->in_num; i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001355 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1356 || (err = device_create_file(dev,
1357 &sda_in_alarm[i].dev_attr))
1358 || (err = device_create_file(dev,
1359 &sda_in_min[i].dev_attr))
1360 || (err = device_create_file(dev,
1361 &sda_in_max[i].dev_attr)))
1362 goto exit_remove;
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001363
Yuan Mu412fec82006-02-05 23:24:16 +01001364 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001365 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001366 if ((err = device_create_file(dev,
1367 &sda_fan_input[i].dev_attr))
1368 || (err = device_create_file(dev,
1369 &sda_fan_alarm[i].dev_attr))
1370 || (err = device_create_file(dev,
1371 &sda_fan_div[i].dev_attr))
1372 || (err = device_create_file(dev,
1373 &sda_fan_min[i].dev_attr)))
1374 goto exit_remove;
1375 if (i < 4 && /* w83627ehf only has 4 pwm */
1376 ((err = device_create_file(dev,
1377 &sda_pwm[i].dev_attr))
1378 || (err = device_create_file(dev,
1379 &sda_pwm_mode[i].dev_attr))
1380 || (err = device_create_file(dev,
1381 &sda_pwm_enable[i].dev_attr))
1382 || (err = device_create_file(dev,
1383 &sda_target_temp[i].dev_attr))
1384 || (err = device_create_file(dev,
1385 &sda_tolerance[i].dev_attr))))
1386 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001387 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001388 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001389
Yuan Mu412fec82006-02-05 23:24:16 +01001390 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001391 if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
1392 goto exit_remove;
1393
David Hubbard1ea6dd32007-06-24 11:16:15 +02001394 err = device_create_file(dev, &dev_attr_name);
1395 if (err)
1396 goto exit_remove;
1397
Tony Jones1beeffe2007-08-20 13:46:20 -07001398 data->hwmon_dev = hwmon_device_register(dev);
1399 if (IS_ERR(data->hwmon_dev)) {
1400 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001401 goto exit_remove;
1402 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001403
1404 return 0;
1405
David Hubbardc18beb52006-09-24 21:04:38 +02001406exit_remove:
1407 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001408 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001409 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001410exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001411 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001412exit:
1413 return err;
1414}
1415
David Hubbard1ea6dd32007-06-24 11:16:15 +02001416static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001417{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001418 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001419
Tony Jones1beeffe2007-08-20 13:46:20 -07001420 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001421 w83627ehf_device_remove_files(&pdev->dev);
1422 release_region(data->addr, IOREGION_LENGTH);
1423 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001424 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001425
1426 return 0;
1427}
1428
David Hubbard1ea6dd32007-06-24 11:16:15 +02001429static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001430 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001431 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001432 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001433 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001434 .probe = w83627ehf_probe,
1435 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001436};
1437
David Hubbard1ea6dd32007-06-24 11:16:15 +02001438/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1439static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1440 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001441{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001442 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1443 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1444 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
1445
Jean Delvare08e7e272005-04-25 22:43:25 +02001446 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001447 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001448
David Hubbard1ea6dd32007-06-24 11:16:15 +02001449 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001450
Jean Delvare67b671b2007-12-06 23:13:42 +01001451 if (force_id)
1452 val = force_id;
1453 else
1454 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1455 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001456 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001457 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001458 sio_data->kind = w83627ehf;
1459 sio_name = sio_name_W83627EHF;
1460 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001461 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001462 sio_data->kind = w83627ehf;
1463 sio_name = sio_name_W83627EHG;
1464 break;
1465 case SIO_W83627DHG_ID:
1466 sio_data->kind = w83627dhg;
1467 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001468 break;
1469 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001470 if (val != 0xffff)
1471 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1472 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001473 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001474 return -ENODEV;
1475 }
1476
David Hubbard1ea6dd32007-06-24 11:16:15 +02001477 /* We have a known chip, find the HWM I/O address */
1478 superio_select(sioaddr, W83627EHF_LD_HWM);
1479 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1480 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001481 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001482 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001483 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1484 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001485 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001486 return -ENODEV;
1487 }
1488
1489 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001490 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001491 if (!(val & 0x01)) {
1492 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1493 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001494 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001495 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001496
David Hubbard1ea6dd32007-06-24 11:16:15 +02001497 superio_exit(sioaddr);
1498 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1499 sio_data->sioreg = sioaddr;
1500
Jean Delvare08e7e272005-04-25 22:43:25 +02001501 return 0;
1502}
1503
David Hubbard1ea6dd32007-06-24 11:16:15 +02001504/* when Super-I/O functions move to a separate file, the Super-I/O
1505 * bus will manage the lifetime of the device and this module will only keep
1506 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1507 * must keep track of the device */
1508static struct platform_device *pdev;
1509
Jean Delvare08e7e272005-04-25 22:43:25 +02001510static int __init sensors_w83627ehf_init(void)
1511{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001512 int err;
1513 unsigned short address;
1514 struct resource res;
1515 struct w83627ehf_sio_data sio_data;
1516
1517 /* initialize sio_data->kind and sio_data->sioreg.
1518 *
1519 * when Super-I/O functions move to a separate file, the Super-I/O
1520 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1521 * w83627ehf hardware monitor, and call probe() */
1522 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1523 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001524 return -ENODEV;
1525
David Hubbard1ea6dd32007-06-24 11:16:15 +02001526 err = platform_driver_register(&w83627ehf_driver);
1527 if (err)
1528 goto exit;
1529
1530 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1531 err = -ENOMEM;
1532 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1533 goto exit_unregister;
1534 }
1535
1536 err = platform_device_add_data(pdev, &sio_data,
1537 sizeof(struct w83627ehf_sio_data));
1538 if (err) {
1539 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1540 goto exit_device_put;
1541 }
1542
1543 memset(&res, 0, sizeof(res));
1544 res.name = DRVNAME;
1545 res.start = address + IOREGION_OFFSET;
1546 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1547 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001548
1549 err = acpi_check_resource_conflict(&res);
1550 if (err)
1551 goto exit;
1552
David Hubbard1ea6dd32007-06-24 11:16:15 +02001553 err = platform_device_add_resources(pdev, &res, 1);
1554 if (err) {
1555 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1556 "(%d)\n", err);
1557 goto exit_device_put;
1558 }
1559
1560 /* platform_device_add calls probe() */
1561 err = platform_device_add(pdev);
1562 if (err) {
1563 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1564 err);
1565 goto exit_device_put;
1566 }
1567
1568 return 0;
1569
1570exit_device_put:
1571 platform_device_put(pdev);
1572exit_unregister:
1573 platform_driver_unregister(&w83627ehf_driver);
1574exit:
1575 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001576}
1577
1578static void __exit sensors_w83627ehf_exit(void)
1579{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001580 platform_device_unregister(pdev);
1581 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001582}
1583
1584MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1585MODULE_DESCRIPTION("W83627EHF driver");
1586MODULE_LICENSE("GPL");
1587
1588module_init(sensors_w83627ehf_init);
1589module_exit(sensors_w83627ehf_exit);