11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * sis5595.c - Part of lm_sensors, Linux kernel modules
38fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	       for hardware monitoring
48fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
58fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
68fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *			     Kyösti Mälkki <kmalkki@cc.hut.fi>, and
78fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *			     Mark D. Studebaker <mdsxyz123@yahoo.com>
88fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
98fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * the help of Jean Delvare <khali@linux-fr.org>
108fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
118fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * This program is free software; you can redistribute it and/or modify
128fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * it under the terms of the GNU General Public License as published by
138fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * the Free Software Foundation; either version 2 of the License, or
148fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * (at your option) any later version.
158fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
168fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * This program is distributed in the hope that it will be useful,
178fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of
188fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
198fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * GNU General Public License for more details.
208fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
218fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * You should have received a copy of the GNU General Public License
228fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * along with this program; if not, write to the Free Software
238fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
248fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
278fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * SiS southbridge has a LM78-like chip integrated on the same IC.
288fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * This driver is a customized copy of lm78.c
298fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
308fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Supports following revisions:
318fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	Version		PCI ID		PCI Revision
328fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	1		1039/0008	AF or less
338fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	2		1039/0008	B0 or greater
348fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
358fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *  Note: these chips contain a 0008 device which is incompatible with the
368fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 5595. We recognize these by the presence of the listed
378fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 "blacklist" PCI ID and refuse to load.
388fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *
398fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * NOT SUPPORTED	PCI ID		BLACKLIST PCI ID
408fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 540		0008		0540
418fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 550		0008		0550
428fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	5513		0008		5511
438fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	5581		0008		5597
448fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	5582		0008		5597
458fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	5597		0008		5597
468fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	5598		0008		5597/5598
478fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 630		0008		0630
488fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 645		0008		0645
498fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 730		0008		0730
508fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck *	 735		0008		0735
518fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
534b2515dbb94341db01db3208f9f40658c5e2a251Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
544b2515dbb94341db01db3208f9f40658c5e2a251Joe Perches
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
5917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare#include <linux/platform_device.h>
60943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
611f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare#include <linux/hwmon-sysfs.h>
62943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
64ff3240946d6a3d9f2ecf273f7330e09eec5484ebDominik Hackl#include <linux/jiffies.h>
659a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
66a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare#include <linux/sysfs.h>
67b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare#include <linux/acpi.h>
686055fae8aceee41471edfd1876e5617d16e028feH Hartley Sweeten#include <linux/io.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
718fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
728fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * If force_addr is set to anything different from 0, we forcibly enable
738fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * the device at the given address.
748fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the base address of the sensors");
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic struct platform_device *pdev;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Many SIS5595 constants specified below */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Length of ISA address segment */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_EXTENT 8
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI Config Registers */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_BASE_REG 0x68
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_PIN_REG 0x7A
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_ENABLE_REG 0x7B
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Where are the ISA address/data registers relative to the base address */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_ADDR_REG_OFFSET 5
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_DATA_REG_OFFSET 6
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The SIS5595 registers */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_IN(nr) (0x20 + (nr))
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_FAN(nr) (0x28 + (nr))
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1038fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1048fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * On the first version of the chip, the temp registers are separate.
1058fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * On the second version,
1068fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * TEMP pin is shared with IN4, configured in PCI register 0x7A.
1078fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * The registers are the same as well.
1088fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * OVER and HYST are really MAX and MIN.
1098fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REV2MIN	0xb0
1128fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck#define SIS5595_REG_TEMP	(((data->revision) >= REV2MIN) ? \
1138fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck					SIS5595_REG_IN(4) : 0x27)
1148fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck#define SIS5595_REG_TEMP_OVER	(((data->revision) >= REV2MIN) ? \
1158fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck					SIS5595_REG_IN_MAX(4) : 0x39)
1168fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck#define SIS5595_REG_TEMP_HYST	(((data->revision) >= REV2MIN) ? \
1178fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck					SIS5595_REG_IN_MIN(4) : 0x3a)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_CONFIG 0x40
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_ALARM1 0x41
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_ALARM2 0x42
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIS5595_REG_FANDIV 0x47
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1248fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1258fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Conversions. Limit checking is only done on the TO_REG
1268fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * variants.
1278fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1298fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1308fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * IN: mV, (0V to 4.08V)
1318fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * REG: 16mV/bit
1328fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 IN_TO_REG(unsigned long val)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (nval + 8) / 16;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) *  16)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm <= 0)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int FAN_FROM_REG(u8 val, int div)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1498fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1528fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1538fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * TEMP: mC (-54.12C to +157.53C)
1548fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * REG: 0.83C/bit + 52.12, two's complement
1558fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int TEMP_FROM_REG(s8 val)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val * 830 + 52120;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline s8 TEMP_TO_REG(int val)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nval = SENSORS_LIMIT(val, -54120, 157530) ;
1638fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1668fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1678fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
1688fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
1698fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 DIV_TO_REG(int val)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1728fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val))
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1768fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
1778fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * For each registered chip, we need to keep some data in memory.
1788fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * The structure is dynamically allocated.
1798fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sis5595_data {
18117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	unsigned short addr;
18217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	const char *name;
1831beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
1849a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex lock;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1869a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 revision;		/* Reg. value */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[5];		/* Register value */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[5];		/* Register value */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[5];		/* Register value */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[2];		/* Register value */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[2];		/* Register value */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp;		/* Register value */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp_over;		/* Register value */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp_hyst;		/* Register value */
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_div[2];		/* Register encoding, shifted right */
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 alarms;		/* Register encoding, combined */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int sis5595_probe(struct platform_device *pdev);
207d0546128980c18748010c758903b02909e634830Jean Delvarestatic int __devexit sis5595_remove(struct platform_device *pdev);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int sis5595_read_value(struct sis5595_data *data, u8 reg);
21017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sis5595_data *sis5595_update_device(struct device *dev);
21217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic void sis5595_init_device(struct sis5595_data *data);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic struct platform_driver sis5595_driver = {
215cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	.driver = {
216872188420997f7f7c1b968fd9bce6578e4c3d45fJean Delvare		.owner	= THIS_MODULE,
217cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard		.name	= "sis5595",
218cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	},
21917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	.probe		= sis5595_probe,
22017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	.remove		= __devexit_p(sis5595_remove),
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4 Voltages */
2241f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_in(struct device *dev, struct device_attribute *da,
2251f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		       char *buf)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
2281f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2291f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_in_min(struct device *dev, struct device_attribute *da,
2341f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			   char *buf)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
2371f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2381f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_in_max(struct device *dev, struct device_attribute *da,
2431f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			   char *buf)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
2461f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2471f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t set_in_min(struct device *dev, struct device_attribute *da,
2521f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			  const char *buf, size_t count)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
2551f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2561f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
2578fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	unsigned long val;
2588fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
2598fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
2608fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtoul(buf, 10, &val);
2618fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
2628fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2649a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->in_min[nr] = IN_TO_REG(val);
26617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
2679a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t set_in_max(struct device *dev, struct device_attribute *da,
2721f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			  const char *buf, size_t count)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
27417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
2751f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2761f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
2778fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	unsigned long val;
2788fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
2798fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
2808fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtoul(buf, 10, &val);
2818fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
2828fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2849a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->in_max[nr] = IN_TO_REG(val);
28617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
2879a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_offset(offset)					\
2921f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
2931f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_in, NULL, offset);				\
2941f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
2951f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_in_min, set_in_min, offset);		\
2961f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
2971f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_in_max, set_in_max, offset);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(0);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(1);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(2);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(3);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(4);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Temperature */
3068fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t show_temp(struct device *dev, struct device_attribute *attr,
3078fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			 char *buf)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3138fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
3148fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			      char *buf)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3208fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t set_temp_over(struct device *dev, struct device_attribute *attr,
3218fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			     const char *buf, size_t count)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
3248fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	long val;
3258fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
3268fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
3278fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtol(buf, 10, &val);
3288fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
3298fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3319a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->temp_over = TEMP_TO_REG(val);
33317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
3349a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3388fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
3398fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			      char *buf)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3458fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr,
3468fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			     const char *buf, size_t count)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
3498fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	long val;
3508fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
3518fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
3528fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtol(buf, 10, &val);
3538fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
3548fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3569a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->temp_hyst = TEMP_TO_REG(val);
35817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
3599a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		show_temp_over, set_temp_over);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		show_temp_hyst, set_temp_hyst);
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2 Fans */
3701f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_fan(struct device *dev, struct device_attribute *da,
3711f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			char *buf)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
3741f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3751f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
3778fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		DIV_FROM_REG(data->fan_div[nr])));
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
3811f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			    char *buf)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
3841f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3851f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
3868fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
3878fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		DIV_FROM_REG(data->fan_div[nr])));
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
3911f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			   const char *buf, size_t count)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
3941f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3951f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
3968fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	unsigned long val;
3978fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
3988fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
3998fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtoul(buf, 10, &val);
4008fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
4018fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4039a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
40517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
4069a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
4111f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			    char *buf)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
4141f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4151f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
4168fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4198fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck/*
4208fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * Note: we save and restore the fan minimum here, because its value is
4218fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * determined in part by the fan divisor.  This follows the principle of
4228fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * least surprise; the user doesn't expect the fan minimum to change just
4238fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck * because the divisor changed.
4248fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck */
4251f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
4261f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare			   const char *buf, size_t count)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
4291f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4301f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	int nr = attr->index;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long min;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg;
4338fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	unsigned long val;
4348fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	int err;
4358fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
4368fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = kstrtoul(buf, 10, &val);
4378fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
4388fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		return err;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4409a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	min = FAN_FROM_REG(data->fan_min[nr],
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DIV_FROM_REG(data->fan_div[nr]));
44317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
4468fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	case 1:
4478fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		data->fan_div[nr] = 0;
4488fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		break;
4498fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	case 2:
4508fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		data->fan_div[nr] = 1;
4518fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		break;
4528fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	case 4:
4538fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		data->fan_div[nr] = 2;
4548fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		break;
4558fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	case 8:
4568fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		data->fan_div[nr] = 3;
4578fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		break;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
45917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_err(dev, "fan_div value %ld not "
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"supported. Choose one of 1, 2, 4 or 8!\n", val);
4619a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar		mutex_unlock(&data->update_lock);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4648fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (nr) {
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] =
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
47617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
4779a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_fan_offset(offset)						\
4821f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
4831f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_fan, NULL, offset - 1);				\
4841f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
4851f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_fan_min, set_fan_min, offset - 1);			\
4861f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
4871f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare		show_fan_div, set_fan_div, offset - 1);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_offset(1);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_offset(2);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Alarms */
4938fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeckstatic ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
4948fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			   char *buf)
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data = sis5595_update_device(dev);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", data->alarms);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
500a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
5015c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic ssize_t show_alarm(struct device *dev, struct device_attribute *da,
5025c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca			  char *buf)
5035c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca{
5045c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	struct sis5595_data *data = sis5595_update_device(dev);
5055c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	int nr = to_sensor_dev_attr(da)->index;
5065c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
5075c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca}
5085c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
5095c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
5105c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
5115c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
5125c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
5135c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
5145c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
5155c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Mancastatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
5165c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca
51717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic ssize_t show_name(struct device *dev, struct device_attribute *attr,
51817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			 char *buf)
51917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare{
52017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
52117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	return sprintf(buf, "%s\n", data->name);
52217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare}
52317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
52417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
525a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic struct attribute *sis5595_attributes[] = {
5261f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in0_input.dev_attr.attr,
5271f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in0_min.dev_attr.attr,
5281f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in0_max.dev_attr.attr,
5295c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_in0_alarm.dev_attr.attr,
5301f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in1_input.dev_attr.attr,
5311f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in1_min.dev_attr.attr,
5321f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in1_max.dev_attr.attr,
5335c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_in1_alarm.dev_attr.attr,
5341f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in2_input.dev_attr.attr,
5351f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in2_min.dev_attr.attr,
5361f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in2_max.dev_attr.attr,
5375c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_in2_alarm.dev_attr.attr,
5381f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in3_input.dev_attr.attr,
5391f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in3_min.dev_attr.attr,
5401f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in3_max.dev_attr.attr,
5415c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_in3_alarm.dev_attr.attr,
5421f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare
5431f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan1_input.dev_attr.attr,
5441f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan1_min.dev_attr.attr,
5451f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan1_div.dev_attr.attr,
5465c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
5471f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan2_input.dev_attr.attr,
5481f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan2_min.dev_attr.attr,
5491f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_fan2_div.dev_attr.attr,
5505c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
551a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
552a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	&dev_attr_alarms.attr,
55317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	&dev_attr_name.attr,
554a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	NULL
555a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
556a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
557a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic const struct attribute_group sis5595_group = {
558a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	.attrs = sis5595_attributes,
559a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
560a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
56176e63860daedb302bddd707a765411c902d936bdIvo Mancastatic struct attribute *sis5595_attributes_in4[] = {
5621f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in4_input.dev_attr.attr,
5631f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in4_min.dev_attr.attr,
5641f5f48dde709ae6951a2f1e044c21f5641684b0aJean Delvare	&sensor_dev_attr_in4_max.dev_attr.attr,
5655c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_in4_alarm.dev_attr.attr,
56676e63860daedb302bddd707a765411c902d936bdIvo Manca	NULL
56776e63860daedb302bddd707a765411c902d936bdIvo Manca};
56876e63860daedb302bddd707a765411c902d936bdIvo Manca
56976e63860daedb302bddd707a765411c902d936bdIvo Mancastatic const struct attribute_group sis5595_group_in4 = {
57076e63860daedb302bddd707a765411c902d936bdIvo Manca	.attrs = sis5595_attributes_in4,
57176e63860daedb302bddd707a765411c902d936bdIvo Manca};
572a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
57376e63860daedb302bddd707a765411c902d936bdIvo Mancastatic struct attribute *sis5595_attributes_temp1[] = {
574a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	&dev_attr_temp1_input.attr,
575a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	&dev_attr_temp1_max.attr,
576a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	&dev_attr_temp1_max_hyst.attr,
5775c726b3ba0d6692253a09d88c701f0c4b45ca248Ivo Manca	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
578a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	NULL
579a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
580a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
58176e63860daedb302bddd707a765411c902d936bdIvo Mancastatic const struct attribute_group sis5595_group_temp1 = {
58276e63860daedb302bddd707a765411c902d936bdIvo Manca	.attrs = sis5595_attributes_temp1,
583a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
5848fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is called when the module is loaded */
58617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int __devinit sis5595_probe(struct platform_device *pdev)
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sis5595_data *data;
59117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct resource *res;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char val;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reserve the ISA region */
59517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
59617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (!request_region(res->start, SIS5595_EXTENT,
597cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard			    sis5595_driver.driver.name)) {
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBUSY;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6028fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL);
6038fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (!data) {
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit_release;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6089a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->lock);
60917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	mutex_init(&data->update_lock);
61017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	data->addr = res->start;
61117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	data->name = "sis5595";
61217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	platform_set_drvdata(pdev, data);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6148fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	/*
6158fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	 * Check revision and pin registers to determine whether 4 or 5 voltages
6168fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	 */
6177b6d1f044d95395ca103bfb6869caa996fedbbd2Auke Kok	data->revision = s_bridge->revision;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 4 voltages, 1 temp */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->maxins = 3;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->revision >= REV2MIN) {
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(val & 0x80))
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 5 voltages, no temps */
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->maxins = 4;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6268fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the SIS5595 chip */
62817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sis5595_init_device(data);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A few vars need to be filled upon startup */
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 2; i++) {
63217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		data->fan_min[i] = sis5595_read_value(data,
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					SIS5595_REG_FAN_MIN(i));
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Register sysfs hooks */
6378fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group);
6388fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	if (err)
63917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit_free;
640a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	if (data->maxins == 4) {
6418fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4);
6428fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		if (err)
643a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare			goto exit_remove_files;
644a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	} else {
6458fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1);
6468fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		if (err)
647a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare			goto exit_remove_files;
648a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	}
649a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
6501beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	data->hwmon_dev = hwmon_device_register(&pdev->dev);
6511beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
6521beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
653a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare		goto exit_remove_files;
654943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	}
655943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
657943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
658a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvareexit_remove_files:
65917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
66076e63860daedb302bddd707a765411c902d936bdIvo Manca	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
66176e63860daedb302bddd707a765411c902d936bdIvo Manca	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_free:
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_release:
66517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	release_region(res->start, SIS5595_EXTENT);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int __devexit sis5595_remove(struct platform_device *pdev)
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
67217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = platform_get_drvdata(pdev);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	hwmon_device_unregister(data->hwmon_dev);
67517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
67676e63860daedb302bddd707a765411c902d936bdIvo Manca	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
67776e63860daedb302bddd707a765411c902d936bdIvo Manca	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	release_region(data->addr, SIS5595_EXTENT);
68017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	platform_set_drvdata(pdev, NULL);
681943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	kfree(data);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ISA access must be locked explicitly. */
68817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int sis5595_read_value(struct sis5595_data *data, u8 reg)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6929a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
69317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
69417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
6959a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7019a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
70217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
70317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
7049a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called when we have found a new SIS5595. */
70817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic void __devinit sis5595_init_device(struct sis5595_data *data)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
71017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(config & 0x01))
71217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		sis5595_write_value(data, SIS5595_REG_CONFIG,
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(config & 0xf7) | 0x01);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sis5595_data *sis5595_update_device(struct device *dev)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
71817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct sis5595_data *data = dev_get_drvdata(dev);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7219a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || !data->valid) {
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= data->maxins; i++) {
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in[i] =
72817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data, SIS5595_REG_IN(i));
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_min[i] =
73017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data,
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       SIS5595_REG_IN_MIN(i));
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_max[i] =
73317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data,
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       SIS5595_REG_IN_MAX(i));
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 2; i++) {
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[i] =
73817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data, SIS5595_REG_FAN(i));
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[i] =
74017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data,
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       SIS5595_REG_FAN_MIN(i));
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->maxins == 3) {
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp =
74517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data, SIS5595_REG_TEMP);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_over =
74717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_hyst =
74917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
75117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] = (i >> 4) & 0x03;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] = i >> 6;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->alarms =
75517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
75617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7619a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
766600151b9de97bd580f9dc09199a10f0c2b65cb97Frans Meulenbroeksstatic DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = {
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int blacklist[] __devinitdata = {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_540,
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_550,
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_630,
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_645,
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_730,
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_735,
7808fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	PCI_DEVICE_ID_SI_5511, /*
7818fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				* 5513 chip has the 0008 device but
7828fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				* that ID shows up in other chips so we
7838fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				* use the 5511 ID for recognition
7848fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				*/
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_5597,
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_SI_5598,
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0 };
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvarestatic int __devinit sis5595_device_add(unsigned short address)
79017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare{
79117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	struct resource res = {
79217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		.start	= address,
79317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		.end	= address + SIS5595_EXTENT - 1,
79417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		.name	= "sis5595",
79517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		.flags	= IORESOURCE_IO,
79617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	};
79717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	int err;
79817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
799b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare	err = acpi_check_resource_conflict(&res);
800b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare	if (err)
801b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare		goto exit;
802b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare
80317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	pdev = platform_device_alloc("sis5595", address);
80417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (!pdev) {
80517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		err = -ENOMEM;
8064b2515dbb94341db01db3208f9f40658c5e2a251Joe Perches		pr_err("Device allocation failed\n");
80717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit;
80817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
80917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
81017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	err = platform_device_add_resources(pdev, &res, 1);
81117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (err) {
8124b2515dbb94341db01db3208f9f40658c5e2a251Joe Perches		pr_err("Device resource addition failed (%d)\n", err);
81317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit_device_put;
81417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
81517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
81617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	err = platform_device_add(pdev);
81717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (err) {
8184b2515dbb94341db01db3208f9f40658c5e2a251Joe Perches		pr_err("Device addition failed (%d)\n", err);
81917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit_device_put;
82017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
82117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
82217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	return 0;
82317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
82417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvareexit_device_put:
82517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	platform_device_put(pdev);
82617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvareexit:
82717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	return err;
82817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare}
82917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit sis5595_pci_probe(struct pci_dev *dev,
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       const struct pci_device_id *id)
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
83317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	u16 address;
83417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	u8 enable;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int *i;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = blacklist; *i != 0; i++) {
8385460a9d0ffc860a370631e096a8a6f3682f3fc94Mark M. Hoffman		struct pci_dev *d;
8398fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
8408fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		if (d) {
8418fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			dev_err(&d->dev,
8428fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				"Looked for SIS5595 but found unsupported device %.4x\n",
8438fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck				*i);
8445460a9d0ffc860a370631e096a8a6f3682f3fc94Mark M. Hoffman			pci_dev_put(d);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8488fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
84917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	force_addr &= ~(SIS5595_EXTENT - 1);
85017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (force_addr) {
85117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
85217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
85317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
85417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PCIBIOS_SUCCESSFUL !=
85617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	    pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
85717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_err(&dev->dev, "Failed to read ISA address\n");
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
85917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
8608fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck
86117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	address &= ~(SIS5595_EXTENT - 1);
86217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (!address) {
8638fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck		dev_err(&dev->dev,
8648fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck			"Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
86717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (force_addr && address != force_addr) {
86817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		/* doesn't work for some chips? */
86917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_err(&dev->dev, "Failed to force ISA address\n");
87017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		return -ENODEV;
87117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (PCIBIOS_SUCCESSFUL !=
87417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
87517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_err(&dev->dev, "Failed to read enable register\n");
87617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		return -ENODEV;
87717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
87817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (!(enable & 0x80)) {
87917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		if ((PCIBIOS_SUCCESSFUL !=
88017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		     pci_write_config_byte(dev, SIS5595_ENABLE_REG,
88117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare					   enable | 0x80))
88217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		 || (PCIBIOS_SUCCESSFUL !=
88317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		     pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
88417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		 || (!(enable & 0x80))) {
88517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			/* doesn't work for some chips! */
88617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			dev_err(&dev->dev, "Failed to enable HWM device\n");
88717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare			return -ENODEV;
88817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		}
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (platform_driver_register(&sis5595_driver)) {
89217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
89317e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit;
89417e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	}
89517e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
89617e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	s_bridge = pci_dev_get(dev);
89717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	/* Sets global pdev as a side effect */
89817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	if (sis5595_device_add(address))
89917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		goto exit_unregister;
90017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
9018fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	/*
9028fda79ec8654afa98fb9bad04d1e08df853fe05eGuenter Roeck	 * Always return failure here.  This is to allow other drivers to bind
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to this pci device.  We don't really want to have control over the
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * pci device, we only wanted to read as few register values from it.
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
90717e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare
90817e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvareexit_unregister:
90917e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	pci_dev_put(dev);
91017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	platform_driver_unregister(&sis5595_driver);
91117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvareexit:
91217e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare	return -ENODEV;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver sis5595_pci_driver = {
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name            = "sis5595",
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table        = sis5595_pci_ids,
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe           = sis5595_pci_probe,
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sm_sis5595_init(void)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_register_driver(&sis5595_pci_driver);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sm_sis5595_exit(void)
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&sis5595_pci_driver);
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (s_bridge != NULL) {
93017e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		platform_device_unregister(pdev);
93117e7dc4373dfcf2a3058d307665263df29dd5fe7Jean Delvare		platform_driver_unregister(&sis5595_driver);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_dev_put(s_bridge);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s_bridge = NULL;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("SiS 5595 Sensor device");
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sm_sis5595_init);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sm_sis5595_exit);
943