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