xref: /openbmc/linux/drivers/hwmon/sis5595.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
38fda79ecSGuenter Roeck  * sis5595.c - Part of lm_sensors, Linux kernel modules
48fda79ecSGuenter Roeck  *	       for hardware monitoring
58fda79ecSGuenter Roeck  *
68fda79ecSGuenter Roeck  * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
78fda79ecSGuenter Roeck  *			     Kyösti Mälkki <kmalkki@cc.hut.fi>, and
88fda79ecSGuenter Roeck  *			     Mark D. Studebaker <mdsxyz123@yahoo.com>
98fda79ecSGuenter Roeck  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
107c81c60fSJean Delvare  * the help of Jean Delvare <jdelvare@suse.de>
118d5d45fbSJean Delvare  */
128d5d45fbSJean Delvare 
138d5d45fbSJean Delvare /*
148fda79ecSGuenter Roeck  * SiS southbridge has a LM78-like chip integrated on the same IC.
158fda79ecSGuenter Roeck  * This driver is a customized copy of lm78.c
168fda79ecSGuenter Roeck  *
178fda79ecSGuenter Roeck  * Supports following revisions:
188fda79ecSGuenter Roeck  *	Version		PCI ID		PCI Revision
198fda79ecSGuenter Roeck  *	1		1039/0008	AF or less
208fda79ecSGuenter Roeck  *	2		1039/0008	B0 or greater
218fda79ecSGuenter Roeck  *
228fda79ecSGuenter Roeck  *  Note: these chips contain a 0008 device which is incompatible with the
238fda79ecSGuenter Roeck  *	 5595. We recognize these by the presence of the listed
248fda79ecSGuenter Roeck  *	 "blacklist" PCI ID and refuse to load.
258fda79ecSGuenter Roeck  *
268fda79ecSGuenter Roeck  * NOT SUPPORTED	PCI ID		BLACKLIST PCI ID
278fda79ecSGuenter Roeck  *	 540		0008		0540
288fda79ecSGuenter Roeck  *	 550		0008		0550
298fda79ecSGuenter Roeck  *	5513		0008		5511
308fda79ecSGuenter Roeck  *	5581		0008		5597
318fda79ecSGuenter Roeck  *	5582		0008		5597
328fda79ecSGuenter Roeck  *	5597		0008		5597
338fda79ecSGuenter Roeck  *	5598		0008		5597/5598
348fda79ecSGuenter Roeck  *	 630		0008		0630
358fda79ecSGuenter Roeck  *	 645		0008		0645
368fda79ecSGuenter Roeck  *	 730		0008		0730
378fda79ecSGuenter Roeck  *	 735		0008		0735
388d5d45fbSJean Delvare  */
398d5d45fbSJean Delvare 
40847a3b04SUwe Kleine-König #define DRIVER_NAME "sis5595"
414b2515dbSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
424b2515dbSJoe Perches 
438d5d45fbSJean Delvare #include <linux/module.h>
448d5d45fbSJean Delvare #include <linux/slab.h>
458d5d45fbSJean Delvare #include <linux/ioport.h>
468d5d45fbSJean Delvare #include <linux/pci.h>
4717e7dc43SJean Delvare #include <linux/platform_device.h>
48943b0830SMark M. Hoffman #include <linux/hwmon.h>
491f5f48ddSJean Delvare #include <linux/hwmon-sysfs.h>
50943b0830SMark M. Hoffman #include <linux/err.h>
518d5d45fbSJean Delvare #include <linux/init.h>
528d5d45fbSJean Delvare #include <linux/jiffies.h>
539a61bf63SIngo Molnar #include <linux/mutex.h>
54a5ebe668SJean Delvare #include <linux/sysfs.h>
55b9acb64aSJean Delvare #include <linux/acpi.h>
566055fae8SH Hartley Sweeten #include <linux/io.h>
578d5d45fbSJean Delvare 
588fda79ecSGuenter Roeck /*
598fda79ecSGuenter Roeck  * If force_addr is set to anything different from 0, we forcibly enable
608fda79ecSGuenter Roeck  * the device at the given address.
618fda79ecSGuenter Roeck  */
628d5d45fbSJean Delvare static u16 force_addr;
638d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
648d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
658d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
668d5d45fbSJean Delvare 
6717e7dc43SJean Delvare static struct platform_device *pdev;
688d5d45fbSJean Delvare 
698d5d45fbSJean Delvare /* Many SIS5595 constants specified below */
708d5d45fbSJean Delvare 
718d5d45fbSJean Delvare /* Length of ISA address segment */
728d5d45fbSJean Delvare #define SIS5595_EXTENT 8
738d5d45fbSJean Delvare /* PCI Config Registers */
748d5d45fbSJean Delvare #define SIS5595_BASE_REG 0x68
758d5d45fbSJean Delvare #define SIS5595_PIN_REG 0x7A
768d5d45fbSJean Delvare #define SIS5595_ENABLE_REG 0x7B
778d5d45fbSJean Delvare 
788d5d45fbSJean Delvare /* Where are the ISA address/data registers relative to the base address */
798d5d45fbSJean Delvare #define SIS5595_ADDR_REG_OFFSET 5
808d5d45fbSJean Delvare #define SIS5595_DATA_REG_OFFSET 6
818d5d45fbSJean Delvare 
828d5d45fbSJean Delvare /* The SIS5595 registers */
838d5d45fbSJean Delvare #define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
848d5d45fbSJean Delvare #define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
858d5d45fbSJean Delvare #define SIS5595_REG_IN(nr) (0x20 + (nr))
868d5d45fbSJean Delvare 
878d5d45fbSJean Delvare #define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
888d5d45fbSJean Delvare #define SIS5595_REG_FAN(nr) (0x28 + (nr))
898d5d45fbSJean Delvare 
908fda79ecSGuenter Roeck /*
918fda79ecSGuenter Roeck  * On the first version of the chip, the temp registers are separate.
928fda79ecSGuenter Roeck  * On the second version,
938fda79ecSGuenter Roeck  * TEMP pin is shared with IN4, configured in PCI register 0x7A.
948fda79ecSGuenter Roeck  * The registers are the same as well.
958fda79ecSGuenter Roeck  * OVER and HYST are really MAX and MIN.
968fda79ecSGuenter Roeck  */
978d5d45fbSJean Delvare 
988d5d45fbSJean Delvare #define REV2MIN	0xb0
998fda79ecSGuenter Roeck #define SIS5595_REG_TEMP	(((data->revision) >= REV2MIN) ? \
1008fda79ecSGuenter Roeck 					SIS5595_REG_IN(4) : 0x27)
1018fda79ecSGuenter Roeck #define SIS5595_REG_TEMP_OVER	(((data->revision) >= REV2MIN) ? \
1028fda79ecSGuenter Roeck 					SIS5595_REG_IN_MAX(4) : 0x39)
1038fda79ecSGuenter Roeck #define SIS5595_REG_TEMP_HYST	(((data->revision) >= REV2MIN) ? \
1048fda79ecSGuenter Roeck 					SIS5595_REG_IN_MIN(4) : 0x3a)
1058d5d45fbSJean Delvare 
1068d5d45fbSJean Delvare #define SIS5595_REG_CONFIG 0x40
1078d5d45fbSJean Delvare #define SIS5595_REG_ALARM1 0x41
1088d5d45fbSJean Delvare #define SIS5595_REG_ALARM2 0x42
1098d5d45fbSJean Delvare #define SIS5595_REG_FANDIV 0x47
1108d5d45fbSJean Delvare 
1118fda79ecSGuenter Roeck /*
1128fda79ecSGuenter Roeck  * Conversions. Limit checking is only done on the TO_REG
1138fda79ecSGuenter Roeck  * variants.
1148fda79ecSGuenter Roeck  */
1158d5d45fbSJean Delvare 
1168fda79ecSGuenter Roeck /*
1178fda79ecSGuenter Roeck  * IN: mV, (0V to 4.08V)
1188fda79ecSGuenter Roeck  * REG: 16mV/bit
1198fda79ecSGuenter Roeck  */
IN_TO_REG(unsigned long val)1208d5d45fbSJean Delvare static inline u8 IN_TO_REG(unsigned long val)
1218d5d45fbSJean Delvare {
1222a844c14SGuenter Roeck 	unsigned long nval = clamp_val(val, 0, 4080);
1238d5d45fbSJean Delvare 	return (nval + 8) / 16;
1248d5d45fbSJean Delvare }
1258d5d45fbSJean Delvare #define IN_FROM_REG(val) ((val) *  16)
1268d5d45fbSJean Delvare 
FAN_TO_REG(long rpm,int div)1278d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1288d5d45fbSJean Delvare {
1298d5d45fbSJean Delvare 	if (rpm <= 0)
1308d5d45fbSJean Delvare 		return 255;
1313806b45bSDan Carpenter 	if (rpm > 1350000)
1323806b45bSDan Carpenter 		return 1;
1332a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1348d5d45fbSJean Delvare }
1358d5d45fbSJean Delvare 
FAN_FROM_REG(u8 val,int div)1368d5d45fbSJean Delvare static inline int FAN_FROM_REG(u8 val, int div)
1378d5d45fbSJean Delvare {
1388d5d45fbSJean Delvare 	return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
1398d5d45fbSJean Delvare }
1408d5d45fbSJean Delvare 
1418fda79ecSGuenter Roeck /*
1428fda79ecSGuenter Roeck  * TEMP: mC (-54.12C to +157.53C)
1438fda79ecSGuenter Roeck  * REG: 0.83C/bit + 52.12, two's complement
1448fda79ecSGuenter Roeck  */
TEMP_FROM_REG(s8 val)1458d5d45fbSJean Delvare static inline int TEMP_FROM_REG(s8 val)
1468d5d45fbSJean Delvare {
1478d5d45fbSJean Delvare 	return val * 830 + 52120;
1488d5d45fbSJean Delvare }
TEMP_TO_REG(long val)149cc336546SAxel Lin static inline s8 TEMP_TO_REG(long val)
1508d5d45fbSJean Delvare {
1512a844c14SGuenter Roeck 	int nval = clamp_val(val, -54120, 157530) ;
1528d5d45fbSJean Delvare 	return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
1538d5d45fbSJean Delvare }
1548d5d45fbSJean Delvare 
1558fda79ecSGuenter Roeck /*
1568fda79ecSGuenter Roeck  * FAN DIV: 1, 2, 4, or 8 (defaults to 2)
1578fda79ecSGuenter Roeck  * REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
1588fda79ecSGuenter Roeck  */
DIV_TO_REG(int val)1598d5d45fbSJean Delvare static inline u8 DIV_TO_REG(int val)
1608d5d45fbSJean Delvare {
1618d5d45fbSJean Delvare 	return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
1628d5d45fbSJean Delvare }
1638d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
1648d5d45fbSJean Delvare 
1658fda79ecSGuenter Roeck /*
1668fda79ecSGuenter Roeck  * For each registered chip, we need to keep some data in memory.
1678fda79ecSGuenter Roeck  * The structure is dynamically allocated.
1688fda79ecSGuenter Roeck  */
1698d5d45fbSJean Delvare struct sis5595_data {
17017e7dc43SJean Delvare 	unsigned short addr;
17117e7dc43SJean Delvare 	const char *name;
1721beeffe4STony Jones 	struct device *hwmon_dev;
1739a61bf63SIngo Molnar 	struct mutex lock;
1748d5d45fbSJean Delvare 
1759a61bf63SIngo Molnar 	struct mutex update_lock;
176952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
1778d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
1788d5d45fbSJean Delvare 	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
1798d5d45fbSJean Delvare 	u8 revision;		/* Reg. value */
1808d5d45fbSJean Delvare 
1818d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
1828d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
1838d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
1848d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
1858d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
1868d5d45fbSJean Delvare 	s8 temp;		/* Register value */
1878d5d45fbSJean Delvare 	s8 temp_over;		/* Register value */
1888d5d45fbSJean Delvare 	s8 temp_hyst;		/* Register value */
1898d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
1908d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
1918d5d45fbSJean Delvare };
1928d5d45fbSJean Delvare 
1938d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
1948d5d45fbSJean Delvare 
1951b2f9b1eSUwe Kleine-König /* ISA access must be locked explicitly. */
sis5595_read_value(struct sis5595_data * data,u8 reg)1961b2f9b1eSUwe Kleine-König static int sis5595_read_value(struct sis5595_data *data, u8 reg)
1971b2f9b1eSUwe Kleine-König {
1981b2f9b1eSUwe Kleine-König 	int res;
1998d5d45fbSJean Delvare 
2001b2f9b1eSUwe Kleine-König 	mutex_lock(&data->lock);
2011b2f9b1eSUwe Kleine-König 	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
2021b2f9b1eSUwe Kleine-König 	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
2031b2f9b1eSUwe Kleine-König 	mutex_unlock(&data->lock);
2041b2f9b1eSUwe Kleine-König 	return res;
2051b2f9b1eSUwe Kleine-König }
2068d5d45fbSJean Delvare 
sis5595_write_value(struct sis5595_data * data,u8 reg,u8 value)2071b2f9b1eSUwe Kleine-König static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
2081b2f9b1eSUwe Kleine-König {
2091b2f9b1eSUwe Kleine-König 	mutex_lock(&data->lock);
2101b2f9b1eSUwe Kleine-König 	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
2111b2f9b1eSUwe Kleine-König 	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
2121b2f9b1eSUwe Kleine-König 	mutex_unlock(&data->lock);
2131b2f9b1eSUwe Kleine-König }
2141b2f9b1eSUwe Kleine-König 
sis5595_update_device(struct device * dev)2151b2f9b1eSUwe Kleine-König static struct sis5595_data *sis5595_update_device(struct device *dev)
2161b2f9b1eSUwe Kleine-König {
2171b2f9b1eSUwe Kleine-König 	struct sis5595_data *data = dev_get_drvdata(dev);
2181b2f9b1eSUwe Kleine-König 	int i;
2191b2f9b1eSUwe Kleine-König 
2201b2f9b1eSUwe Kleine-König 	mutex_lock(&data->update_lock);
2211b2f9b1eSUwe Kleine-König 
2221b2f9b1eSUwe Kleine-König 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
2231b2f9b1eSUwe Kleine-König 	    || !data->valid) {
2241b2f9b1eSUwe Kleine-König 
2251b2f9b1eSUwe Kleine-König 		for (i = 0; i <= data->maxins; i++) {
2261b2f9b1eSUwe Kleine-König 			data->in[i] =
2271b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data, SIS5595_REG_IN(i));
2281b2f9b1eSUwe Kleine-König 			data->in_min[i] =
2291b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data,
2301b2f9b1eSUwe Kleine-König 					       SIS5595_REG_IN_MIN(i));
2311b2f9b1eSUwe Kleine-König 			data->in_max[i] =
2321b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data,
2331b2f9b1eSUwe Kleine-König 					       SIS5595_REG_IN_MAX(i));
2341b2f9b1eSUwe Kleine-König 		}
2351b2f9b1eSUwe Kleine-König 		for (i = 0; i < 2; i++) {
2361b2f9b1eSUwe Kleine-König 			data->fan[i] =
2371b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data, SIS5595_REG_FAN(i));
2381b2f9b1eSUwe Kleine-König 			data->fan_min[i] =
2391b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data,
2401b2f9b1eSUwe Kleine-König 					       SIS5595_REG_FAN_MIN(i));
2411b2f9b1eSUwe Kleine-König 		}
2421b2f9b1eSUwe Kleine-König 		if (data->maxins == 3) {
2431b2f9b1eSUwe Kleine-König 			data->temp =
2441b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data, SIS5595_REG_TEMP);
2451b2f9b1eSUwe Kleine-König 			data->temp_over =
2461b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
2471b2f9b1eSUwe Kleine-König 			data->temp_hyst =
2481b2f9b1eSUwe Kleine-König 			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
2491b2f9b1eSUwe Kleine-König 		}
2501b2f9b1eSUwe Kleine-König 		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
2511b2f9b1eSUwe Kleine-König 		data->fan_div[0] = (i >> 4) & 0x03;
2521b2f9b1eSUwe Kleine-König 		data->fan_div[1] = i >> 6;
2531b2f9b1eSUwe Kleine-König 		data->alarms =
2541b2f9b1eSUwe Kleine-König 		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
2551b2f9b1eSUwe Kleine-König 		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
2561b2f9b1eSUwe Kleine-König 		data->last_updated = jiffies;
2571b2f9b1eSUwe Kleine-König 		data->valid = true;
2581b2f9b1eSUwe Kleine-König 	}
2591b2f9b1eSUwe Kleine-König 
2601b2f9b1eSUwe Kleine-König 	mutex_unlock(&data->update_lock);
2611b2f9b1eSUwe Kleine-König 
2621b2f9b1eSUwe Kleine-König 	return data;
2631b2f9b1eSUwe Kleine-König }
2648d5d45fbSJean Delvare 
2658d5d45fbSJean Delvare /* 4 Voltages */
in_show(struct device * dev,struct device_attribute * da,char * buf)26660a9c3f1SGuenter Roeck static ssize_t in_show(struct device *dev, struct device_attribute *da,
2671f5f48ddSJean Delvare 		       char *buf)
2688d5d45fbSJean Delvare {
2698d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2701f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2711f5f48ddSJean Delvare 	int nr = attr->index;
2728d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
2738d5d45fbSJean Delvare }
2748d5d45fbSJean Delvare 
in_min_show(struct device * dev,struct device_attribute * da,char * buf)27560a9c3f1SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *da,
2761f5f48ddSJean Delvare 			   char *buf)
2778d5d45fbSJean Delvare {
2788d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2791f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2801f5f48ddSJean Delvare 	int nr = attr->index;
2818d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
2828d5d45fbSJean Delvare }
2838d5d45fbSJean Delvare 
in_max_show(struct device * dev,struct device_attribute * da,char * buf)28460a9c3f1SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *da,
2851f5f48ddSJean Delvare 			   char *buf)
2868d5d45fbSJean Delvare {
2878d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
2881f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2891f5f48ddSJean Delvare 	int nr = attr->index;
2908d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
2918d5d45fbSJean Delvare }
2928d5d45fbSJean Delvare 
in_min_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)29360a9c3f1SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *da,
2941f5f48ddSJean Delvare 			    const char *buf, size_t count)
2958d5d45fbSJean Delvare {
29617e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
2971f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2981f5f48ddSJean Delvare 	int nr = attr->index;
2998fda79ecSGuenter Roeck 	unsigned long val;
3008fda79ecSGuenter Roeck 	int err;
3018fda79ecSGuenter Roeck 
3028fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
3038fda79ecSGuenter Roeck 	if (err)
3048fda79ecSGuenter Roeck 		return err;
3058d5d45fbSJean Delvare 
3069a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3078d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val);
30817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
3099a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3108d5d45fbSJean Delvare 	return count;
3118d5d45fbSJean Delvare }
3128d5d45fbSJean Delvare 
in_max_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)31360a9c3f1SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *da,
3141f5f48ddSJean Delvare 			    const char *buf, size_t count)
3158d5d45fbSJean Delvare {
31617e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3171f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3181f5f48ddSJean Delvare 	int nr = attr->index;
3198fda79ecSGuenter Roeck 	unsigned long val;
3208fda79ecSGuenter Roeck 	int err;
3218fda79ecSGuenter Roeck 
3228fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
3238fda79ecSGuenter Roeck 	if (err)
3248fda79ecSGuenter Roeck 		return err;
3258d5d45fbSJean Delvare 
3269a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3278d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val);
32817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
3299a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3308d5d45fbSJean Delvare 	return count;
3318d5d45fbSJean Delvare }
3328d5d45fbSJean Delvare 
33360a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
33460a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
33560a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
33660a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
33760a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
33860a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
33960a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
34060a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
34160a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
34260a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
34360a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
34460a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
34560a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
34660a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
34760a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
3488d5d45fbSJean Delvare 
3498d5d45fbSJean Delvare /* Temperature */
temp1_input_show(struct device * dev,struct device_attribute * attr,char * buf)350feaf8bd4SJulia Lawall static ssize_t temp1_input_show(struct device *dev,
351feaf8bd4SJulia Lawall 				struct device_attribute *attr, char *buf)
3528d5d45fbSJean Delvare {
3538d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3548d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
3558d5d45fbSJean Delvare }
3568d5d45fbSJean Delvare 
temp1_max_show(struct device * dev,struct device_attribute * attr,char * buf)357feaf8bd4SJulia Lawall static ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr,
3588fda79ecSGuenter Roeck 			      char *buf)
3598d5d45fbSJean Delvare {
3608d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3618d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
3628d5d45fbSJean Delvare }
3638d5d45fbSJean Delvare 
temp1_max_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)364feaf8bd4SJulia Lawall static ssize_t temp1_max_store(struct device *dev,
365feaf8bd4SJulia Lawall 			       struct device_attribute *attr, const char *buf,
366feaf8bd4SJulia Lawall 			       size_t count)
3678d5d45fbSJean Delvare {
36817e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3698fda79ecSGuenter Roeck 	long val;
3708fda79ecSGuenter Roeck 	int err;
3718fda79ecSGuenter Roeck 
3728fda79ecSGuenter Roeck 	err = kstrtol(buf, 10, &val);
3738fda79ecSGuenter Roeck 	if (err)
3748fda79ecSGuenter Roeck 		return err;
3758d5d45fbSJean Delvare 
3769a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3778d5d45fbSJean Delvare 	data->temp_over = TEMP_TO_REG(val);
37817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
3799a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3808d5d45fbSJean Delvare 	return count;
3818d5d45fbSJean Delvare }
3828d5d45fbSJean Delvare 
temp1_max_hyst_show(struct device * dev,struct device_attribute * attr,char * buf)383feaf8bd4SJulia Lawall static ssize_t temp1_max_hyst_show(struct device *dev,
384feaf8bd4SJulia Lawall 				   struct device_attribute *attr, char *buf)
3858d5d45fbSJean Delvare {
3868d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
3878d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
3888d5d45fbSJean Delvare }
3898d5d45fbSJean Delvare 
temp1_max_hyst_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)390feaf8bd4SJulia Lawall static ssize_t temp1_max_hyst_store(struct device *dev,
391feaf8bd4SJulia Lawall 				    struct device_attribute *attr,
3928fda79ecSGuenter Roeck 				    const char *buf, size_t count)
3938d5d45fbSJean Delvare {
39417e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
3958fda79ecSGuenter Roeck 	long val;
3968fda79ecSGuenter Roeck 	int err;
3978fda79ecSGuenter Roeck 
3988fda79ecSGuenter Roeck 	err = kstrtol(buf, 10, &val);
3998fda79ecSGuenter Roeck 	if (err)
4008fda79ecSGuenter Roeck 		return err;
4018d5d45fbSJean Delvare 
4029a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4038d5d45fbSJean Delvare 	data->temp_hyst = TEMP_TO_REG(val);
40417e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
4059a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4068d5d45fbSJean Delvare 	return count;
4078d5d45fbSJean Delvare }
4088d5d45fbSJean Delvare 
409feaf8bd4SJulia Lawall static DEVICE_ATTR_RO(temp1_input);
410feaf8bd4SJulia Lawall static DEVICE_ATTR_RW(temp1_max);
411feaf8bd4SJulia Lawall static DEVICE_ATTR_RW(temp1_max_hyst);
4128d5d45fbSJean Delvare 
4138d5d45fbSJean Delvare /* 2 Fans */
fan_show(struct device * dev,struct device_attribute * da,char * buf)41460a9c3f1SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da,
4151f5f48ddSJean Delvare 			char *buf)
4168d5d45fbSJean Delvare {
4178d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
4181f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4191f5f48ddSJean Delvare 	int nr = attr->index;
4208d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
4218d5d45fbSJean Delvare 		DIV_FROM_REG(data->fan_div[nr])));
4228d5d45fbSJean Delvare }
4238d5d45fbSJean Delvare 
fan_min_show(struct device * dev,struct device_attribute * da,char * buf)42460a9c3f1SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *da,
4251f5f48ddSJean Delvare 			    char *buf)
4268d5d45fbSJean Delvare {
4278d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
4281f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4291f5f48ddSJean Delvare 	int nr = attr->index;
4308d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
4318d5d45fbSJean Delvare 		DIV_FROM_REG(data->fan_div[nr])));
4328d5d45fbSJean Delvare }
4338d5d45fbSJean Delvare 
fan_min_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)43460a9c3f1SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da,
4351f5f48ddSJean Delvare 			     const char *buf, size_t count)
4368d5d45fbSJean Delvare {
43717e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
4381f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4391f5f48ddSJean Delvare 	int nr = attr->index;
4408fda79ecSGuenter Roeck 	unsigned long val;
4418fda79ecSGuenter Roeck 	int err;
4428fda79ecSGuenter Roeck 
4438fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4448fda79ecSGuenter Roeck 	if (err)
4458fda79ecSGuenter Roeck 		return err;
4468d5d45fbSJean Delvare 
4479a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4488d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
44917e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
4509a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4518d5d45fbSJean Delvare 	return count;
4528d5d45fbSJean Delvare }
4538d5d45fbSJean Delvare 
fan_div_show(struct device * dev,struct device_attribute * da,char * buf)45460a9c3f1SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *da,
4551f5f48ddSJean Delvare 			    char *buf)
4568d5d45fbSJean Delvare {
4578d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
4581f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4591f5f48ddSJean Delvare 	int nr = attr->index;
4608d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
4618d5d45fbSJean Delvare }
4628d5d45fbSJean Delvare 
4638fda79ecSGuenter Roeck /*
4648fda79ecSGuenter Roeck  * Note: we save and restore the fan minimum here, because its value is
4658fda79ecSGuenter Roeck  * determined in part by the fan divisor.  This follows the principle of
4668fda79ecSGuenter Roeck  * least surprise; the user doesn't expect the fan minimum to change just
4678fda79ecSGuenter Roeck  * because the divisor changed.
4688fda79ecSGuenter Roeck  */
fan_div_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)46960a9c3f1SGuenter Roeck static ssize_t fan_div_store(struct device *dev, struct device_attribute *da,
4701f5f48ddSJean Delvare 			     const char *buf, size_t count)
4718d5d45fbSJean Delvare {
47217e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
4731f5f48ddSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4741f5f48ddSJean Delvare 	int nr = attr->index;
4758d5d45fbSJean Delvare 	unsigned long min;
4768d5d45fbSJean Delvare 	int reg;
4778fda79ecSGuenter Roeck 	unsigned long val;
4788fda79ecSGuenter Roeck 	int err;
4798fda79ecSGuenter Roeck 
4808fda79ecSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4818fda79ecSGuenter Roeck 	if (err)
4828fda79ecSGuenter Roeck 		return err;
4838d5d45fbSJean Delvare 
4849a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4858d5d45fbSJean Delvare 	min = FAN_FROM_REG(data->fan_min[nr],
4868d5d45fbSJean Delvare 			DIV_FROM_REG(data->fan_div[nr]));
48717e7dc43SJean Delvare 	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
4888d5d45fbSJean Delvare 
4898d5d45fbSJean Delvare 	switch (val) {
4908fda79ecSGuenter Roeck 	case 1:
4918fda79ecSGuenter Roeck 		data->fan_div[nr] = 0;
4928fda79ecSGuenter Roeck 		break;
4938fda79ecSGuenter Roeck 	case 2:
4948fda79ecSGuenter Roeck 		data->fan_div[nr] = 1;
4958fda79ecSGuenter Roeck 		break;
4968fda79ecSGuenter Roeck 	case 4:
4978fda79ecSGuenter Roeck 		data->fan_div[nr] = 2;
4988fda79ecSGuenter Roeck 		break;
4998fda79ecSGuenter Roeck 	case 8:
5008fda79ecSGuenter Roeck 		data->fan_div[nr] = 3;
5018fda79ecSGuenter Roeck 		break;
5028d5d45fbSJean Delvare 	default:
503b55f3757SGuenter Roeck 		dev_err(dev,
504b55f3757SGuenter Roeck 			"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
505b55f3757SGuenter Roeck 			val);
5069a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
5078d5d45fbSJean Delvare 		return -EINVAL;
5088d5d45fbSJean Delvare 	}
5098d5d45fbSJean Delvare 
5108d5d45fbSJean Delvare 	switch (nr) {
5118d5d45fbSJean Delvare 	case 0:
5128d5d45fbSJean Delvare 		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
5138d5d45fbSJean Delvare 		break;
5148d5d45fbSJean Delvare 	case 1:
5158d5d45fbSJean Delvare 		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
5168d5d45fbSJean Delvare 		break;
5178d5d45fbSJean Delvare 	}
51817e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
5198d5d45fbSJean Delvare 	data->fan_min[nr] =
5208d5d45fbSJean Delvare 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
52117e7dc43SJean Delvare 	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
5229a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5238d5d45fbSJean Delvare 	return count;
5248d5d45fbSJean Delvare }
5258d5d45fbSJean Delvare 
52660a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
52760a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
52860a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
52960a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
53060a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
53160a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
5328d5d45fbSJean Delvare 
5338d5d45fbSJean Delvare /* Alarms */
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)534feaf8bd4SJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
5358fda79ecSGuenter Roeck 			   char *buf)
5368d5d45fbSJean Delvare {
5378d5d45fbSJean Delvare 	struct sis5595_data *data = sis5595_update_device(dev);
5388d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->alarms);
5398d5d45fbSJean Delvare }
540feaf8bd4SJulia Lawall static DEVICE_ATTR_RO(alarms);
5418d5d45fbSJean Delvare 
alarm_show(struct device * dev,struct device_attribute * da,char * buf)54260a9c3f1SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *da,
5435c726b3bSIvo Manca 			  char *buf)
5445c726b3bSIvo Manca {
5455c726b3bSIvo Manca 	struct sis5595_data *data = sis5595_update_device(dev);
5465c726b3bSIvo Manca 	int nr = to_sensor_dev_attr(da)->index;
5475c726b3bSIvo Manca 	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
5485c726b3bSIvo Manca }
54960a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
55060a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
55160a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
55260a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
55360a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 15);
55460a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
55560a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
55660a9c3f1SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 15);
5575c726b3bSIvo Manca 
name_show(struct device * dev,struct device_attribute * attr,char * buf)558feaf8bd4SJulia Lawall static ssize_t name_show(struct device *dev, struct device_attribute *attr,
55917e7dc43SJean Delvare 			 char *buf)
56017e7dc43SJean Delvare {
56117e7dc43SJean Delvare 	struct sis5595_data *data = dev_get_drvdata(dev);
56217e7dc43SJean Delvare 	return sprintf(buf, "%s\n", data->name);
56317e7dc43SJean Delvare }
564feaf8bd4SJulia Lawall static DEVICE_ATTR_RO(name);
56517e7dc43SJean Delvare 
566a5ebe668SJean Delvare static struct attribute *sis5595_attributes[] = {
5671f5f48ddSJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
5681f5f48ddSJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
5691f5f48ddSJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
5705c726b3bSIvo Manca 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
5711f5f48ddSJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
5721f5f48ddSJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
5731f5f48ddSJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
5745c726b3bSIvo Manca 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
5751f5f48ddSJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
5761f5f48ddSJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
5771f5f48ddSJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
5785c726b3bSIvo Manca 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
5791f5f48ddSJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
5801f5f48ddSJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
5811f5f48ddSJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
5825c726b3bSIvo Manca 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
583a5ebe668SJean Delvare 
5841f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
5851f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
5861f5f48ddSJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
5875c726b3bSIvo Manca 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
5881f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
5891f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
5901f5f48ddSJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
5915c726b3bSIvo Manca 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
592a5ebe668SJean Delvare 
593a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
59417e7dc43SJean Delvare 	&dev_attr_name.attr,
595a5ebe668SJean Delvare 	NULL
596a5ebe668SJean Delvare };
597a5ebe668SJean Delvare 
598a5ebe668SJean Delvare static const struct attribute_group sis5595_group = {
599a5ebe668SJean Delvare 	.attrs = sis5595_attributes,
600a5ebe668SJean Delvare };
601a5ebe668SJean Delvare 
60276e63860SIvo Manca static struct attribute *sis5595_attributes_in4[] = {
6031f5f48ddSJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
6041f5f48ddSJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
6051f5f48ddSJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
6065c726b3bSIvo Manca 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
60776e63860SIvo Manca 	NULL
60876e63860SIvo Manca };
609a5ebe668SJean Delvare 
61076e63860SIvo Manca static const struct attribute_group sis5595_group_in4 = {
61176e63860SIvo Manca 	.attrs = sis5595_attributes_in4,
61276e63860SIvo Manca };
61376e63860SIvo Manca 
61476e63860SIvo Manca static struct attribute *sis5595_attributes_temp1[] = {
615a5ebe668SJean Delvare 	&dev_attr_temp1_input.attr,
616a5ebe668SJean Delvare 	&dev_attr_temp1_max.attr,
617a5ebe668SJean Delvare 	&dev_attr_temp1_max_hyst.attr,
6185c726b3bSIvo Manca 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
619a5ebe668SJean Delvare 	NULL
620a5ebe668SJean Delvare };
621a5ebe668SJean Delvare 
62276e63860SIvo Manca static const struct attribute_group sis5595_group_temp1 = {
62376e63860SIvo Manca 	.attrs = sis5595_attributes_temp1,
624a5ebe668SJean Delvare };
625a5ebe668SJean Delvare 
6261b2f9b1eSUwe Kleine-König /* Called when we have found a new SIS5595. */
sis5595_init_device(struct sis5595_data * data)6271b2f9b1eSUwe Kleine-König static void sis5595_init_device(struct sis5595_data *data)
6281b2f9b1eSUwe Kleine-König {
6291b2f9b1eSUwe Kleine-König 	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
6301b2f9b1eSUwe Kleine-König 	if (!(config & 0x01))
6311b2f9b1eSUwe Kleine-König 		sis5595_write_value(data, SIS5595_REG_CONFIG,
6321b2f9b1eSUwe Kleine-König 				(config & 0xf7) | 0x01);
6331b2f9b1eSUwe Kleine-König }
6341b2f9b1eSUwe Kleine-König 
6358d5d45fbSJean Delvare /* This is called when the module is loaded */
sis5595_probe(struct platform_device * pdev)6366c931ae1SBill Pemberton static int sis5595_probe(struct platform_device *pdev)
6378d5d45fbSJean Delvare {
6388d5d45fbSJean Delvare 	int err = 0;
6398d5d45fbSJean Delvare 	int i;
6408d5d45fbSJean Delvare 	struct sis5595_data *data;
64117e7dc43SJean Delvare 	struct resource *res;
6428d5d45fbSJean Delvare 	char val;
6438d5d45fbSJean Delvare 
6448d5d45fbSJean Delvare 	/* Reserve the ISA region */
64517e7dc43SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
6465d224adeSGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT,
647847a3b04SUwe Kleine-König 				 DRIVER_NAME))
6485d224adeSGuenter Roeck 		return -EBUSY;
6498d5d45fbSJean Delvare 
6505d224adeSGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data),
6515d224adeSGuenter Roeck 			    GFP_KERNEL);
6525d224adeSGuenter Roeck 	if (!data)
6535d224adeSGuenter Roeck 		return -ENOMEM;
6548d5d45fbSJean Delvare 
6559a61bf63SIngo Molnar 	mutex_init(&data->lock);
65617e7dc43SJean Delvare 	mutex_init(&data->update_lock);
65717e7dc43SJean Delvare 	data->addr = res->start;
658847a3b04SUwe Kleine-König 	data->name = DRIVER_NAME;
65917e7dc43SJean Delvare 	platform_set_drvdata(pdev, data);
6608d5d45fbSJean Delvare 
6618fda79ecSGuenter Roeck 	/*
6628fda79ecSGuenter Roeck 	 * Check revision and pin registers to determine whether 4 or 5 voltages
6638fda79ecSGuenter Roeck 	 */
6647b6d1f04SAuke Kok 	data->revision = s_bridge->revision;
6658d5d45fbSJean Delvare 	/* 4 voltages, 1 temp */
6668d5d45fbSJean Delvare 	data->maxins = 3;
6678d5d45fbSJean Delvare 	if (data->revision >= REV2MIN) {
6688d5d45fbSJean Delvare 		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
6698d5d45fbSJean Delvare 		if (!(val & 0x80))
6708d5d45fbSJean Delvare 			/* 5 voltages, no temps */
6718d5d45fbSJean Delvare 			data->maxins = 4;
6728d5d45fbSJean Delvare 	}
6738d5d45fbSJean Delvare 
6748d5d45fbSJean Delvare 	/* Initialize the SIS5595 chip */
67517e7dc43SJean Delvare 	sis5595_init_device(data);
6768d5d45fbSJean Delvare 
6778d5d45fbSJean Delvare 	/* A few vars need to be filled upon startup */
6788d5d45fbSJean Delvare 	for (i = 0; i < 2; i++) {
67917e7dc43SJean Delvare 		data->fan_min[i] = sis5595_read_value(data,
6808d5d45fbSJean Delvare 					SIS5595_REG_FAN_MIN(i));
6818d5d45fbSJean Delvare 	}
6828d5d45fbSJean Delvare 
6838d5d45fbSJean Delvare 	/* Register sysfs hooks */
6848fda79ecSGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group);
6858fda79ecSGuenter Roeck 	if (err)
6865d224adeSGuenter Roeck 		return err;
687a5ebe668SJean Delvare 	if (data->maxins == 4) {
6888fda79ecSGuenter Roeck 		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4);
6898fda79ecSGuenter Roeck 		if (err)
690a5ebe668SJean Delvare 			goto exit_remove_files;
691a5ebe668SJean Delvare 	} else {
6928fda79ecSGuenter Roeck 		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1);
6938fda79ecSGuenter Roeck 		if (err)
694a5ebe668SJean Delvare 			goto exit_remove_files;
695a5ebe668SJean Delvare 	}
696a5ebe668SJean Delvare 
6971beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
6981beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
6991beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
700a5ebe668SJean Delvare 		goto exit_remove_files;
701943b0830SMark M. Hoffman 	}
702943b0830SMark M. Hoffman 
7038d5d45fbSJean Delvare 	return 0;
7048d5d45fbSJean Delvare 
705a5ebe668SJean Delvare exit_remove_files:
70617e7dc43SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
70776e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
70876e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
7098d5d45fbSJean Delvare 	return err;
7108d5d45fbSJean Delvare }
7118d5d45fbSJean Delvare 
sis5595_remove(struct platform_device * pdev)712281dfd0bSBill Pemberton static int sis5595_remove(struct platform_device *pdev)
7138d5d45fbSJean Delvare {
71417e7dc43SJean Delvare 	struct sis5595_data *data = platform_get_drvdata(pdev);
7158d5d45fbSJean Delvare 
7161beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
71717e7dc43SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
71876e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
71976e63860SIvo Manca 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
720943b0830SMark M. Hoffman 
7218d5d45fbSJean Delvare 	return 0;
7228d5d45fbSJean Delvare }
7238d5d45fbSJean Delvare 
724cd9bb056SJingoo Han static const struct pci_device_id sis5595_pci_ids[] = {
7258d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
7268d5d45fbSJean Delvare 	{ 0, }
7278d5d45fbSJean Delvare };
7288d5d45fbSJean Delvare 
7298d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
7308d5d45fbSJean Delvare 
731a5977246SBill Pemberton static int blacklist[] = {
7328d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_540,
7338d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_550,
7348d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_630,
7358d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_645,
7368d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_730,
7378d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_735,
7388fda79ecSGuenter Roeck 	PCI_DEVICE_ID_SI_5511, /*
7398fda79ecSGuenter Roeck 				* 5513 chip has the 0008 device but
7408fda79ecSGuenter Roeck 				* that ID shows up in other chips so we
7418fda79ecSGuenter Roeck 				* use the 5511 ID for recognition
7428fda79ecSGuenter Roeck 				*/
7438d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_5597,
7448d5d45fbSJean Delvare 	PCI_DEVICE_ID_SI_5598,
7458d5d45fbSJean Delvare 	0 };
7468d5d45fbSJean Delvare 
sis5595_device_add(unsigned short address)7476c931ae1SBill Pemberton static int sis5595_device_add(unsigned short address)
74817e7dc43SJean Delvare {
74917e7dc43SJean Delvare 	struct resource res = {
75017e7dc43SJean Delvare 		.start	= address,
75117e7dc43SJean Delvare 		.end	= address + SIS5595_EXTENT - 1,
752847a3b04SUwe Kleine-König 		.name	= DRIVER_NAME,
75317e7dc43SJean Delvare 		.flags	= IORESOURCE_IO,
75417e7dc43SJean Delvare 	};
75517e7dc43SJean Delvare 	int err;
75617e7dc43SJean Delvare 
757b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
758b9acb64aSJean Delvare 	if (err)
759b9acb64aSJean Delvare 		goto exit;
760b9acb64aSJean Delvare 
761847a3b04SUwe Kleine-König 	pdev = platform_device_alloc(DRIVER_NAME, address);
76217e7dc43SJean Delvare 	if (!pdev) {
76317e7dc43SJean Delvare 		err = -ENOMEM;
7644b2515dbSJoe Perches 		pr_err("Device allocation failed\n");
76517e7dc43SJean Delvare 		goto exit;
76617e7dc43SJean Delvare 	}
76717e7dc43SJean Delvare 
76817e7dc43SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
76917e7dc43SJean Delvare 	if (err) {
7704b2515dbSJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
77117e7dc43SJean Delvare 		goto exit_device_put;
77217e7dc43SJean Delvare 	}
77317e7dc43SJean Delvare 
77417e7dc43SJean Delvare 	err = platform_device_add(pdev);
77517e7dc43SJean Delvare 	if (err) {
7764b2515dbSJoe Perches 		pr_err("Device addition failed (%d)\n", err);
77717e7dc43SJean Delvare 		goto exit_device_put;
77817e7dc43SJean Delvare 	}
77917e7dc43SJean Delvare 
78017e7dc43SJean Delvare 	return 0;
78117e7dc43SJean Delvare 
78217e7dc43SJean Delvare exit_device_put:
78317e7dc43SJean Delvare 	platform_device_put(pdev);
78417e7dc43SJean Delvare exit:
78517e7dc43SJean Delvare 	return err;
78617e7dc43SJean Delvare }
78717e7dc43SJean Delvare 
7881b2f9b1eSUwe Kleine-König static struct platform_driver sis5595_driver = {
7891b2f9b1eSUwe Kleine-König 	.driver = {
7901b2f9b1eSUwe Kleine-König 		.name	= DRIVER_NAME,
7911b2f9b1eSUwe Kleine-König 	},
7921b2f9b1eSUwe Kleine-König 	.probe		= sis5595_probe,
7931b2f9b1eSUwe Kleine-König 	.remove		= sis5595_remove,
7941b2f9b1eSUwe Kleine-König };
7951b2f9b1eSUwe Kleine-König 
sis5595_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)7966c931ae1SBill Pemberton static int sis5595_pci_probe(struct pci_dev *dev,
7978d5d45fbSJean Delvare 				       const struct pci_device_id *id)
7988d5d45fbSJean Delvare {
79917e7dc43SJean Delvare 	u16 address;
80017e7dc43SJean Delvare 	u8 enable;
801*a1f38987SIlpo Järvinen 	int *i, err;
8028d5d45fbSJean Delvare 
8038d5d45fbSJean Delvare 	for (i = blacklist; *i != 0; i++) {
8045460a9d0SMark M. Hoffman 		struct pci_dev *d;
8058fda79ecSGuenter Roeck 		d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
8068fda79ecSGuenter Roeck 		if (d) {
8078fda79ecSGuenter Roeck 			dev_err(&d->dev,
8088fda79ecSGuenter Roeck 				"Looked for SIS5595 but found unsupported device %.4x\n",
8098fda79ecSGuenter Roeck 				*i);
8105460a9d0SMark M. Hoffman 			pci_dev_put(d);
8118d5d45fbSJean Delvare 			return -ENODEV;
8128d5d45fbSJean Delvare 		}
8138d5d45fbSJean Delvare 	}
8148d5d45fbSJean Delvare 
81517e7dc43SJean Delvare 	force_addr &= ~(SIS5595_EXTENT - 1);
81617e7dc43SJean Delvare 	if (force_addr) {
81717e7dc43SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
81817e7dc43SJean Delvare 		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
81917e7dc43SJean Delvare 	}
8208d5d45fbSJean Delvare 
821*a1f38987SIlpo Järvinen 	err = pci_read_config_word(dev, SIS5595_BASE_REG, &address);
822*a1f38987SIlpo Järvinen 	if (err != PCIBIOS_SUCCESSFUL) {
82317e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to read ISA address\n");
82417e7dc43SJean Delvare 		return -ENODEV;
82517e7dc43SJean Delvare 	}
82617e7dc43SJean Delvare 
82717e7dc43SJean Delvare 	address &= ~(SIS5595_EXTENT - 1);
82817e7dc43SJean Delvare 	if (!address) {
8298fda79ecSGuenter Roeck 		dev_err(&dev->dev,
8308fda79ecSGuenter Roeck 			"Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8318d5d45fbSJean Delvare 		return -ENODEV;
8328d5d45fbSJean Delvare 	}
83317e7dc43SJean Delvare 	if (force_addr && address != force_addr) {
83417e7dc43SJean Delvare 		/* doesn't work for some chips? */
83517e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to force ISA address\n");
83617e7dc43SJean Delvare 		return -ENODEV;
83717e7dc43SJean Delvare 	}
83817e7dc43SJean Delvare 
839*a1f38987SIlpo Järvinen 	err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
840*a1f38987SIlpo Järvinen 	if (err != PCIBIOS_SUCCESSFUL) {
84117e7dc43SJean Delvare 		dev_err(&dev->dev, "Failed to read enable register\n");
84217e7dc43SJean Delvare 		return -ENODEV;
84317e7dc43SJean Delvare 	}
84417e7dc43SJean Delvare 	if (!(enable & 0x80)) {
845*a1f38987SIlpo Järvinen 		err = pci_write_config_byte(dev, SIS5595_ENABLE_REG, enable | 0x80);
846*a1f38987SIlpo Järvinen 		if (err != PCIBIOS_SUCCESSFUL)
847*a1f38987SIlpo Järvinen 			goto enable_fail;
848*a1f38987SIlpo Järvinen 
849*a1f38987SIlpo Järvinen 		err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
850*a1f38987SIlpo Järvinen 		if (err != PCIBIOS_SUCCESSFUL)
851*a1f38987SIlpo Järvinen 			goto enable_fail;
852*a1f38987SIlpo Järvinen 
85317e7dc43SJean Delvare 		/* doesn't work for some chips! */
854*a1f38987SIlpo Järvinen 		if (!(enable & 0x80))
855*a1f38987SIlpo Järvinen 			goto enable_fail;
85617e7dc43SJean Delvare 	}
85717e7dc43SJean Delvare 
85817e7dc43SJean Delvare 	if (platform_driver_register(&sis5595_driver)) {
85917e7dc43SJean Delvare 		dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
86017e7dc43SJean Delvare 		goto exit;
86117e7dc43SJean Delvare 	}
8628d5d45fbSJean Delvare 
8638d5d45fbSJean Delvare 	s_bridge = pci_dev_get(dev);
86417e7dc43SJean Delvare 	/* Sets global pdev as a side effect */
86517e7dc43SJean Delvare 	if (sis5595_device_add(address))
86617e7dc43SJean Delvare 		goto exit_unregister;
8678d5d45fbSJean Delvare 
8688fda79ecSGuenter Roeck 	/*
8698fda79ecSGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
8708d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
8718d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
8728d5d45fbSJean Delvare 	 */
8738d5d45fbSJean Delvare 	return -ENODEV;
87417e7dc43SJean Delvare 
875*a1f38987SIlpo Järvinen enable_fail:
876*a1f38987SIlpo Järvinen 	dev_err(&dev->dev, "Failed to enable HWM device\n");
877*a1f38987SIlpo Järvinen 	goto exit;
878*a1f38987SIlpo Järvinen 
87917e7dc43SJean Delvare exit_unregister:
88017e7dc43SJean Delvare 	pci_dev_put(dev);
88117e7dc43SJean Delvare 	platform_driver_unregister(&sis5595_driver);
88217e7dc43SJean Delvare exit:
88317e7dc43SJean Delvare 	return -ENODEV;
8848d5d45fbSJean Delvare }
8858d5d45fbSJean Delvare 
8868d5d45fbSJean Delvare static struct pci_driver sis5595_pci_driver = {
887847a3b04SUwe Kleine-König 	.name            = DRIVER_NAME,
8888d5d45fbSJean Delvare 	.id_table        = sis5595_pci_ids,
8898d5d45fbSJean Delvare 	.probe           = sis5595_pci_probe,
8908d5d45fbSJean Delvare };
8918d5d45fbSJean Delvare 
sm_sis5595_init(void)8928d5d45fbSJean Delvare static int __init sm_sis5595_init(void)
8938d5d45fbSJean Delvare {
8948d5d45fbSJean Delvare 	return pci_register_driver(&sis5595_pci_driver);
8958d5d45fbSJean Delvare }
8968d5d45fbSJean Delvare 
sm_sis5595_exit(void)8978d5d45fbSJean Delvare static void __exit sm_sis5595_exit(void)
8988d5d45fbSJean Delvare {
8998d5d45fbSJean Delvare 	pci_unregister_driver(&sis5595_pci_driver);
9008d5d45fbSJean Delvare 	if (s_bridge != NULL) {
90117e7dc43SJean Delvare 		platform_device_unregister(pdev);
90217e7dc43SJean Delvare 		platform_driver_unregister(&sis5595_driver);
9038d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9048d5d45fbSJean Delvare 		s_bridge = NULL;
9058d5d45fbSJean Delvare 	}
9068d5d45fbSJean Delvare }
9078d5d45fbSJean Delvare 
9088d5d45fbSJean Delvare MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
9098d5d45fbSJean Delvare MODULE_DESCRIPTION("SiS 5595 Sensor device");
9108d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9118d5d45fbSJean Delvare 
9128d5d45fbSJean Delvare module_init(sm_sis5595_init);
9138d5d45fbSJean Delvare module_exit(sm_sis5595_exit);
914