162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sis5595.c - Part of lm_sensors, Linux kernel modules 462306a36Sopenharmony_ci * for hardware monitoring 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, 762306a36Sopenharmony_ci * Kyösti Mälkki <kmalkki@cc.hut.fi>, and 862306a36Sopenharmony_ci * Mark D. Studebaker <mdsxyz123@yahoo.com> 962306a36Sopenharmony_ci * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with 1062306a36Sopenharmony_ci * the help of Jean Delvare <jdelvare@suse.de> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * SiS southbridge has a LM78-like chip integrated on the same IC. 1562306a36Sopenharmony_ci * This driver is a customized copy of lm78.c 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Supports following revisions: 1862306a36Sopenharmony_ci * Version PCI ID PCI Revision 1962306a36Sopenharmony_ci * 1 1039/0008 AF or less 2062306a36Sopenharmony_ci * 2 1039/0008 B0 or greater 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Note: these chips contain a 0008 device which is incompatible with the 2362306a36Sopenharmony_ci * 5595. We recognize these by the presence of the listed 2462306a36Sopenharmony_ci * "blacklist" PCI ID and refuse to load. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * NOT SUPPORTED PCI ID BLACKLIST PCI ID 2762306a36Sopenharmony_ci * 540 0008 0540 2862306a36Sopenharmony_ci * 550 0008 0550 2962306a36Sopenharmony_ci * 5513 0008 5511 3062306a36Sopenharmony_ci * 5581 0008 5597 3162306a36Sopenharmony_ci * 5582 0008 5597 3262306a36Sopenharmony_ci * 5597 0008 5597 3362306a36Sopenharmony_ci * 5598 0008 5597/5598 3462306a36Sopenharmony_ci * 630 0008 0630 3562306a36Sopenharmony_ci * 645 0008 0645 3662306a36Sopenharmony_ci * 730 0008 0730 3762306a36Sopenharmony_ci * 735 0008 0735 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define DRIVER_NAME "sis5595" 4162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/module.h> 4462306a36Sopenharmony_ci#include <linux/slab.h> 4562306a36Sopenharmony_ci#include <linux/ioport.h> 4662306a36Sopenharmony_ci#include <linux/pci.h> 4762306a36Sopenharmony_ci#include <linux/platform_device.h> 4862306a36Sopenharmony_ci#include <linux/hwmon.h> 4962306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 5062306a36Sopenharmony_ci#include <linux/err.h> 5162306a36Sopenharmony_ci#include <linux/init.h> 5262306a36Sopenharmony_ci#include <linux/jiffies.h> 5362306a36Sopenharmony_ci#include <linux/mutex.h> 5462306a36Sopenharmony_ci#include <linux/sysfs.h> 5562306a36Sopenharmony_ci#include <linux/acpi.h> 5662306a36Sopenharmony_ci#include <linux/io.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * If force_addr is set to anything different from 0, we forcibly enable 6062306a36Sopenharmony_ci * the device at the given address. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cistatic u16 force_addr; 6362306a36Sopenharmony_cimodule_param(force_addr, ushort, 0); 6462306a36Sopenharmony_ciMODULE_PARM_DESC(force_addr, 6562306a36Sopenharmony_ci "Initialize the base address of the sensors"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct platform_device *pdev; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Many SIS5595 constants specified below */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Length of ISA address segment */ 7262306a36Sopenharmony_ci#define SIS5595_EXTENT 8 7362306a36Sopenharmony_ci/* PCI Config Registers */ 7462306a36Sopenharmony_ci#define SIS5595_BASE_REG 0x68 7562306a36Sopenharmony_ci#define SIS5595_PIN_REG 0x7A 7662306a36Sopenharmony_ci#define SIS5595_ENABLE_REG 0x7B 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Where are the ISA address/data registers relative to the base address */ 7962306a36Sopenharmony_ci#define SIS5595_ADDR_REG_OFFSET 5 8062306a36Sopenharmony_ci#define SIS5595_DATA_REG_OFFSET 6 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* The SIS5595 registers */ 8362306a36Sopenharmony_ci#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) 8462306a36Sopenharmony_ci#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) 8562306a36Sopenharmony_ci#define SIS5595_REG_IN(nr) (0x20 + (nr)) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) 8862306a36Sopenharmony_ci#define SIS5595_REG_FAN(nr) (0x28 + (nr)) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * On the first version of the chip, the temp registers are separate. 9262306a36Sopenharmony_ci * On the second version, 9362306a36Sopenharmony_ci * TEMP pin is shared with IN4, configured in PCI register 0x7A. 9462306a36Sopenharmony_ci * The registers are the same as well. 9562306a36Sopenharmony_ci * OVER and HYST are really MAX and MIN. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define REV2MIN 0xb0 9962306a36Sopenharmony_ci#define SIS5595_REG_TEMP (((data->revision) >= REV2MIN) ? \ 10062306a36Sopenharmony_ci SIS5595_REG_IN(4) : 0x27) 10162306a36Sopenharmony_ci#define SIS5595_REG_TEMP_OVER (((data->revision) >= REV2MIN) ? \ 10262306a36Sopenharmony_ci SIS5595_REG_IN_MAX(4) : 0x39) 10362306a36Sopenharmony_ci#define SIS5595_REG_TEMP_HYST (((data->revision) >= REV2MIN) ? \ 10462306a36Sopenharmony_ci SIS5595_REG_IN_MIN(4) : 0x3a) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define SIS5595_REG_CONFIG 0x40 10762306a36Sopenharmony_ci#define SIS5595_REG_ALARM1 0x41 10862306a36Sopenharmony_ci#define SIS5595_REG_ALARM2 0x42 10962306a36Sopenharmony_ci#define SIS5595_REG_FANDIV 0x47 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * Conversions. Limit checking is only done on the TO_REG 11362306a36Sopenharmony_ci * variants. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci * IN: mV, (0V to 4.08V) 11862306a36Sopenharmony_ci * REG: 16mV/bit 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic inline u8 IN_TO_REG(unsigned long val) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci unsigned long nval = clamp_val(val, 0, 4080); 12362306a36Sopenharmony_ci return (nval + 8) / 16; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci#define IN_FROM_REG(val) ((val) * 16) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline u8 FAN_TO_REG(long rpm, int div) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci if (rpm <= 0) 13062306a36Sopenharmony_ci return 255; 13162306a36Sopenharmony_ci if (rpm > 1350000) 13262306a36Sopenharmony_ci return 1; 13362306a36Sopenharmony_ci return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic inline int FAN_FROM_REG(u8 val, int div) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* 14262306a36Sopenharmony_ci * TEMP: mC (-54.12C to +157.53C) 14362306a36Sopenharmony_ci * REG: 0.83C/bit + 52.12, two's complement 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic inline int TEMP_FROM_REG(s8 val) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci return val * 830 + 52120; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_cistatic inline s8 TEMP_TO_REG(long val) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int nval = clamp_val(val, -54120, 157530) ; 15262306a36Sopenharmony_ci return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * FAN DIV: 1, 2, 4, or 8 (defaults to 2) 15762306a36Sopenharmony_ci * REG: 0, 1, 2, or 3 (respectively) (defaults to 1) 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic inline u8 DIV_TO_REG(int val) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci#define DIV_FROM_REG(val) (1 << (val)) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * For each registered chip, we need to keep some data in memory. 16762306a36Sopenharmony_ci * The structure is dynamically allocated. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_cistruct sis5595_data { 17062306a36Sopenharmony_ci unsigned short addr; 17162306a36Sopenharmony_ci const char *name; 17262306a36Sopenharmony_ci struct device *hwmon_dev; 17362306a36Sopenharmony_ci struct mutex lock; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci struct mutex update_lock; 17662306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 17762306a36Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 17862306a36Sopenharmony_ci char maxins; /* == 3 if temp enabled, otherwise == 4 */ 17962306a36Sopenharmony_ci u8 revision; /* Reg. value */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci u8 in[5]; /* Register value */ 18262306a36Sopenharmony_ci u8 in_max[5]; /* Register value */ 18362306a36Sopenharmony_ci u8 in_min[5]; /* Register value */ 18462306a36Sopenharmony_ci u8 fan[2]; /* Register value */ 18562306a36Sopenharmony_ci u8 fan_min[2]; /* Register value */ 18662306a36Sopenharmony_ci s8 temp; /* Register value */ 18762306a36Sopenharmony_ci s8 temp_over; /* Register value */ 18862306a36Sopenharmony_ci s8 temp_hyst; /* Register value */ 18962306a36Sopenharmony_ci u8 fan_div[2]; /* Register encoding, shifted right */ 19062306a36Sopenharmony_ci u16 alarms; /* Register encoding, combined */ 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* ISA access must be locked explicitly. */ 19662306a36Sopenharmony_cistatic int sis5595_read_value(struct sis5595_data *data, u8 reg) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int res; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci mutex_lock(&data->lock); 20162306a36Sopenharmony_ci outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); 20262306a36Sopenharmony_ci res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET); 20362306a36Sopenharmony_ci mutex_unlock(&data->lock); 20462306a36Sopenharmony_ci return res; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci mutex_lock(&data->lock); 21062306a36Sopenharmony_ci outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); 21162306a36Sopenharmony_ci outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET); 21262306a36Sopenharmony_ci mutex_unlock(&data->lock); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic struct sis5595_data *sis5595_update_device(struct device *dev) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 21862306a36Sopenharmony_ci int i; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 22362306a36Sopenharmony_ci || !data->valid) { 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci for (i = 0; i <= data->maxins; i++) { 22662306a36Sopenharmony_ci data->in[i] = 22762306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_IN(i)); 22862306a36Sopenharmony_ci data->in_min[i] = 22962306a36Sopenharmony_ci sis5595_read_value(data, 23062306a36Sopenharmony_ci SIS5595_REG_IN_MIN(i)); 23162306a36Sopenharmony_ci data->in_max[i] = 23262306a36Sopenharmony_ci sis5595_read_value(data, 23362306a36Sopenharmony_ci SIS5595_REG_IN_MAX(i)); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 23662306a36Sopenharmony_ci data->fan[i] = 23762306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_FAN(i)); 23862306a36Sopenharmony_ci data->fan_min[i] = 23962306a36Sopenharmony_ci sis5595_read_value(data, 24062306a36Sopenharmony_ci SIS5595_REG_FAN_MIN(i)); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci if (data->maxins == 3) { 24362306a36Sopenharmony_ci data->temp = 24462306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_TEMP); 24562306a36Sopenharmony_ci data->temp_over = 24662306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_TEMP_OVER); 24762306a36Sopenharmony_ci data->temp_hyst = 24862306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_TEMP_HYST); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci i = sis5595_read_value(data, SIS5595_REG_FANDIV); 25162306a36Sopenharmony_ci data->fan_div[0] = (i >> 4) & 0x03; 25262306a36Sopenharmony_ci data->fan_div[1] = i >> 6; 25362306a36Sopenharmony_ci data->alarms = 25462306a36Sopenharmony_ci sis5595_read_value(data, SIS5595_REG_ALARM1) | 25562306a36Sopenharmony_ci (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8); 25662306a36Sopenharmony_ci data->last_updated = jiffies; 25762306a36Sopenharmony_ci data->valid = true; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return data; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* 4 Voltages */ 26662306a36Sopenharmony_cistatic ssize_t in_show(struct device *dev, struct device_attribute *da, 26762306a36Sopenharmony_ci char *buf) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 27062306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 27162306a36Sopenharmony_ci int nr = attr->index; 27262306a36Sopenharmony_ci return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic ssize_t in_min_show(struct device *dev, struct device_attribute *da, 27662306a36Sopenharmony_ci char *buf) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 27962306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 28062306a36Sopenharmony_ci int nr = attr->index; 28162306a36Sopenharmony_ci return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic ssize_t in_max_show(struct device *dev, struct device_attribute *da, 28562306a36Sopenharmony_ci char *buf) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 28862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 28962306a36Sopenharmony_ci int nr = attr->index; 29062306a36Sopenharmony_ci return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic ssize_t in_min_store(struct device *dev, struct device_attribute *da, 29462306a36Sopenharmony_ci const char *buf, size_t count) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 29762306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 29862306a36Sopenharmony_ci int nr = attr->index; 29962306a36Sopenharmony_ci unsigned long val; 30062306a36Sopenharmony_ci int err; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 30362306a36Sopenharmony_ci if (err) 30462306a36Sopenharmony_ci return err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 30762306a36Sopenharmony_ci data->in_min[nr] = IN_TO_REG(val); 30862306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); 30962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 31062306a36Sopenharmony_ci return count; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic ssize_t in_max_store(struct device *dev, struct device_attribute *da, 31462306a36Sopenharmony_ci const char *buf, size_t count) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 31762306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 31862306a36Sopenharmony_ci int nr = attr->index; 31962306a36Sopenharmony_ci unsigned long val; 32062306a36Sopenharmony_ci int err; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 32362306a36Sopenharmony_ci if (err) 32462306a36Sopenharmony_ci return err; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 32762306a36Sopenharmony_ci data->in_max[nr] = IN_TO_REG(val); 32862306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); 32962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 33062306a36Sopenharmony_ci return count; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); 33462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0); 33562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0); 33662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in1_input, in, 1); 33762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); 33862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); 33962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in2_input, in, 2); 34062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); 34162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); 34262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in3_input, in, 3); 34362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); 34462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); 34562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in4_input, in, 4); 34662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); 34762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* Temperature */ 35062306a36Sopenharmony_cistatic ssize_t temp1_input_show(struct device *dev, 35162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 35462306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr, 35862306a36Sopenharmony_ci char *buf) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 36162306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic ssize_t temp1_max_store(struct device *dev, 36562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 36662306a36Sopenharmony_ci size_t count) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 36962306a36Sopenharmony_ci long val; 37062306a36Sopenharmony_ci int err; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 37362306a36Sopenharmony_ci if (err) 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 37762306a36Sopenharmony_ci data->temp_over = TEMP_TO_REG(val); 37862306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over); 37962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 38062306a36Sopenharmony_ci return count; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic ssize_t temp1_max_hyst_show(struct device *dev, 38462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 38762306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic ssize_t temp1_max_hyst_store(struct device *dev, 39162306a36Sopenharmony_ci struct device_attribute *attr, 39262306a36Sopenharmony_ci const char *buf, size_t count) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 39562306a36Sopenharmony_ci long val; 39662306a36Sopenharmony_ci int err; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 39962306a36Sopenharmony_ci if (err) 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci mutex_lock(&data->update_lock); 40362306a36Sopenharmony_ci data->temp_hyst = TEMP_TO_REG(val); 40462306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst); 40562306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 40662306a36Sopenharmony_ci return count; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(temp1_input); 41062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(temp1_max); 41162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(temp1_max_hyst); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* 2 Fans */ 41462306a36Sopenharmony_cistatic ssize_t fan_show(struct device *dev, struct device_attribute *da, 41562306a36Sopenharmony_ci char *buf) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 41862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 41962306a36Sopenharmony_ci int nr = attr->index; 42062306a36Sopenharmony_ci return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], 42162306a36Sopenharmony_ci DIV_FROM_REG(data->fan_div[nr]))); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic ssize_t fan_min_show(struct device *dev, struct device_attribute *da, 42562306a36Sopenharmony_ci char *buf) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 42862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 42962306a36Sopenharmony_ci int nr = attr->index; 43062306a36Sopenharmony_ci return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], 43162306a36Sopenharmony_ci DIV_FROM_REG(data->fan_div[nr]))); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic ssize_t fan_min_store(struct device *dev, struct device_attribute *da, 43562306a36Sopenharmony_ci const char *buf, size_t count) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 43862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 43962306a36Sopenharmony_ci int nr = attr->index; 44062306a36Sopenharmony_ci unsigned long val; 44162306a36Sopenharmony_ci int err; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 44462306a36Sopenharmony_ci if (err) 44562306a36Sopenharmony_ci return err; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 44862306a36Sopenharmony_ci data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 44962306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); 45062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 45162306a36Sopenharmony_ci return count; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic ssize_t fan_div_show(struct device *dev, struct device_attribute *da, 45562306a36Sopenharmony_ci char *buf) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 45862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 45962306a36Sopenharmony_ci int nr = attr->index; 46062306a36Sopenharmony_ci return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/* 46462306a36Sopenharmony_ci * Note: we save and restore the fan minimum here, because its value is 46562306a36Sopenharmony_ci * determined in part by the fan divisor. This follows the principle of 46662306a36Sopenharmony_ci * least surprise; the user doesn't expect the fan minimum to change just 46762306a36Sopenharmony_ci * because the divisor changed. 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_cistatic ssize_t fan_div_store(struct device *dev, struct device_attribute *da, 47062306a36Sopenharmony_ci const char *buf, size_t count) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 47362306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 47462306a36Sopenharmony_ci int nr = attr->index; 47562306a36Sopenharmony_ci unsigned long min; 47662306a36Sopenharmony_ci int reg; 47762306a36Sopenharmony_ci unsigned long val; 47862306a36Sopenharmony_ci int err; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 48162306a36Sopenharmony_ci if (err) 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 48562306a36Sopenharmony_ci min = FAN_FROM_REG(data->fan_min[nr], 48662306a36Sopenharmony_ci DIV_FROM_REG(data->fan_div[nr])); 48762306a36Sopenharmony_ci reg = sis5595_read_value(data, SIS5595_REG_FANDIV); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (val) { 49062306a36Sopenharmony_ci case 1: 49162306a36Sopenharmony_ci data->fan_div[nr] = 0; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case 2: 49462306a36Sopenharmony_ci data->fan_div[nr] = 1; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case 4: 49762306a36Sopenharmony_ci data->fan_div[nr] = 2; 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case 8: 50062306a36Sopenharmony_ci data->fan_div[nr] = 3; 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci dev_err(dev, 50462306a36Sopenharmony_ci "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", 50562306a36Sopenharmony_ci val); 50662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci switch (nr) { 51162306a36Sopenharmony_ci case 0: 51262306a36Sopenharmony_ci reg = (reg & 0xcf) | (data->fan_div[nr] << 4); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci case 1: 51562306a36Sopenharmony_ci reg = (reg & 0x3f) | (data->fan_div[nr] << 6); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_FANDIV, reg); 51962306a36Sopenharmony_ci data->fan_min[nr] = 52062306a36Sopenharmony_ci FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 52162306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); 52262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 52362306a36Sopenharmony_ci return count; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); 52762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 52862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0); 52962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); 53062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 53162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/* Alarms */ 53462306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 53562306a36Sopenharmony_ci char *buf) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 53862306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->alarms); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *da, 54362306a36Sopenharmony_ci char *buf) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct sis5595_data *data = sis5595_update_device(dev); 54662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(da)->index; 54762306a36Sopenharmony_ci return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); 55062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1); 55162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2); 55262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3); 55362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 15); 55462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6); 55562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7); 55662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 15); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, 55962306a36Sopenharmony_ci char *buf) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct sis5595_data *data = dev_get_drvdata(dev); 56262306a36Sopenharmony_ci return sprintf(buf, "%s\n", data->name); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic struct attribute *sis5595_attributes[] = { 56762306a36Sopenharmony_ci &sensor_dev_attr_in0_input.dev_attr.attr, 56862306a36Sopenharmony_ci &sensor_dev_attr_in0_min.dev_attr.attr, 56962306a36Sopenharmony_ci &sensor_dev_attr_in0_max.dev_attr.attr, 57062306a36Sopenharmony_ci &sensor_dev_attr_in0_alarm.dev_attr.attr, 57162306a36Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 57262306a36Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr.attr, 57362306a36Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr.attr, 57462306a36Sopenharmony_ci &sensor_dev_attr_in1_alarm.dev_attr.attr, 57562306a36Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 57662306a36Sopenharmony_ci &sensor_dev_attr_in2_min.dev_attr.attr, 57762306a36Sopenharmony_ci &sensor_dev_attr_in2_max.dev_attr.attr, 57862306a36Sopenharmony_ci &sensor_dev_attr_in2_alarm.dev_attr.attr, 57962306a36Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 58062306a36Sopenharmony_ci &sensor_dev_attr_in3_min.dev_attr.attr, 58162306a36Sopenharmony_ci &sensor_dev_attr_in3_max.dev_attr.attr, 58262306a36Sopenharmony_ci &sensor_dev_attr_in3_alarm.dev_attr.attr, 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 58562306a36Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 58662306a36Sopenharmony_ci &sensor_dev_attr_fan1_div.dev_attr.attr, 58762306a36Sopenharmony_ci &sensor_dev_attr_fan1_alarm.dev_attr.attr, 58862306a36Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 58962306a36Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 59062306a36Sopenharmony_ci &sensor_dev_attr_fan2_div.dev_attr.attr, 59162306a36Sopenharmony_ci &sensor_dev_attr_fan2_alarm.dev_attr.attr, 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci &dev_attr_alarms.attr, 59462306a36Sopenharmony_ci &dev_attr_name.attr, 59562306a36Sopenharmony_ci NULL 59662306a36Sopenharmony_ci}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic const struct attribute_group sis5595_group = { 59962306a36Sopenharmony_ci .attrs = sis5595_attributes, 60062306a36Sopenharmony_ci}; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic struct attribute *sis5595_attributes_in4[] = { 60362306a36Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 60462306a36Sopenharmony_ci &sensor_dev_attr_in4_min.dev_attr.attr, 60562306a36Sopenharmony_ci &sensor_dev_attr_in4_max.dev_attr.attr, 60662306a36Sopenharmony_ci &sensor_dev_attr_in4_alarm.dev_attr.attr, 60762306a36Sopenharmony_ci NULL 60862306a36Sopenharmony_ci}; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic const struct attribute_group sis5595_group_in4 = { 61162306a36Sopenharmony_ci .attrs = sis5595_attributes_in4, 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic struct attribute *sis5595_attributes_temp1[] = { 61562306a36Sopenharmony_ci &dev_attr_temp1_input.attr, 61662306a36Sopenharmony_ci &dev_attr_temp1_max.attr, 61762306a36Sopenharmony_ci &dev_attr_temp1_max_hyst.attr, 61862306a36Sopenharmony_ci &sensor_dev_attr_temp1_alarm.dev_attr.attr, 61962306a36Sopenharmony_ci NULL 62062306a36Sopenharmony_ci}; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic const struct attribute_group sis5595_group_temp1 = { 62362306a36Sopenharmony_ci .attrs = sis5595_attributes_temp1, 62462306a36Sopenharmony_ci}; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci/* Called when we have found a new SIS5595. */ 62762306a36Sopenharmony_cistatic void sis5595_init_device(struct sis5595_data *data) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG); 63062306a36Sopenharmony_ci if (!(config & 0x01)) 63162306a36Sopenharmony_ci sis5595_write_value(data, SIS5595_REG_CONFIG, 63262306a36Sopenharmony_ci (config & 0xf7) | 0x01); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/* This is called when the module is loaded */ 63662306a36Sopenharmony_cistatic int sis5595_probe(struct platform_device *pdev) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci int err = 0; 63962306a36Sopenharmony_ci int i; 64062306a36Sopenharmony_ci struct sis5595_data *data; 64162306a36Sopenharmony_ci struct resource *res; 64262306a36Sopenharmony_ci char val; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Reserve the ISA region */ 64562306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IO, 0); 64662306a36Sopenharmony_ci if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT, 64762306a36Sopenharmony_ci DRIVER_NAME)) 64862306a36Sopenharmony_ci return -EBUSY; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data), 65162306a36Sopenharmony_ci GFP_KERNEL); 65262306a36Sopenharmony_ci if (!data) 65362306a36Sopenharmony_ci return -ENOMEM; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci mutex_init(&data->lock); 65662306a36Sopenharmony_ci mutex_init(&data->update_lock); 65762306a36Sopenharmony_ci data->addr = res->start; 65862306a36Sopenharmony_ci data->name = DRIVER_NAME; 65962306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* 66262306a36Sopenharmony_ci * Check revision and pin registers to determine whether 4 or 5 voltages 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci data->revision = s_bridge->revision; 66562306a36Sopenharmony_ci /* 4 voltages, 1 temp */ 66662306a36Sopenharmony_ci data->maxins = 3; 66762306a36Sopenharmony_ci if (data->revision >= REV2MIN) { 66862306a36Sopenharmony_ci pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); 66962306a36Sopenharmony_ci if (!(val & 0x80)) 67062306a36Sopenharmony_ci /* 5 voltages, no temps */ 67162306a36Sopenharmony_ci data->maxins = 4; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* Initialize the SIS5595 chip */ 67562306a36Sopenharmony_ci sis5595_init_device(data); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* A few vars need to be filled upon startup */ 67862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 67962306a36Sopenharmony_ci data->fan_min[i] = sis5595_read_value(data, 68062306a36Sopenharmony_ci SIS5595_REG_FAN_MIN(i)); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Register sysfs hooks */ 68462306a36Sopenharmony_ci err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group); 68562306a36Sopenharmony_ci if (err) 68662306a36Sopenharmony_ci return err; 68762306a36Sopenharmony_ci if (data->maxins == 4) { 68862306a36Sopenharmony_ci err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4); 68962306a36Sopenharmony_ci if (err) 69062306a36Sopenharmony_ci goto exit_remove_files; 69162306a36Sopenharmony_ci } else { 69262306a36Sopenharmony_ci err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1); 69362306a36Sopenharmony_ci if (err) 69462306a36Sopenharmony_ci goto exit_remove_files; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci data->hwmon_dev = hwmon_device_register(&pdev->dev); 69862306a36Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 69962306a36Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 70062306a36Sopenharmony_ci goto exit_remove_files; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ciexit_remove_files: 70662306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group); 70762306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4); 70862306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1); 70962306a36Sopenharmony_ci return err; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic int sis5595_remove(struct platform_device *pdev) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct sis5595_data *data = platform_get_drvdata(pdev); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 71762306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group); 71862306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4); 71962306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic const struct pci_device_id sis5595_pci_ids[] = { 72562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 72662306a36Sopenharmony_ci { 0, } 72762306a36Sopenharmony_ci}; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sis5595_pci_ids); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int blacklist[] = { 73262306a36Sopenharmony_ci PCI_DEVICE_ID_SI_540, 73362306a36Sopenharmony_ci PCI_DEVICE_ID_SI_550, 73462306a36Sopenharmony_ci PCI_DEVICE_ID_SI_630, 73562306a36Sopenharmony_ci PCI_DEVICE_ID_SI_645, 73662306a36Sopenharmony_ci PCI_DEVICE_ID_SI_730, 73762306a36Sopenharmony_ci PCI_DEVICE_ID_SI_735, 73862306a36Sopenharmony_ci PCI_DEVICE_ID_SI_5511, /* 73962306a36Sopenharmony_ci * 5513 chip has the 0008 device but 74062306a36Sopenharmony_ci * that ID shows up in other chips so we 74162306a36Sopenharmony_ci * use the 5511 ID for recognition 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci PCI_DEVICE_ID_SI_5597, 74462306a36Sopenharmony_ci PCI_DEVICE_ID_SI_5598, 74562306a36Sopenharmony_ci 0 }; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int sis5595_device_add(unsigned short address) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct resource res = { 75062306a36Sopenharmony_ci .start = address, 75162306a36Sopenharmony_ci .end = address + SIS5595_EXTENT - 1, 75262306a36Sopenharmony_ci .name = DRIVER_NAME, 75362306a36Sopenharmony_ci .flags = IORESOURCE_IO, 75462306a36Sopenharmony_ci }; 75562306a36Sopenharmony_ci int err; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci err = acpi_check_resource_conflict(&res); 75862306a36Sopenharmony_ci if (err) 75962306a36Sopenharmony_ci goto exit; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci pdev = platform_device_alloc(DRIVER_NAME, address); 76262306a36Sopenharmony_ci if (!pdev) { 76362306a36Sopenharmony_ci err = -ENOMEM; 76462306a36Sopenharmony_ci pr_err("Device allocation failed\n"); 76562306a36Sopenharmony_ci goto exit; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci err = platform_device_add_resources(pdev, &res, 1); 76962306a36Sopenharmony_ci if (err) { 77062306a36Sopenharmony_ci pr_err("Device resource addition failed (%d)\n", err); 77162306a36Sopenharmony_ci goto exit_device_put; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci err = platform_device_add(pdev); 77562306a36Sopenharmony_ci if (err) { 77662306a36Sopenharmony_ci pr_err("Device addition failed (%d)\n", err); 77762306a36Sopenharmony_ci goto exit_device_put; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ciexit_device_put: 78362306a36Sopenharmony_ci platform_device_put(pdev); 78462306a36Sopenharmony_ciexit: 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic struct platform_driver sis5595_driver = { 78962306a36Sopenharmony_ci .driver = { 79062306a36Sopenharmony_ci .name = DRIVER_NAME, 79162306a36Sopenharmony_ci }, 79262306a36Sopenharmony_ci .probe = sis5595_probe, 79362306a36Sopenharmony_ci .remove = sis5595_remove, 79462306a36Sopenharmony_ci}; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int sis5595_pci_probe(struct pci_dev *dev, 79762306a36Sopenharmony_ci const struct pci_device_id *id) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci u16 address; 80062306a36Sopenharmony_ci u8 enable; 80162306a36Sopenharmony_ci int *i, err; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci for (i = blacklist; *i != 0; i++) { 80462306a36Sopenharmony_ci struct pci_dev *d; 80562306a36Sopenharmony_ci d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); 80662306a36Sopenharmony_ci if (d) { 80762306a36Sopenharmony_ci dev_err(&d->dev, 80862306a36Sopenharmony_ci "Looked for SIS5595 but found unsupported device %.4x\n", 80962306a36Sopenharmony_ci *i); 81062306a36Sopenharmony_ci pci_dev_put(d); 81162306a36Sopenharmony_ci return -ENODEV; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci force_addr &= ~(SIS5595_EXTENT - 1); 81662306a36Sopenharmony_ci if (force_addr) { 81762306a36Sopenharmony_ci dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr); 81862306a36Sopenharmony_ci pci_write_config_word(dev, SIS5595_BASE_REG, force_addr); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci err = pci_read_config_word(dev, SIS5595_BASE_REG, &address); 82262306a36Sopenharmony_ci if (err != PCIBIOS_SUCCESSFUL) { 82362306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to read ISA address\n"); 82462306a36Sopenharmony_ci return -ENODEV; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci address &= ~(SIS5595_EXTENT - 1); 82862306a36Sopenharmony_ci if (!address) { 82962306a36Sopenharmony_ci dev_err(&dev->dev, 83062306a36Sopenharmony_ci "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); 83162306a36Sopenharmony_ci return -ENODEV; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci if (force_addr && address != force_addr) { 83462306a36Sopenharmony_ci /* doesn't work for some chips? */ 83562306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to force ISA address\n"); 83662306a36Sopenharmony_ci return -ENODEV; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable); 84062306a36Sopenharmony_ci if (err != PCIBIOS_SUCCESSFUL) { 84162306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to read enable register\n"); 84262306a36Sopenharmony_ci return -ENODEV; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci if (!(enable & 0x80)) { 84562306a36Sopenharmony_ci err = pci_write_config_byte(dev, SIS5595_ENABLE_REG, enable | 0x80); 84662306a36Sopenharmony_ci if (err != PCIBIOS_SUCCESSFUL) 84762306a36Sopenharmony_ci goto enable_fail; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable); 85062306a36Sopenharmony_ci if (err != PCIBIOS_SUCCESSFUL) 85162306a36Sopenharmony_ci goto enable_fail; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* doesn't work for some chips! */ 85462306a36Sopenharmony_ci if (!(enable & 0x80)) 85562306a36Sopenharmony_ci goto enable_fail; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (platform_driver_register(&sis5595_driver)) { 85962306a36Sopenharmony_ci dev_dbg(&dev->dev, "Failed to register sis5595 driver\n"); 86062306a36Sopenharmony_ci goto exit; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci s_bridge = pci_dev_get(dev); 86462306a36Sopenharmony_ci /* Sets global pdev as a side effect */ 86562306a36Sopenharmony_ci if (sis5595_device_add(address)) 86662306a36Sopenharmony_ci goto exit_unregister; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* 86962306a36Sopenharmony_ci * Always return failure here. This is to allow other drivers to bind 87062306a36Sopenharmony_ci * to this pci device. We don't really want to have control over the 87162306a36Sopenharmony_ci * pci device, we only wanted to read as few register values from it. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ci return -ENODEV; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cienable_fail: 87662306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to enable HWM device\n"); 87762306a36Sopenharmony_ci goto exit; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ciexit_unregister: 88062306a36Sopenharmony_ci pci_dev_put(dev); 88162306a36Sopenharmony_ci platform_driver_unregister(&sis5595_driver); 88262306a36Sopenharmony_ciexit: 88362306a36Sopenharmony_ci return -ENODEV; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic struct pci_driver sis5595_pci_driver = { 88762306a36Sopenharmony_ci .name = DRIVER_NAME, 88862306a36Sopenharmony_ci .id_table = sis5595_pci_ids, 88962306a36Sopenharmony_ci .probe = sis5595_pci_probe, 89062306a36Sopenharmony_ci}; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic int __init sm_sis5595_init(void) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci return pci_register_driver(&sis5595_pci_driver); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic void __exit sm_sis5595_exit(void) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci pci_unregister_driver(&sis5595_pci_driver); 90062306a36Sopenharmony_ci if (s_bridge != NULL) { 90162306a36Sopenharmony_ci platform_device_unregister(pdev); 90262306a36Sopenharmony_ci platform_driver_unregister(&sis5595_driver); 90362306a36Sopenharmony_ci pci_dev_put(s_bridge); 90462306a36Sopenharmony_ci s_bridge = NULL; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ciMODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>"); 90962306a36Sopenharmony_ciMODULE_DESCRIPTION("SiS 5595 Sensor device"); 91062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cimodule_init(sm_sis5595_init); 91362306a36Sopenharmony_cimodule_exit(sm_sis5595_exit); 914