w83627hf.c revision df48ed804f44a040e990976b537efc1e133c74d8
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                monitoring
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Philip Edelbrock <phil@netroedge.com>,
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    and Mark Studebaker <mdsxyz123@yahoo.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
8787c72b107888805981faf148c8fea96a752d22eJean Delvare    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Supports following chips:
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)
32c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare    w83687thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    For other winbond chips, and for i2c support in the above chips,
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    use w83781d.c.
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Note: automatic ("cruise") fan control for 697, 637 & 627thf not
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    supported yet.
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h>
46787c72b107888805981faf148c8fea96a752d22eJean Delvare#include <linux/platform_device.h>
47943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
4807584c762541672e35735b52af031183ca17a5a2Jim Cromie#include <linux/hwmon-sysfs.h>
49303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h>
50943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
519a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
52d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare#include <linux/ioport.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "lm75.h"
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic struct platform_device *pdev;
57d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
58d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare#define DRVNAME "w83627hf"
59d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvareenum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
60d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the base address of the sensors");
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 force_i2c = 0x1f;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_i2c, byte, 0);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_i2c,
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the i2c address of the sensors");
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
702251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvarestatic int reset;
712251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvaremodule_param(reset, bool, 0);
722251cf1a4b37bd483501614c2d78f5b8286f20d7Jean DelvareMODULE_PARM_DESC(reset, "Set to one to reset chip on load");
732251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, bool, 0);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* modified from kernel/include/traps.c */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int REG;		/* The register to read/write */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEV	0x07	/* Register: Logical device select */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int VAL;		/* The value to read/write */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* logical device numbers for superio_select (below) */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_FDC		0x00
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_PRT		0x01
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART1	0x02
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART2	0x03
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_KBC		0x05
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_CIR		0x06 /* w83627hf only */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GAME	0x07
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_MIDI	0x07
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO1	0x07
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO2	0x08
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO3	0x09
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_ACPI	0x0a
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_HWM		0x0b
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEVID	0x20	/* Register: Device ID */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
106c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_EN	0x29 /* w83687thf only */
107c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
108c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
109c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_outb(int reg, int val)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(val, VAL);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_inb(int reg)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return inb(VAL);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_select(int ld)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(DEV, REG);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ld, VAL);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_enter(void)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_exit(void)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xAA, REG);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627_DEVID 0x52
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627THF_DEVID 0x82
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W697_DEVID 0x60
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W637_DEVID 0x70
148c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W687THF_DEVID 0x85
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_ACT_REG 0x30
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_BASE_REG 0x60
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Constants specified below */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Alignment of the base address */
154ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_ALIGNMENT		~7
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Offset & size of I/O region we are interested in */
157ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_OFFSET	5
158ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_SIZE	2
159ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec
160787c72b107888805981faf148c8fea96a752d22eJean Delvare/* Where are the sensors address/data registers relative to the region offset */
161787c72b107888805981faf148c8fea96a752d22eJean Delvare#define W83781D_ADDR_REG_OFFSET 0
162787c72b107888805981faf148c8fea96a752d22eJean Delvare#define W83781D_DATA_REG_OFFSET 1
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83781D registers */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83782D registers for nr=7,8 are in bank 5 */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x554 + (((nr) - 7) * 2)))
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x555 + (((nr) - 7) * 2)))
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x550 + (nr) - 7))
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN(nr) (0x27 + (nr))
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
176df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie#define W83627HF_REG_TEMP2_CONFIG 0x152
177df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie#define W83627HF_REG_TEMP3_CONFIG 0x252
178df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie/* these are zero-based, unlike config constants above */
179df48ed804f44a040e990976b537efc1e133c74d8Jim Cromiestatic const u16 w83627hf_reg_temp[]		= { 0x27, 0x150, 0x250 };
180df48ed804f44a040e990976b537efc1e133c74d8Jim Cromiestatic const u16 w83627hf_reg_temp_hyst[]	= { 0x3A, 0x153, 0x253 };
181df48ed804f44a040e990976b537efc1e133c74d8Jim Cromiestatic const u16 w83627hf_reg_temp_over[]	= { 0x39, 0x155, 0x255 };
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BANK 0x4E
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CONFIG 0x40
1864a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM1 0x459
1874a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM2 0x45A
1884a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM3 0x45B
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_CONFIG 0x4D
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS1 0x56
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS2 0x57
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS3 0x453
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VID_FANDIV 0x47
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPID 0x49
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_WCHIPID 0x58
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPMAN 0x4F
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_PIN 0x4B
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VBAT 0x5D
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM1 0x5A
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM2 0x5B
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM1		0x01	/* 697HF/637HF/687THF too */
208c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM2		0x03	/* 697HF/637HF/687THF too */
209c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM3		0x11	/* 637HF/687THF too */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF/687THF too */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                             W83627THF_REG_PWM3 };
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
21707584c762541672e35735b52af031183ca17a5a2Jim Cromie				    regpwm_627hf[nr] : regpwm[nr])
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83627HF_REG_PWM_FREQ		0x5C	/* Only for the 627HF */
2201550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2211550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ1		0x00	/* 697HF/687THF too */
2221550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ2		0x02	/* 697HF/687THF too */
2231550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ3		0x10	/* 687THF too */
2241550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2251550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
2261550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					W83637HF_REG_PWM_FREQ2,
2271550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					W83637HF_REG_PWM_FREQ3 };
2281550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2291550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83627HF_BASE_PWM_FREQ	46870
2301550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_ADDR 0x48
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_SUBADDR 0x4A
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sensor selection */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG1 0x5D
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG2 0x59
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DEFAULT_BETA 3435
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Conversions. Limit checking is only done on the TO_REG
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   variants. Note that you should be a bit careful with which arguments
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   these macros are called: arguments may be evaluated more than once.
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Fixing this is just not worth it. */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) * 16)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm == 0)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     254);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MIN (-128000)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MAX ( 127000)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMP: 0.001C/bit (-128C to +127C)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 1C/bit, two's complement */
2625bfedac045082a97e20d47d876071279ef984d28Christian Hohnstaedtstatic u8 TEMP_TO_REG(long temp)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ntemp += (ntemp<0 ? -500 : 500);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (u8)(ntemp / 1000);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TEMP_FROM_REG(u8 reg)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (s8)reg * 1000;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
2791550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
2801550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	unsigned long freq;
2811550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	freq = W83627HF_BASE_PWM_FREQ >> reg;
2821550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return freq;
2831550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
2841550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline u8 pwm_freq_to_reg_627hf(unsigned long val)
2851550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
2861550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u8 i;
2871550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Only 5 dividers (1 2 4 8 16)
2881550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	   Search for the nearest available frequency */
2891550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	for (i = 0; i < 4; i++) {
2901550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
2911550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			    (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
2921550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			break;
2931550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	}
2941550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return i;
2951550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
2961550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2971550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline unsigned long pwm_freq_from_reg(u8 reg)
2981550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
2991550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Clock bit 8 -> 180 kHz or 24 MHz */
3001550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
3011550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
3021550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	reg &= 0x7f;
3031550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* This should not happen but anyway... */
3041550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (reg == 0)
3051550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		reg++;
3061550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return (clock / (reg << 8));
3071550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
3081550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline u8 pwm_freq_to_reg(unsigned long val)
3091550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
3101550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Minimum divider value is 0x01 and maximum is 0x7F */
3111550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val >= 93750)	/* The highest we can do */
3121550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return 0x01;
3131550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val >= 720)	/* Use 24 MHz clock */
3141550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return (24000000UL / (val << 8));
3151550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val < 6)		/* The lowest we can do */
3161550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return 0xFF;
3171550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	else			/* Use 180 kHz clock */
3181550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return (0x80 | (180000UL / (val << 8)));
3191550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
3201550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_FROM_REG(val)		 (val)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_FROM_REG(val)	((val)?1:0)
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val))
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 DIV_TO_REG(long val)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = SENSORS_LIMIT(val, 1, 128) >> 1;
332abc01922477104e8d72b494902aff37135c409e7Grant Coady	for (i = 0; i < 7; i++) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val == 0)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val >>= 1;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ((u8) i);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
340ed6bafbf6017d6a007b39de6b65ad3b8ae4c8aeeJean Delvare/* For each registered chip, we need to keep some data in memory.
341ed6bafbf6017d6a007b39de6b65ad3b8ae4c8aeeJean Delvare   The structure is dynamically allocated. */
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct w83627hf_data {
343787c72b107888805981faf148c8fea96a752d22eJean Delvare	unsigned short addr;
344787c72b107888805981faf148c8fea96a752d22eJean Delvare	const char *name;
3451beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
3469a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex lock;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum chips type;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3499a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[9];		/* Register value */
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[9];		/* Register value */
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[9];		/* Register value */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[3];		/* Register value */
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[3];		/* Register value */
358df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 temp[3];		/* Register value */
359df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 temp_max[3];	/* Register value */
360df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 temp_max_hyst[3];	/* Register value */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_div[3];		/* Register encoding, shifted right */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid;			/* Register encoding, combined */
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 alarms;		/* Register encoding, combined */
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 beep_mask;		/* Register encoding, combined */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 beep_enable;		/* Boolean */
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwm[3];		/* Register value */
3671550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u8 pwm_freq[3];		/* Register value */
368b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare	u16 sens[3];		/* 1 = pentium diode; 2 = 3904 diode;
369b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare				   4 = thermistor */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm;
371c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
374787c72b107888805981faf148c8fea96a752d22eJean Delvarestruct w83627hf_sio_data {
375787c72b107888805981faf148c8fea96a752d22eJean Delvare	enum chips type;
376787c72b107888805981faf148c8fea96a752d22eJean Delvare};
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
379787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_probe(struct platform_device *pdev);
380d0546128980c18748010c758903b02909e634830Jean Delvarestatic int __devexit w83627hf_remove(struct platform_device *pdev);
381787c72b107888805981faf148c8fea96a752d22eJean Delvare
382787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
383787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
384c09c5184a26158da32801e89d5849d774605f0ddJean Delvarestatic void w83627hf_update_fan_div(struct w83627hf_data *data);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev);
386787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic void w83627hf_init_device(struct platform_device *pdev);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
388787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic struct platform_driver w83627hf_driver = {
389cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	.driver = {
390872188420997f7f7c1b968fd9bce6578e4c3d45fJean Delvare		.owner	= THIS_MODULE,
391d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		.name	= DRVNAME,
392cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	},
393787c72b107888805981faf148c8fea96a752d22eJean Delvare	.probe		= w83627hf_probe,
394787c72b107888805981faf148c8fea96a752d22eJean Delvare	.remove		= __devexit_p(w83627hf_remove),
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
39807584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
39907584c762541672e35735b52af031183ca17a5a2Jim Cromie{
40007584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
40107584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
40207584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40407584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
40507584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
40607584c762541672e35735b52af031183ca17a5a2Jim Cromie{
40707584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
40807584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
40907584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
41007584c762541672e35735b52af031183ca17a5a2Jim Cromie}
41107584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
41207584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
41307584c762541672e35735b52af031183ca17a5a2Jim Cromie{
41407584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
41507584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
41607584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41807584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
41907584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_in_min(struct device *dev, struct device_attribute *devattr,
42007584c762541672e35735b52af031183ca17a5a2Jim Cromie	     const char *buf, size_t count)
42107584c762541672e35735b52af031183ca17a5a2Jim Cromie{
42207584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
42307584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = dev_get_drvdata(dev);
42407584c762541672e35735b52af031183ca17a5a2Jim Cromie	long val = simple_strtol(buf, NULL, 10);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42607584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_lock(&data->update_lock);
42707584c762541672e35735b52af031183ca17a5a2Jim Cromie	data->in_min[nr] = IN_TO_REG(val);
42807584c762541672e35735b52af031183ca17a5a2Jim Cromie	w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
42907584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_unlock(&data->update_lock);
43007584c762541672e35735b52af031183ca17a5a2Jim Cromie	return count;
43107584c762541672e35735b52af031183ca17a5a2Jim Cromie}
43207584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
43307584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_in_max(struct device *dev, struct device_attribute *devattr,
43407584c762541672e35735b52af031183ca17a5a2Jim Cromie	     const char *buf, size_t count)
43507584c762541672e35735b52af031183ca17a5a2Jim Cromie{
43607584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
43707584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = dev_get_drvdata(dev);
43807584c762541672e35735b52af031183ca17a5a2Jim Cromie	long val = simple_strtol(buf, NULL, 10);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44007584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_lock(&data->update_lock);
44107584c762541672e35735b52af031183ca17a5a2Jim Cromie	data->in_max[nr] = IN_TO_REG(val);
44207584c762541672e35735b52af031183ca17a5a2Jim Cromie	w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
44307584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_unlock(&data->update_lock);
44407584c762541672e35735b52af031183ca17a5a2Jim Cromie	return count;
44507584c762541672e35735b52af031183ca17a5a2Jim Cromie}
44607584c762541672e35735b52af031183ca17a5a2Jim Cromie#define sysfs_vin_decl(offset) \
44707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
44807584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_in_input, NULL, offset);		\
44907584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR,	\
45007584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_in_min, store_in_min, offset);	\
45107584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR,	\
45207584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_in_max, store_in_max, offset);
45307584c762541672e35735b52af031183ca17a5a2Jim Cromie
45407584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(1);
45507584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(2);
45607584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(3);
45707584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(4);
45807584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(5);
45907584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(6);
46007584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(7);
46107584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_vin_decl(8);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* use a different set of functions for in0 */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long in0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
469c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
470c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)((reg * 488 + 70000 + 50) / 100);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)IN_FROM_REG(reg);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", in0);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in[0]);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
487a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_min[0]);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_max[0]);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
499a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
502787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5079a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
510c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
511c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
5142723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_min[0] =
5152723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
5162723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_min[0] = IN_TO_REG(val);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
5229a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
526a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
529787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5349a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
537c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
538c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
5412723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_max[0] =
5422723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
5432723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_max[0] = IN_TO_REG(val);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
548787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
5499a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_min0, store_regs_in_min0);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_max0, store_regs_in_max0);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55907584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
56007584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
56107584c762541672e35735b52af031183ca17a5a2Jim Cromie{
56207584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
56307584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
56407584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
56507584c762541672e35735b52af031183ca17a5a2Jim Cromie				(long)DIV_FROM_REG(data->fan_div[nr])));
56607584c762541672e35735b52af031183ca17a5a2Jim Cromie}
56707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
56807584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
56907584c762541672e35735b52af031183ca17a5a2Jim Cromie{
57007584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
57107584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
57207584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
57307584c762541672e35735b52af031183ca17a5a2Jim Cromie				(long)DIV_FROM_REG(data->fan_div[nr])));
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
57607584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_fan_min(struct device *dev, struct device_attribute *devattr,
57707584c762541672e35735b52af031183ca17a5a2Jim Cromie	      const char *buf, size_t count)
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
57907584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
580787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
58107584c762541672e35735b52af031183ca17a5a2Jim Cromie	u32 val = simple_strtoul(buf, NULL, 10);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5839a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
58407584c762541672e35735b52af031183ca17a5a2Jim Cromie	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
58507584c762541672e35735b52af031183ca17a5a2Jim Cromie	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
58607584c762541672e35735b52af031183ca17a5a2Jim Cromie			     data->fan_min[nr]);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5889a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
59107584c762541672e35735b52af031183ca17a5a2Jim Cromie#define sysfs_fan_decl(offset)	\
59207584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
59307584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_fan_input, NULL, offset - 1);		\
59407584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
59507584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_fan_min, store_fan_min, offset - 1);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59707584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_fan_decl(1);
59807584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_fan_decl(2);
59907584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_fan_decl(3);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60107584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
60207584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_temp(struct device *dev, struct device_attribute *devattr, char *buf)
60307584c762541672e35735b52af031183ca17a5a2Jim Cromie{
60407584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
60507584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
606df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie
607df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 tmp = data->temp[nr];
608df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
609df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie					  : (long) TEMP_FROM_REG(tmp));
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61207584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
61307584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_temp_max(struct device *dev, struct device_attribute *devattr,
61407584c762541672e35735b52af031183ca17a5a2Jim Cromie	      char *buf)
61507584c762541672e35735b52af031183ca17a5a2Jim Cromie{
61607584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
61707584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
618df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie
619df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 tmp = data->temp_max[nr];
620df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
621df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie					  : (long) TEMP_FROM_REG(tmp));
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62407584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
62507584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
62607584c762541672e35735b52af031183ca17a5a2Jim Cromie		   char *buf)
62707584c762541672e35735b52af031183ca17a5a2Jim Cromie{
62807584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
62907584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = w83627hf_update_device(dev);
630df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie
631df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 tmp = data->temp_max_hyst[nr];
632df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
633df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie					  : (long) TEMP_FROM_REG(tmp));
63407584c762541672e35735b52af031183ca17a5a2Jim Cromie}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63607584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
63707584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_temp_max(struct device *dev, struct device_attribute *devattr,
63807584c762541672e35735b52af031183ca17a5a2Jim Cromie	       const char *buf, size_t count)
63907584c762541672e35735b52af031183ca17a5a2Jim Cromie{
64007584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
64107584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = dev_get_drvdata(dev);
64207584c762541672e35735b52af031183ca17a5a2Jim Cromie	long val = simple_strtol(buf, NULL, 10);
643df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64507584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_lock(&data->update_lock);
646df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	data->temp_max[nr] = tmp;
647df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
64807584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_unlock(&data->update_lock);
64907584c762541672e35735b52af031183ca17a5a2Jim Cromie	return count;
65007584c762541672e35735b52af031183ca17a5a2Jim Cromie}
65107584c762541672e35735b52af031183ca17a5a2Jim Cromie
65207584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
65307584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
65407584c762541672e35735b52af031183ca17a5a2Jim Cromie		    const char *buf, size_t count)
65507584c762541672e35735b52af031183ca17a5a2Jim Cromie{
65607584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
65707584c762541672e35735b52af031183ca17a5a2Jim Cromie	struct w83627hf_data *data = dev_get_drvdata(dev);
65807584c762541672e35735b52af031183ca17a5a2Jim Cromie	long val = simple_strtol(buf, NULL, 10);
659df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
66007584c762541672e35735b52af031183ca17a5a2Jim Cromie
66107584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_lock(&data->update_lock);
662df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	data->temp_max_hyst[nr] = tmp;
663df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
66407584c762541672e35735b52af031183ca17a5a2Jim Cromie	mutex_unlock(&data->update_lock);
66507584c762541672e35735b52af031183ca17a5a2Jim Cromie	return count;
66607584c762541672e35735b52af031183ca17a5a2Jim Cromie}
66707584c762541672e35735b52af031183ca17a5a2Jim Cromie
66807584c762541672e35735b52af031183ca17a5a2Jim Cromie#define sysfs_temp_decl(offset) \
66907584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
670df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			  show_temp, NULL, offset - 1);			\
67107584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR,	 	\
672df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			  show_temp_max, store_temp_max, offset - 1);	\
67307584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR,	\
674df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			  show_temp_max_hyst, store_temp_max_hyst, offset - 1);
67507584c762541672e35735b52af031183ca17a5a2Jim Cromie
67607584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_decl(1);
67707584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_decl(2);
67807584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_decl(3);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
681a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
689a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69190d6619a916062cb75a176aacb318d108758b4a5Jean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->vrm);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
695a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
697787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->vrm = val;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
708a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->alarms);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_beep_reg(REG, reg) \
716a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", \
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(ENABLE, enable)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(MASK, mask)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE			0	/* Store beep_enable */
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK			1	/* Store beep_mask */
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_beep_reg(struct device *dev, const char *buf, size_t count,
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       int update_mask)
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
732787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, val2;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7379a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = BEEP_MASK_TO_REG(val);
741787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    data->beep_mask & 0xff);
743787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((data->beep_mask) >> 16) & 0xff);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = (data->beep_mask >> 8) & 0x7f;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {		/* We are storing beep_enable */
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 =
748787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = BEEP_ENABLE_TO_REG(val);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
752787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    val2 | data->beep_enable << 7);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7559a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_beep(REG, reg) \
760a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
762a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannou	return show_beep_##reg(dev, attr, buf); \
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
765a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_beep_reg(dev, buf, count, BEEP_##REG); \
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_beep_##reg, store_regs_beep_##reg);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(ENABLE, enable);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(MASK, mask);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
77607584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
77807584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n",
78107584c762541672e35735b52af031183ca17a5a2Jim Cromie		       (long) DIV_FROM_REG(data->fan_div[nr]));
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we save and restore the fan minimum here, because its value is
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined in part by the fan divisor.  This follows the principle of
785d6e05edc59ecd79e8badf440c0d295a979bdfa3eAndreas Mohr   least surprise; the user doesn't expect the fan minimum to change just
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   because the divisor changed. */
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
78807584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_fan_div(struct device *dev, struct device_attribute *devattr,
78907584c762541672e35735b52af031183ca17a5a2Jim Cromie	      const char *buf, size_t count)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
79107584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
792787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long min;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 reg;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7979a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save fan_min */
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	min = FAN_FROM_REG(data->fan_min[nr],
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   DIV_FROM_REG(data->fan_div[nr]));
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_div[nr] = DIV_TO_REG(val);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
805787c72b107888805981faf148c8fea96a752d22eJean Delvare	reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & (nr==0 ? 0xcf : 0x3f))
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
808787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
810787c72b107888805981faf148c8fea96a752d22eJean Delvare	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & ~(1 << (5 + nr)))
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
813787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore fan_min */
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
817787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8199a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82307584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
82407584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_fan_div, store_fan_div, 0);
82507584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
82607584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_fan_div, store_fan_div, 1);
82707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
82807584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_fan_div, store_fan_div, 2);
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
83107584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
83307584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
83507584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
83907584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_pwm(struct device *dev, struct device_attribute *devattr,
84007584c762541672e35735b52af031183ca17a5a2Jim Cromie	  const char *buf, size_t count)
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
84207584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
843787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
84407584c762541672e35735b52af031183ca17a5a2Jim Cromie	u32 val = simple_strtoul(buf, NULL, 10);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8469a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->type == w83627thf) {
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bits 0-3 are reserved  in 627THF */
85007584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
851787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data,
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
85307584c762541672e35735b52af031183ca17a5a2Jim Cromie				     data->pwm[nr] |
854787c72b107888805981faf148c8fea96a752d22eJean Delvare				     (w83627hf_read_value(data,
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
85707584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->pwm[nr] = PWM_TO_REG(val);
858787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data,
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
86007584c762541672e35735b52af031183ca17a5a2Jim Cromie				     data->pwm[nr]);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8639a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
86707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
86807584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
86907584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
87207584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
8731550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
87407584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
8751550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	struct w83627hf_data *data = w83627hf_update_device(dev);
8761550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83627hf)
8771550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return sprintf(buf, "%ld\n",
87807584c762541672e35735b52af031183ca17a5a2Jim Cromie			pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
8791550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	else
8801550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return sprintf(buf, "%ld\n",
88107584c762541672e35735b52af031183ca17a5a2Jim Cromie			pwm_freq_from_reg(data->pwm_freq[nr]));
8821550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
8831550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
8841550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t
88507584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_pwm_freq(struct device *dev, struct device_attribute *devattr,
88607584c762541672e35735b52af031183ca17a5a2Jim Cromie	       const char *buf, size_t count)
8871550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
88807584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
8891550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	struct w83627hf_data *data = dev_get_drvdata(dev);
8901550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	static const u8 mask[]={0xF8, 0x8F};
8911550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u32 val;
8921550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
8931550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	val = simple_strtoul(buf, NULL, 10);
8941550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
8951550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	mutex_lock(&data->update_lock);
8961550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
8971550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83627hf) {
89807584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
8991550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
90007584c762541672e35735b52af031183ca17a5a2Jim Cromie				(data->pwm_freq[nr] << (nr*4)) |
9011550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				(w83627hf_read_value(data,
90207584c762541672e35735b52af031183ca17a5a2Jim Cromie				W83627HF_REG_PWM_FREQ) & mask[nr]));
9031550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	} else {
90407584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->pwm_freq[nr] = pwm_freq_to_reg(val);
90507584c762541672e35735b52af031183ca17a5a2Jim Cromie		w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
90607584c762541672e35735b52af031183ca17a5a2Jim Cromie				data->pwm_freq[nr]);
9071550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	}
9081550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9091550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	mutex_unlock(&data->update_lock);
9101550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return count;
9111550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
9121550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
91307584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
91407584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_pwm_freq, store_pwm_freq, 0);
91507584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
91607584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_pwm_freq, store_pwm_freq, 1);
91707584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
91807584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_pwm_freq, store_pwm_freq, 2);
9191550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9201550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t
92107584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_temp_type(struct device *dev, struct device_attribute *devattr,
92207584c762541672e35735b52af031183ca17a5a2Jim Cromie	       char *buf)
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
92407584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
92607584c762541672e35735b52af031183ca17a5a2Jim Cromie	return sprintf(buf, "%ld\n", (long) data->sens[nr]);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
93007584c762541672e35735b52af031183ca17a5a2Jim Cromiestore_temp_type(struct device *dev, struct device_attribute *devattr,
93107584c762541672e35735b52af031183ca17a5a2Jim Cromie		const char *buf, size_t count)
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
93307584c762541672e35735b52af031183ca17a5a2Jim Cromie	int nr = to_sensor_dev_attr(devattr)->index;
934787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, tmp;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9399a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* PII/Celeron diode */
943787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
944787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
94507584c762541672e35735b52af031183ca17a5a2Jim Cromie				    tmp | BIT_SCFG1[nr]);
946787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
947787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG2,
94807584c762541672e35735b52af031183ca17a5a2Jim Cromie				    tmp | BIT_SCFG2[nr]);
94907584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->sens[nr] = val;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* 3904 */
952787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
953787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
95407584c762541672e35735b52af031183ca17a5a2Jim Cromie				    tmp | BIT_SCFG1[nr]);
955787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
956787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG2,
95707584c762541672e35735b52af031183ca17a5a2Jim Cromie				    tmp & ~BIT_SCFG2[nr]);
95807584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->sens[nr] = val;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
960b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare	case W83781D_DEFAULT_BETA:
961b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare		dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
962b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare			 "instead\n", W83781D_DEFAULT_BETA);
963b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare		/* fall through */
964b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare	case 4:		/* thermistor */
965787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
966787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
96707584c762541672e35735b52af031183ca17a5a2Jim Cromie				    tmp & ~BIT_SCFG1[nr]);
96807584c762541672e35735b52af031183ca17a5a2Jim Cromie		data->sens[nr] = val;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
971787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_err(dev,
972b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare		       "Invalid sensor type %ld; must be 1, 2, or 4\n",
973b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare		       (long) val);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9779a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98107584c762541672e35735b52af031183ca17a5a2Jim Cromie#define sysfs_temp_type(offset) \
98207584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
98307584c762541672e35735b52af031183ca17a5a2Jim Cromie			  show_temp_type, store_temp_type, offset - 1);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98507584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_type(1);
98607584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_type(2);
98707584c762541672e35735b52af031183ca17a5a2Jim Cromiesysfs_temp_type(3);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98907584c762541672e35735b52af031183ca17a5a2Jim Cromiestatic ssize_t
99007584c762541672e35735b52af031183ca17a5a2Jim Cromieshow_name(struct device *dev, struct device_attribute *devattr, char *buf)
991787c72b107888805981faf148c8fea96a752d22eJean Delvare{
992787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
993787c72b107888805981faf148c8fea96a752d22eJean Delvare
994787c72b107888805981faf148c8fea96a752d22eJean Delvare	return sprintf(buf, "%s\n", data->name);
995787c72b107888805981faf148c8fea96a752d22eJean Delvare}
996787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
997787c72b107888805981faf148c8fea96a752d22eJean Delvare
998787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __init w83627hf_find(int sioaddr, unsigned short *addr,
999787c72b107888805981faf148c8fea96a752d22eJean Delvare				struct w83627hf_sio_data *sio_data)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	int err = -ENODEV;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 val;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1004787c72b107888805981faf148c8fea96a752d22eJean Delvare	static const __initdata char *names[] = {
1005787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83627HF",
1006787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83627THF",
1007787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83697HF",
1008787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83637HF",
1009787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83687THF",
1010787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1011787c72b107888805981faf148c8fea96a752d22eJean Delvare
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REG = sioaddr;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	VAL = sioaddr + 1;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val= superio_inb(DEVID);
1017787c72b107888805981faf148c8fea96a752d22eJean Delvare	switch (val) {
1018787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W627_DEVID:
1019787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83627hf;
1020787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1021787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W627THF_DEVID:
1022787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83627thf;
1023787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1024787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W697_DEVID:
1025787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83697hf;
1026787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1027787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W637_DEVID:
1028787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83637hf;
1029787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1030787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W687THF_DEVID:
1031787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83687thf;
1032787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1033e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare	case 0xff:	/* No device at all */
1034e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare		goto exit;
1035787c72b107888805981faf148c8fea96a752d22eJean Delvare	default:
1036e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
1037d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		goto exit;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_HWM);
1041d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	force_addr &= WINB_ALIGNMENT;
1042d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (force_addr) {
1043d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1044d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		       force_addr);
1045d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_BASE_REG, force_addr >> 8);
1046d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1047d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	}
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = (superio_inb(WINB_BASE_REG) << 8) |
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       superio_inb(WINB_BASE_REG + 1);
1050ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	*addr = val & WINB_ALIGNMENT;
1051d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (*addr == 0) {
1052d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Base address not set, "
1053d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		       "skipping\n");
1054d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		goto exit;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1057d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	val = superio_inb(WINB_ACT_REG);
1058d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (!(val & 0x01)) {
1059d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1060d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_ACT_REG, val | 0x01);
1061d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	}
1062d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
1063d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	err = 0;
1064787c72b107888805981faf148c8fea96a752d22eJean Delvare	pr_info(DRVNAME ": Found %s chip at %#x\n",
1065787c72b107888805981faf148c8fea96a752d22eJean Delvare		names[sio_data->type], *addr);
1066d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
1067d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare exit:
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
1069d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	return err;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107207584c762541672e35735b52af031183ca17a5a2Jim Cromie#define VIN_UNIT_ATTRS(_X_)	\
107307584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
107407584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
107507584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_in##_X_##_max.dev_attr.attr
107607584c762541672e35735b52af031183ca17a5a2Jim Cromie
107707584c762541672e35735b52af031183ca17a5a2Jim Cromie#define FAN_UNIT_ATTRS(_X_)	\
107807584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_fan##_X_##_input.dev_attr.attr,	\
107907584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_fan##_X_##_min.dev_attr.attr,		\
108007584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_fan##_X_##_div.dev_attr.attr
108107584c762541672e35735b52af031183ca17a5a2Jim Cromie
108207584c762541672e35735b52af031183ca17a5a2Jim Cromie#define TEMP_UNIT_ATTRS(_X_)	\
108307584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_temp##_X_##_input.dev_attr.attr,	\
108407584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_temp##_X_##_max.dev_attr.attr,		\
108507584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr,	\
108607584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_temp##_X_##_type.dev_attr.attr
108707584c762541672e35735b52af031183ca17a5a2Jim Cromie
1088c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *w83627hf_attributes[] = {
1089c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_input.attr,
1090c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_min.attr,
1091c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_max.attr,
109207584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(2),
109307584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(3),
109407584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(4),
109507584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(7),
109607584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(8),
109707584c762541672e35735b52af031183ca17a5a2Jim Cromie
109807584c762541672e35735b52af031183ca17a5a2Jim Cromie	FAN_UNIT_ATTRS(1),
109907584c762541672e35735b52af031183ca17a5a2Jim Cromie	FAN_UNIT_ATTRS(2),
110007584c762541672e35735b52af031183ca17a5a2Jim Cromie
110107584c762541672e35735b52af031183ca17a5a2Jim Cromie	TEMP_UNIT_ATTRS(1),
110207584c762541672e35735b52af031183ca17a5a2Jim Cromie	TEMP_UNIT_ATTRS(2),
1103c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1104c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_alarms.attr,
1105c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_beep_enable.attr,
1106c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_beep_mask.attr,
1107c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
110807584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm1.dev_attr.attr,
110907584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm2.dev_attr.attr,
1110787c72b107888805981faf148c8fea96a752d22eJean Delvare	&dev_attr_name.attr,
1111c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	NULL
1112c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1113c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1114c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group w83627hf_group = {
1115c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	.attrs = w83627hf_attributes,
1116c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1117c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1118c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *w83627hf_attributes_opt[] = {
111907584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(1),
112007584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(5),
112107584c762541672e35735b52af031183ca17a5a2Jim Cromie	VIN_UNIT_ATTRS(6),
112207584c762541672e35735b52af031183ca17a5a2Jim Cromie
112307584c762541672e35735b52af031183ca17a5a2Jim Cromie	FAN_UNIT_ATTRS(3),
112407584c762541672e35735b52af031183ca17a5a2Jim Cromie	TEMP_UNIT_ATTRS(3),
112507584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm3.dev_attr.attr,
112607584c762541672e35735b52af031183ca17a5a2Jim Cromie
112707584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
112807584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
112907584c762541672e35735b52af031183ca17a5a2Jim Cromie	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
1130c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	NULL
1131c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1132c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1133c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group w83627hf_group_opt = {
1134c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	.attrs = w83627hf_attributes_opt,
1135c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1136c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1137787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83627hf_probe(struct platform_device *pdev)
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1139787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct device *dev = &pdev->dev;
1140787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_sio_data *sio_data = dev->platform_data;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data;
1142787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource *res;
1143787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1145787c72b107888805981faf148c8fea96a752d22eJean Delvare	static const char *names[] = {
1146787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83627hf",
1147787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83627thf",
1148787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83697hf",
1149787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83637hf",
1150787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83687thf",
1151787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1152787c72b107888805981faf148c8fea96a752d22eJean Delvare
1153787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1154787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1155787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1156787c72b107888805981faf148c8fea96a752d22eJean Delvare			(unsigned long)res->start,
1157787c72b107888805981faf148c8fea96a752d22eJean Delvare			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBUSY;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR0;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1162ba9c2e8d15da029ea3051c95e446b2d638ef02e2Deepak Saxena	if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR1;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1166787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->addr = res->start;
1167787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->type = sio_data->type;
1168787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->name = names[sio_data->type];
11699a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->lock);
11709a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->update_lock);
1171787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_set_drvdata(pdev, data);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the chip */
1174787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_init_device(pdev);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A few vars need to be filled upon startup */
1177787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
1178787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
1179787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
1180c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	w83627hf_update_fan_div(data);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1182c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	/* Register common device attributes */
1183787c72b107888805981faf148c8fea96a752d22eJean Delvare	if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
1184943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman		goto ERROR3;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1186c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	/* Register chip-specific device attributes */
1187787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type == w83627hf || data->type == w83697hf)
118807584c762541672e35735b52af031183ca17a5a2Jim Cromie		if ((err = device_create_file(dev,
118907584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in5_input.dev_attr))
119007584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
119107584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in5_min.dev_attr))
119207584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
119307584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in5_max.dev_attr))
119407584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
119507584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in6_input.dev_attr))
119607584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
119707584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in6_min.dev_attr))
119807584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
119907584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in6_max.dev_attr))
120007584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
120107584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm1_freq.dev_attr))
120207584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
120307584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm2_freq.dev_attr)))
1204c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1206787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type != w83697hf)
120707584c762541672e35735b52af031183ca17a5a2Jim Cromie		if ((err = device_create_file(dev,
120807584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in1_input.dev_attr))
120907584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
121007584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in1_min.dev_attr))
121107584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
121207584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_in1_max.dev_attr))
121307584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
121407584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_fan3_input.dev_attr))
121507584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
121607584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_fan3_min.dev_attr))
121707584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
121807584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_fan3_div.dev_attr))
121907584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
122007584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_temp3_input.dev_attr))
122107584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
122207584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_temp3_max.dev_attr))
122307584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
122407584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_temp3_max_hyst.dev_attr))
122507584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
122607584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_temp3_type.dev_attr)))
1227c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
1228c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1229787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type != w83697hf && data->vid != 0xff) {
12308a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare		/* Convert VID to voltage based on VRM */
12318a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare		data->vrm = vid_which_vrm();
12328a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare
1233787c72b107888805981faf148c8fea96a752d22eJean Delvare		if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1234787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_vrm)))
1235c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12368a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare	}
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1238787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type == w83627thf || data->type == w83637hf
1239787c72b107888805981faf148c8fea96a752d22eJean Delvare	 || data->type == w83687thf)
124007584c762541672e35735b52af031183ca17a5a2Jim Cromie		if ((err = device_create_file(dev,
124107584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm3.dev_attr)))
1242c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83637hf || data->type == w83687thf)
124507584c762541672e35735b52af031183ca17a5a2Jim Cromie		if ((err = device_create_file(dev,
124607584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm1_freq.dev_attr))
124707584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
124807584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm2_freq.dev_attr))
124907584c762541672e35735b52af031183ca17a5a2Jim Cromie		 || (err = device_create_file(dev,
125007584c762541672e35735b52af031183ca17a5a2Jim Cromie				&sensor_dev_attr_pwm3_freq.dev_attr)))
12511550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			goto ERROR4;
12521550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
12531beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	data->hwmon_dev = hwmon_device_register(dev);
12541beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
12551beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
1256c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman		goto ERROR4;
1257c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	}
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman      ERROR4:
1262787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&dev->kobj, &w83627hf_group);
1263787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
1264943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman      ERROR3:
126504a6217df28e3004ba4e76eb0a356a30f72c564fJean Delvare	platform_set_drvdata(pdev, NULL);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR1:
1268787c72b107888805981faf148c8fea96a752d22eJean Delvare	release_region(res->start, WINB_REGION_SIZE);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR0:
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1273787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devexit w83627hf_remove(struct platform_device *pdev)
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1275787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = platform_get_drvdata(pdev);
1276787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource *res;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	hwmon_device_unregister(data->hwmon_dev);
1279943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
1280787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1281787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
128204a6217df28e3004ba4e76eb0a356a30f72c564fJean Delvare	platform_set_drvdata(pdev, NULL);
1283943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	kfree(data);
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1285787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1286787c72b107888805981faf148c8fea96a752d22eJean Delvare	release_region(res->start, WINB_REGION_SIZE);
1287787c72b107888805981faf148c8fea96a752d22eJean Delvare
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1292d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare/* Registers 0x50-0x5f are banked */
1293d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvarestatic inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
1294d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare{
1295d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	if ((reg & 0x00f0) == 0x50) {
1296d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1297d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare		outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
1298d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	}
1299d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare}
1300d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare
1301d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare/* Not strictly necessary, but play it safe for now */
1302d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvarestatic inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
1303d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare{
1304d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	if (reg & 0xff00) {
1305d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
1306d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
1307d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	}
1308d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare}
1309d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare
1310787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, word_sized;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13149a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x50)
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x53)
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
1320d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	w83627hf_set_bank(data, reg);
1321787c72b107888805981faf148c8fea96a752d22eJean Delvare	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1322787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
1325787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res =
1327787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (res << 8) + inb_p(data->addr +
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       W83781D_DATA_REG_OFFSET);
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1330d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	w83627hf_reset_bank(data, reg);
13319a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1335787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 0xff, sel;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_GPIO5);
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure these GPIO pins are enabled */
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
1344787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure the pins are configured for input
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
1350dd149c52223cfb05cdefb0755d3c2793e8d33edeYuan Mu	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sel & 0x1f) != 0x1f) {
1352787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"function\n");
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1357787c72b107888805981faf148c8fea96a752d22eJean Delvare	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = superio_inb(W83627THF_GPIO5_DR) & sel;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1365787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83687thf_read_vid(struct platform_device *pdev)
1366c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare{
1367c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	int res = 0xff;
1368c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1369c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_enter();
1370c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_select(W83627HF_LD_HWM);
1371c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1372c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	/* Make sure these GPIO pins are enabled */
1373c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
1374787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
1375c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		goto exit;
1376c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	}
1377c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1378c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	/* Make sure the pins are configured for input */
1379c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
1380787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "VID configured as output, "
1381c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare			"no VID function\n");
1382c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		goto exit;
1383c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	}
1384c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1385c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1386c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1387c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvareexit:
1388c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_exit();
1389c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	return res;
1390c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare}
1391c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1392787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int word_sized;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13969a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x53)
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
1401d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	w83627hf_set_bank(data, reg);
1402787c72b107888805981faf148c8fea96a752d22eJean Delvare	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(value >> 8,
1405787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_DATA_REG_OFFSET);
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
1407787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(value & 0xff,
1410787c72b107888805981faf148c8fea96a752d22eJean Delvare	       data->addr + W83781D_DATA_REG_OFFSET);
1411d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44Jean Delvare	w83627hf_reset_bank(data, reg);
14129a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1416787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic void __devinit w83627hf_init_device(struct platform_device *pdev)
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1418787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = platform_get_drvdata(pdev);
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1420d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	enum chips type = data->type;
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tmp;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14232251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare	if (reset) {
14242251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		/* Resetting the chip has been the default for a long time,
14252251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   but repeatedly caused problems (fans going to full
14262251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   speed...) so it is now optional. It might even go away if
14272251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   nobody reports it as being useful, as I see very little
14282251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   reason why this would be needed at all. */
1429787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_info(&pdev->dev, "If reset=1 solved a problem you were "
14302251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare			 "having, please report!\n");
14312251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save this register */
1433787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset all except Watchdog values and last conversion values
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This sets fan-divs to 2, among others */
1436787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Restore the register and disable power-on abnormal beep.
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This saves FAN 1/2/3 input/output values set by BIOS. */
1439787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable master beep-enable (reset turns it on).
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Individual beeps should be reset to off but for some reason
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   disabling this bit helps some people not get beeped */
1443787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Minimize conflicts with other winbond i2c-only clients...  */
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable i2c subclients... how to disable main i2c client?? */
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* force i2c address to relatively uncommon address */
1449787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1450787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VID only once */
1453d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (type == w83627hf || type == w83637hf) {
1454787c72b107888805981faf148c8fea96a752d22eJean Delvare		int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1455787c72b107888805981faf148c8fea96a752d22eJean Delvare		int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
1457d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	} else if (type == w83627thf) {
1458787c72b107888805981faf148c8fea96a752d22eJean Delvare		data->vid = w83627thf_read_gpio5(pdev);
1459d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	} else if (type == w83687thf) {
1460787c72b107888805981faf148c8fea96a752d22eJean Delvare		data->vid = w83687thf_read_vid(pdev);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VRM & OVT Config only once */
1464d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (type == w83627thf || type == w83637hf || type == w83687thf) {
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vrm_ovt =
1466787c72b107888805981faf148c8fea96a752d22eJean Delvare			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1469787c72b107888805981faf148c8fea96a752d22eJean Delvare	tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 3; i++) {
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(tmp & BIT_SCFG1[i - 1])) {
1472b26f93309282bdfebb3edb8939e022a4bbe56dfeJean Delvare			data->sens[i - 1] = 4;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (w83627hf_read_value
1475787c72b107888805981faf148c8fea96a752d22eJean Delvare			    (data,
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 1;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 2;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((type == w83697hf) && (i == 2))
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(init) {
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp2 */
1487df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp & 0x01) {
1489787c72b107888805981faf148c8fea96a752d22eJean Delvare			dev_warn(&pdev->dev, "Enabling temp2, readings "
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "might not make sense\n");
1491df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp & 0xfe);
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp3 */
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (type != w83697hf) {
1497787c72b107888805981faf148c8fea96a752d22eJean Delvare			tmp = w83627hf_read_value(data,
1498df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie				W83627HF_REG_TEMP3_CONFIG);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp & 0x01) {
1500787c72b107888805981faf148c8fea96a752d22eJean Delvare				dev_warn(&pdev->dev, "Enabling temp3, "
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "readings might not make sense\n");
1502787c72b107888805981faf148c8fea96a752d22eJean Delvare				w83627hf_write_value(data,
1503df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie					W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start monitoring */
1509787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_CONFIG,
1510787c72b107888805981faf148c8fea96a752d22eJean Delvare			    (w83627hf_read_value(data,
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						W83781D_REG_CONFIG) & 0xf7)
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    | 0x01);
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1515c09c5184a26158da32801e89d5849d774605f0ddJean Delvarestatic void w83627hf_update_fan_div(struct w83627hf_data *data)
1516c09c5184a26158da32801e89d5849d774605f0ddJean Delvare{
1517c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	int reg;
1518c09c5184a26158da32801e89d5849d774605f0ddJean Delvare
1519c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1520c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	data->fan_div[0] = (reg >> 4) & 0x03;
1521c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	data->fan_div[1] = (reg >> 6) & 0x03;
1522c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	if (data->type != w83697hf) {
1523c09c5184a26158da32801e89d5849d774605f0ddJean Delvare		data->fan_div[2] = (w83627hf_read_value(data,
1524c09c5184a26158da32801e89d5849d774605f0ddJean Delvare				       W83781D_REG_PIN) >> 6) & 0x03;
1525c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	}
1526c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	reg = w83627hf_read_value(data, W83781D_REG_VBAT);
1527c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	data->fan_div[0] |= (reg >> 3) & 0x04;
1528c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	data->fan_div[1] |= (reg >> 4) & 0x04;
1529c09c5184a26158da32801e89d5849d774605f0ddJean Delvare	if (data->type != w83697hf)
1530c09c5184a26158da32801e89d5849d774605f0ddJean Delvare		data->fan_div[2] |= (reg >> 5) & 0x04;
1531c09c5184a26158da32801e89d5849d774605f0ddJean Delvare}
1532c09c5184a26158da32801e89d5849d774605f0ddJean Delvare
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev)
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1535787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
1536df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie	int i, num_temps = (data->type == w83697hf) ? 2 : 3;
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15389a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || !data->valid) {
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 8; i++) {
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* skip missing sensors */
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((data->type == w83697hf) && (i == 1)) ||
1545c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare			    ((data->type != w83627hf && data->type != w83697hf)
15464a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu			    && (i == 5 || i == 6)))
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in[i] =
1549787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data, W83781D_REG_IN(i));
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_min[i] =
1551787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MIN(i));
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_max[i] =
1554787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MAX(i));
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 3; i++) {
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[i - 1] =
1559787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data, W83781D_REG_FAN(i));
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[i - 1] =
1561787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_FAN_MIN(i));
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
156407584c762541672e35735b52af031183ca17a5a2Jim Cromie		for (i = 0; i <= 2; i++) {
1565787c72b107888805981faf148c8fea96a752d22eJean Delvare			u8 tmp = w83627hf_read_value(data,
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W836X7HF_REG_PWM(data->type, i));
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			/* bits 0-3 are reserved  in 627THF */
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			if (data->type == w83627thf)
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp &= 0xf0;
157007584c762541672e35735b52af031183ca17a5a2Jim Cromie			data->pwm[i] = tmp;
157107584c762541672e35735b52af031183ca17a5a2Jim Cromie			if (i == 1 &&
157207584c762541672e35735b52af031183ca17a5a2Jim Cromie			    (data->type == w83627hf || data->type == w83697hf))
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15751550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		if (data->type == w83627hf) {
15761550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				u8 tmp = w83627hf_read_value(data,
15771550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez						W83627HF_REG_PWM_FREQ);
15781550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[0] = tmp & 0x07;
15791550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[1] = (tmp >> 4) & 0x07;
15801550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		} else if (data->type != w83627thf) {
15811550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			for (i = 1; i <= 3; i++) {
15821550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[i - 1] =
15831550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					w83627hf_read_value(data,
15841550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez						W83637HF_REG_PWM_FREQ[i - 1]);
15851550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				if (i == 2 && (data->type == w83697hf))
15861550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					break;
15871550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			}
15881550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		}
1589df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie		for (i = 0; i < num_temps; i++) {
1590df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			data->temp[i] = w83627hf_read_value(
1591df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie						data, w83627hf_reg_temp[i]);
1592df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			data->temp_max[i] = w83627hf_read_value(
1593df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie						data, w83627hf_reg_temp_over[i]);
1594df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie			data->temp_max_hyst[i] = w83627hf_read_value(
1595df48ed804f44a040e990976b537efc1e133c74d8Jim Cromie						data, w83627hf_reg_temp_hyst[i]);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1598c09c5184a26158da32801e89d5849d774605f0ddJean Delvare		w83627hf_update_fan_div(data);
1599c09c5184a26158da32801e89d5849d774605f0ddJean Delvare
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->alarms =
1601787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_ALARM1) |
1602787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1603787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1604787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = i >> 7;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = ((i & 0x7f) << 8) |
1607787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1608787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16139a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1618787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __init w83627hf_device_add(unsigned short address,
1619787c72b107888805981faf148c8fea96a752d22eJean Delvare				      const struct w83627hf_sio_data *sio_data)
1620787c72b107888805981faf148c8fea96a752d22eJean Delvare{
1621787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource res = {
1622787c72b107888805981faf148c8fea96a752d22eJean Delvare		.start	= address + WINB_REGION_OFFSET,
1623787c72b107888805981faf148c8fea96a752d22eJean Delvare		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1624787c72b107888805981faf148c8fea96a752d22eJean Delvare		.name	= DRVNAME,
1625787c72b107888805981faf148c8fea96a752d22eJean Delvare		.flags	= IORESOURCE_IO,
1626787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1627787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
1628787c72b107888805981faf148c8fea96a752d22eJean Delvare
1629787c72b107888805981faf148c8fea96a752d22eJean Delvare	pdev = platform_device_alloc(DRVNAME, address);
1630787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (!pdev) {
1631787c72b107888805981faf148c8fea96a752d22eJean Delvare		err = -ENOMEM;
1632787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1633787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit;
1634787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1635787c72b107888805981faf148c8fea96a752d22eJean Delvare
1636787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_device_add_resources(pdev, &res, 1);
1637787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err) {
1638787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device resource addition failed "
1639787c72b107888805981faf148c8fea96a752d22eJean Delvare		       "(%d)\n", err);
1640787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1641787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1642787c72b107888805981faf148c8fea96a752d22eJean Delvare
16432df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare	err = platform_device_add_data(pdev, sio_data,
16442df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare				       sizeof(struct w83627hf_sio_data));
16452df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare	if (err) {
1646787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1647787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1648787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1649787c72b107888805981faf148c8fea96a752d22eJean Delvare
1650787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_device_add(pdev);
1651787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err) {
1652787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1653787c72b107888805981faf148c8fea96a752d22eJean Delvare		       err);
1654787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1655787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1656787c72b107888805981faf148c8fea96a752d22eJean Delvare
1657787c72b107888805981faf148c8fea96a752d22eJean Delvare	return 0;
1658787c72b107888805981faf148c8fea96a752d22eJean Delvare
1659787c72b107888805981faf148c8fea96a752d22eJean Delvareexit_device_put:
1660787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_device_put(pdev);
1661787c72b107888805981faf148c8fea96a752d22eJean Delvareexit:
1662787c72b107888805981faf148c8fea96a752d22eJean Delvare	return err;
1663787c72b107888805981faf148c8fea96a752d22eJean Delvare}
1664787c72b107888805981faf148c8fea96a752d22eJean Delvare
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sensors_w83627hf_init(void)
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1667787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
1668787c72b107888805981faf148c8fea96a752d22eJean Delvare	unsigned short address;
1669787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_sio_data sio_data;
1670787c72b107888805981faf148c8fea96a752d22eJean Delvare
1671787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (w83627hf_find(0x2e, &address, &sio_data)
1672787c72b107888805981faf148c8fea96a752d22eJean Delvare	 && w83627hf_find(0x4e, &address, &sio_data))
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1675787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_driver_register(&w83627hf_driver);
1676787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err)
1677787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit;
1678787c72b107888805981faf148c8fea96a752d22eJean Delvare
1679787c72b107888805981faf148c8fea96a752d22eJean Delvare	/* Sets global pdev as a side effect */
1680787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = w83627hf_device_add(address, &sio_data);
1681787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err)
1682787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_driver;
1683787c72b107888805981faf148c8fea96a752d22eJean Delvare
1684787c72b107888805981faf148c8fea96a752d22eJean Delvare	return 0;
1685787c72b107888805981faf148c8fea96a752d22eJean Delvare
1686787c72b107888805981faf148c8fea96a752d22eJean Delvareexit_driver:
1687787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_driver_unregister(&w83627hf_driver);
1688787c72b107888805981faf148c8fea96a752d22eJean Delvareexit:
1689787c72b107888805981faf148c8fea96a752d22eJean Delvare	return err;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sensors_w83627hf_exit(void)
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1694787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_device_unregister(pdev);
1695787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_driver_unregister(&w83627hf_driver);
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "Philip Edelbrock <phil@netroedge.com>, "
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("W83627HF driver");
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sensors_w83627hf_init);
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sensors_w83627hf_exit);
1706