w83627hf.c revision 2723ab91cb4019def10bdb01b0fecb85e6ac7884
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>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Supports following chips:
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    For other winbond chips, and for i2c support in the above chips,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    use w83781d.c.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Note: automatic ("cruise") fan control for 697, 637 & 627thf not
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    supported yet.
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
45fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare#include <linux/i2c-isa.h>
46943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
47303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h>
48943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "lm75.h"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the base address of the sensors");
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 force_i2c = 0x1f;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_i2c, byte, 0);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_i2c,
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the i2c address of the sensors");
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
612d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare/* The actual ISA address is read from Super-I/O configuration space */
622d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic unsigned short address;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Insmod parameters */
652d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvareenum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
672251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvarestatic int reset;
682251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvaremodule_param(reset, bool, 0);
692251cf1a4b37bd483501614c2d78f5b8286f20d7Jean DelvareMODULE_PARM_DESC(reset, "Set to one to reset chip on load");
702251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, bool, 0);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* modified from kernel/include/traps.c */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int REG;		/* The register to read/write */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEV	0x07	/* Register: Logical device select */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int VAL;		/* The value to read/write */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* logical device numbers for superio_select (below) */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_FDC		0x00
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_PRT		0x01
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART1	0x02
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART2	0x03
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_KBC		0x05
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_CIR		0x06 /* w83627hf only */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GAME	0x07
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_MIDI	0x07
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO1	0x07
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO2	0x08
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO3	0x09
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_ACPI	0x0a
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_HWM		0x0b
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DEVID	0x20	/* Register: Device ID */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_outb(int reg, int val)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(val, VAL);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_inb(int reg)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, REG);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return inb(VAL);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_select(int ld)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(DEV, REG);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(ld, VAL);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_enter(void)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x87, REG);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_exit(void)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xAA, REG);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627_DEVID 0x52
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627THF_DEVID 0x82
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W697_DEVID 0x60
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W637_DEVID 0x70
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_ACT_REG 0x30
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_BASE_REG 0x60
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Constants specified below */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Alignment of the base address */
146ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_ALIGNMENT		~7
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Offset & size of I/O region we are interested in */
149ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_OFFSET	5
150ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_SIZE	2
151ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec
152ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Where are the sensors address/data registers relative to the base address */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_ADDR_REG_OFFSET 5
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DATA_REG_OFFSET 6
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83781D registers */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83782D registers for nr=7,8 are in bank 5 */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x554 + (((nr) - 7) * 2)))
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x555 + (((nr) - 7) * 2)))
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   (0x550 + (nr) - 7))
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN(nr) (0x27 + (nr))
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP2_CONFIG 0x152
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP3_CONFIG 0x252
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x0150) : \
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x27)))
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x153) : \
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x3A)))
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					((nr == 2) ? (0x155) : \
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					             (0x39)))
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BANK 0x4E
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CONFIG 0x40
1834a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM1 0x459
1844a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM2 0x45A
1854a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu#define W83781D_REG_ALARM3 0x45B
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_CONFIG 0x4D
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS1 0x56
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS2 0x57
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS3 0x453
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VID_FANDIV 0x47
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPID 0x49
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_WCHIPID 0x58
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPMAN 0x4F
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_PIN 0x4B
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VBAT 0x5D
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM1 0x5A
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM2 0x5B
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM1		0x01	/* 697HF and 637HF too */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM2		0x03	/* 697HF and 637HF too */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM3		0x11	/* 637HF too */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                             W83627THF_REG_PWM3 };
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_ADDR 0x48
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_SUBADDR 0x4A
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sensor selection */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG1 0x5D
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG2 0x59
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DEFAULT_BETA 3435
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Conversions. Limit checking is only done on the TO_REG
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   variants. Note that you should be a bit careful with which arguments
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   these macros are called: arguments may be evaluated more than once.
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Fixing this is just not worth it. */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) * 16)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm == 0)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     254);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MIN (-128000)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MAX ( 127000)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMP: 0.001C/bit (-128C to +127C)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 1C/bit, two's complement */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 TEMP_TO_REG(int temp)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ntemp += (ntemp<0 ? -500 : 500);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (u8)(ntemp / 1000);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TEMP_FROM_REG(u8 reg)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return (s8)reg * 1000;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_FROM_REG(val)		 (val)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_FROM_REG(val)	((val)?1:0)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val))
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 DIV_TO_REG(long val)
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = SENSORS_LIMIT(val, 1, 128) >> 1;
274abc01922477104e8d72b494902aff37135c409e7Grant Coady	for (i = 0; i < 7; i++) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val == 0)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val >>= 1;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ((u8) i);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* For each registered chip, we need to keep some data in memory. That
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   data is pointed to by w83627hf_list[NR]->data. The structure itself is
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dynamically allocated, at the same time when a new client is allocated. */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct w83627hf_data {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client client;
287943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	struct class_device *class_dev;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct semaphore lock;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum chips type;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct semaphore update_lock;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *lm75;	/* for secondary I2C addresses */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* pointer to array of 2 subclients */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[9];		/* Register value */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[9];		/* Register value */
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[9];		/* Register value */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[3];		/* Register value */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[3];		/* Register value */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_max;		/* Register value */
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_max_hyst;	/* Register value */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_add[2];	/* Register value */
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_max_add[2];	/* Register value */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_max_hyst_add[2]; /* Register value */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_div[3];		/* Register encoding, shifted right */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid;			/* Register encoding, combined */
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 alarms;		/* Register encoding, combined */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 beep_mask;		/* Register encoding, combined */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 beep_enable;		/* Boolean */
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwm[3];		/* Register value */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 sens[3];		/* 782D/783S only.
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   1 = pentium diode; 2 = 3904 diode;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   3000-5000 = thermistor beta.
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   Default = 3435.
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   Other Betas unimplemented */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm_ovt;		/* Register value, 627thf & 637hf only */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3252d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic int w83627hf_detect(struct i2c_adapter *adapter);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_detach_client(struct i2c_client *client);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_read_value(struct i2c_client *client, u16 register);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_write_value(struct i2c_client *client, u16 register,
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       u16 value);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void w83627hf_init_client(struct i2c_client *client);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_driver w83627hf_driver = {
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "w83627hf",
3372d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	.attach_adapter	= w83627hf_detect,
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.detach_client	= w83627hf_detach_client,
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* following are the sysfs callback functions */
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_reg(reg) \
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in)
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_min)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_max)
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_in_reg(REG, reg) \
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev); \
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client); \
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val; \
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10); \
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock); \
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->in_##reg[nr] = IN_TO_REG(val); \
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    data->in_##reg[nr]); \
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock); \
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MIN, min)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MAX, max)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offset(offset) \
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
375a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return show_in(dev, buf, offset); \
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_reg_offset(reg, offset) \
382a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_##reg (dev, buf, offset); \
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
387a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    const char *buf, size_t count) \
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_in_##reg (dev, buf, count, offset); \
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_in_##reg##offset, store_regs_in_##reg##offset);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offsets(offset) \
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offset(offset) \
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(min, offset) \
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(max, offset)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(1);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(2);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(3);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(4);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(5);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(6);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(7);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(8);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* use a different set of functions for in0 */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long in0;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(w83627thf == data->type || w83637hf == data->type))
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)((reg * 488 + 70000 + 50) / 100);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in0 = (long)IN_FROM_REG(reg);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", in0);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
426a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in[0]);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
432a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_min[0]);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
438a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_in_0(data, buf, data->in_max[0]);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
444a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(w83627thf == data->type || w83637hf == data->type))
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
4592723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_min[0] =
4602723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
4612723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_min[0] = IN_TO_REG(val);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *buf, size_t count)
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->vrm_ovt & 0x01) &&
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(w83627thf == data->type || w83637hf == data->type))
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM9 calculation */
4862723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu		data->in_max[0] =
4872723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
4882723ab91cb4019def10bdb01b0fecb85e6ac7884Yuan Mu					255);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* use VRM8 (standard) calculation */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_max[0] = IN_TO_REG(val);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_min0, store_regs_in_min0);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs_in_max0, store_regs_in_max0);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_in(client, offset) \
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_input); \
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_min); \
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_max); \
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_fan_reg(reg) \
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", \
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FAN_FROM_REG(data->reg[nr-1], \
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan_min);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_min(struct device *dev, const char *buf, size_t count, int nr)
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr - 1] =
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    data->fan_min[nr - 1]);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_offset(offset) \
542a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan(dev, buf, offset); \
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_min_offset(offset) \
549a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan_min(dev, buf, offset); \
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
554a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_fan_min(dev, buf, count, offset); \
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_fan_min##offset, store_regs_fan_min##offset);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(1);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(1);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(2);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(2);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(3);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(3);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_fan(client, offset) \
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_input); \
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_min); \
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_temp_reg(reg) \
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sprintf(buf,"%ld\n", \
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {	/* TEMP1 */ \
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} \
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max_hyst);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_temp_reg(REG, reg) \
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev); \
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client); \
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val; \
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10); \
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock); \
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp_##reg##_add[nr-2]); \
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {	/* TEMP1 */ \
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_##reg = TEMP_TO_REG(val); \
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_##reg); \
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} \
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 \
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock); \
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(OVER, max);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(HYST, max_hyst);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offset(offset) \
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
619a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_temp(dev, buf, offset); \
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_reg_offset(reg, offset) \
626a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_temp_##reg (dev, buf, offset); \
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
631a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      const char *buf, size_t count) \
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_temp_##reg (dev, buf, count, offset); \
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offsets(offset) \
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offset(offset) \
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max, offset) \
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max_hyst, offset)
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(1);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(2);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(3);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_temp(client, offset) \
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_input); \
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_max); \
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
656a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_vid(client) \
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_cpu0_vid)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
666a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->vrm);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
672a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->vrm = val;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_vrm(client) \
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_vrm)
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
688a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->alarms);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_alarms(client) \
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_alarms)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_beep_reg(REG, reg) \
698a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev); \
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf,"%ld\n", \
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(ENABLE, enable)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(MASK, mask)
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE			0	/* Store beep_enable */
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK			1	/* Store beep_mask */
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_beep_reg(struct device *dev, const char *buf, size_t count,
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       int update_mask)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, val2;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = BEEP_MASK_TO_REG(val);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    data->beep_mask & 0xff);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_BEEP_INTS3,
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((data->beep_mask) >> 16) & 0xff);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = (data->beep_mask >> 8) & 0x7f;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {		/* We are storing beep_enable */
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 =
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = BEEP_ENABLE_TO_REG(val);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    val2 | data->beep_enable << 7);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_beep(REG, reg) \
743a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
745a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannou	return show_beep_##reg(dev, attr, buf); \
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
748a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_beep_reg(dev, buf, count, BEEP_##REG); \
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_beep_##reg, store_regs_beep_##reg);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(ENABLE, enable);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(MASK, mask);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_beep(client) \
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_beep_enable); \
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_beep_mask); \
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_div_reg(struct device *dev, char *buf, int nr)
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n",
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we save and restore the fan minimum here, because its value is
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined in part by the fan divisor.  This follows the principle of
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   least suprise; the user doesn't expect the fan minimum to change just
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   because the divisor changed. */
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long min;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 reg;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save fan_min */
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	min = FAN_FROM_REG(data->fan_min[nr],
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   DIV_FROM_REG(data->fan_div[nr]));
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_div[nr] = DIV_TO_REG(val);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & (nr==0 ? 0xcf : 0x3f))
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = (w83627hf_read_value(client, W83781D_REG_VBAT)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       & ~(1 << (5 + nr)))
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_VBAT, reg);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore fan_min */
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_div(offset) \
812a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_fan_div_reg(dev, buf, offset); \
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
817a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    const char *buf, size_t count) \
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_fan_div_reg(dev, buf, count, offset - 1); \
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_fan_div_##offset, store_regs_fan_div_##offset);
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(1);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(2);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(3);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_fan_div(client, offset) \
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_div); \
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_pwm_reg(struct device *dev, char *buf, int nr)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->type == w83627thf) {
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bits 0-3 are reserved  in 627THF */
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client,
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     data->pwm[nr - 1] |
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     (w83627hf_read_value(client,
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->pwm[nr - 1] = PWM_TO_REG(val);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client,
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     W836X7HF_REG_PWM(data->type, nr),
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     data->pwm[nr - 1]);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_pwm(offset) \
872a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return show_pwm_reg(dev, buf, offset); \
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
877a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return store_pwm_reg(dev, buf, count, offset); \
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_pwm_##offset, store_regs_pwm_##offset);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(1);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(2);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(3);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_pwm(client, offset) \
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_pwm##offset); \
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_sensor_reg(struct device *dev, char *buf, int nr)
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = w83627hf_update_device(dev);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val, tmp;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(buf, NULL, 10);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* PII/Celeron diode */
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_SCFG1,
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG1[nr - 1]);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_SCFG2,
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG2[nr - 1]);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* 3904 */
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_SCFG1,
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp | BIT_SCFG1[nr - 1]);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_SCFG2,
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp & ~BIT_SCFG2[nr - 1]);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case W83781D_DEFAULT_BETA:	/* thermistor */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_SCFG1,
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    tmp & ~BIT_SCFG1[nr - 1]);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->sens[nr - 1] = val;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&client->dev,
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "Invalid sensor type %ld; must be 1, 2, or %d\n",
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (long) val, W83781D_DEFAULT_BETA);
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_sensor(offset) \
948a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return show_sensor_reg(dev, buf, offset); \
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \
953a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return store_sensor_reg(dev, buf, count, offset); \
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  show_regs_sensor_##offset, store_regs_sensor_##offset);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(1);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(2);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(3);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_sensor(client, offset) \
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_type); \
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
970e6cfb3ad7209e4f4dcdc14f5fc437db55667041fJean Delvarestatic int __init w83627hf_find(int sioaddr, unsigned short *addr)
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 val;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REG = sioaddr;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	VAL = sioaddr + 1;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val= superio_inb(DEVID);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(val != W627_DEVID &&
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   val != W627THF_DEVID &&
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   val != W697_DEVID &&
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   val != W637_DEVID) {
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_exit();
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_HWM);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = (superio_inb(WINB_BASE_REG) << 8) |
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       superio_inb(WINB_BASE_REG + 1);
990ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	*addr = val & WINB_ALIGNMENT;
9912d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	if (*addr == 0 && force_addr == 0) {
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_exit();
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10002d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic int w83627hf_detect(struct i2c_adapter *adapter)
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10022d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	int val, kind;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *new_client;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *client_name = "";
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(force_addr)
1009ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec		address = force_addr & WINB_ALIGNMENT;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE,
1012ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	                    w83627hf_driver.name)) {
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBUSY;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR0;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(force_addr) {
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_enter();
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_select(W83627HF_LD_HWM);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_outb(WINB_BASE_REG, address >> 8);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_outb(WINB_BASE_REG+1, address & 0xff);
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_exit();
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val= superio_inb(DEVID);
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(val == W627_DEVID)
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kind = w83627hf;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if(val == W697_DEVID)
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kind = w83697hf;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if(val == W627THF_DEVID)
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kind = w83627thf;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if(val == W637_DEVID)
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kind = w83637hf;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_info(&adapter->dev,
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 "Unsupported chip (dev_id=0x%02X).\n", val);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR1;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_HWM);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_outb(WINB_ACT_REG, 1);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. For now, we presume we have a valid client. We now create the
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   client structure, even though we cannot fill it completely yet.
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   But it allows us to access w83627hf_{read,write}_value. */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051ba9c2e8d15da029ea3051c95e446b2d638ef02e2Deepak Saxena	if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR1;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_client = &data->client;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2c_set_clientdata(new_client, data);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_client->addr = address;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_MUTEX(&data->lock);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_client->adapter = adapter;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_client->driver = &w83627hf_driver;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_client->flags = 0;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind == w83627hf) {
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_name = "w83627hf";
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (kind == w83627thf) {
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_name = "w83627thf";
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (kind == w83697hf) {
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_name = "w83697hf";
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (kind == w83637hf) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_name = "w83637hf";
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in the remaining client fields and put into the global list */
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->type = kind;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->valid = 0;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_MUTEX(&data->update_lock);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Tell the I2C layer a new client has arrived */
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((err = i2c_attach_client(new_client)))
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR2;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->lm75 = NULL;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the chip */
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_init_client(new_client);
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A few vars need to be filled upon startup */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1));
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Register sysfs hooks */
1096943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	data->class_dev = hwmon_device_register(&new_client->dev);
1097943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	if (IS_ERR(data->class_dev)) {
1098943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman		err = PTR_ERR(data->class_dev);
1099943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman		goto ERROR3;
1100943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	}
1101943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 0);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_in(new_client, 1);
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 2);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 3);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 4);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83627thf && kind != w83637hf) {
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_in(new_client, 5);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_in(new_client, 6);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 7);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_in(new_client, 8);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_fan(new_client, 1);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_fan(new_client, 2);
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_fan(new_client, 3);
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_temp(new_client, 1);
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_temp(new_client, 2);
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_temp(new_client, 3);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_vid(new_client);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_vrm(new_client);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_fan_div(new_client, 1);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_fan_div(new_client, 2);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_fan_div(new_client, 3);
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_alarms(new_client);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_beep(new_client);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_pwm(new_client, 1);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_pwm(new_client, 2);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind == w83627thf || kind == w83637hf)
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_pwm(new_client, 3);
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_sensor(new_client, 1);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file_sensor(new_client, 2);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind != w83697hf)
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_create_file_sensor(new_client, 3);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1152943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman      ERROR3:
1153943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	i2c_detach_client(new_client);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR2:
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR1:
1157ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      ERROR0:
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_detach_client(struct i2c_client *client)
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1164943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	struct w83627hf_data *data = i2c_get_clientdata(client);
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1167943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	hwmon_device_unregister(data->class_dev);
1168943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
11697bef559455fc71f66f8573cc1aafe1dd33966c1cJean Delvare	if ((err = i2c_detach_client(client)))
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1172ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec	release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE);
1173943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	kfree(data);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ISA access must always be locked explicitly!
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   would slow down the W83781D access and should not be necessary.
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   There are some ugly typecasts here, but the good news is - they should
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   nowhere else be necessary! */
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_read_value(struct i2c_client *client, u16 reg)
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, word_sized;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->lock);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x50)
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x53)
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(reg >> 8,
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_DATA_REG_OFFSET);
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res =
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (res << 8) + inb_p(client->addr +
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       W83781D_DATA_REG_OFFSET);
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->lock);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627thf_read_gpio5(struct i2c_client *client)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 0xff, sel;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enter();
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_select(W83627HF_LD_GPIO5);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure these GPIO pins are enabled */
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n");
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure the pins are configured for input
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sel = superio_inb(W83627THF_GPIO5_IOSR);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sel & 0x1f) != 0x1f) {
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&client->dev, "GPIO5 not configured for VID "
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"function\n");
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info(&client->dev, "Reading VID from GPIO5\n");
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = superio_inb(W83627THF_GPIO5_DR) & sel;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit();
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int word_sized;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->lock);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word_sized = (((reg & 0xff00) == 0x100)
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0xff00) == 0x200))
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (((reg & 0x00ff) == 0x53)
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || ((reg & 0x00ff) == 0x55));
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(reg >> 8,
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_DATA_REG_OFFSET);
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sized) {
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(value >> 8,
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_DATA_REG_OFFSET);
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p((reg & 0xff) + 1,
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(value & 0xff,
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       client->addr + W83781D_DATA_REG_OFFSET);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reg & 0xff00) {
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(W83781D_REG_BANK,
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       client->addr + W83781D_ADDR_REG_OFFSET);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->lock);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void w83627hf_init_client(struct i2c_client *client)
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type = data->type;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tmp;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12912251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare	if (reset) {
12922251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		/* Resetting the chip has been the default for a long time,
12932251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   but repeatedly caused problems (fans going to full
12942251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   speed...) so it is now optional. It might even go away if
12952251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   nobody reports it as being useful, as I see very little
12962251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		   reason why this would be needed at all. */
12972251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare		dev_info(&client->dev, "If reset=1 solved a problem you were "
12982251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare			 "having, please report!\n");
12992251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save this register */
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset all except Watchdog values and last conversion values
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This sets fan-divs to 2, among others */
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Restore the register and disable power-on abnormal beep.
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This saves FAN 1/2/3 input/output values set by BIOS. */
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable master beep-enable (reset turns it on).
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Individual beeps should be reset to off but for some reason
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   disabling this bit helps some people not get beeped */
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Minimize conflicts with other winbond i2c-only clients...  */
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable i2c subclients... how to disable main i2c client?? */
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* force i2c address to relatively uncommon address */
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VID only once */
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (w83627hf == data->type || w83637hf == data->type) {
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (w83627thf == data->type) {
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid = w83627thf_read_gpio5(client) & 0x3f;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read VRM & OVT Config only once */
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (w83627thf == data->type || w83637hf == data->type) {
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vrm_ovt =
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Convert VID to voltage based on default VRM */
1336303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare		data->vrm = vid_which_vrm();
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 3; i++) {
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(tmp & BIT_SCFG1[i - 1])) {
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->sens[i - 1] = W83781D_DEFAULT_BETA;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (w83627hf_read_value
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (client,
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 1;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->sens[i - 1] = 2;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((type == w83697hf) && (i == 2))
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(init) {
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp2 */
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG);
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp & 0x01) {
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_warn(&client->dev, "Enabling temp2, readings "
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "might not make sense\n");
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG,
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp & 0xfe);
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable temp3 */
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (type != w83697hf) {
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tmp = w83627hf_read_value(client,
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W83781D_REG_TEMP3_CONFIG);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp & 0x01) {
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev_warn(&client->dev, "Enabling temp3, "
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "readings might not make sense\n");
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				w83627hf_write_value(client,
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start monitoring */
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	w83627hf_write_value(client, W83781D_REG_CONFIG,
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (w83627hf_read_value(client,
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						W83781D_REG_CONFIG) & 0xf7)
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    | 0x01);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev)
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct w83627hf_data *data = i2c_get_clientdata(client);
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&data->update_lock);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || !data->valid) {
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 8; i++) {
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* skip missing sensors */
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((data->type == w83697hf) && (i == 1)) ||
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ((data->type == w83627thf || data->type == w83637hf)
13994a1c4447e523003019a2bf9b972ed6fe411e84d2Yuan Mu			    && (i == 5 || i == 6)))
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in[i] =
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    w83627hf_read_value(client, W83781D_REG_IN(i));
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_min[i] =
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    w83627hf_read_value(client,
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MIN(i));
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_max[i] =
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    w83627hf_read_value(client,
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_IN_MAX(i));
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 3; i++) {
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[i - 1] =
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    w83627hf_read_value(client, W83781D_REG_FAN(i));
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[i - 1] =
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    w83627hf_read_value(client,
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_FAN_MIN(i));
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 3; i++) {
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u8 tmp = w83627hf_read_value(client,
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W836X7HF_REG_PWM(data->type, i));
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			/* bits 0-3 are reserved  in 627THF */
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 			if (data->type == w83627thf)
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp &= 0xf0;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->pwm[i - 1] = tmp;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(i == 2 &&
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   (data->type == w83627hf || data->type == w83697hf))
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max =
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_hyst =
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_add[0] =
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_TEMP(2));
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_add[0] =
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->temp_max_hyst_add[0] =
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf) {
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_add[1] =
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  w83627hf_read_value(client, W83781D_REG_TEMP(3));
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_max_add[1] =
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_max_hyst_add[1] =
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] = (i >> 4) & 0x03;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] = (i >> 6) & 0x03;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf) {
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_div[2] = (w83627hf_read_value(client,
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       W83781D_REG_PIN) >> 6) & 0x03;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = w83627hf_read_value(client, W83781D_REG_VBAT);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] |= (i >> 3) & 0x04;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] |= (i >> 4) & 0x04;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->type != w83697hf)
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_div[2] |= (i >> 5) & 0x04;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->alarms =
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_ALARM1) |
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_enable = i >> 7;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->beep_mask = ((i & 0x7f) << 8) |
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&data->update_lock);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sensors_w83627hf_init(void)
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14812d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	if (w83627hf_find(0x2e, &address)
14822d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	 && w83627hf_find(0x4e, &address)) {
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1486fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare	return i2c_isa_add_driver(&w83627hf_driver);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sensors_w83627hf_exit(void)
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1491fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare	i2c_isa_del_driver(&w83627hf_driver);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "Philip Edelbrock <phil@netroedge.com>, "
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("W83627HF driver");
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sensors_w83627hf_init);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sensors_w83627hf_exit);
1502