w83627hf.c revision 1550cb6d7e78c7cfdd7b48bee6809795d43d6a33
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>
48303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h>
49943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
509a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
51d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare#include <linux/ioport.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "lm75.h"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic struct platform_device *pdev;
56d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
57d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare#define DRVNAME "w83627hf"
58d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvareenum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
59d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the base address of the sensors");
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 force_i2c = 0x1f;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_i2c, byte, 0);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_i2c,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the i2c address of the sensors");
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
692251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvarestatic int reset;
702251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvaremodule_param(reset, bool, 0);
712251cf1a4b37bd483501614c2d78f5b8286f20d7Jean DelvareMODULE_PARM_DESC(reset, "Set to one to reset chip on load");
722251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, bool, 0);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* modified from kernel/include/traps.c */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int REG;		/* The register to read/write */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEV	0x07	/* Register: Logical device select */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int VAL;		/* The value to read/write */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* logical device numbers for superio_select (below) */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_FDC		0x00
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_PRT		0x01
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART1	0x02
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART2	0x03
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_KBC		0x05
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_CIR		0x06 /* w83627hf only */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GAME	0x07
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_MIDI	0x07
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO1	0x07
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO2	0x08
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO3	0x09
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_ACPI	0x0a
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_HWM		0x0b
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEVID	0x20	/* Register: Device ID */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_EN	0x29 /* w83687thf only */
106c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
107c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
108c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_outb(int reg, int val)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(val, VAL);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_inb(int reg)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return inb(VAL);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_select(int ld)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(DEV, REG);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ld, VAL);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_enter(void)
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_exit(void)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xAA, REG);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627_DEVID 0x52
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627THF_DEVID 0x82
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W697_DEVID 0x60
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W637_DEVID 0x70
147c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W687THF_DEVID 0x85
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_ACT_REG 0x30
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_BASE_REG 0x60
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Constants specified below */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Alignment of the base address */
153ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_ALIGNMENT		~7
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Offset & size of I/O region we are interested in */
156ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_OFFSET	5
157ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_SIZE	2
158ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec
159787c72b107888805981faf148c8fea96a752d22eJean Delvare/* Where are the sensors address/data registers relative to the region offset */
160787c72b107888805981faf148c8fea96a752d22eJean Delvare#define W83781D_ADDR_REG_OFFSET 0
161787c72b107888805981faf148c8fea96a752d22eJean Delvare#define W83781D_DATA_REG_OFFSET 1
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83781D registers */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83782D registers for nr=7,8 are in bank 5 */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x554 + (((nr) - 7) * 2)))
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x555 + (((nr) - 7) * 2)))
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x550 + (nr) - 7))
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN(nr) (0x27 + (nr))
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP2_CONFIG 0x152
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP3_CONFIG 0x252
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x0150) : \
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x27)))
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x153) : \
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x3A)))
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x155) : \
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x39)))
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BANK 0x4E
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CONFIG 0x40
1904a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM1 0x459
1914a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM2 0x45A
1924a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM3 0x45B
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_CONFIG 0x4D
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS1 0x56
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS2 0x57
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS3 0x453
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VID_FANDIV 0x47
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPID 0x49
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_WCHIPID 0x58
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPMAN 0x4F
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_PIN 0x4B
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VBAT 0x5D
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM1 0x5A
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM2 0x5B
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM1		0x01	/* 697HF/637HF/687THF too */
212c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM2		0x03	/* 697HF/637HF/687THF too */
213c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_PWM3		0x11	/* 637HF/687THF too */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
215c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF/687THF too */
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                             W83627THF_REG_PWM3 };
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83627HF_REG_PWM_FREQ		0x5C	/* Only for the 627HF */
2241550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2251550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ1		0x00	/* 697HF/687THF too */
2261550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ2		0x02	/* 697HF/687THF too */
2271550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83637HF_REG_PWM_FREQ3		0x10	/* 687THF too */
2281550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2291550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
2301550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					W83637HF_REG_PWM_FREQ2,
2311550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					W83637HF_REG_PWM_FREQ3 };
2321550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2331550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define W83627HF_BASE_PWM_FREQ	46870
2341550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_ADDR 0x48
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_SUBADDR 0x4A
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sensor selection */
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG1 0x5D
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG2 0x59
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DEFAULT_BETA 3435
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Conversions. Limit checking is only done on the TO_REG
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   variants. Note that you should be a bit careful with which arguments
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   these macros are called: arguments may be evaluated more than once.
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Fixing this is just not worth it. */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) * 16)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm == 0)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     254);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MIN (-128000)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MAX ( 127000)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMP: 0.001C/bit (-128C to +127C)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 1C/bit, two's complement */
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 TEMP_TO_REG(int temp)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ntemp += (ntemp<0 ? -500 : 500);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (u8)(ntemp / 1000);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TEMP_FROM_REG(u8 reg)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (s8)reg * 1000;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
2831550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
2841550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	unsigned long freq;
2851550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	freq = W83627HF_BASE_PWM_FREQ >> reg;
2861550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return freq;
2871550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
2881550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline u8 pwm_freq_to_reg_627hf(unsigned long val)
2891550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
2901550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u8 i;
2911550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Only 5 dividers (1 2 4 8 16)
2921550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	   Search for the nearest available frequency */
2931550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	for (i = 0; i < 4; i++) {
2941550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
2951550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			    (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
2961550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			break;
2971550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	}
2981550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return i;
2991550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
3001550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
3011550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline unsigned long pwm_freq_from_reg(u8 reg)
3021550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
3031550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Clock bit 8 -> 180 kHz or 24 MHz */
3041550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
3051550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
3061550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	reg &= 0x7f;
3071550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* This should not happen but anyway... */
3081550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (reg == 0)
3091550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		reg++;
3101550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return (clock / (reg << 8));
3111550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
3121550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic inline u8 pwm_freq_to_reg(unsigned long val)
3131550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
3141550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	/* Minimum divider value is 0x01 and maximum is 0x7F */
3151550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val >= 93750)	/* The highest we can do */
3161550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return 0x01;
3171550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val >= 720)	/* Use 24 MHz clock */
3181550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return (24000000UL / (val << 8));
3191550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (val < 6)		/* The lowest we can do */
3201550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return 0xFF;
3211550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	else			/* Use 180 kHz clock */
3221550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return (0x80 | (180000UL / (val << 8)));
3231550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
3241550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_FROM_REG(val)		 (val)
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_FROM_REG(val)	((val)?1:0)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val))
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 DIV_TO_REG(long val)
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = SENSORS_LIMIT(val, 1, 128) >> 1;
336abc01922477104e8d72b494902aff37135c409e7Grant Coady	for (i = 0; i < 7; i++) {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val == 0)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val >>= 1;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ((u8) i);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
344ed6bafbf6017d6a007b39de6b65ad3b8ae4c8aeeJean Delvare/* For each registered chip, we need to keep some data in memory.
345ed6bafbf6017d6a007b39de6b65ad3b8ae4c8aeeJean Delvare   The structure is dynamically allocated. */
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct w83627hf_data {
347787c72b107888805981faf148c8fea96a752d22eJean Delvare	unsigned short addr;
348787c72b107888805981faf148c8fea96a752d22eJean Delvare	const char *name;
349943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	struct class_device *class_dev;
3509a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex lock;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum chips type;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3539a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[9];		/* Register value */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[9];		/* Register value */
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[9];		/* Register value */
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[3];		/* Register value */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[3];		/* Register value */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_max;		/* Register value */
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_max_hyst;	/* Register value */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_add[2];	/* Register value */
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_max_add[2];	/* Register value */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_max_hyst_add[2]; /* Register value */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_div[3];		/* Register encoding, shifted right */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid;			/* Register encoding, combined */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 alarms;		/* Register encoding, combined */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 beep_mask;		/* Register encoding, combined */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 beep_enable;		/* Boolean */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwm[3];		/* Register value */
3741550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u8 pwm_freq[3];		/* Register value */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 sens[3];		/* 782D/783S only.
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   1 = pentium diode; 2 = 3904 diode;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   3000-5000 = thermistor beta.
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   Default = 3435.
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   Other Betas unimplemented */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm;
381c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
384787c72b107888805981faf148c8fea96a752d22eJean Delvarestruct w83627hf_sio_data {
385787c72b107888805981faf148c8fea96a752d22eJean Delvare	enum chips type;
386787c72b107888805981faf148c8fea96a752d22eJean Delvare};
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
389787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_probe(struct platform_device *pdev);
390787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_remove(struct platform_device *pdev);
391787c72b107888805981faf148c8fea96a752d22eJean Delvare
392787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
393787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev);
395787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic void w83627hf_init_device(struct platform_device *pdev);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
397787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic struct platform_driver w83627hf_driver = {
398cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	.driver = {
399872188420997f7f7c1b968fd9bce6578e4c3d45fJean Delvare		.owner	= THIS_MODULE,
400d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		.name	= DRVNAME,
401cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	},
402787c72b107888805981faf148c8fea96a752d22eJean Delvare	.probe		= w83627hf_probe,
403787c72b107888805981faf148c8fea96a752d22eJean Delvare	.remove		= __devexit_p(w83627hf_remove),
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* following are the sysfs callback functions */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_reg(reg) \
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_min)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_max)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_in_reg(REG, reg) \
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
421787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev); \
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val; \
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10); \
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
4269a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock); \
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->in_##reg[nr] = IN_TO_REG(val); \
428787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    data->in_##reg[nr]); \
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
4319a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock); \
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MIN, min)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MAX, max)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offset(offset) \
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
439a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return show_in(dev, buf, offset); \
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_reg_offset(reg, offset) \
446a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_##reg (dev, buf, offset); \
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
451a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    const char *buf, size_t count) \
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_in_##reg (dev, buf, count, offset); \
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_in_##reg##offset, store_regs_in_##reg##offset);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offsets(offset) \
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offset(offset) \
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(min, offset) \
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(max, offset)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(1);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(2);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(3);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(4);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(5);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(6);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(7);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(8);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* use a different set of functions for in0 */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long in0;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
479c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
480c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)((reg * 488 + 70000 + 50) / 100);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)IN_FROM_REG(reg);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", in0);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in[0]);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
497a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_min[0]);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
503a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_max[0]);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
509a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
512787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5179a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
520c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
521c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
5242723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_min[0] =
5252723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
5262723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_min[0] = IN_TO_REG(val);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
5329a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
536a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
539787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5449a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
547c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		(w83627thf == data->type || w83637hf == data->type
548c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		 || w83687thf == data->type))
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
5512723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_max[0] =
5522723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
5532723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_max[0] = IN_TO_REG(val);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
558787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
5599a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_min0, store_regs_in_min0);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_max0, store_regs_in_max0);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_fan_reg(reg) \
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", \
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FAN_FROM_REG(data->reg[nr-1], \
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan_min);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_min(struct device *dev, const char *buf, size_t count, int nr)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
583787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5889a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr - 1] =
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
591787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    data->fan_min[nr - 1]);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5949a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_offset(offset) \
599a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan(dev, buf, offset); \
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_min_offset(offset) \
606a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan_min(dev, buf, offset); \
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
611a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_fan_min(dev, buf, count, offset); \
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_fan_min##offset, store_regs_fan_min##offset);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(1);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(1);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(2);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(2);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(3);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(3);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_temp_reg(reg) \
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sprintf(buf,"%ld\n", \
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {	/* TEMP1 */ \
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} \
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max_hyst);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_temp_reg(REG, reg) \
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
644787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev); \
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val; \
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10); \
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6499a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock); \
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
653787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp_##reg##_add[nr-2]); \
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {	/* TEMP1 */ \
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_##reg = TEMP_TO_REG(val); \
657787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_##reg); \
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} \
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6619a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock); \
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(OVER, max);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(HYST, max_hyst);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offset(offset) \
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
669a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_temp(dev, buf, offset); \
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_reg_offset(reg, offset) \
676a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_temp_##reg (dev, buf, offset); \
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
681a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      const char *buf, size_t count) \
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_temp_##reg (dev, buf, count, offset); \
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offsets(offset) \
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offset(offset) \
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max, offset) \
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max_hyst, offset)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(1);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(2);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(3);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
699a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
707a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->vrm);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
713a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
715787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->vrm = val;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
726a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->alarms);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_beep_reg(REG, reg) \
734a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", \
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(ENABLE, enable)
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(MASK, mask)
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE			0	/* Store beep_enable */
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK			1	/* Store beep_mask */
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_beep_reg(struct device *dev, const char *buf, size_t count,
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       int update_mask)
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
750787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, val2;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7559a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = BEEP_MASK_TO_REG(val);
759787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    data->beep_mask & 0xff);
761787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((data->beep_mask) >> 16) & 0xff);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = (data->beep_mask >> 8) & 0x7f;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {		/* We are storing beep_enable */
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 =
766787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = BEEP_ENABLE_TO_REG(val);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
770787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    val2 | data->beep_enable << 7);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7739a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_beep(REG, reg) \
778a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
780a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannou	return show_beep_##reg(dev, attr, buf); \
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
783a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_beep_reg(dev, buf, count, BEEP_##REG); \
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_beep_##reg, store_regs_beep_##reg);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(ENABLE, enable);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(MASK, mask);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_div_reg(struct device *dev, char *buf, int nr)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n",
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we save and restore the fan minimum here, because its value is
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined in part by the fan divisor.  This follows the principle of
803d6e05edc59ecd79e8badf440c0d295a979bdfa3eAndreas Mohr   least surprise; the user doesn't expect the fan minimum to change just
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   because the divisor changed. */
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
808787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long min;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 reg;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8139a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save fan_min */
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	min = FAN_FROM_REG(data->fan_min[nr],
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   DIV_FROM_REG(data->fan_div[nr]));
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_div[nr] = DIV_TO_REG(val);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821787c72b107888805981faf148c8fea96a752d22eJean Delvare	reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & (nr==0 ? 0xcf : 0x3f))
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
824787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
826787c72b107888805981faf148c8fea96a752d22eJean Delvare	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & ~(1 << (5 + nr)))
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
829787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore fan_min */
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
833787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8359a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_div(offset) \
840a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan_div_reg(dev, buf, offset); \
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
845a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    const char *buf, size_t count) \
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_fan_div_reg(dev, buf, count, offset - 1); \
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_fan_div_##offset, store_regs_fan_div_##offset);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(1);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(2);
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(3);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_pwm_reg(struct device *dev, char *buf, int nr)
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
867787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8729a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->type == w83627thf) {
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bits 0-3 are reserved  in 627THF */
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
877787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data,
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     data->pwm[nr - 1] |
880787c72b107888805981faf148c8fea96a752d22eJean Delvare				     (w83627hf_read_value(data,
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->pwm[nr - 1] = PWM_TO_REG(val);
884787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data,
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     data->pwm[nr - 1]);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8899a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_pwm(offset) \
894a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_pwm_reg(dev, buf, offset); \
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
899a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_pwm_reg(dev, buf, count, offset); \
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_pwm_##offset, store_regs_pwm_##offset);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(1);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(2);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(3);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
9111550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezshow_pwm_freq_reg(struct device *dev, char *buf, int nr)
9121550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
9131550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	struct w83627hf_data *data = w83627hf_update_device(dev);
9141550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83627hf)
9151550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return sprintf(buf, "%ld\n",
9161550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
9171550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	else
9181550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		return sprintf(buf, "%ld\n",
9191550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			pwm_freq_from_reg(data->pwm_freq[nr - 1]));
9201550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
9211550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9221550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t
9231550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstore_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
9241550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{
9251550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	struct w83627hf_data *data = dev_get_drvdata(dev);
9261550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	static const u8 mask[]={0xF8, 0x8F};
9271550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	u32 val;
9281550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9291550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	val = simple_strtoul(buf, NULL, 10);
9301550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9311550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	mutex_lock(&data->update_lock);
9321550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9331550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83627hf) {
9341550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
9351550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
9361550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				(data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
9371550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				(w83627hf_read_value(data,
9381550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
9391550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	} else {
9401550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
9411550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
9421550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[nr - 1]);
9431550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	}
9441550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9451550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	mutex_unlock(&data->update_lock);
9461550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return count;
9471550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez}
9481550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9491550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez#define sysfs_pwm_freq(offset) \
9501550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
9511550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		struct device_attribute *attr, char *buf) \
9521550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{ \
9531550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return show_pwm_freq_reg(dev, buf, offset); \
9541550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez} \
9551550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t \
9561550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstore_regs_pwm_freq_##offset(struct device *dev, \
9571550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		struct device_attribute *attr, const char *buf, size_t count) \
9581550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez{ \
9591550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	return store_pwm_freq_reg(dev, buf, count, offset); \
9601550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez} \
9611550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
9621550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		  show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
9631550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9641550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezsysfs_pwm_freq(1);
9651550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezsysfs_pwm_freq(2);
9661550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezsysfs_pwm_freq(3);
9671550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
9681550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinezstatic ssize_t
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_sensor_reg(struct device *dev, char *buf, int nr)
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
978787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, tmp;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9839a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* PII/Celeron diode */
987787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
988787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG1[nr - 1]);
990787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
991787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG2,
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG2[nr - 1]);
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* 3904 */
996787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
997787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG1[nr - 1]);
999787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
1000787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG2,
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp & ~BIT_SCFG2[nr - 1]);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case W83781D_DEFAULT_BETA:	/* thermistor */
1005787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
1006787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_SCFG1,
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp & ~BIT_SCFG1[nr - 1]);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1011787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_err(dev,
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "Invalid sensor type %ld; must be 1, 2, or %d\n",
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (long) val, W83781D_DEFAULT_BETA);
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10179a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_sensor(offset) \
1022a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return show_sensor_reg(dev, buf, offset); \
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
1027a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return store_sensor_reg(dev, buf, count, offset); \
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_sensor_##offset, store_regs_sensor_##offset);
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(1);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(2);
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(3);
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1038787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic ssize_t show_name(struct device *dev, struct device_attribute
1039787c72b107888805981faf148c8fea96a752d22eJean Delvare			 *devattr, char *buf)
1040787c72b107888805981faf148c8fea96a752d22eJean Delvare{
1041787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
1042787c72b107888805981faf148c8fea96a752d22eJean Delvare
1043787c72b107888805981faf148c8fea96a752d22eJean Delvare	return sprintf(buf, "%s\n", data->name);
1044787c72b107888805981faf148c8fea96a752d22eJean Delvare}
1045787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1046787c72b107888805981faf148c8fea96a752d22eJean Delvare
1047787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __init w83627hf_find(int sioaddr, unsigned short *addr,
1048787c72b107888805981faf148c8fea96a752d22eJean Delvare				struct w83627hf_sio_data *sio_data)
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1050d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	int err = -ENODEV;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 val;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1053787c72b107888805981faf148c8fea96a752d22eJean Delvare	static const __initdata char *names[] = {
1054787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83627HF",
1055787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83627THF",
1056787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83697HF",
1057787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83637HF",
1058787c72b107888805981faf148c8fea96a752d22eJean Delvare		"W83687THF",
1059787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1060787c72b107888805981faf148c8fea96a752d22eJean Delvare
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REG = sioaddr;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	VAL = sioaddr + 1;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val= superio_inb(DEVID);
1066787c72b107888805981faf148c8fea96a752d22eJean Delvare	switch (val) {
1067787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W627_DEVID:
1068787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83627hf;
1069787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1070787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W627THF_DEVID:
1071787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83627thf;
1072787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1073787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W697_DEVID:
1074787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83697hf;
1075787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1076787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W637_DEVID:
1077787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83637hf;
1078787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1079787c72b107888805981faf148c8fea96a752d22eJean Delvare	case W687THF_DEVID:
1080787c72b107888805981faf148c8fea96a752d22eJean Delvare		sio_data->type = w83687thf;
1081787c72b107888805981faf148c8fea96a752d22eJean Delvare		break;
1082e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare	case 0xff:	/* No device at all */
1083e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare		goto exit;
1084787c72b107888805981faf148c8fea96a752d22eJean Delvare	default:
1085e142e2a30787e9fa1bf0f66aa1d01727ce718cc7Jean Delvare		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
1086d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		goto exit;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_HWM);
1090d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	force_addr &= WINB_ALIGNMENT;
1091d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (force_addr) {
1092d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1093d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		       force_addr);
1094d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_BASE_REG, force_addr >> 8);
1095d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1096d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	}
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = (superio_inb(WINB_BASE_REG) << 8) |
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       superio_inb(WINB_BASE_REG + 1);
1099ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	*addr = val & WINB_ALIGNMENT;
1100d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (*addr == 0) {
1101d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Base address not set, "
1102d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		       "skipping\n");
1103d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		goto exit;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1106d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	val = superio_inb(WINB_ACT_REG);
1107d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (!(val & 0x01)) {
1108d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1109d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare		superio_outb(WINB_ACT_REG, val | 0x01);
1110d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	}
1111d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
1112d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	err = 0;
1113787c72b107888805981faf148c8fea96a752d22eJean Delvare	pr_info(DRVNAME ": Found %s chip at %#x\n",
1114787c72b107888805981faf148c8fea96a752d22eJean Delvare		names[sio_data->type], *addr);
1115d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare
1116d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare exit:
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
1118d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	return err;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *w83627hf_attributes[] = {
1122c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_input.attr,
1123c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_min.attr,
1124c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in0_max.attr,
1125c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in2_input.attr,
1126c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in2_min.attr,
1127c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in2_max.attr,
1128c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in3_input.attr,
1129c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in3_min.attr,
1130c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in3_max.attr,
1131c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in4_input.attr,
1132c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in4_min.attr,
1133c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in4_max.attr,
1134c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in7_input.attr,
1135c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in7_min.attr,
1136c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in7_max.attr,
1137c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in8_input.attr,
1138c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in8_min.attr,
1139c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in8_max.attr,
1140c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1141c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan1_input.attr,
1142c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan1_min.attr,
1143c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan1_div.attr,
1144c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan2_input.attr,
1145c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan2_min.attr,
1146c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan2_div.attr,
1147c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1148c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp1_input.attr,
1149c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp1_max.attr,
1150c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp1_max_hyst.attr,
1151c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp1_type.attr,
1152c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp2_input.attr,
1153c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp2_max.attr,
1154c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp2_max_hyst.attr,
1155c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp2_type.attr,
1156c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1157c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_alarms.attr,
1158c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_beep_enable.attr,
1159c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_beep_mask.attr,
1160c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1161c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_pwm1.attr,
1162c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_pwm2.attr,
1163c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1164787c72b107888805981faf148c8fea96a752d22eJean Delvare	&dev_attr_name.attr,
1165c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	NULL
1166c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1167c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1168c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group w83627hf_group = {
1169c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	.attrs = w83627hf_attributes,
1170c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1171c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1172c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *w83627hf_attributes_opt[] = {
1173c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in1_input.attr,
1174c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in1_min.attr,
1175c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in1_max.attr,
1176c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in5_input.attr,
1177c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in5_min.attr,
1178c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in5_max.attr,
1179c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in6_input.attr,
1180c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in6_min.attr,
1181c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_in6_max.attr,
1182c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1183c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan3_input.attr,
1184c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan3_min.attr,
1185c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_fan3_div.attr,
1186c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1187c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp3_input.attr,
1188c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp3_max.attr,
1189c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp3_max_hyst.attr,
1190c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_temp3_type.attr,
1191c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1192c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_pwm3.attr,
1193c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
11941550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	&dev_attr_pwm1_freq.attr,
11951550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	&dev_attr_pwm2_freq.attr,
11961550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	&dev_attr_pwm3_freq.attr,
1197c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	NULL
1198c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1199c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1200c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group w83627hf_group_opt = {
1201c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	.attrs = w83627hf_attributes_opt,
1202c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
1203c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1204787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83627hf_probe(struct platform_device *pdev)
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1206787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct device *dev = &pdev->dev;
1207787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_sio_data *sio_data = dev->platform_data;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data;
1209787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource *res;
1210787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1212787c72b107888805981faf148c8fea96a752d22eJean Delvare	static const char *names[] = {
1213787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83627hf",
1214787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83627thf",
1215787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83697hf",
1216787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83637hf",
1217787c72b107888805981faf148c8fea96a752d22eJean Delvare		"w83687thf",
1218787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1219787c72b107888805981faf148c8fea96a752d22eJean Delvare
1220787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1221787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1222787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1223787c72b107888805981faf148c8fea96a752d22eJean Delvare			(unsigned long)res->start,
1224787c72b107888805981faf148c8fea96a752d22eJean Delvare			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBUSY;
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR0;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1229ba9c2e8d15da029ea3051c95e446b2d638ef02e2Deepak Saxena	if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR1;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1233787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->addr = res->start;
1234787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->type = sio_data->type;
1235787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->name = names[sio_data->type];
12369a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->lock);
12379a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->update_lock);
1238787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_set_drvdata(pdev, data);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the chip */
1241787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_init_device(pdev);
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A few vars need to be filled upon startup */
1244787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
1245787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
1246787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1248c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	/* Register common device attributes */
1249787c72b107888805981faf148c8fea96a752d22eJean Delvare	if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
1250943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman		goto ERROR3;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1252c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	/* Register chip-specific device attributes */
1253787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type == w83627hf || data->type == w83697hf)
1254787c72b107888805981faf148c8fea96a752d22eJean Delvare		if ((err = device_create_file(dev, &dev_attr_in5_input))
1255787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in5_min))
1256787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in5_max))
1257787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in6_input))
1258787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in6_min))
12591550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		 || (err = device_create_file(dev, &dev_attr_in6_max))
12601550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		 || (err = device_create_file(dev, &dev_attr_pwm1_freq))
12611550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		 || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
1262c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1264787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type != w83697hf)
1265787c72b107888805981faf148c8fea96a752d22eJean Delvare		if ((err = device_create_file(dev, &dev_attr_in1_input))
1266787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in1_min))
1267787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_in1_max))
1268787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_fan3_input))
1269787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_fan3_min))
1270787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_fan3_div))
1271787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_temp3_input))
1272787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_temp3_max))
1273787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_temp3_max_hyst))
1274787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_temp3_type)))
1275c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
1276c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
1277787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type != w83697hf && data->vid != 0xff) {
12788a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare		/* Convert VID to voltage based on VRM */
12798a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare		data->vrm = vid_which_vrm();
12808a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare
1281787c72b107888805981faf148c8fea96a752d22eJean Delvare		if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1282787c72b107888805981faf148c8fea96a752d22eJean Delvare		 || (err = device_create_file(dev, &dev_attr_vrm)))
1283c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12848a665a0552c414af88788cc0e2cf0e4626182c20Jean Delvare	}
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1286787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (data->type == w83627thf || data->type == w83637hf
1287787c72b107888805981faf148c8fea96a752d22eJean Delvare	 || data->type == w83687thf)
1288787c72b107888805981faf148c8fea96a752d22eJean Delvare		if ((err = device_create_file(dev, &dev_attr_pwm3)))
1289c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman			goto ERROR4;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12911550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez	if (data->type == w83637hf || data->type == w83687thf)
12921550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
12931550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		 || (err = device_create_file(dev, &dev_attr_pwm2_freq))
12941550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		 || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
12951550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			goto ERROR4;
12961550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez
1297787c72b107888805981faf148c8fea96a752d22eJean Delvare	data->class_dev = hwmon_device_register(dev);
1298c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	if (IS_ERR(data->class_dev)) {
1299c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman		err = PTR_ERR(data->class_dev);
1300c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman		goto ERROR4;
1301c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	}
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1305c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman      ERROR4:
1306787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&dev->kobj, &w83627hf_group);
1307787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
1308943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman      ERROR3:
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR1:
1311787c72b107888805981faf148c8fea96a752d22eJean Delvare	release_region(res->start, WINB_REGION_SIZE);
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR0:
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1316787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devexit w83627hf_remove(struct platform_device *pdev)
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1318787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = platform_get_drvdata(pdev);
1319787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource *res;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_set_drvdata(pdev, NULL);
1322943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	hwmon_device_unregister(data->class_dev);
1323943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
1324787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1325787c72b107888805981faf148c8fea96a752d22eJean Delvare	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
1326943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	kfree(data);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1328787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1329787c72b107888805981faf148c8fea96a752d22eJean Delvare	release_region(res->start, WINB_REGION_SIZE);
1330787c72b107888805981faf148c8fea96a752d22eJean Delvare
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1335787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, word_sized;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13399a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x50)
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x53)
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
1347787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(reg >> 8,
1349787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_DATA_REG_OFFSET);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1351787c72b107888805981faf148c8fea96a752d22eJean Delvare	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1352787c72b107888805981faf148c8fea96a752d22eJean Delvare	res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
1355787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res =
1357787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (res << 8) + inb_p(data->addr +
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       W83781D_DATA_REG_OFFSET);
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
1362787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
1363787c72b107888805981faf148c8fea96a752d22eJean Delvare		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13659a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1369787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 0xff, sel;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_GPIO5);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure these GPIO pins are enabled */
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
1378787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure the pins are configured for input
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
1384dd149c52223cfb05cdefb0755d3c2793e8d33edeYuan Mu	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sel & 0x1f) != 0x1f) {
1386787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"function\n");
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391787c72b107888805981faf148c8fea96a752d22eJean Delvare	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = superio_inb(W83627THF_GPIO5_DR) & sel;
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1399787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __devinit w83687thf_read_vid(struct platform_device *pdev)
1400c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare{
1401c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	int res = 0xff;
1402c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1403c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_enter();
1404c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_select(W83627HF_LD_HWM);
1405c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1406c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	/* Make sure these GPIO pins are enabled */
1407c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
1408787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
1409c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		goto exit;
1410c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	}
1411c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1412c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	/* Make sure the pins are configured for input */
1413c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
1414787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_dbg(&pdev->dev, "VID configured as output, "
1415c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare			"no VID function\n");
1416c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare		goto exit;
1417c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	}
1418c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1419c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1420c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1421c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvareexit:
1422c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	superio_exit();
1423c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare	return res;
1424c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare}
1425c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare
1426787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int word_sized;
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14309a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x53)
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
1437787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(reg >> 8,
1439787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_DATA_REG_OFFSET);
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1441787c72b107888805981faf148c8fea96a752d22eJean Delvare	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(value >> 8,
1444787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_DATA_REG_OFFSET);
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
1446787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(value & 0xff,
1449787c72b107888805981faf148c8fea96a752d22eJean Delvare	       data->addr + W83781D_DATA_REG_OFFSET);
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
1452787c72b107888805981faf148c8fea96a752d22eJean Delvare		       data->addr + W83781D_ADDR_REG_OFFSET);
1453787c72b107888805981faf148c8fea96a752d22eJean Delvare		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14559a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1459787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic void __devinit w83627hf_init_device(struct platform_device *pdev)
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1461787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = platform_get_drvdata(pdev);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1463d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	enum chips type = data->type;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tmp;
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14662251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare	if (reset) {
14672251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		/* Resetting the chip has been the default for a long time,
14682251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   but repeatedly caused problems (fans going to full
14692251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   speed...) so it is now optional. It might even go away if
14702251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   nobody reports it as being useful, as I see very little
14712251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   reason why this would be needed at all. */
1472787c72b107888805981faf148c8fea96a752d22eJean Delvare		dev_info(&pdev->dev, "If reset=1 solved a problem you were "
14732251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare			 "having, please report!\n");
14742251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save this register */
1476787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset all except Watchdog values and last conversion values
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This sets fan-divs to 2, among others */
1479787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Restore the register and disable power-on abnormal beep.
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This saves FAN 1/2/3 input/output values set by BIOS. */
1482787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable master beep-enable (reset turns it on).
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Individual beeps should be reset to off but for some reason
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   disabling this bit helps some people not get beeped */
1486787c72b107888805981faf148c8fea96a752d22eJean Delvare		w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Minimize conflicts with other winbond i2c-only clients...  */
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable i2c subclients... how to disable main i2c client?? */
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* force i2c address to relatively uncommon address */
1492787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1493787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VID only once */
1496d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (type == w83627hf || type == w83637hf) {
1497787c72b107888805981faf148c8fea96a752d22eJean Delvare		int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1498787c72b107888805981faf148c8fea96a752d22eJean Delvare		int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
1500d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	} else if (type == w83627thf) {
1501787c72b107888805981faf148c8fea96a752d22eJean Delvare		data->vid = w83627thf_read_gpio5(pdev);
1502d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	} else if (type == w83687thf) {
1503787c72b107888805981faf148c8fea96a752d22eJean Delvare		data->vid = w83687thf_read_vid(pdev);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VRM & OVT Config only once */
1507d27c37c0be3fd97a696dafb28507277d49875dcbJean Delvare	if (type == w83627thf || type == w83637hf || type == w83687thf) {
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vrm_ovt =
1509787c72b107888805981faf148c8fea96a752d22eJean Delvare			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1512787c72b107888805981faf148c8fea96a752d22eJean Delvare	tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 3; i++) {
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(tmp & BIT_SCFG1[i - 1])) {
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->sens[i - 1] = W83781D_DEFAULT_BETA;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (w83627hf_read_value
1518787c72b107888805981faf148c8fea96a752d22eJean Delvare			    (data,
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 1;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 2;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((type == w83697hf) && (i == 2))
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(init) {
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp2 */
1530787c72b107888805981faf148c8fea96a752d22eJean Delvare		tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp & 0x01) {
1532787c72b107888805981faf148c8fea96a752d22eJean Delvare			dev_warn(&pdev->dev, "Enabling temp2, readings "
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "might not make sense\n");
1534787c72b107888805981faf148c8fea96a752d22eJean Delvare			w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp & 0xfe);
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp3 */
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (type != w83697hf) {
1540787c72b107888805981faf148c8fea96a752d22eJean Delvare			tmp = w83627hf_read_value(data,
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W83781D_REG_TEMP3_CONFIG);
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp & 0x01) {
1543787c72b107888805981faf148c8fea96a752d22eJean Delvare				dev_warn(&pdev->dev, "Enabling temp3, "
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "readings might not make sense\n");
1545787c72b107888805981faf148c8fea96a752d22eJean Delvare				w83627hf_write_value(data,
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start monitoring */
1552787c72b107888805981faf148c8fea96a752d22eJean Delvare	w83627hf_write_value(data, W83781D_REG_CONFIG,
1553787c72b107888805981faf148c8fea96a752d22eJean Delvare			    (w83627hf_read_value(data,
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						W83781D_REG_CONFIG) & 0xf7)
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    | 0x01);
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev)
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1560787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_data *data = dev_get_drvdata(dev);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15639a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || !data->valid) {
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 8; i++) {
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* skip missing sensors */
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((data->type == w83697hf) && (i == 1)) ||
1570c2db6ce14a743ac5f8973124272cf425c4f86b90Jean Delvare			    ((data->type != w83627hf && data->type != w83697hf)
15714a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu			    && (i == 5 || i == 6)))
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in[i] =
1574787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data, W83781D_REG_IN(i));
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_min[i] =
1576787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MIN(i));
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_max[i] =
1579787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MAX(i));
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 3; i++) {
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[i - 1] =
1584787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data, W83781D_REG_FAN(i));
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[i - 1] =
1586787c72b107888805981faf148c8fea96a752d22eJean Delvare			    w83627hf_read_value(data,
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_FAN_MIN(i));
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 3; i++) {
1590787c72b107888805981faf148c8fea96a752d22eJean Delvare			u8 tmp = w83627hf_read_value(data,
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W836X7HF_REG_PWM(data->type, i));
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			/* bits 0-3 are reserved  in 627THF */
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			if (data->type == w83627thf)
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp &= 0xf0;
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->pwm[i - 1] = tmp;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(i == 2 &&
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   (data->type == w83627hf || data->type == w83697hf))
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16001550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		if (data->type == w83627hf) {
16011550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				u8 tmp = w83627hf_read_value(data,
16021550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez						W83627HF_REG_PWM_FREQ);
16031550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[0] = tmp & 0x07;
16041550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[1] = (tmp >> 4) & 0x07;
16051550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		} else if (data->type != w83627thf) {
16061550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			for (i = 1; i <= 3; i++) {
16071550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				data->pwm_freq[i - 1] =
16081550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					w83627hf_read_value(data,
16091550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez						W83637HF_REG_PWM_FREQ[i - 1]);
16101550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez				if (i == 2 && (data->type == w83697hf))
16111550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez					break;
16121550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez			}
16131550cb6d7e78c7cfdd7b48bee6809795d43d6a33Carlos Olalla Martinez		}
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1615787c72b107888805981faf148c8fea96a752d22eJean Delvare		data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max =
1617787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_hyst =
1619787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_add[0] =
1621787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_TEMP(2));
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_add[0] =
1623787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_hyst_add[0] =
1625787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf) {
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_add[1] =
1628787c72b107888805981faf148c8fea96a752d22eJean Delvare			  w83627hf_read_value(data, W83781D_REG_TEMP(3));
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_max_add[1] =
1630787c72b107888805981faf148c8fea96a752d22eJean Delvare			  w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_max_hyst_add[1] =
1632787c72b107888805981faf148c8fea96a752d22eJean Delvare			  w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1635787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] = (i >> 4) & 0x03;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] = (i >> 6) & 0x03;
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf) {
1639787c72b107888805981faf148c8fea96a752d22eJean Delvare			data->fan_div[2] = (w83627hf_read_value(data,
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_PIN) >> 6) & 0x03;
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1642787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_VBAT);
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] |= (i >> 3) & 0x04;
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] |= (i >> 4) & 0x04;
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf)
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_div[2] |= (i >> 5) & 0x04;
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->alarms =
1648787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_ALARM1) |
1649787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1650787c72b107888805981faf148c8fea96a752d22eJean Delvare		    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1651787c72b107888805981faf148c8fea96a752d22eJean Delvare		i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = i >> 7;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = ((i & 0x7f) << 8) |
1654787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1655787c72b107888805981faf148c8fea96a752d22eJean Delvare		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16609a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1665787c72b107888805981faf148c8fea96a752d22eJean Delvarestatic int __init w83627hf_device_add(unsigned short address,
1666787c72b107888805981faf148c8fea96a752d22eJean Delvare				      const struct w83627hf_sio_data *sio_data)
1667787c72b107888805981faf148c8fea96a752d22eJean Delvare{
1668787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct resource res = {
1669787c72b107888805981faf148c8fea96a752d22eJean Delvare		.start	= address + WINB_REGION_OFFSET,
1670787c72b107888805981faf148c8fea96a752d22eJean Delvare		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1671787c72b107888805981faf148c8fea96a752d22eJean Delvare		.name	= DRVNAME,
1672787c72b107888805981faf148c8fea96a752d22eJean Delvare		.flags	= IORESOURCE_IO,
1673787c72b107888805981faf148c8fea96a752d22eJean Delvare	};
1674787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
1675787c72b107888805981faf148c8fea96a752d22eJean Delvare
1676787c72b107888805981faf148c8fea96a752d22eJean Delvare	pdev = platform_device_alloc(DRVNAME, address);
1677787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (!pdev) {
1678787c72b107888805981faf148c8fea96a752d22eJean Delvare		err = -ENOMEM;
1679787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1680787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit;
1681787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1682787c72b107888805981faf148c8fea96a752d22eJean Delvare
1683787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_device_add_resources(pdev, &res, 1);
1684787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err) {
1685787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device resource addition failed "
1686787c72b107888805981faf148c8fea96a752d22eJean Delvare		       "(%d)\n", err);
1687787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1688787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1689787c72b107888805981faf148c8fea96a752d22eJean Delvare
16902df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare	err = platform_device_add_data(pdev, sio_data,
16912df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare				       sizeof(struct w83627hf_sio_data));
16922df6d811574f46bea0d38bf91aa54df4c05488cdJean Delvare	if (err) {
1693787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1694787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1695787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1696787c72b107888805981faf148c8fea96a752d22eJean Delvare
1697787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_device_add(pdev);
1698787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err) {
1699787c72b107888805981faf148c8fea96a752d22eJean Delvare		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1700787c72b107888805981faf148c8fea96a752d22eJean Delvare		       err);
1701787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_device_put;
1702787c72b107888805981faf148c8fea96a752d22eJean Delvare	}
1703787c72b107888805981faf148c8fea96a752d22eJean Delvare
1704787c72b107888805981faf148c8fea96a752d22eJean Delvare	return 0;
1705787c72b107888805981faf148c8fea96a752d22eJean Delvare
1706787c72b107888805981faf148c8fea96a752d22eJean Delvareexit_device_put:
1707787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_device_put(pdev);
1708787c72b107888805981faf148c8fea96a752d22eJean Delvareexit:
1709787c72b107888805981faf148c8fea96a752d22eJean Delvare	return err;
1710787c72b107888805981faf148c8fea96a752d22eJean Delvare}
1711787c72b107888805981faf148c8fea96a752d22eJean Delvare
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sensors_w83627hf_init(void)
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1714787c72b107888805981faf148c8fea96a752d22eJean Delvare	int err;
1715787c72b107888805981faf148c8fea96a752d22eJean Delvare	unsigned short address;
1716787c72b107888805981faf148c8fea96a752d22eJean Delvare	struct w83627hf_sio_data sio_data;
1717787c72b107888805981faf148c8fea96a752d22eJean Delvare
1718787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (w83627hf_find(0x2e, &address, &sio_data)
1719787c72b107888805981faf148c8fea96a752d22eJean Delvare	 && w83627hf_find(0x4e, &address, &sio_data))
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1722787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = platform_driver_register(&w83627hf_driver);
1723787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err)
1724787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit;
1725787c72b107888805981faf148c8fea96a752d22eJean Delvare
1726787c72b107888805981faf148c8fea96a752d22eJean Delvare	/* Sets global pdev as a side effect */
1727787c72b107888805981faf148c8fea96a752d22eJean Delvare	err = w83627hf_device_add(address, &sio_data);
1728787c72b107888805981faf148c8fea96a752d22eJean Delvare	if (err)
1729787c72b107888805981faf148c8fea96a752d22eJean Delvare		goto exit_driver;
1730787c72b107888805981faf148c8fea96a752d22eJean Delvare
1731787c72b107888805981faf148c8fea96a752d22eJean Delvare	return 0;
1732787c72b107888805981faf148c8fea96a752d22eJean Delvare
1733787c72b107888805981faf148c8fea96a752d22eJean Delvareexit_driver:
1734787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_driver_unregister(&w83627hf_driver);
1735787c72b107888805981faf148c8fea96a752d22eJean Delvareexit:
1736787c72b107888805981faf148c8fea96a752d22eJean Delvare	return err;
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sensors_w83627hf_exit(void)
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1741787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_device_unregister(pdev);
1742787c72b107888805981faf148c8fea96a752d22eJean Delvare	platform_driver_unregister(&w83627hf_driver);
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "Philip Edelbrock <phil@netroedge.com>, "
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("W83627HF driver");
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sensors_w83627hf_init);
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sensors_w83627hf_exit);
1753