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