xref: /openbmc/linux/drivers/hwmon/sis5595.c (revision 7c81c60f3789a082e141d7a013392af5f78db16a)
18d5d45fbSJean Delvare /*
28fda79ecSGuenter Roeck  * sis5595.c - Part of lm_sensors, Linux kernel modules
38fda79ecSGuenter Roeck  *	       for hardware monitoring
48fda79ecSGuenter Roeck  *
58fda79ecSGuenter Roeck  * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
68fda79ecSGuenter Roeck  *			     Kyösti Mälkki <kmalkki@cc.hut.fi>, and
78fda79ecSGuenter Roeck  *			     Mark D. Studebaker <mdsxyz123@yahoo.com>
88fda79ecSGuenter Roeck  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
9*7c81c60fSJean Delvare  * the help of Jean Delvare <jdelvare@suse.de>
108fda79ecSGuenter Roeck  *
118fda79ecSGuenter Roeck  * This program is free software; you can redistribute it and/or modify
128fda79ecSGuenter Roeck  * it under the terms of the GNU General Public License as published by
138fda79ecSGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
148fda79ecSGuenter Roeck  * (at your option) any later version.
158fda79ecSGuenter Roeck  *
168fda79ecSGuenter Roeck  * This program is distributed in the hope that it will be useful,
178fda79ecSGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
188fda79ecSGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
198fda79ecSGuenter Roeck  * GNU General Public License for more details.
208fda79ecSGuenter Roeck  *
218fda79ecSGuenter Roeck  * You should have received a copy of the GNU General Public License
228fda79ecSGuenter Roeck  * along with this program; if not, write to the Free Software
238fda79ecSGuenter Roeck  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
248d5d45fbSJean Delvare  */
258d5d45fbSJean Delvare 
268d5d45fbSJean Delvare /*
278fda79ecSGuenter Roeck  * SiS southbridge has a LM78-like chip integrated on the same IC.
288fda79ecSGuenter Roeck  * This driver is a customized copy of lm78.c
298fda79ecSGuenter Roeck  *
308fda79ecSGuenter Roeck  * Supports following revisions:
318fda79ecSGuenter Roeck  *	Version		PCI ID		PCI Revision
328fda79ecSGuenter Roeck  *	1		1039/0008	AF or less
338fda79ecSGuenter Roeck  *	2		1039/0008	B0 or greater
348fda79ecSGuenter Roeck  *
358fda79ecSGuenter Roeck  *  Note: these chips contain a 0008 device which is incompatible with the
368fda79ecSGuenter Roeck  *	 5595. We recognize these by the presence of the listed
378fda79ecSGuenter Roeck  *	 "blacklist" PCI ID and refuse to load.
388fda79ecSGuenter Roeck  *
398fda79ecSGuenter Roeck  * NOT SUPPORTED	PCI ID		BLACKLIST PCI ID
408fda79ecSGuenter Roeck  *	 540		0008		0540
418fda79ecSGuenter Roeck  *	 550		0008		0550
428fda79ecSGuenter Roeck  *	5513		0008		5511
438fda79ecSGuenter Roeck  *	5581		0008		5597
448fda79ecSGuenter Roeck  *	5582		0008		5597
458fda79ecSGuenter Roeck  *	5597		0008		5597
468fda79ecSGuenter Roeck  *	5598		0008		5597/5598
478fda79ecSGuenter Roeck  *	 630		0008		0630
488fda79ecSGuenter Roeck  *	 645		0008		0645
498fda79ecSGuenter Roeck  *	 730		0008		0730
508fda79ecSGuenter Roeck  *	 735		0008		0735
518d5d45fbSJean Delvare  */
528d5d45fbSJean Delvare 
534b2515dbSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
544b2515dbSJoe Perches 
558d5d45fbSJean Delvare #include <linux/module.h>
568d5d45fbSJean Delvare #include <linux/slab.h>
578d5d45fbSJean Delvare #include <linux/ioport.h>
588d5d45fbSJean Delvare #include <linux/pci.h>
5917e7dc43SJean Delvare #include <linux/platform_device.h>
60943b0830SMark M. Hoffman #include <linux/hwmon.h>
611f5f48ddSJean Delvare #include <linux/hwmon-sysfs.h>
62943b0830SMark M. Hoffman #include <linux/err.h>
638d5d45fbSJean Delvare #include <linux/init.h>
648d5d45fbSJean Delvare #include <linux/jiffies.h>
659a61bf63SIngo Molnar #include <linux/mutex.h>
66a5ebe668SJean Delvare #include <linux/sysfs.h>
67b9acb64aSJean Delvare #include <linux/acpi.h>
686055fae8SH Hartley Sweeten #include <linux/io.h>
698d5d45fbSJean Delvare 
708d5d45fbSJean Delvare 
718fda79ecSGuenter Roeck /*
728fda79ecSGuenter Roeck  * If force_addr is set to anything different from 0, we forcibly enable
738fda79ecSGuenter Roeck  * the device at the given address.
748fda79ecSGuenter Roeck  */
758d5d45fbSJean Delvare static u16 force_addr;
768d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
778d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
788d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
798d5d45fbSJean Delvare 
8017e7dc43SJean Delvare static struct platform_device *pdev;
818d5d45fbSJean Delvare 
828d5d45fbSJean Delvare /* Many SIS5595 constants specified below */
838d5d45fbSJean Delvare 
848d5d45fbSJean Delvare /* Length of ISA address segment */
858d5d45fbSJean Delvare #define SIS5595_EXTENT 8
868d5d45fbSJean Delvare /* PCI Config Registers */
878d5d45fbSJean Delvare #define SIS5595_BASE_REG 0x68
888d5d45fbSJean Delvare #define SIS5595_PIN_REG 0x7A
898d5d45fbSJean Delvare #define SIS5595_ENABLE_REG 0x7B
908d5d45fbSJean Delvare 
918d5d45fbSJean Delvare /* Where are the ISA address/data registers relative to the base address */
928d5d45fbSJean Delvare #define SIS5595_ADDR_REG_OFFSET 5
938d5d45fbSJean Delvare #define SIS5595_DATA_REG_OFFSET 6
948d5d45fbSJean Delvare 
958d5d45fbSJean Delvare /* The SIS5595 registers */
968d5d45fbSJean Delvare #define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
978d5d45fbSJean Delvare #define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
988d5d45fbSJean Delvare #define SIS5595_REG_IN(nr) (0x20 + (nr))
998d5d45fbSJean Delvare 
1008d5d45fbSJean Delvare #define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
1018d5d45fbSJean Delvare #define SIS5595_REG_FAN(nr) (0x28 + (nr))
1028d5d45fbSJean Delvare 
1038fda79ecSGuenter Roeck /*
1048fda79ecSGuenter Roeck  * On the first version of the chip, the temp registers are separate.
1058fda79ecSGuenter Roeck  * On the second version,
1068fda79ecSGuenter Roeck  * TEMP pin is shared with IN4, configured in PCI register 0x7A.
1078fda79ecSGuenter Roeck  * The registers are the same as well.
1088fda79ecSGuenter Roeck  * OVER and HYST are really MAX and MIN.
1098fda79ecSGuenter Roeck  */
1108d5d45fbSJean Delvare 
1118d5d45fbSJean Delvare #define REV2MIN	0xb0
1128fda79ecSGuenter Roeck #define SIS5595_REG_TEMP	(((data->revision) >= REV2MIN) ? \
1138fda79ecSGuenter Roeck 					SIS5595_REG_IN(4) : 0x27)
1148fda79ecSGuenter Roeck #define SIS5595_REG_TEMP_OVER	(((data->revision) >= REV2MIN) ? \
1158fda79ecSGuenter Roeck 					SIS5595_REG_IN_MAX(4) : 0x39)
1168fda79ecSGuenter Roeck #define SIS5595_REG_TEMP_HYST	(((data->revision) >= REV2MIN) ? \
1178fda79ecSGuenter Roeck 					SIS5595_REG_IN_MIN(4) : 0x3a)
1188d5d45fbSJean Delvare 
1198d5d45fbSJean Delvare #define SIS5595_REG_CONFIG 0x40
1208d5d45fbSJean Delvare #define SIS5595_REG_ALARM1 0x41
1218d5d45fbSJean Delvare #define SIS5595_REG_ALARM2 0x42
1228d5d45fbSJean Delvare #define SIS5595_REG_FANDIV 0x47
1238d5d45fbSJean Delvare 
1248fda79ecSGuenter Roeck /*
1258fda79ecSGuenter Roeck  * Conversions. Limit checking is only done on the TO_REG
1268fda79ecSGuenter Roeck  * variants.
1278fda79ecSGuenter Roeck  */
1288d5d45fbSJean Delvare 
1298fda79ecSGuenter Roeck /*
1308fda79ecSGuenter Roeck  * IN: mV, (0V to 4.08V)
1318fda79ecSGuenter Roeck  * REG: 16mV/bit
1328fda79ecSGuenter Roeck  */
1338d5d45fbSJean Delvare static inline u8 IN_TO_REG(unsigned long val)
1348d5d45fbSJean Delvare {
1352a844c14SGuenter Roeck 	unsigned long nval = clamp_val(val, 0, 4080);
1368d5d45fbSJean Delvare 	return (nval + 8) / 16;
1378d5d45fbSJean Delvare }
1388d5d45fbSJean Delvare #define IN_FROM_REG(val) ((val) *  16)
1398d5d45fbSJean Delvare 
1408d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1418d5d45fbSJean Delvare {
1428d5d45fbSJean Delvare 	if (rpm <= 0)
1438d5d45fbSJean Delvare 		return 255;
1443806b45bSDan Carpenter 	if (rpm > 1350000)
1453806b45bSDan Carpenter 		return 1;
1462a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1478d5d45fbSJean Delvare }
1488d5d45fbSJean Delvare 
1498d5d45fbSJean Delvare static inline int FAN_FROM_REG(u8 val, int div)
1508d5d45fbSJean Delvare {
1518d5d45fbSJean Delvare 	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
1528d5d45fbSJean Delvare }
1538d5d45fbSJean Delvare 
1548fda79ecSGuenter Roeck /*
1558fda79ecSGuenter Roeck  * TEMP: mC (-54.12C to +157.53C)
1568fda79ecSGuenter Roeck  * REG: 0.83C/bit + 52.12, two's complement
1578fda79ecSGuenter Roeck  */
1588d5d45fbSJean Delvare static inline int TEMP_FROM_REG(s8 val)
1598d5d45fbSJean Delvare {
1608d5d45fbSJean Delvare 	return val * 830 + 52120;
1618d5d45fbSJean Delvare }
1628d5d45fbSJean Delvare static inline s8 TEMP_TO_REG(int val)
1638d5d45fbSJean Delvare {
1642a844c14SGuenter Roeck 	int nval = clamp_val(val, -54120, 157530) ;
1658d5d45fbSJean Delvare 	return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
1668d5d45fbSJean Delvare }
1678d5d45fbSJean Delvare 
1688fda79ecSGuenter Roeck /*
1698fda79ecSGuenter Roeck  * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
1708fda79ecSGuenter Roeck  * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
1718fda79ecSGuenter Roeck  */
1728d5d45fbSJean Delvare static inline u8 DIV_TO_REG(int val)
1738d5d45fbSJean Delvare {
1748d5d45fbSJean Delvare 	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
1758d5d45fbSJean Delvare }
1768d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
1778d5d45fbSJean Delvare 
1788fda79ecSGuenter Roeck /*
1798fda79ecSGuenter Roeck  * For each registered chip, we need to keep some data in memory.
1808fda79ecSGuenter Roeck  * The structure is dynamically allocated.
1818fda79ecSGuenter Roeck  */
1828d5d45fbSJean Delvare struct sis5595_data {
18317e7dc43SJean Delvare 	unsigned short addr;
18417e7dc43SJean Delvare 	const char *name;
1851beeffe4STony Jones 	struct device *hwmon_dev;
1869a61bf63SIngo Molnar 	struct mutex lock;
1878d5d45fbSJean Delvare 
1889a61bf63SIngo Molnar 	struct mutex update_lock;
1898d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
1908d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
1918d5d45fbSJean Delvare 	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
1928d5d45fbSJean Delvare 	u8 revision;		/* Reg. value */
1938d5d45fbSJean Delvare 
1948d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
1958d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
1968d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
1978d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
1988d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
1998d5d45fbSJean Delvare 	s8 temp;		/* Register value */
2008d5d45fbSJean Delvare 	s8 temp_over;		/* Register value */
2018d5d45fbSJean Delvare 	s8 temp_hyst;		/* Register value */
2028d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
2038d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
2048d5d45fbSJean Delvare };
2058d5d45fbSJean Delvare 
2068d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
2078d5d45fbSJean Delvare 
20817e7dc43SJean Delvare static int sis5595_probe(struct platform_device *pdev);
209281dfd0bSBill Pemberton static int sis5595_remove(struct platform_device *pdev);
2108d5d45fbSJean Delvare 
21117e7dc43SJean Delvare static int sis5595_read_value(struct sis5595_data *data, u8 reg);
21217e7dc43SJean Delvare static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
2138d5d45fbSJean Delvare static struct sis5595_data *sis5595_update_device(struct device *dev);
21417e7dc43SJean Delvare static void sis5595_init_device(struct sis5595_data *data);
2158d5d45fbSJean Delvare 
21617e7dc43SJean Delvare static struct platform_driver sis5595_driver = {
217cdaf7934SLaurent Riffard 	.driver = {
21887218842SJean Delvare 		.owner	= THIS_MODULE,
2198d5d45fbSJean Delvare 		.name	= "sis5595",
220cdaf7934SLaurent Riffard 	},
22117e7dc43SJean Delvare 	.probe		= sis5595_probe,
2229e5e9b7aSBill Pemberton 	.remove		= sis5595_remove,
2238d5d45fbSJean Delvare };
2248d5d45fbSJean Delvare 
2258d5d45fbSJean Delvare /* 4 Voltages */
2261f5f48ddSJean Delvare static ssize_t show_in(struct device *dev, struct device_attribute *da,
2271f5f48ddSJean Delvare 		       char *buf)
2288d5d45fbSJean Delvare {
2298d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2301f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2311f5f48ddSJean Delvare 	int nr = attr->index;
2328d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
2338d5d45fbSJean Delvare }
2348d5d45fbSJean Delvare 
2351f5f48ddSJean Delvare static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
2361f5f48ddSJean Delvare 			   char *buf)
2378d5d45fbSJean Delvare {
2388d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2391f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2401f5f48ddSJean Delvare 	int nr = attr->index;
2418d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
2428d5d45fbSJean Delvare }
2438d5d45fbSJean Delvare 
2441f5f48ddSJean Delvare static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
2451f5f48ddSJean Delvare 			   char *buf)
2468d5d45fbSJean Delvare {
2478d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2481f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2491f5f48ddSJean Delvare 	int nr = attr->index;
2508d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
2518d5d45fbSJean Delvare }
2528d5d45fbSJean Delvare 
2531f5f48ddSJean Delvare static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
2541f5f48ddSJean Delvare 			  const char *buf, size_t count)
2558d5d45fbSJean Delvare {
25617e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
2571f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2581f5f48ddSJean Delvare 	int nr = attr->index;
2598fda79ecSGuenter Roeck 	unsigned long val;
2608fda79ecSGuenter Roeck 	int err;
2618fda79ecSGuenter Roeck 
2628fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
2638fda79ecSGuenter Roeck 	if (err)
2648fda79ecSGuenter Roeck 		return err;
2658d5d45fbSJean Delvare 
2669a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
2678d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val);
26817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
2699a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
2708d5d45fbSJean Delvare 	return count;
2718d5d45fbSJean Delvare }
2728d5d45fbSJean Delvare 
2731f5f48ddSJean Delvare static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
2741f5f48ddSJean Delvare 			  const char *buf, size_t count)
2758d5d45fbSJean Delvare {
27617e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
2771f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2781f5f48ddSJean Delvare 	int nr = attr->index;
2798fda79ecSGuenter Roeck 	unsigned long val;
2808fda79ecSGuenter Roeck 	int err;
2818fda79ecSGuenter Roeck 
2828fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
2838fda79ecSGuenter Roeck 	if (err)
2848fda79ecSGuenter Roeck 		return err;
2858d5d45fbSJean Delvare 
2869a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
2878d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val);
28817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
2899a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
2908d5d45fbSJean Delvare 	return count;
2918d5d45fbSJean Delvare }
2928d5d45fbSJean Delvare 
2938d5d45fbSJean Delvare #define show_in_offset(offset)					\
2941f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
2951f5f48ddSJean Delvare 		show_in, NULL, offset);				\
2961f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
2971f5f48ddSJean Delvare 		show_in_min, set_in_min, offset);		\
2981f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
2991f5f48ddSJean Delvare 		show_in_max, set_in_max, offset);
3008d5d45fbSJean Delvare 
3018d5d45fbSJean Delvare show_in_offset(0);
3028d5d45fbSJean Delvare show_in_offset(1);
3038d5d45fbSJean Delvare show_in_offset(2);
3048d5d45fbSJean Delvare show_in_offset(3);
3058d5d45fbSJean Delvare show_in_offset(4);
3068d5d45fbSJean Delvare 
3078d5d45fbSJean Delvare /* Temperature */
3088fda79ecSGuenter Roeck static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
3098fda79ecSGuenter Roeck 			 char *buf)
3108d5d45fbSJean Delvare {
3118d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3128d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
3138d5d45fbSJean Delvare }
3148d5d45fbSJean Delvare 
3158fda79ecSGuenter Roeck static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
3168fda79ecSGuenter Roeck 			      char *buf)
3178d5d45fbSJean Delvare {
3188d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3198d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
3208d5d45fbSJean Delvare }
3218d5d45fbSJean Delvare 
3228fda79ecSGuenter Roeck static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr,
3238fda79ecSGuenter Roeck 			     const char *buf, size_t count)
3248d5d45fbSJean Delvare {
32517e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3268fda79ecSGuenter Roeck 	long val;
3278fda79ecSGuenter Roeck 	int err;
3288fda79ecSGuenter Roeck 
3298fda79ecSGuenter Roeck 	err = kstrtol(buf, 10, &val);
3308fda79ecSGuenter Roeck 	if (err)
3318fda79ecSGuenter Roeck 		return err;
3328d5d45fbSJean Delvare 
3339a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3348d5d45fbSJean Delvare 	data->temp_over = TEMP_TO_REG(val);
33517e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
3369a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3378d5d45fbSJean Delvare 	return count;
3388d5d45fbSJean Delvare }
3398d5d45fbSJean Delvare 
3408fda79ecSGuenter Roeck static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
3418fda79ecSGuenter Roeck 			      char *buf)
3428d5d45fbSJean Delvare {
3438d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3448d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
3458d5d45fbSJean Delvare }
3468d5d45fbSJean Delvare 
3478fda79ecSGuenter Roeck static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr,
3488fda79ecSGuenter Roeck 			     const char *buf, size_t count)
3498d5d45fbSJean Delvare {
35017e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3518fda79ecSGuenter Roeck 	long val;
3528fda79ecSGuenter Roeck 	int err;
3538fda79ecSGuenter Roeck 
3548fda79ecSGuenter Roeck 	err = kstrtol(buf, 10, &val);
3558fda79ecSGuenter Roeck 	if (err)
3568fda79ecSGuenter Roeck 		return err;
3578d5d45fbSJean Delvare 
3589a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3598d5d45fbSJean Delvare 	data->temp_hyst = TEMP_TO_REG(val);
36017e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
3619a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3628d5d45fbSJean Delvare 	return count;
3638d5d45fbSJean Delvare }
3648d5d45fbSJean Delvare 
3658d5d45fbSJean Delvare static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
3668d5d45fbSJean Delvare static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
3678d5d45fbSJean Delvare 		show_temp_over, set_temp_over);
3688d5d45fbSJean Delvare static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
3698d5d45fbSJean Delvare 		show_temp_hyst, set_temp_hyst);
3708d5d45fbSJean Delvare 
3718d5d45fbSJean Delvare /* 2 Fans */
3721f5f48ddSJean Delvare static ssize_t show_fan(struct device *dev, struct device_attribute *da,
3731f5f48ddSJean Delvare 			char *buf)
3748d5d45fbSJean Delvare {
3758d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3761f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3771f5f48ddSJean Delvare 	int nr = attr->index;
3788d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
3798d5d45fbSJean Delvare 		DIV_FROM_REG(data->fan_div[nr])));
3808d5d45fbSJean Delvare }
3818d5d45fbSJean Delvare 
3821f5f48ddSJean Delvare static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
3831f5f48ddSJean Delvare 			    char *buf)
3848d5d45fbSJean Delvare {
3858d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3861f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3871f5f48ddSJean Delvare 	int nr = attr->index;
3888d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
3898d5d45fbSJean Delvare 		DIV_FROM_REG(data->fan_div[nr])));
3908d5d45fbSJean Delvare }
3918d5d45fbSJean Delvare 
3921f5f48ddSJean Delvare static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
3931f5f48ddSJean Delvare 			   const char *buf, size_t count)
3948d5d45fbSJean Delvare {
39517e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3961f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3971f5f48ddSJean Delvare 	int nr = attr->index;
3988fda79ecSGuenter Roeck 	unsigned long val;
3998fda79ecSGuenter Roeck 	int err;
4008fda79ecSGuenter Roeck 
4018fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4028fda79ecSGuenter Roeck 	if (err)
4038fda79ecSGuenter Roeck 		return err;
4048d5d45fbSJean Delvare 
4059a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4068d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
40717e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
4089a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4098d5d45fbSJean Delvare 	return count;
4108d5d45fbSJean Delvare }
4118d5d45fbSJean Delvare 
4121f5f48ddSJean Delvare static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
4131f5f48ddSJean Delvare 			    char *buf)
4148d5d45fbSJean Delvare {
4158d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
4161f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4171f5f48ddSJean Delvare 	int nr = attr->index;
4188d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
4198d5d45fbSJean Delvare }
4208d5d45fbSJean Delvare 
4218fda79ecSGuenter Roeck /*
4228fda79ecSGuenter Roeck  * Note: we save and restore the fan minimum here, because its value is
4238fda79ecSGuenter Roeck  * determined in part by the fan divisor.  This follows the principle of
4248fda79ecSGuenter Roeck  * least surprise; the user doesn't expect the fan minimum to change just
4258fda79ecSGuenter Roeck  * because the divisor changed.
4268fda79ecSGuenter Roeck  */
4271f5f48ddSJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
4281f5f48ddSJean Delvare 			   const char *buf, size_t count)
4298d5d45fbSJean Delvare {
43017e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
4311f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4321f5f48ddSJean Delvare 	int nr = attr->index;
4338d5d45fbSJean Delvare 	unsigned long min;
4348d5d45fbSJean Delvare 	int reg;
4358fda79ecSGuenter Roeck 	unsigned long val;
4368fda79ecSGuenter Roeck 	int err;
4378fda79ecSGuenter Roeck 
4388fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4398fda79ecSGuenter Roeck 	if (err)
4408fda79ecSGuenter Roeck 		return err;
4418d5d45fbSJean Delvare 
4429a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4438d5d45fbSJean Delvare 	min = FAN_FROM_REG(data->fan_min[nr],
4448d5d45fbSJean Delvare 			DIV_FROM_REG(data->fan_div[nr]));
44517e7dc43SJean Delvare 	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
4468d5d45fbSJean Delvare 
4478d5d45fbSJean Delvare 	switch (val) {
4488fda79ecSGuenter Roeck 	case 1:
4498fda79ecSGuenter Roeck 		data->fan_div[nr] = 0;
4508fda79ecSGuenter Roeck 		break;
4518fda79ecSGuenter Roeck 	case 2:
4528fda79ecSGuenter Roeck 		data->fan_div[nr] = 1;
4538fda79ecSGuenter Roeck 		break;
4548fda79ecSGuenter Roeck 	case 4:
4558fda79ecSGuenter Roeck 		data->fan_div[nr] = 2;
4568fda79ecSGuenter Roeck 		break;
4578fda79ecSGuenter Roeck 	case 8:
4588fda79ecSGuenter Roeck 		data->fan_div[nr] = 3;
4598fda79ecSGuenter Roeck 		break;
4608d5d45fbSJean Delvare 	default:
461b55f3757SGuenter Roeck 		dev_err(dev,
462b55f3757SGuenter Roeck 			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
463b55f3757SGuenter Roeck 			val);
4649a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
4658d5d45fbSJean Delvare 		return -EINVAL;
4668d5d45fbSJean Delvare 	}
4678d5d45fbSJean Delvare 
4688d5d45fbSJean Delvare 	switch (nr) {
4698d5d45fbSJean Delvare 	case 0:
4708d5d45fbSJean Delvare 		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
4718d5d45fbSJean Delvare 		break;
4728d5d45fbSJean Delvare 	case 1:
4738d5d45fbSJean Delvare 		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
4748d5d45fbSJean Delvare 		break;
4758d5d45fbSJean Delvare 	}
47617e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
4778d5d45fbSJean Delvare 	data->fan_min[nr] =
4788d5d45fbSJean Delvare 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
47917e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
4809a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4818d5d45fbSJean Delvare 	return count;
4828d5d45fbSJean Delvare }
4838d5d45fbSJean Delvare 
4848d5d45fbSJean Delvare #define show_fan_offset(offset)						\
4851f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
4861f5f48ddSJean Delvare 		show_fan, NULL, offset - 1);				\
4871f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
4881f5f48ddSJean Delvare 		show_fan_min, set_fan_min, offset - 1);			\
4891f5f48ddSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
4901f5f48ddSJean Delvare 		show_fan_div, set_fan_div, offset - 1);
4918d5d45fbSJean Delvare 
4928d5d45fbSJean Delvare show_fan_offset(1);
4938d5d45fbSJean Delvare show_fan_offset(2);
4948d5d45fbSJean Delvare 
4958d5d45fbSJean Delvare /* Alarms */
4968fda79ecSGuenter Roeck static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
4978fda79ecSGuenter Roeck 			   char *buf)
4988d5d45fbSJean Delvare {
4998d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
5008d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->alarms);
5018d5d45fbSJean Delvare }
5028d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
5038d5d45fbSJean Delvare 
5045c726b3bSIvo Manca static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
5055c726b3bSIvo Manca 			  char *buf)
5065c726b3bSIvo Manca {
5075c726b3bSIvo Manca 	struct sis5595_data *data = sis5595_update_device(dev);
5085c726b3bSIvo Manca 	int nr = to_sensor_dev_attr(da)->index;
5095c726b3bSIvo Manca 	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
5105c726b3bSIvo Manca }
5115c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
5125c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
5135c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
5145c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
5155c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
5165c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
5175c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
5185c726b3bSIvo Manca static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
5195c726b3bSIvo Manca 
52017e7dc43SJean Delvare static ssize_t show_name(struct device *dev, struct device_attribute *attr,
52117e7dc43SJean Delvare 			 char *buf)
52217e7dc43SJean Delvare {
52317e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
52417e7dc43SJean Delvare 	return sprintf(buf, "%s\n", data->name);
52517e7dc43SJean Delvare }
52617e7dc43SJean Delvare static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
52717e7dc43SJean Delvare 
528a5ebe668SJean Delvare static struct attribute *sis5595_attributes[] = {
5291f5f48ddSJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
5301f5f48ddSJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
5311f5f48ddSJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
5325c726b3bSIvo Manca 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
5331f5f48ddSJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
5341f5f48ddSJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
5351f5f48ddSJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
5365c726b3bSIvo Manca 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
5371f5f48ddSJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
5381f5f48ddSJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
5391f5f48ddSJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
5405c726b3bSIvo Manca 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
5411f5f48ddSJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
5421f5f48ddSJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
5431f5f48ddSJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
5445c726b3bSIvo Manca 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
545a5ebe668SJean Delvare 
5461f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
5471f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
5481f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
5495c726b3bSIvo Manca 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
5501f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
5511f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
5521f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
5535c726b3bSIvo Manca 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
554a5ebe668SJean Delvare 
555a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
55617e7dc43SJean Delvare 	&dev_attr_name.attr,
557a5ebe668SJean Delvare 	NULL
558a5ebe668SJean Delvare };
559a5ebe668SJean Delvare 
560a5ebe668SJean Delvare static const struct attribute_group sis5595_group = {
561a5ebe668SJean Delvare 	.attrs = sis5595_attributes,
562a5ebe668SJean Delvare };
563a5ebe668SJean Delvare 
56476e63860SIvo Manca static struct attribute *sis5595_attributes_in4[] = {
5651f5f48ddSJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
5661f5f48ddSJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
5671f5f48ddSJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
5685c726b3bSIvo Manca 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
56976e63860SIvo Manca 	NULL
57076e63860SIvo Manca };
571a5ebe668SJean Delvare 
57276e63860SIvo Manca static const struct attribute_group sis5595_group_in4 = {
57376e63860SIvo Manca 	.attrs = sis5595_attributes_in4,
57476e63860SIvo Manca };
57576e63860SIvo Manca 
57676e63860SIvo Manca static struct attribute *sis5595_attributes_temp1[] = {
577a5ebe668SJean Delvare 	&dev_attr_temp1_input.attr,
578a5ebe668SJean Delvare 	&dev_attr_temp1_max.attr,
579a5ebe668SJean Delvare 	&dev_attr_temp1_max_hyst.attr,
5805c726b3bSIvo Manca 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
581a5ebe668SJean Delvare 	NULL
582a5ebe668SJean Delvare };
583a5ebe668SJean Delvare 
58476e63860SIvo Manca static const struct attribute_group sis5595_group_temp1 = {
58576e63860SIvo Manca 	.attrs = sis5595_attributes_temp1,
586a5ebe668SJean Delvare };
587a5ebe668SJean Delvare 
5888d5d45fbSJean Delvare /* This is called when the module is loaded */
5896c931ae1SBill Pemberton static int sis5595_probe(struct platform_device *pdev)
5908d5d45fbSJean Delvare {
5918d5d45fbSJean Delvare 	int err = 0;
5928d5d45fbSJean Delvare 	int i;
5938d5d45fbSJean Delvare 	struct sis5595_data *data;
59417e7dc43SJean Delvare 	struct resource *res;
5958d5d45fbSJean Delvare 	char val;
5968d5d45fbSJean Delvare 
5978d5d45fbSJean Delvare 	/* Reserve the ISA region */
59817e7dc43SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
5995d224adeSGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT,
6005d224adeSGuenter Roeck 				 sis5595_driver.driver.name))
6015d224adeSGuenter Roeck 		return -EBUSY;
6028d5d45fbSJean Delvare 
6035d224adeSGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data),
6045d224adeSGuenter Roeck 			    GFP_KERNEL);
6055d224adeSGuenter Roeck 	if (!data)
6065d224adeSGuenter Roeck 		return -ENOMEM;
6078d5d45fbSJean Delvare 
6089a61bf63SIngo Molnar 	mutex_init(&data->lock);
60917e7dc43SJean Delvare 	mutex_init(&data->update_lock);
61017e7dc43SJean Delvare 	data->addr = res->start;
61117e7dc43SJean Delvare 	data->name = "sis5595";
61217e7dc43SJean Delvare 	platform_set_drvdata(pdev, data);
6138d5d45fbSJean Delvare 
6148fda79ecSGuenter Roeck 	/*
6158fda79ecSGuenter Roeck 	 * Check revision and pin registers to determine whether 4 or 5 voltages
6168fda79ecSGuenter Roeck 	 */
6177b6d1f04SAuke Kok 	data->revision = s_bridge->revision;
6188d5d45fbSJean Delvare 	/* 4 voltages, 1 temp */
6198d5d45fbSJean Delvare 	data->maxins = 3;
6208d5d45fbSJean Delvare 	if (data->revision >= REV2MIN) {
6218d5d45fbSJean Delvare 		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
6228d5d45fbSJean Delvare 		if (!(val & 0x80))
6238d5d45fbSJean Delvare 			/* 5 voltages, no temps */
6248d5d45fbSJean Delvare 			data->maxins = 4;
6258d5d45fbSJean Delvare 	}
6268d5d45fbSJean Delvare 
6278d5d45fbSJean Delvare 	/* Initialize the SIS5595 chip */
62817e7dc43SJean Delvare 	sis5595_init_device(data);
6298d5d45fbSJean Delvare 
6308d5d45fbSJean Delvare 	/* A few vars need to be filled upon startup */
6318d5d45fbSJean Delvare 	for (i = 0; i < 2; i++) {
63217e7dc43SJean Delvare 		data->fan_min[i] = sis5595_read_value(data,
6338d5d45fbSJean Delvare 					SIS5595_REG_FAN_MIN(i));
6348d5d45fbSJean Delvare 	}
6358d5d45fbSJean Delvare 
6368d5d45fbSJean Delvare 	/* Register sysfs hooks */
6378fda79ecSGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group);
6388fda79ecSGuenter Roeck 	if (err)
6395d224adeSGuenter Roeck 		return err;
640a5ebe668SJean Delvare 	if (data->maxins == 4) {
6418fda79ecSGuenter Roeck 		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4);
6428fda79ecSGuenter Roeck 		if (err)
643a5ebe668SJean Delvare 			goto exit_remove_files;
644a5ebe668SJean Delvare 	} else {
6458fda79ecSGuenter Roeck 		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1);
6468fda79ecSGuenter Roeck 		if (err)
647a5ebe668SJean Delvare 			goto exit_remove_files;
648a5ebe668SJean Delvare 	}
649a5ebe668SJean Delvare 
6501beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
6511beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
6521beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
653a5ebe668SJean Delvare 		goto exit_remove_files;
654943b0830SMark M. Hoffman 	}
655943b0830SMark M. Hoffman 
6568d5d45fbSJean Delvare 	return 0;
6578d5d45fbSJean Delvare 
658a5ebe668SJean Delvare exit_remove_files:
65917e7dc43SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
66076e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
66176e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
6628d5d45fbSJean Delvare 	return err;
6638d5d45fbSJean Delvare }
6648d5d45fbSJean Delvare 
665281dfd0bSBill Pemberton static int sis5595_remove(struct platform_device *pdev)
6668d5d45fbSJean Delvare {
66717e7dc43SJean Delvare 	struct sis5595_data *data = platform_get_drvdata(pdev);
6688d5d45fbSJean Delvare 
6691beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
67017e7dc43SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
67176e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
67276e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
673943b0830SMark M. Hoffman 
6748d5d45fbSJean Delvare 	return 0;
6758d5d45fbSJean Delvare }
6768d5d45fbSJean Delvare 
6778d5d45fbSJean Delvare 
6788d5d45fbSJean Delvare /* ISA access must be locked explicitly. */
67917e7dc43SJean Delvare static int sis5595_read_value(struct sis5595_data *data, u8 reg)
6808d5d45fbSJean Delvare {
6818d5d45fbSJean Delvare 	int res;
6828d5d45fbSJean Delvare 
6839a61bf63SIngo Molnar 	mutex_lock(&data->lock);
68417e7dc43SJean Delvare 	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
68517e7dc43SJean Delvare 	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
6869a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
6878d5d45fbSJean Delvare 	return res;
6888d5d45fbSJean Delvare }
6898d5d45fbSJean Delvare 
69017e7dc43SJean Delvare static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
6918d5d45fbSJean Delvare {
6929a61bf63SIngo Molnar 	mutex_lock(&data->lock);
69317e7dc43SJean Delvare 	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
69417e7dc43SJean Delvare 	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
6959a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
6968d5d45fbSJean Delvare }
6978d5d45fbSJean Delvare 
6988d5d45fbSJean Delvare /* Called when we have found a new SIS5595. */
6996c931ae1SBill Pemberton static void sis5595_init_device(struct sis5595_data *data)
7008d5d45fbSJean Delvare {
70117e7dc43SJean Delvare 	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
7028d5d45fbSJean Delvare 	if (!(config & 0x01))
70317e7dc43SJean Delvare 		sis5595_write_value(data, SIS5595_REG_CONFIG,
7048d5d45fbSJean Delvare 				(config & 0xf7) | 0x01);
7058d5d45fbSJean Delvare }
7068d5d45fbSJean Delvare 
7078d5d45fbSJean Delvare static struct sis5595_data *sis5595_update_device(struct device *dev)
7088d5d45fbSJean Delvare {
70917e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
7108d5d45fbSJean Delvare 	int i;
7118d5d45fbSJean Delvare 
7129a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7138d5d45fbSJean Delvare 
7148d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7158d5d45fbSJean Delvare 	    || !data->valid) {
7168d5d45fbSJean Delvare 
7178d5d45fbSJean Delvare 		for (i = 0; i <= data->maxins; i++) {
7188d5d45fbSJean Delvare 			data->in[i] =
71917e7dc43SJean Delvare 			    sis5595_read_value(data, SIS5595_REG_IN(i));
7208d5d45fbSJean Delvare 			data->in_min[i] =
72117e7dc43SJean Delvare 			    sis5595_read_value(data,
7228d5d45fbSJean Delvare 					       SIS5595_REG_IN_MIN(i));
7238d5d45fbSJean Delvare 			data->in_max[i] =
72417e7dc43SJean Delvare 			    sis5595_read_value(data,
7258d5d45fbSJean Delvare 					       SIS5595_REG_IN_MAX(i));
7268d5d45fbSJean Delvare 		}
7278d5d45fbSJean Delvare 		for (i = 0; i < 2; i++) {
7288d5d45fbSJean Delvare 			data->fan[i] =
72917e7dc43SJean Delvare 			    sis5595_read_value(data, SIS5595_REG_FAN(i));
7308d5d45fbSJean Delvare 			data->fan_min[i] =
73117e7dc43SJean Delvare 			    sis5595_read_value(data,
7328d5d45fbSJean Delvare 					       SIS5595_REG_FAN_MIN(i));
7338d5d45fbSJean Delvare 		}
7348d5d45fbSJean Delvare 		if (data->maxins == 3) {
7358d5d45fbSJean Delvare 			data->temp =
73617e7dc43SJean Delvare 			    sis5595_read_value(data, SIS5595_REG_TEMP);
7378d5d45fbSJean Delvare 			data->temp_over =
73817e7dc43SJean Delvare 			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
7398d5d45fbSJean Delvare 			data->temp_hyst =
74017e7dc43SJean Delvare 			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
7418d5d45fbSJean Delvare 		}
74217e7dc43SJean Delvare 		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
7438d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 0x03;
7448d5d45fbSJean Delvare 		data->fan_div[1] = i >> 6;
7458d5d45fbSJean Delvare 		data->alarms =
74617e7dc43SJean Delvare 		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
74717e7dc43SJean Delvare 		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
7488d5d45fbSJean Delvare 		data->last_updated = jiffies;
7498d5d45fbSJean Delvare 		data->valid = 1;
7508d5d45fbSJean Delvare 	}
7518d5d45fbSJean Delvare 
7529a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7538d5d45fbSJean Delvare 
7548d5d45fbSJean Delvare 	return data;
7558d5d45fbSJean Delvare }
7568d5d45fbSJean Delvare 
757600151b9SFrans Meulenbroeks static DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = {
7588d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
7598d5d45fbSJean Delvare 	{ 0, }
7608d5d45fbSJean Delvare };
7618d5d45fbSJean Delvare 
7628d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
7638d5d45fbSJean Delvare 
764a5977246SBill Pemberton static int blacklist[] = {
7658d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_540,
7668d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_550,
7678d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_630,
7688d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_645,
7698d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_730,
7708d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_735,
7718fda79ecSGuenter Roeck 	PCI_DEVICE_ID_SI_5511, /*
7728fda79ecSGuenter Roeck 				* 5513 chip has the 0008 device but
7738fda79ecSGuenter Roeck 				* that ID shows up in other chips so we
7748fda79ecSGuenter Roeck 				* use the 5511 ID for recognition
7758fda79ecSGuenter Roeck 				*/
7768d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_5597,
7778d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_5598,
7788d5d45fbSJean Delvare 	0 };
7798d5d45fbSJean Delvare 
7806c931ae1SBill Pemberton static int sis5595_device_add(unsigned short address)
78117e7dc43SJean Delvare {
78217e7dc43SJean Delvare 	struct resource res = {
78317e7dc43SJean Delvare 		.start	= address,
78417e7dc43SJean Delvare 		.end	= address + SIS5595_EXTENT - 1,
78517e7dc43SJean Delvare 		.name	= "sis5595",
78617e7dc43SJean Delvare 		.flags	= IORESOURCE_IO,
78717e7dc43SJean Delvare 	};
78817e7dc43SJean Delvare 	int err;
78917e7dc43SJean Delvare 
790b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
791b9acb64aSJean Delvare 	if (err)
792b9acb64aSJean Delvare 		goto exit;
793b9acb64aSJean Delvare 
79417e7dc43SJean Delvare 	pdev = platform_device_alloc("sis5595", address);
79517e7dc43SJean Delvare 	if (!pdev) {
79617e7dc43SJean Delvare 		err = -ENOMEM;
7974b2515dbSJoe Perches 		pr_err("Device allocation failed\n");
79817e7dc43SJean Delvare 		goto exit;
79917e7dc43SJean Delvare 	}
80017e7dc43SJean Delvare 
80117e7dc43SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
80217e7dc43SJean Delvare 	if (err) {
8034b2515dbSJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
80417e7dc43SJean Delvare 		goto exit_device_put;
80517e7dc43SJean Delvare 	}
80617e7dc43SJean Delvare 
80717e7dc43SJean Delvare 	err = platform_device_add(pdev);
80817e7dc43SJean Delvare 	if (err) {
8094b2515dbSJoe Perches 		pr_err("Device addition failed (%d)\n", err);
81017e7dc43SJean Delvare 		goto exit_device_put;
81117e7dc43SJean Delvare 	}
81217e7dc43SJean Delvare 
81317e7dc43SJean Delvare 	return 0;
81417e7dc43SJean Delvare 
81517e7dc43SJean Delvare exit_device_put:
81617e7dc43SJean Delvare 	platform_device_put(pdev);
81717e7dc43SJean Delvare exit:
81817e7dc43SJean Delvare 	return err;
81917e7dc43SJean Delvare }
82017e7dc43SJean Delvare 
8216c931ae1SBill Pemberton static int sis5595_pci_probe(struct pci_dev *dev,
8228d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8238d5d45fbSJean Delvare {
82417e7dc43SJean Delvare 	u16 address;
82517e7dc43SJean Delvare 	u8 enable;
8268d5d45fbSJean Delvare 	int *i;
8278d5d45fbSJean Delvare 
8288d5d45fbSJean Delvare 	for (i = blacklist; *i != 0; i++) {
8295460a9d0SMark M. Hoffman 		struct pci_dev *d;
8308fda79ecSGuenter Roeck 		d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
8318fda79ecSGuenter Roeck 		if (d) {
8328fda79ecSGuenter Roeck 			dev_err(&d->dev,
8338fda79ecSGuenter Roeck 				"Looked for SIS5595 but found unsupported device %.4x\n",
8348fda79ecSGuenter Roeck 				*i);
8355460a9d0SMark M. Hoffman 			pci_dev_put(d);
8368d5d45fbSJean Delvare 			return -ENODEV;
8378d5d45fbSJean Delvare 		}
8388d5d45fbSJean Delvare 	}
8398d5d45fbSJean Delvare 
84017e7dc43SJean Delvare 	force_addr &= ~(SIS5595_EXTENT - 1);
84117e7dc43SJean Delvare 	if (force_addr) {
84217e7dc43SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
84317e7dc43SJean Delvare 		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
84417e7dc43SJean Delvare 	}
8458d5d45fbSJean Delvare 
84617e7dc43SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
84717e7dc43SJean Delvare 	    pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
84817e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to read ISA address\n");
84917e7dc43SJean Delvare 		return -ENODEV;
85017e7dc43SJean Delvare 	}
85117e7dc43SJean Delvare 
85217e7dc43SJean Delvare 	address &= ~(SIS5595_EXTENT - 1);
85317e7dc43SJean Delvare 	if (!address) {
8548fda79ecSGuenter Roeck 		dev_err(&dev->dev,
8558fda79ecSGuenter Roeck 			"Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8568d5d45fbSJean Delvare 		return -ENODEV;
8578d5d45fbSJean Delvare 	}
85817e7dc43SJean Delvare 	if (force_addr && address != force_addr) {
85917e7dc43SJean Delvare 		/* doesn't work for some chips? */
86017e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to force ISA address\n");
86117e7dc43SJean Delvare 		return -ENODEV;
86217e7dc43SJean Delvare 	}
86317e7dc43SJean Delvare 
86417e7dc43SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
86517e7dc43SJean Delvare 	    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
86617e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to read enable register\n");
86717e7dc43SJean Delvare 		return -ENODEV;
86817e7dc43SJean Delvare 	}
86917e7dc43SJean Delvare 	if (!(enable & 0x80)) {
87017e7dc43SJean Delvare 		if ((PCIBIOS_SUCCESSFUL !=
87117e7dc43SJean Delvare 		     pci_write_config_byte(dev, SIS5595_ENABLE_REG,
87217e7dc43SJean Delvare 					   enable | 0x80))
87317e7dc43SJean Delvare 		 || (PCIBIOS_SUCCESSFUL !=
87417e7dc43SJean Delvare 		     pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
87517e7dc43SJean Delvare 		 || (!(enable & 0x80))) {
87617e7dc43SJean Delvare 			/* doesn't work for some chips! */
87717e7dc43SJean Delvare 			dev_err(&dev->dev, "Failed to enable HWM device\n");
87817e7dc43SJean Delvare 			return -ENODEV;
87917e7dc43SJean Delvare 		}
88017e7dc43SJean Delvare 	}
88117e7dc43SJean Delvare 
88217e7dc43SJean Delvare 	if (platform_driver_register(&sis5595_driver)) {
88317e7dc43SJean Delvare 		dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
88417e7dc43SJean Delvare 		goto exit;
88517e7dc43SJean Delvare 	}
8868d5d45fbSJean Delvare 
8878d5d45fbSJean Delvare 	s_bridge = pci_dev_get(dev);
88817e7dc43SJean Delvare 	/* Sets global pdev as a side effect */
88917e7dc43SJean Delvare 	if (sis5595_device_add(address))
89017e7dc43SJean Delvare 		goto exit_unregister;
8918d5d45fbSJean Delvare 
8928fda79ecSGuenter Roeck 	/*
8938fda79ecSGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
8948d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
8958d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
8968d5d45fbSJean Delvare 	 */
8978d5d45fbSJean Delvare 	return -ENODEV;
89817e7dc43SJean Delvare 
89917e7dc43SJean Delvare exit_unregister:
90017e7dc43SJean Delvare 	pci_dev_put(dev);
90117e7dc43SJean Delvare 	platform_driver_unregister(&sis5595_driver);
90217e7dc43SJean Delvare exit:
90317e7dc43SJean Delvare 	return -ENODEV;
9048d5d45fbSJean Delvare }
9058d5d45fbSJean Delvare 
9068d5d45fbSJean Delvare static struct pci_driver sis5595_pci_driver = {
9078d5d45fbSJean Delvare 	.name            = "sis5595",
9088d5d45fbSJean Delvare 	.id_table        = sis5595_pci_ids,
9098d5d45fbSJean Delvare 	.probe           = sis5595_pci_probe,
9108d5d45fbSJean Delvare };
9118d5d45fbSJean Delvare 
9128d5d45fbSJean Delvare static int __init sm_sis5595_init(void)
9138d5d45fbSJean Delvare {
9148d5d45fbSJean Delvare 	return pci_register_driver(&sis5595_pci_driver);
9158d5d45fbSJean Delvare }
9168d5d45fbSJean Delvare 
9178d5d45fbSJean Delvare static void __exit sm_sis5595_exit(void)
9188d5d45fbSJean Delvare {
9198d5d45fbSJean Delvare 	pci_unregister_driver(&sis5595_pci_driver);
9208d5d45fbSJean Delvare 	if (s_bridge != NULL) {
92117e7dc43SJean Delvare 		platform_device_unregister(pdev);
92217e7dc43SJean Delvare 		platform_driver_unregister(&sis5595_driver);
9238d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9248d5d45fbSJean Delvare 		s_bridge = NULL;
9258d5d45fbSJean Delvare 	}
9268d5d45fbSJean Delvare }
9278d5d45fbSJean Delvare 
9288d5d45fbSJean Delvare MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
9298d5d45fbSJean Delvare MODULE_DESCRIPTION("SiS 5595 Sensor device");
9308d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9318d5d45fbSJean Delvare 
9328d5d45fbSJean Delvare module_init(sm_sis5595_init);
9338d5d45fbSJean Delvare module_exit(sm_sis5595_exit);
934