diff options
Diffstat (limited to 'drivers/hwmon')
108 files changed, 4271 insertions, 1727 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c4633de64465..89ac1cb26f24 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -180,11 +180,11 @@ config SENSORS_ADM9240 will be called adm9240. config SENSORS_ADT7410 - tristate "Analog Devices ADT7410" + tristate "Analog Devices ADT7410/ADT7420" depends on I2C help If you say yes here you get support for the Analog Devices - ADT7410 temperature monitoring chip. + ADT7410 and ADT7420 temperature monitoring chips. This driver can also be built as a module. If so, the module will be called adt7410. @@ -334,6 +334,16 @@ config SENSORS_DA9052_ADC This driver can also be built as module. If so, the module will be called da9052-hwmon. +config SENSORS_DA9055 + tristate "Dialog Semiconductor DA9055 ADC" + depends on MFD_DA9055 + help + If you say yes here you get support for ADC on the Dialog + Semiconductor DA9055 PMIC. + + This driver can also be built as a module. If so, the module + will be called da9055-hwmon. + config SENSORS_I5K_AMB tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets" depends on PCI @@ -455,7 +465,7 @@ config SENSORS_HIH6130 config SENSORS_CORETEMP tristate "Intel Core/Core2/Atom temperature sensor" - depends on X86 && PCI + depends on X86 help If you say yes here you get support for the temperature sensor inside your CPU. Most of the family 6 CPUs @@ -496,7 +506,8 @@ config SENSORS_IT87 help If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, - IT8782F, and IT8783E/F sensor chips, and the SiS950 clone. + IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the + SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. @@ -519,8 +530,8 @@ config SENSORS_JC42 temperature sensors, which are used on many DDR3 memory modules for mobile devices and servers. Support will include, but not be limited to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805, - MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002, - STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2. + MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E), + STTS2002, STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2. This driver can also be built as a module. If so, the module will be called jc42. @@ -844,6 +855,17 @@ config SENSORS_MAX6650 This driver can also be built as a module. If so, the module will be called max6650. +config SENSORS_MAX6697 + tristate "Maxim MAX6697 and compatibles" + depends on I2C + help + If you say yes here you get support for MAX6581, MAX6602, MAX6622, + MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699 + temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called max6697. + config SENSORS_MCP3021 tristate "Microchip MCP3021 and compatibles" depends on I2C @@ -1106,11 +1128,12 @@ config SENSORS_ADS1015 will be called ads1015. config SENSORS_ADS7828 - tristate "Texas Instruments ADS7828" + tristate "Texas Instruments ADS7828 and compatibles" depends on I2C help - If you say yes here you get support for Texas Instruments ADS7828 - 12-bit 8-channel ADC device. + If you say yes here you get support for Texas Instruments ADS7828 and + ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while + it is 8-bit on ADS7830. This driver can also be built as a module. If so, the module will be called ads7828. @@ -1134,6 +1157,16 @@ config SENSORS_AMC6821 This driver can also be build as a module. If so, the module will be called amc6821. +config SENSORS_INA209 + tristate "TI / Burr Brown INA209" + depends on I2C + help + If you say yes here you get support for the TI / Burr Brown INA209 + voltage / current / power monitor I2C interface. + + This driver can also be built as a module. If so, the module will + be called ina209. + config SENSORS_INA2XX tristate "Texas Instruments INA219 and compatibles" depends on I2C @@ -1197,6 +1230,14 @@ config SENSORS_TWL4030_MADC This driver can also be built as a module. If so it will be called twl4030-madc-hwmon. +config SENSORS_VEXPRESS + tristate "Versatile Express" + depends on VEXPRESS_CONFIG + help + This driver provides support for hardware sensors available on + the ARM Ltd's Versatile Express platform. It can provide wide + range of information like temperature, power, energy. + config SENSORS_VIA_CPUTEMP tristate "VIA CPU temperature sensor" depends on X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8d5fcb5e8e9f..8d6d97ea7c1e 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o +obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DS620) += ds620.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o @@ -64,6 +65,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o +obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o @@ -98,6 +100,7 @@ obj-$(CONFIG_SENSORS_MAX197) += max197.o obj-$(CONFIG_SENSORS_MAX6639) += max6639.o obj-$(CONFIG_SENSORS_MAX6642) += max6642.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o +obj-$(CONFIG_SENSORS_MAX6697) += max6697.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o @@ -121,6 +124,7 @@ obj-$(CONFIG_SENSORS_TMP102) += tmp102.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o +obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 78b81793ddd9..6119ff8e8c87 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -478,7 +478,7 @@ static int abituguru_write(struct abituguru_data *data, * alarm for sensor type X and then enabling the sensor as sensor type * X, if we then get an alarm it is a sensor of type X. */ -static int __devinit +static int abituguru_detect_bank1_sensor_type(struct abituguru_data *data, u8 sensor_addr) { @@ -635,7 +635,7 @@ abituguru_detect_bank1_sensor_type_exit: * read/write test would be feasible because of the reaction above, I've * however opted to stay on the safe side. */ -static void __devinit +static void abituguru_detect_no_bank2_sensors(struct abituguru_data *data) { int i; @@ -691,7 +691,7 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data) (int)data->bank2_sensors); } -static void __devinit +static void abituguru_detect_no_pwms(struct abituguru_data *data) { int i, j; @@ -1264,7 +1264,7 @@ static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = { SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), }; -static int __devinit abituguru_probe(struct platform_device *pdev) +static int abituguru_probe(struct platform_device *pdev) { struct abituguru_data *data; int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV; @@ -1434,7 +1434,7 @@ abituguru_probe_error: return res; } -static int __devexit abituguru_remove(struct platform_device *pdev) +static int abituguru_remove(struct platform_device *pdev) { int i; struct abituguru_data *data = platform_get_drvdata(pdev); @@ -1545,7 +1545,7 @@ static struct platform_driver abituguru_driver = { .pm = ABIT_UGURU_PM, }, .probe = abituguru_probe, - .remove = __devexit_p(abituguru_remove), + .remove = abituguru_remove, }; static int __init abituguru_detect(void) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index b174b8b2b4df..205327d33c4d 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -966,7 +966,7 @@ static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = { SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), }; -static int __devinit abituguru3_probe(struct platform_device *pdev) +static int abituguru3_probe(struct platform_device *pdev) { const int no_sysfs_attr[3] = { 10, 8, 7 }; int sensor_index[3] = { 0, 1, 1 }; @@ -1072,7 +1072,7 @@ abituguru3_probe_error: return res; } -static int __devexit abituguru3_remove(struct platform_device *pdev) +static int abituguru3_remove(struct platform_device *pdev) { int i; struct abituguru3_data *data = platform_get_drvdata(pdev); @@ -1171,7 +1171,7 @@ static struct platform_driver abituguru3_driver = { .pm = ABIT_UGURU3_PM }, .probe = abituguru3_probe, - .remove = __devexit_p(abituguru3_remove), + .remove = abituguru3_remove, }; static int __init abituguru3_dmi_detect(void) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 1672e2a5db46..6351aba8819c 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -911,7 +911,7 @@ exit: return res; } -static int acpi_power_meter_remove(struct acpi_device *device, int type) +static int acpi_power_meter_remove(struct acpi_device *device) { struct acpi_power_meter_resource *resource; diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 37c01e72d699..a57584d28a40 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -107,7 +107,7 @@ static const struct attribute_group ad7314_group = { .attrs = ad7314_attributes, }; -static int __devinit ad7314_probe(struct spi_device *spi_dev) +static int ad7314_probe(struct spi_device *spi_dev) { int ret; struct ad7314_data *chip; @@ -135,7 +135,7 @@ error_remove_group: return ret; } -static int __devexit ad7314_remove(struct spi_device *spi_dev) +static int ad7314_remove(struct spi_device *spi_dev) { struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); @@ -159,7 +159,7 @@ static struct spi_driver ad7314_driver = { .owner = THIS_MODULE, }, .probe = ad7314_probe, - .remove = __devexit_p(ad7314_remove), + .remove = ad7314_remove, .id_table = ad7314_id, }; diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index b420fb3f3a71..5d501adc3e54 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -137,7 +137,7 @@ static ssize_t set_max_min(struct device *dev, if (ret < 0) return ret; - temp = SENSORS_LIMIT(temp, -40000, 85000); + temp = clamp_val(temp, -40000, 85000); temp = (temp + (temp < 0 ? -500 : 500)) / 1000; mutex_lock(&data->lock); @@ -226,7 +226,7 @@ exit_remove: return err; } -static int __devexit ad7414_remove(struct i2c_client *client) +static int ad7414_remove(struct i2c_client *client) { struct ad7414_data *data = i2c_get_clientdata(client); @@ -246,7 +246,7 @@ static struct i2c_driver ad7414_driver = { .name = "ad7414", }, .probe = ad7414_probe, - .remove = __devexit_p(ad7414_remove), + .remove = ad7414_remove, .id_table = ad7414_id, }; diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index f4c5867170d6..751b1f0264a4 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -161,7 +161,7 @@ static struct sensor_device_attribute ad_input[] = { /*----------------------------------------------------------------------*/ -static int __devinit adcxx_probe(struct spi_device *spi) +static int adcxx_probe(struct spi_device *spi) { int channels = spi_get_device_id(spi)->driver_data; struct adcxx *adc; @@ -208,7 +208,7 @@ out_err: return status; } -static int __devexit adcxx_remove(struct spi_device *spi) +static int adcxx_remove(struct spi_device *spi) { struct adcxx *adc = spi_get_drvdata(spi); int i; @@ -240,7 +240,7 @@ static struct spi_driver adcxx_driver = { }, .id_table = adcxx_ids, .probe = adcxx_probe, - .remove = __devexit_p(adcxx_remove), + .remove = adcxx_remove, }; module_spi_driver(adcxx_driver); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index fd1d1b15854e..71bcba8abfc0 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -193,7 +193,7 @@ static ssize_t set_temp_max(struct device *dev, temp /= 1000; mutex_lock(&data->update_lock); - data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127); + data->temp_max[index] = clamp_val(temp, -128, 127); if (!read_only) i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index), data->temp_max[index]); @@ -218,7 +218,7 @@ static ssize_t set_temp_min(struct device *dev, temp /= 1000; mutex_lock(&data->update_lock); - data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127); + data->temp_min[index] = clamp_val(temp, -128, 127); if (!read_only) i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index), data->temp_min[index]); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 0f068e7297ee..ea09046e651d 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -197,7 +197,7 @@ static int adm1026_scaling[] = { /* .001 Volts */ }; #define NEG12_OFFSET 16000 #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n, val) (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\ +#define INS_TO_REG(n, val) (clamp_val(SCALE(val, adm1026_scaling[n], 192),\ 0, 255)) #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n])) @@ -207,7 +207,7 @@ static int adm1026_scaling[] = { /* .001 Volts */ * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 */ #define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \ - SENSORS_LIMIT(1350000 / ((val) * (div)), \ + clamp_val(1350000 / ((val) * (div)), \ 1, 254)) #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \ 1350000 / ((val) * (div))) @@ -215,14 +215,14 @@ static int adm1026_scaling[] = { /* .001 Volts */ #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) /* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \ +#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \ / 1000, -127, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \ +#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \ / 1000, -127, 127)) #define OFFSET_FROM_REG(val) ((val) * 1000) -#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255)) +#define PWM_TO_REG(val) (clamp_val(val, 0, 255)) #define PWM_FROM_REG(val) (val) #define PWM_MIN_TO_REG(val) ((val) & 0xf0) @@ -233,7 +233,7 @@ static int adm1026_scaling[] = { /* .001 Volts */ * indicates that the DAC could be used to drive the fans, but in our * example board (Arima HDAMA) it isn't connected to the fans at all. */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255)) +#define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255)) #define DAC_FROM_REG(val) (((val) * 2500) / 255) /* @@ -933,7 +933,7 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div) return; new_min = data->fan_min[fan] * old_div / new_div; - new_min = SENSORS_LIMIT(new_min, 1, 254); + new_min = clamp_val(new_min, 1, 254); data->fan_min[fan] = new_min; adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); } @@ -1527,7 +1527,7 @@ static ssize_t set_auto_pwm_min(struct device *dev, return err; mutex_lock(&data->update_lock); - data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255); + data->pwm1.auto_pwm_min = clamp_val(val, 0, 255); if (data->pwm1.enable == 2) { /* apply immediately */ data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index c6a4631e833f..253ea396106d 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -162,13 +162,13 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) static int FAN_TO_REG(int reg, int div) { int tmp; - tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); + tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div); return tmp > 255 ? 255 : tmp; } #define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) +#define PWM_TO_REG(val) (clamp_val((val), 0, 255) >> 4) #define PWM_FROM_REG(val) ((val) << 4) #define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) @@ -675,7 +675,7 @@ static ssize_t set_temp_offset(struct device *dev, if (ret) return ret; - val = SENSORS_LIMIT(val, -15000, 15000); + val = clamp_val(val, -15000, 15000); mutex_lock(&data->update_lock); data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr), @@ -696,7 +696,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), @@ -717,7 +717,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), @@ -738,7 +738,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_crit[nr] = TEMP_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index dafa477715e3..2416628e0ab1 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -98,13 +98,13 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n) static inline u8 IN_TO_REG(unsigned long val, int n) { - return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); + return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255); } /* temperature range: -40..125, 127 disables temperature alarm */ static inline s8 TEMP_TO_REG(long val) { - return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); + return clamp_val(SCALE(val, 1, 1000), -40, 127); } /* two fans, each with low fan speed limit */ @@ -122,7 +122,7 @@ static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) /* analog out 0..1250mV */ static inline u8 AOUT_TO_REG(unsigned long val) { - return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); + return clamp_val(SCALE(val, 255, 1250), 0, 255); } static inline unsigned int AOUT_FROM_REG(u8 reg) diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 1f9e8af0f322..ba962ac4b81f 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -1,12 +1,14 @@ /* - * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC + * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles * (C) 2007 EADS Astrium * * This driver is based on the lm75 and other lm_sensors/hwmon drivers * * Written by Steve Hardy <shardy@redhat.com> * - * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf + * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * + * For further information, see the Documentation/hwmon/ads7828 file. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,63 +25,48 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/jiffies.h> -#include <linux/i2c.h> +#include <linux/err.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/module.h> #include <linux/mutex.h> +#include <linux/platform_data/ads7828.h> +#include <linux/slab.h> /* The ADS7828 registers */ -#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */ -#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ -#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */ -#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */ -#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */ -#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */ -#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */ -#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ - -/* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - I2C_CLIENT_END }; - -/* Module parameters */ -static bool se_input = 1; /* Default is SE, 0 == diff */ -static bool int_vref = 1; /* Default is internal ref ON */ -static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ -module_param(se_input, bool, S_IRUGO); -module_param(int_vref, bool, S_IRUGO); -module_param(vref_mv, int, S_IRUGO); - -/* Global Variables */ -static u8 ads7828_cmd_byte; /* cmd byte without channel bits */ -static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */ - -/* Each client has this additional data */ +#define ADS7828_NCH 8 /* 8 channels supported */ +#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ +#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */ +#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */ +#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ +#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */ +#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */ + +/* List of supported devices */ +enum ads7828_chips { ads7828, ads7830 }; + +/* Client specific data */ struct ads7828_data { struct device *hwmon_dev; - struct mutex update_lock; /* mutex protect updates */ - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */ + struct mutex update_lock; /* Mutex protecting updates */ + unsigned long last_updated; /* Last updated time (in jiffies) */ + u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */ + bool valid; /* Validity flag */ + bool diff_input; /* Differential input */ + bool ext_vref; /* External voltage reference */ + unsigned int vref_mv; /* voltage reference value */ + u8 cmd_byte; /* Command byte without channel bits */ + unsigned int lsb_resol; /* Resolution of the ADC sample LSB */ + s32 (*read_channel)(const struct i2c_client *client, u8 command); }; -/* Function declaration - necessary due to function dependencies */ -static int ads7828_detect(struct i2c_client *client, - struct i2c_board_info *info); -static int ads7828_probe(struct i2c_client *client, - const struct i2c_device_id *id); - -static inline u8 channel_cmd_byte(int ch) +/* Command byte C2,C1,C0 - see datasheet */ +static inline u8 ads7828_cmd_byte(u8 cmd, int ch) { - /* cmd byte C2,C1,C0 - see datasheet */ - u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4); - cmd |= ads7828_cmd_byte; - return cmd; + return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4); } /* Update data for the device (all 8 channels) */ @@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev) dev_dbg(&client->dev, "Starting ads7828 update\n"); for (ch = 0; ch < ADS7828_NCH; ch++) { - u8 cmd = channel_cmd_byte(ch); - data->adc_input[ch] = - i2c_smbus_read_word_swapped(client, cmd); + u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch); + data->adc_input[ch] = data->read_channel(client, cmd); } data->last_updated = jiffies; - data->valid = 1; + data->valid = true; } mutex_unlock(&data->update_lock); @@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev) } /* sysfs callback function */ -static ssize_t show_in(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da, + char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct ads7828_data *data = ads7828_update_device(dev); - /* Print value (in mV as specified in sysfs-interface documentation) */ - return sprintf(buf, "%d\n", (data->adc_input[attr->index] * - ads7828_lsb_resol)/1000); -} + unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] * + data->lsb_resol, 1000); -#define in_reg(offset)\ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ - NULL, offset) + return sprintf(buf, "%d\n", value); +} -in_reg(0); -in_reg(1); -in_reg(2); -in_reg(3); -in_reg(4); -in_reg(5); -in_reg(6); -in_reg(7); +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7); static struct attribute *ads7828_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, @@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = { static int ads7828_remove(struct i2c_client *client) { struct ads7828_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ads7828_group); - return 0; -} - -static const struct i2c_device_id ads7828_id[] = { - { "ads7828", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ads7828_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver ads7828_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "ads7828", - }, - .probe = ads7828_probe, - .remove = ads7828_remove, - .id_table = ads7828_id, - .detect = ads7828_detect, - .address_list = normal_i2c, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int ads7828_detect(struct i2c_client *client, - struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - int ch; - - /* Check we have a valid client */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -ENODEV; - - /* - * Now, we do the remaining detection. There is no identification - * dedicated register so attempt to sanity check using knowledge of - * the chip - * - Read from the 8 channel addresses - * - Check the top 4 bits of each result are not set (12 data bits) - */ - for (ch = 0; ch < ADS7828_NCH; ch++) { - u16 in_data; - u8 cmd = channel_cmd_byte(ch); - in_data = i2c_smbus_read_word_swapped(client, cmd); - if (in_data & 0xF000) { - pr_debug("%s : Doesn't look like an ads7828 device\n", - __func__); - return -ENODEV; - } - } - - strlcpy(info->type, "ads7828", I2C_NAME_SIZE); return 0; } @@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client, static int ads7828_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct ads7828_platform_data *pdata = client->dev.platform_data; struct ads7828_data *data; int err; @@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client, if (!data) return -ENOMEM; + if (pdata) { + data->diff_input = pdata->diff_input; + data->ext_vref = pdata->ext_vref; + if (data->ext_vref) + data->vref_mv = pdata->vref_mv; + } + + /* Bound Vref with min/max values if it was provided */ + if (data->vref_mv) + data->vref_mv = clamp_val(data->vref_mv, + ADS7828_EXT_VREF_MV_MIN, + ADS7828_EXT_VREF_MV_MAX); + else + data->vref_mv = ADS7828_INT_VREF_MV; + + /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */ + if (id->driver_data == ads7828) { + data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096); + data->read_channel = i2c_smbus_read_word_swapped; + } else { + data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256); + data->read_channel = i2c_smbus_read_byte_data; + } + + data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3; + if (!data->diff_input) + data->cmd_byte |= ADS7828_CMD_SD_SE; + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &ads7828_group); if (err) return err; @@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client, data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); - goto exit_remove; + goto error; } return 0; -exit_remove: +error: sysfs_remove_group(&client->dev.kobj, &ads7828_group); return err; } -static int __init sensors_ads7828_init(void) -{ - /* Initialize the command byte according to module parameters */ - ads7828_cmd_byte = se_input ? - ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF; - ads7828_cmd_byte |= int_vref ? - ADS7828_CMD_PD3 : ADS7828_CMD_PD1; +static const struct i2c_device_id ads7828_device_ids[] = { + { "ads7828", ads7828 }, + { "ads7830", ads7830 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads7828_device_ids); - /* Calculate the LSB resolution */ - ads7828_lsb_resol = (vref_mv*1000)/4096; +static struct i2c_driver ads7828_driver = { + .driver = { + .name = "ads7828", + }, - return i2c_add_driver(&ads7828_driver); -} + .id_table = ads7828_device_ids, + .probe = ads7828_probe, + .remove = ads7828_remove, +}; -static void __exit sensors_ads7828_exit(void) -{ - i2c_del_driver(&ads7828_driver); -} +module_i2c_driver(ads7828_driver); -MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); -MODULE_DESCRIPTION("ADS7828 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_ads7828_init); -module_exit(sensors_ads7828_exit); +MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); +MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles"); diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index 1b53aa42b6db..a79875986f91 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -173,7 +173,7 @@ static const struct attribute_group ads7871_group = { .attrs = ads7871_attributes, }; -static int __devinit ads7871_probe(struct spi_device *spi) +static int ads7871_probe(struct spi_device *spi) { int ret, err; uint8_t val; @@ -225,7 +225,7 @@ error_remove: return err; } -static int __devexit ads7871_remove(struct spi_device *spi) +static int ads7871_remove(struct spi_device *spi) { struct ads7871_data *pdata = spi_get_drvdata(spi); @@ -241,7 +241,7 @@ static struct spi_driver ads7871_driver = { }, .probe = ads7871_probe, - .remove = __devexit_p(ads7871_remove), + .remove = ads7871_remove, }; module_spi_driver(ads7871_driver); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 030c8d7c33a5..99a7290da0a3 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -78,10 +78,6 @@ enum adt7410_type { /* keep sorted in alphabetical order */ adt7410, }; -/* Addresses scanned */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - I2C_CLIENT_END }; - static const u8 ADT7410_REG_TEMP[4] = { ADT7410_TEMPERATURE, /* input */ ADT7410_T_ALARM_HIGH, /* high */ @@ -173,8 +169,8 @@ abort: static s16 ADT7410_TEMP_TO_REG(long temp) { - return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN, - ADT7410_TEMP_MAX) * 128, 1000); + return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN, + ADT7410_TEMP_MAX) * 128, 1000); } static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg) @@ -269,9 +265,9 @@ static ssize_t adt7410_set_t_hyst(struct device *dev, return ret; /* convert absolute hysteresis value to a 4 bit delta value */ limit = ADT7410_REG_TO_TEMP(data, data->temp[1]); - hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX); - data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000), - 0, ADT7410_T_HYST_MASK); + hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX); + data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, + ADT7410_T_HYST_MASK); ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst); if (ret) return ret; @@ -364,6 +360,7 @@ static int adt7410_probe(struct i2c_client *client, /* * Set to 16 bit resolution, continous conversion and comparator mode. */ + ret &= ~ADT7410_MODE_MASK; data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE; if (data->config != data->oldconfig) { @@ -410,11 +407,12 @@ static int adt7410_remove(struct i2c_client *client) static const struct i2c_device_id adt7410_ids[] = { { "adt7410", adt7410, }, + { "adt7420", adt7410, }, { /* LIST END */ } }; MODULE_DEVICE_TABLE(i2c, adt7410_ids); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int adt7410_suspend(struct device *dev) { int ret; @@ -436,10 +434,8 @@ static int adt7410_resume(struct device *dev) return ret; } -static const struct dev_pm_ops adt7410_dev_pm_ops = { - .suspend = adt7410_suspend, - .resume = adt7410_resume, -}; +static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume); + #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops) #else #define ADT7410_DEV_PM_OPS NULL @@ -454,11 +450,11 @@ static struct i2c_driver adt7410_driver = { .probe = adt7410_probe, .remove = adt7410_remove, .id_table = adt7410_ids, - .address_list = normal_i2c, + .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b), }; module_i2c_driver(adt7410_driver); MODULE_AUTHOR("Hartmut Knaack"); -MODULE_DESCRIPTION("ADT7410 driver"); +MODULE_DESCRIPTION("ADT7410/ADT7420 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 517f1856c706..34ff03abb50b 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -276,7 +276,7 @@ static int adt7411_detect(struct i2c_client *client, return 0; } -static int __devinit adt7411_probe(struct i2c_client *client, +static int adt7411_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adt7411_data *data; @@ -317,7 +317,7 @@ static int __devinit adt7411_probe(struct i2c_client *client, return ret; } -static int __devexit adt7411_remove(struct i2c_client *client) +static int adt7411_remove(struct i2c_client *client) { struct adt7411_data *data = i2c_get_clientdata(client); @@ -337,7 +337,7 @@ static struct i2c_driver adt7411_driver = { .name = "adt7411", }, .probe = adt7411_probe, - .remove = __devexit_p(adt7411_remove), + .remove = adt7411_remove, .id_table = adt7411_id, .detect = adt7411_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 98a7d81e25c5..69481d3a3d23 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -836,7 +836,7 @@ static ssize_t set_temp_min(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->temp_min[attr->index] = temp; @@ -874,7 +874,7 @@ static ssize_t set_temp_max(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->temp_max[attr->index] = temp; @@ -939,7 +939,7 @@ static ssize_t set_volt_max(struct device *dev, temp *= 1000; /* convert mV to uV */ temp = DIV_ROUND_CLOSEST(temp, x); - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->volt_max[attr->index] = temp; @@ -981,7 +981,7 @@ static ssize_t set_volt_min(struct device *dev, temp *= 1000; /* convert mV to uV */ temp = DIV_ROUND_CLOSEST(temp, x); - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->volt_min[attr->index] = temp; @@ -1071,7 +1071,7 @@ static ssize_t set_fan_min(struct device *dev, temp = FAN_RPM_TO_PERIOD(temp); temp >>= 8; - temp = SENSORS_LIMIT(temp, 1, 255); + temp = clamp_val(temp, 1, 255); mutex_lock(&data->lock); data->fan_min[attr->index] = temp; @@ -1149,7 +1149,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm[attr->index] = temp; @@ -1179,7 +1179,7 @@ static ssize_t set_pwm_max(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_max = temp; @@ -1211,7 +1211,7 @@ static ssize_t set_pwm_min(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_min[attr->index] = temp; @@ -1246,7 +1246,7 @@ static ssize_t set_pwm_hyst(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = SENSORS_LIMIT(temp, 0, 15); + temp = clamp_val(temp, 0, 15); /* package things up */ temp &= ADT7462_PWM_HYST_MASK; @@ -1333,7 +1333,7 @@ static ssize_t set_pwm_tmin(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_tmin[attr->index] = temp; diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 39ecb1a3b9ef..b83bf4bb95eb 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -452,7 +452,7 @@ static ssize_t set_auto_update_interval(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 60000); + temp = clamp_val(temp, 0, 60000); mutex_lock(&data->lock); data->auto_update_interval = temp; @@ -481,7 +481,7 @@ static ssize_t set_num_temp_sensors(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, -1, 10); + temp = clamp_val(temp, -1, 10); mutex_lock(&data->lock); data->num_temp_sensors = temp; @@ -515,7 +515,7 @@ static ssize_t set_temp_min(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->temp_min[attr->index] = temp; @@ -549,7 +549,7 @@ static ssize_t set_temp_max(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->temp_max[attr->index] = temp; @@ -604,7 +604,7 @@ static ssize_t set_fan_max(struct device *dev, return -EINVAL; temp = FAN_RPM_TO_PERIOD(temp); - temp = SENSORS_LIMIT(temp, 1, 65534); + temp = clamp_val(temp, 1, 65534); mutex_lock(&data->lock); data->fan_max[attr->index] = temp; @@ -641,7 +641,7 @@ static ssize_t set_fan_min(struct device *dev, return -EINVAL; temp = FAN_RPM_TO_PERIOD(temp); - temp = SENSORS_LIMIT(temp, 1, 65534); + temp = clamp_val(temp, 1, 65534); mutex_lock(&data->lock); data->fan_min[attr->index] = temp; @@ -717,7 +717,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm[attr->index] = temp; @@ -749,7 +749,7 @@ static ssize_t set_pwm_max(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_max[attr->index] = temp; @@ -782,7 +782,7 @@ static ssize_t set_pwm_min(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_min[attr->index] = temp; @@ -826,7 +826,7 @@ static ssize_t set_pwm_tmin(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = SENSORS_LIMIT(temp, 0, 255); + temp = clamp_val(temp, 0, 255); mutex_lock(&data->lock); data->pwm_tmin[attr->index] = temp; diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 989e54c39252..22d008bbdc10 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -201,10 +201,10 @@ static inline u16 temp2reg(struct adt7475_data *data, long val) u16 ret; if (!(data->config5 & CONFIG5_TWOSCOMP)) { - val = SENSORS_LIMIT(val, -64000, 191000); + val = clamp_val(val, -64000, 191000); ret = (val + 64500) / 1000; } else { - val = SENSORS_LIMIT(val, -128000, 127000); + val = clamp_val(val, -128000, 127000); if (val < -500) ret = (256500 + val) / 1000; else @@ -240,7 +240,7 @@ static inline u16 rpm2tach(unsigned long rpm) if (rpm == 0) return 0; - return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF); + return clamp_val((90000 * 60) / rpm, 1, 0xFFFF); } /* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */ @@ -271,7 +271,7 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) reg = (volt * 1024) / 2250; else reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250); - return SENSORS_LIMIT(reg, 0, 1023) & (0xff << 2); + return clamp_val(reg, 0, 1023) & (0xff << 2); } static u16 adt7475_read_word(struct i2c_client *client, int reg) @@ -451,10 +451,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, switch (sattr->nr) { case OFFSET: if (data->config5 & CONFIG5_TEMPOFFSET) { - val = SENSORS_LIMIT(val, -63000, 127000); + val = clamp_val(val, -63000, 127000); out = data->temp[OFFSET][sattr->index] = val / 1000; } else { - val = SENSORS_LIMIT(val, -63000, 64000); + val = clamp_val(val, -63000, 64000); out = data->temp[OFFSET][sattr->index] = val / 500; } break; @@ -471,7 +471,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, adt7475_read_hystersis(client); temp = reg2temp(data, data->temp[THERM][sattr->index]); - val = SENSORS_LIMIT(val, temp - 15000, temp); + val = clamp_val(val, temp - 15000, temp); val = (temp - val) / 1000; if (sattr->index != 1) { @@ -577,7 +577,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr, * to figure the range */ temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]); - val = SENSORS_LIMIT(val, temp + autorange_table[0], + val = clamp_val(val, temp + autorange_table[0], temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]); val -= temp; @@ -701,7 +701,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, break; } - data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF); + data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF); i2c_smbus_write_byte_data(client, reg, data->pwm[sattr->nr][sattr->index]); diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index ae482e3afdac..4fe49d2bfe1d 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -241,7 +241,7 @@ static ssize_t set_temp( int ret = kstrtol(buf, 10, &val); if (ret) return ret; - val = SENSORS_LIMIT(val / 1000, -128, 127); + val = clamp_val(val / 1000, -128, 127); mutex_lock(&data->update_lock); data->temp[ix] = val; @@ -332,7 +332,7 @@ static ssize_t set_pwm1( return ret; mutex_lock(&data->update_lock); - data->pwm1 = SENSORS_LIMIT(val , 0, 255); + data->pwm1 = clamp_val(val , 0, 255); i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1); mutex_unlock(&data->update_lock); return count; @@ -499,11 +499,11 @@ static ssize_t set_temp_auto_point_temp( mutex_lock(&data->update_lock); switch (ix) { case 0: - ptemp[0] = SENSORS_LIMIT(val / 1000, 0, - data->temp1_auto_point_temp[1]); - ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, - data->temp2_auto_point_temp[1]); - ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63); + ptemp[0] = clamp_val(val / 1000, 0, + data->temp1_auto_point_temp[1]); + ptemp[0] = clamp_val(ptemp[0], 0, + data->temp2_auto_point_temp[1]); + ptemp[0] = clamp_val(ptemp[0], 0, 63); if (i2c_smbus_write_byte_data( client, AMC6821_REG_PSV_TEMP, @@ -515,20 +515,12 @@ static ssize_t set_temp_auto_point_temp( goto EXIT; break; case 1: - ptemp[1] = SENSORS_LIMIT( - val / 1000, - (ptemp[0] & 0x7C) + 4, - 124); + ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124); ptemp[1] &= 0x7C; - ptemp[2] = SENSORS_LIMIT( - ptemp[2], ptemp[1] + 1, - 255); + ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255); break; case 2: - ptemp[2] = SENSORS_LIMIT( - val / 1000, - ptemp[1]+1, - 255); + ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255); break; default: dev_dbg(dev, "Unknown attr->index (%d).\n", ix); @@ -561,7 +553,7 @@ static ssize_t set_pwm1_auto_point_pwm( return ret; mutex_lock(&data->update_lock); - data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254); + data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254); if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP, data->pwm1_auto_point_pwm[1])) { dev_err(&client->dev, "Register write error, aborting.\n"); @@ -629,7 +621,7 @@ static ssize_t set_fan( val = 1 > val ? 0xFFFF : 6000000/val; mutex_lock(&data->update_lock); - data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF); + data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF); if (i2c_smbus_write_byte_data(client, fan_reg_low[ix], data->fan[ix] & 0xFF)) { dev_err(&client->dev, "Register write error, aborting.\n"); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index a227be47149f..6ac612cabda1 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -32,7 +32,7 @@ * ASB100-A supports pwm1, while plain ASB100 does not. There is no known * way for the driver to tell which one is there. * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * asb100 7 3 1 4 0x31 0x0694 yes no */ @@ -114,7 +114,7 @@ static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; */ static u8 IN_TO_REG(unsigned val) { - unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); + unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX); return (nval + 8) / 16; } @@ -129,8 +129,8 @@ static u8 FAN_TO_REG(long rpm, int div) return 0; if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static int FAN_FROM_REG(u8 val, int div) @@ -148,7 +148,7 @@ static int FAN_FROM_REG(u8 val, int div) */ static u8 TEMP_TO_REG(long temp) { - int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); + int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); ntemp += (ntemp < 0 ? -500 : 500); return (u8)(ntemp / 1000); } @@ -164,7 +164,7 @@ static int TEMP_FROM_REG(u8 reg) */ static u8 ASB100_PWM_TO_REG(int pwm) { - pwm = SENSORS_LIMIT(pwm, 0, 255); + pwm = clamp_val(pwm, 0, 255); return (u8)(pwm / 16); } diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index b867aab78049..da7f5b5d5db5 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -191,7 +191,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - reqval = SENSORS_LIMIT(reqval, 0, 255); + reqval = clamp_val(reqval, 0, 255); mutex_lock(&data->update_lock); data->reg[param->msb[0]] = reqval; @@ -224,7 +224,7 @@ static ssize_t store_bitmask(struct device *dev, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - reqval = SENSORS_LIMIT(reqval, 0, param->mask[0]); + reqval = clamp_val(reqval, 0, param->mask[0]); reqval = (reqval & param->mask[0]) << param->shift[0]; @@ -274,7 +274,7 @@ static ssize_t store_fan16(struct device *dev, * generating an alarm. */ reqval = - (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe)); + (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe)); mutex_lock(&data->update_lock); data->reg[param->msb[0]] = (reqval >> 8) & 0xff; @@ -343,11 +343,11 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - reqval = SENSORS_LIMIT(reqval, 0, 0xffff); + reqval = clamp_val(reqval, 0, 0xffff); reqval = reqval * 0xc0 / asc7621_in_scaling[nr]; - reqval = SENSORS_LIMIT(reqval, 0, 0xff); + reqval = clamp_val(reqval, 0, 0xff); mutex_lock(&data->update_lock); data->reg[param->msb[0]] = reqval; @@ -376,7 +376,7 @@ static ssize_t store_temp8(struct device *dev, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - reqval = SENSORS_LIMIT(reqval, -127000, 127000); + reqval = clamp_val(reqval, -127000, 127000); temp = reqval / 1000; @@ -432,7 +432,7 @@ static ssize_t store_temp62(struct device *dev, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - reqval = SENSORS_LIMIT(reqval, -32000, 31750); + reqval = clamp_val(reqval, -32000, 31750); i = reqval / 1000; f = reqval - (i * 1000); temp = i << 2; @@ -468,7 +468,7 @@ static ssize_t show_ap2_temp(struct device *dev, auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000; regval = ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]); - temp = auto_point1 + asc7621_range_map[SENSORS_LIMIT(regval, 0, 15)]; + temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)]; mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", temp); @@ -489,7 +489,7 @@ static ssize_t store_ap2_temp(struct device *dev, mutex_lock(&data->update_lock); auto_point1 = data->reg[param->msb[1]] * 1000; - reqval = SENSORS_LIMIT(reqval, auto_point1 + 2000, auto_point1 + 80000); + reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000); for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) { if (reqval >= auto_point1 + asc7621_range_map[i]) { @@ -523,7 +523,7 @@ static ssize_t show_pwm_ac(struct device *dev, regval = config | (altbit << 3); mutex_unlock(&data->update_lock); - return sprintf(buf, "%u\n", map[SENSORS_LIMIT(regval, 0, 15)]); + return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]); } static ssize_t store_pwm_ac(struct device *dev, @@ -663,7 +663,7 @@ static ssize_t show_pwm_freq(struct device *dev, u8 regval = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; - regval = SENSORS_LIMIT(regval, 0, 15); + regval = clamp_val(regval, 0, 15); return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]); } @@ -711,7 +711,7 @@ static ssize_t show_pwm_ast(struct device *dev, u8 regval = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; - regval = SENSORS_LIMIT(regval, 0, 7); + regval = clamp_val(regval, 0, 7); return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]); @@ -759,7 +759,7 @@ static ssize_t show_temp_st(struct device *dev, SETUP_SHOW_data_param(dev, attr); u8 regval = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; - regval = SENSORS_LIMIT(regval, 0, 7); + regval = clamp_val(regval, 0, 7); return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]); } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 56dbcfb3e301..b25c64302cbc 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -190,7 +190,7 @@ struct atk_acpi_input_buf { }; static int atk_add(struct acpi_device *device); -static int atk_remove(struct acpi_device *device, int type); +static int atk_remove(struct acpi_device *device); static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); static void atk_free_sensors(struct atk_data *data); @@ -1416,7 +1416,7 @@ out: return err; } -static int atk_remove(struct acpi_device *device, int type) +static int atk_remove(struct acpi_device *device) { struct atk_data *data = device->driver_data; dev_dbg(&device->dev, "removing...\n"); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 47b8d84b489d..3f1e297663ad 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -34,7 +34,6 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/cpu.h> -#include <linux/pci.h> #include <linux/smp.h> #include <linux/moduleparam.h> #include <asm/msr.h> @@ -197,21 +196,36 @@ struct tjmax { }; static const struct tjmax __cpuinitconst tjmax_table[] = { - { "CPU D410", 100000 }, - { "CPU D425", 100000 }, - { "CPU D510", 100000 }, - { "CPU D525", 100000 }, - { "CPU N450", 100000 }, - { "CPU N455", 100000 }, - { "CPU N470", 100000 }, - { "CPU N475", 100000 }, { "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */ { "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */ - { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */ + { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 Sodaville */ { "CPU CE4150", 110000 }, /* Model 0x1c, stepping 10 */ { "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */ }; +struct tjmax_model { + u8 model; + u8 mask; + int tjmax; +}; + +#define ANY 0xff + +static const struct tjmax_model __cpuinitconst tjmax_model_table[] = { + { 0x1c, 10, 100000 }, /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */ + { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others + * Note: Also matches 230 and 330, + * which are covered by tjmax_table + */ + { 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx) + * Note: TjMax for E6xxT is 110C, but CPU type + * is undetectable by software + */ + { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */ + { 0x35, ANY, 90000 }, /* Atom Clover Trail/Cloverview (Z2760) */ + { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */ +}; + static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) { @@ -222,7 +236,6 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, int usemsr_ee = 1; int err; u32 eax, edx; - struct pci_dev *host_bridge; int i; /* explicit tjmax table entries override heuristics */ @@ -231,32 +244,18 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, return tjmax_table[i].tjmax; } + for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) { + const struct tjmax_model *tm = &tjmax_model_table[i]; + if (c->x86_model == tm->model && + (tm->mask == ANY || c->x86_mask == tm->mask)) + return tm->tjmax; + } + /* Early chips have no MSR for TjMax */ if (c->x86_model == 0xf && c->x86_mask < 4) usemsr_ee = 0; - /* Atom CPUs */ - - if (c->x86_model == 0x1c || c->x86_model == 0x26 - || c->x86_model == 0x27) { - usemsr_ee = 0; - - host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); - - if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL - && (host_bridge->device == 0xa000 /* NM10 based nettop */ - || host_bridge->device == 0xa010)) /* NM10 based netbook */ - tjmax = 100000; - else - tjmax = 90000; - - pci_dev_put(host_bridge); - } else if (c->x86_model == 0x36) { - usemsr_ee = 0; - tjmax = 100000; - } - if (c->x86_model > 0xe && usemsr_ee) { u8 platform_id; @@ -358,7 +357,7 @@ static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id, return adjust_tjmax(c, id, dev); } -static int __devinit create_name_attr(struct platform_data *pdata, +static int create_name_attr(struct platform_data *pdata, struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); @@ -553,7 +552,7 @@ static void coretemp_remove_core(struct platform_data *pdata, pdata->core_data[indx] = NULL; } -static int __devinit coretemp_probe(struct platform_device *pdev) +static int coretemp_probe(struct platform_device *pdev) { struct platform_data *pdata; int err; @@ -586,7 +585,7 @@ exit_free: return err; } -static int __devexit coretemp_remove(struct platform_device *pdev) +static int coretemp_remove(struct platform_device *pdev) { struct platform_data *pdata = platform_get_drvdata(pdev); int i; @@ -608,7 +607,7 @@ static struct platform_driver coretemp_driver = { .name = DRVNAME, }, .probe = coretemp_probe, - .remove = __devexit_p(coretemp_remove), + .remove = coretemp_remove, }; static int __cpuinit coretemp_device_add(unsigned int cpu) diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index b8d01c5f5713..ab4452c5a98c 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -60,30 +60,17 @@ static inline int vbbat_reg_to_mV(int value) return DIV_ROUND_CLOSEST(value * 2500, 512); } -static int da9052_enable_vddout_channel(struct da9052 *da9052) +static inline int da9052_enable_vddout_channel(struct da9052 *da9052) { - int ret; - - ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG); - if (ret < 0) - return ret; - - ret |= DA9052_ADCCONT_AUTOVDDEN; - - return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret); + return da9052_reg_update(da9052, DA9052_ADC_CONT_REG, + DA9052_ADCCONT_AUTOVDDEN, + DA9052_ADCCONT_AUTOVDDEN); } -static int da9052_disable_vddout_channel(struct da9052 *da9052) +static inline int da9052_disable_vddout_channel(struct da9052 *da9052) { - int ret; - - ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG); - if (ret < 0) - return ret; - - ret &= ~DA9052_ADCCONT_AUTOVDDEN; - - return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret); + return da9052_reg_update(da9052, DA9052_ADC_CONT_REG, + DA9052_ADCCONT_AUTOVDDEN, 0); } static ssize_t da9052_read_vddout(struct device *dev, @@ -283,7 +270,7 @@ static struct attribute *da9052_attr[] = { static const struct attribute_group da9052_attr_group = {.attrs = da9052_attr}; -static int __devinit da9052_hwmon_probe(struct platform_device *pdev) +static int da9052_hwmon_probe(struct platform_device *pdev) { struct da9052_hwmon *hwmon; int ret; @@ -316,7 +303,7 @@ err_mem: return ret; } -static int __devexit da9052_hwmon_remove(struct platform_device *pdev) +static int da9052_hwmon_remove(struct platform_device *pdev) { struct da9052_hwmon *hwmon = platform_get_drvdata(pdev); @@ -328,7 +315,7 @@ static int __devexit da9052_hwmon_remove(struct platform_device *pdev) static struct platform_driver da9052_hwmon_driver = { .probe = da9052_hwmon_probe, - .remove = __devexit_p(da9052_hwmon_remove), + .remove = da9052_hwmon_remove, .driver = { .name = "da9052-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c new file mode 100644 index 000000000000..9465c050c326 --- /dev/null +++ b/drivers/hwmon/da9055-hwmon.c @@ -0,0 +1,336 @@ +/* + * HWMON Driver for Dialog DA9055 + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/completion.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> + +#define DA9055_ADCIN_DIV 102 +#define DA9055_VSYS_DIV 85 + +#define DA9055_ADC_VSYS 0 +#define DA9055_ADC_ADCIN1 1 +#define DA9055_ADC_ADCIN2 2 +#define DA9055_ADC_ADCIN3 3 +#define DA9055_ADC_TJUNC 4 + +struct da9055_hwmon { + struct da9055 *da9055; + struct device *class_device; + struct mutex hwmon_lock; + struct mutex irq_lock; + struct completion done; +}; + +static const char * const input_names[] = { + [DA9055_ADC_VSYS] = "VSYS", + [DA9055_ADC_ADCIN1] = "ADC IN1", + [DA9055_ADC_ADCIN2] = "ADC IN2", + [DA9055_ADC_ADCIN3] = "ADC IN3", + [DA9055_ADC_TJUNC] = "CHIP TEMP", +}; + +static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = { + [DA9055_ADC_VSYS] = DA9055_ADC_MUX_VSYS, + [DA9055_ADC_ADCIN1] = DA9055_ADC_MUX_ADCIN1, + [DA9055_ADC_ADCIN2] = DA9055_ADC_MUX_ADCIN2, + [DA9055_ADC_ADCIN3] = DA9055_ADC_MUX_ADCIN3, + [DA9055_ADC_TJUNC] = DA9055_ADC_MUX_T_SENSE, +}; + +static int da9055_adc_manual_read(struct da9055_hwmon *hwmon, + unsigned char channel) +{ + int ret; + unsigned short calc_data; + unsigned short data; + unsigned char mux_sel; + struct da9055 *da9055 = hwmon->da9055; + + if (channel > DA9055_ADC_TJUNC) + return -EINVAL; + + mutex_lock(&hwmon->irq_lock); + + /* Selects desired MUX for manual conversion */ + mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV; + + ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel); + if (ret < 0) + goto err; + + /* Wait for an interrupt */ + if (!wait_for_completion_timeout(&hwmon->done, + msecs_to_jiffies(500))) { + dev_err(da9055->dev, + "timeout waiting for ADC conversion interrupt\n"); + ret = -ETIMEDOUT; + goto err; + } + + ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H); + if (ret < 0) + goto err; + + calc_data = (unsigned short)ret; + data = calc_data << 2; + + ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L); + if (ret < 0) + goto err; + + calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK); + data |= calc_data; + + ret = data; + +err: + mutex_unlock(&hwmon->irq_lock); + return ret; +} + +static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data) +{ + struct da9055_hwmon *hwmon = irq_data; + + complete(&hwmon->done); + + return IRQ_HANDLED; +} + +/* Conversion function for VSYS and ADCINx */ +static inline int volt_reg_to_mV(int value, int channel) +{ + if (channel == DA9055_ADC_VSYS) + return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500; + else + return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV); +} + +static int da9055_enable_auto_mode(struct da9055 *da9055, int channel) +{ + + return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, + 1 << channel); + +} + +static int da9055_disable_auto_mode(struct da9055 *da9055, int channel) +{ + + return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0); +} + +static ssize_t da9055_read_auto_ch(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct da9055_hwmon *hwmon = dev_get_drvdata(dev); + int ret, adc; + int channel = to_sensor_dev_attr(devattr)->index; + + mutex_lock(&hwmon->hwmon_lock); + + ret = da9055_enable_auto_mode(hwmon->da9055, channel); + if (ret < 0) + goto hwmon_err; + + usleep_range(10000, 10500); + + adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel); + if (adc < 0) { + ret = adc; + goto hwmon_err_release; + } + + ret = da9055_disable_auto_mode(hwmon->da9055, channel); + if (ret < 0) + goto hwmon_err; + + mutex_unlock(&hwmon->hwmon_lock); + + return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel)); + +hwmon_err_release: + da9055_disable_auto_mode(hwmon->da9055, channel); +hwmon_err: + mutex_unlock(&hwmon->hwmon_lock); + return ret; +} + +static ssize_t da9055_read_tjunc(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct da9055_hwmon *hwmon = dev_get_drvdata(dev); + int tjunc; + int toffset; + + tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC); + if (tjunc < 0) + return tjunc; + + toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET); + if (toffset < 0) + return toffset; + + /* + * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332 + * T_OFFSET is a trim value used to improve accuracy of the result + */ + return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset) + + 3076332, 10000)); +} + +static ssize_t da9055_hwmon_show_name(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "da9055-hwmon\n"); +} + +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%s\n", + input_names[to_sensor_dev_attr(devattr)->index]); +} + +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_VSYS); +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, + DA9055_ADC_VSYS); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN1); +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN2); +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN3); +static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN3); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL, + DA9055_ADC_TJUNC); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, + DA9055_ADC_TJUNC); + +static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL); + +static struct attribute *da9055_attr[] = { + &dev_attr_name.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_label.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_label.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + NULL +}; + +static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr}; + +static int da9055_hwmon_probe(struct platform_device *pdev) +{ + struct da9055_hwmon *hwmon; + int hwmon_irq, ret; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon), + GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + mutex_init(&hwmon->hwmon_lock); + mutex_init(&hwmon->irq_lock); + + init_completion(&hwmon->done); + hwmon->da9055 = dev_get_drvdata(pdev->dev.parent); + + platform_set_drvdata(pdev, hwmon); + + hwmon_irq = platform_get_irq_byname(pdev, "HWMON"); + if (hwmon_irq < 0) + return hwmon_irq; + + hwmon_irq = regmap_irq_get_virq(hwmon->da9055->irq_data, hwmon_irq); + if (hwmon_irq < 0) + return hwmon_irq; + + ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq, + NULL, da9055_auxadc_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "adc-irq", hwmon); + if (ret != 0) { + dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n", + ret); + return ret; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group); + if (ret) + return ret; + + hwmon->class_device = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon->class_device)) { + ret = PTR_ERR(hwmon->class_device); + goto err; + } + + return 0; + +err: + sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group); + return ret; +} + +static int da9055_hwmon_remove(struct platform_device *pdev) +{ + struct da9055_hwmon *hwmon = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group); + hwmon_device_unregister(hwmon->class_device); + + return 0; +} + +static struct platform_driver da9055_hwmon_driver = { + .probe = da9055_hwmon_probe, + .remove = da9055_hwmon_remove, + .driver = { + .name = "da9055-hwmon", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9055_hwmon_driver); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("DA9055 HWMON driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-hwmon"); diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index fe0eeec0b750..c347c94f2f73 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -277,7 +277,7 @@ static inline int IN_FROM_REG(int reg, int nominal, int res) static inline int IN_TO_REG(int val, int nominal) { - return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255); + return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255); } /* @@ -293,8 +293,7 @@ static inline int TEMP_FROM_REG(int reg, int res) static inline int TEMP_TO_REG(int val) { - return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000, - -128, 127); + return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127); } /* Temperature range */ @@ -332,7 +331,7 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix) static inline int TEMP_HYST_TO_REG(int val, int ix, int reg) { - int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15); + int hyst = clamp_val((val + 500) / 1000, 0, 15); return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4); } @@ -349,10 +348,10 @@ static inline int FAN_FROM_REG(int reg, int tpc) static inline int FAN_TO_REG(int val, int tpc) { if (tpc) { - return SENSORS_LIMIT(val / tpc, 0, 0xffff); + return clamp_val(val / tpc, 0, 0xffff); } else { return (val <= 0) ? 0xffff : - SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe); + clamp_val(90000 * 60 / val, 0, 0xfffe); } } @@ -1282,7 +1281,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); switch (fn) { case SYS_PWM: - data->pwm[ix] = SENSORS_LIMIT(val, 0, 255); + data->pwm[ix] = clamp_val(val, 0, 255); dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]); break; case SYS_PWM_FREQ: @@ -1450,7 +1449,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, break; case SYS_PWM_AUTO_POINT1_PWM: /* Only valid for pwm[1-3] */ - data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255); + data->pwm_min[ix] = clamp_val(val, 0, 255); dme1737_write(data, DME1737_REG_PWM_MIN(ix), data->pwm_min[ix]); break; @@ -2630,7 +2629,7 @@ exit: return err; } -static int __devinit dme1737_isa_probe(struct platform_device *pdev) +static int dme1737_isa_probe(struct platform_device *pdev) { u8 company, device; struct resource *res; @@ -2718,7 +2717,7 @@ exit_remove_files: return err; } -static int __devexit dme1737_isa_remove(struct platform_device *pdev) +static int dme1737_isa_remove(struct platform_device *pdev) { struct dme1737_data *data = platform_get_drvdata(pdev); @@ -2734,7 +2733,7 @@ static struct platform_driver dme1737_isa_driver = { .name = "dme1737", }, .probe = dme1737_isa_probe, - .remove = __devexit_p(dme1737_isa_remove), + .remove = dme1737_isa_remove, }; /* --------------------------------------------------------------------- diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 77f434c58236..b07305622087 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -405,7 +405,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, if (rpm_target == 0) data->fan_target = 0x1fff; else - data->fan_target = SENSORS_LIMIT( + data->fan_target = clamp_val( (FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target, 0, 0x1fff); diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index a98c917b5888..936898f82f94 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -187,7 +187,7 @@ static struct emc6w201_data *emc6w201_update_device(struct device *dev) * Sysfs callback functions */ -static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 }; +static const s16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 }; static ssize_t show_in(struct device *dev, struct device_attribute *devattr, char *buf) @@ -220,7 +220,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr, : EMC6W201_REG_IN_HIGH(nr); mutex_lock(&data->update_lock); - data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255); + data->in[sf][nr] = clamp_val(val, 0, 255); err = emc6w201_write8(client, reg, data->in[sf][nr]); mutex_unlock(&data->update_lock); @@ -257,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, : EMC6W201_REG_TEMP_HIGH(nr); mutex_lock(&data->update_lock); - data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128); + data->temp[sf][nr] = clamp_val(val, -127, 128); err = emc6w201_write8(client, reg, data->temp[sf][nr]); mutex_unlock(&data->update_lock); @@ -298,7 +298,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *devattr, val = 0xFFFF; } else { val = DIV_ROUND_CLOSEST(5400000U, val); - val = SENSORS_LIMIT(val, 0, 0xFFFE); + val = clamp_val(val, 0, 0xFFFE); } mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 4dd7723d257f..a9816979c5de 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1343,7 +1343,7 @@ static struct attribute *f71805f_attr_pwm[] = { * Device registration and initialization */ -static void __devinit f71805f_init_device(struct f71805f_data *data) +static void f71805f_init_device(struct f71805f_data *data) { u8 reg; int i; @@ -1374,7 +1374,7 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) } } -static int __devinit f71805f_probe(struct platform_device *pdev) +static int f71805f_probe(struct platform_device *pdev) { struct f71805f_sio_data *sio_data = pdev->dev.platform_data; struct f71805f_data *data; @@ -1490,7 +1490,7 @@ exit_remove_files: return err; } -static int __devexit f71805f_remove(struct platform_device *pdev) +static int f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); int i; @@ -1510,7 +1510,7 @@ static struct platform_driver f71805f_driver = { .name = DRVNAME, }, .probe = f71805f_probe, - .remove = __devexit_p(f71805f_remove), + .remove = f71805f_remove, }; static int __init f71805f_device_add(unsigned short address, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 50e4ce2d22d8..cfb02dd91aad 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -364,7 +364,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf); -static int __devinit f71882fg_probe(struct platform_device *pdev); +static int f71882fg_probe(struct platform_device *pdev); static int f71882fg_remove(struct platform_device *pdev); static struct platform_driver f71882fg_driver = { @@ -1350,7 +1350,7 @@ static ssize_t store_fan_full_speed(struct device *dev, if (err) return err; - val = SENSORS_LIMIT(val, 23, 1500000); + val = clamp_val(val, 23, 1500000); val = fan_to_reg(val); mutex_lock(&data->update_lock); @@ -1438,7 +1438,7 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute return err; val /= 8; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); @@ -1542,7 +1542,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute return err; val /= 1000; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val); @@ -1589,8 +1589,7 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute /* convert abs to relative and check */ data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr)); - val = SENSORS_LIMIT(val, data->temp_high[nr] - 15, - data->temp_high[nr]); + val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]); val = data->temp_high[nr] - val; /* convert value to register contents */ @@ -1627,7 +1626,7 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute return err; val /= 1000; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val); @@ -1754,7 +1753,7 @@ static ssize_t store_pwm(struct device *dev, if (err) return err; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); @@ -1805,7 +1804,7 @@ static ssize_t store_simple_pwm(struct device *dev, if (err) return err; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); f71882fg_write8(data, F71882FG_REG_PWM(nr), val); @@ -1932,7 +1931,7 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev, if (err) return err; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); @@ -1991,8 +1990,8 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, mutex_lock(&data->update_lock); data->pwm_auto_point_temp[nr][point] = f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point)); - val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15, - data->pwm_auto_point_temp[nr][point]); + val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15, + data->pwm_auto_point_temp[nr][point]); val = data->pwm_auto_point_temp[nr][point] - val; reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2)); @@ -2126,9 +2125,9 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, val /= 1000; if (data->auto_point_temp_signed) - val = SENSORS_LIMIT(val, -128, 127); + val = clamp_val(val, -128, 127); else - val = SENSORS_LIMIT(val, 0, 127); + val = clamp_val(val, 0, 127); mutex_lock(&data->update_lock); f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val); @@ -2145,7 +2144,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%s\n", f71882fg_names[data->type]); } -static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev, +static int f71882fg_create_sysfs_files(struct platform_device *pdev, struct sensor_device_attribute_2 *attr, int count) { int err, i; @@ -2167,7 +2166,7 @@ static void f71882fg_remove_sysfs_files(struct platform_device *pdev, device_remove_file(&pdev->dev, &attr[i].dev_attr); } -static int __devinit f71882fg_create_fan_sysfs_files( +static int f71882fg_create_fan_sysfs_files( struct platform_device *pdev, int idx) { struct f71882fg_data *data = platform_get_drvdata(pdev); @@ -2265,7 +2264,7 @@ static int __devinit f71882fg_create_fan_sysfs_files( return err; } -static int __devinit f71882fg_probe(struct platform_device *pdev) +static int f71882fg_probe(struct platform_device *pdev) { struct f71882fg_data *data; struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index f7dba229395f..9e300e567f15 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -359,7 +359,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + data->pwm[nr] = clamp_val(val, 0, 255); f75375_write_pwm(client, nr); mutex_unlock(&data->update_lock); return count; @@ -556,7 +556,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + val = clamp_val(VOLT_TO_REG(val), 0, 0xff); mutex_lock(&data->update_lock); data->in_max[nr] = val; f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]); @@ -577,7 +577,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + val = clamp_val(VOLT_TO_REG(val), 0, 0xff); mutex_lock(&data->update_lock); data->in_min[nr] = val; f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]); @@ -625,7 +625,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + val = clamp_val(TEMP_TO_REG(val), 0, 127); mutex_lock(&data->update_lock); data->temp_high[nr] = val; f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]); @@ -646,7 +646,7 @@ static ssize_t set_temp_max_hyst(struct device *dev, if (err < 0) return err; - val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + val = clamp_val(TEMP_TO_REG(val), 0, 127); mutex_lock(&data->update_lock); data->temp_max_hyst[nr] = val; f75375_write8(client, F75375_REG_TEMP_HYST(nr), @@ -822,7 +822,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) || !duty_mode_enabled(f75375s_pdata->pwm_enable[nr])) continue; - data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255); + data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255); f75375_write_pwm(client, nr); } diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 4f4110407387..b757088aeddb 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>"); MODULE_LICENSE("GPL"); +/* Family 16h Northbridge's function 4 PCI ID */ +#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 + /* D18F3 */ #define REG_NORTHBRIDGE_CAP 0xe8 @@ -111,7 +114,7 @@ static const struct attribute_group fam15h_power_attr_group = { .attrs = fam15h_power_attrs, }; -static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) +static bool fam15h_power_is_internal_node0(struct pci_dev *f4) { u32 val; @@ -168,7 +171,7 @@ static int fam15h_power_resume(struct pci_dev *pdev) #define fam15h_power_resume NULL #endif -static void __devinit fam15h_power_init_data(struct pci_dev *f4, +static void fam15h_power_init_data(struct pci_dev *f4, struct fam15h_power_data *data) { u32 val; @@ -194,7 +197,7 @@ static void __devinit fam15h_power_init_data(struct pci_dev *f4, data->processor_pwr_watts = (tmp * 15625) >> 10; } -static int __devinit fam15h_power_probe(struct pci_dev *pdev, +static int fam15h_power_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct fam15h_power_data *data; @@ -235,7 +238,7 @@ exit_remove_group: return err; } -static void __devexit fam15h_power_remove(struct pci_dev *pdev) +static void fam15h_power_remove(struct pci_dev *pdev) { struct device *dev; struct fam15h_power_data *data; @@ -248,6 +251,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev) static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, {} }; MODULE_DEVICE_TABLE(pci, fam15h_power_id_table); @@ -256,7 +260,7 @@ static struct pci_driver fam15h_power_driver = { .name = "fam15h_power", .id_table = fam15h_power_id_table, .probe = fam15h_power_probe, - .remove = __devexit_p(fam15h_power_remove), + .remove = fam15h_power_remove, .resume = fam15h_power_resume, }; diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 519ce8b9c142..8af2755cdb87 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -379,7 +379,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute if (err) return err; - v = SENSORS_LIMIT(v / 1000, -128, 127) + 128; + v = clamp_val(v / 1000, -128, 127) + 128; mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(to_i2c_client(dev), @@ -540,7 +540,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ if (v || data->kind == fscsyl) { - v = SENSORS_LIMIT(v, 128, 255); + v = clamp_val(v, 128, 255); v = (v - 128) * 2 + 1; } diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 8b2106f60eda..ea6480b80e7f 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -171,7 +171,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *da, return -EINVAL; mutex_lock(&data->update_lock); - data->set_cnt = PWM_TO_CNT(SENSORS_LIMIT(val, 0, 255)); + data->set_cnt = PWM_TO_CNT(clamp_val(val, 0, 255)); g760a_write_value(client, G760A_REG_SET_CNT, data->set_cnt); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 2c74673f48e5..e2e5909a34df 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -86,7 +86,7 @@ enum chips { gl518sm_r00, gl518sm_r80 }; #define BOOL_FROM_REG(val) ((val) ? 0 : 1) #define BOOL_TO_REG(val) ((val) ? 0 : 1) -#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \ +#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \ (val) - 500 : \ (val) + 500) / 1000) + 119), 0, 255) #define TEMP_FROM_REG(val) (((val) - 119) * 1000) @@ -96,15 +96,15 @@ static inline u8 FAN_TO_REG(long rpm, int div) long rpmdiv; if (rpm == 0) return 0; - rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div; - return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255); + rpmdiv = clamp_val(rpm, 1, 960000) * div; + return clamp_val((480000 + rpmdiv / 2) / rpmdiv, 1, 255); } #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div)))) -#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255) +#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255) #define IN_FROM_REG(val) ((val) * 19) -#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255) +#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255) #define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) #define DIV_FROM_REG(val) (1 << (val)) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index a21ff252f2f1..ed56e09c3dd7 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -144,10 +144,10 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); #define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) -#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255) +#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255) #define IN_FROM_REG(val) ((val) * 19) -#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255) +#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255) static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -285,8 +285,7 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, #define DIV_FROM_REG(val) (1 << (val)) #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div)))) #define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \ - SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \ - 255)) + clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)) static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -450,7 +449,7 @@ static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, get_fan_off, set_fan_off); #define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \ +#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \ (val) - 500 : (val) + 500) / 1000) + 130), 0, 255) static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 1381a2e3bbd4..39781945a5d2 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -422,7 +422,7 @@ static int gpio_fan_get_of_pdata(struct device *dev, /* Fill GPIO pin array */ pdata->num_ctrl = of_gpio_count(node); - if (!pdata->num_ctrl) { + if (pdata->num_ctrl <= 0) { dev_err(dev, "gpios DT property empty / missing"); return -ENODEV; } @@ -477,7 +477,7 @@ static int gpio_fan_get_of_pdata(struct device *dev, pdata->speed = speed; /* Alarm GPIO if one exists */ - if (of_gpio_named_count(node, "alarm-gpios")) { + if (of_gpio_named_count(node, "alarm-gpios") > 0) { struct gpio_fan_alarm *alarm; int val; enum of_gpio_flags flags; @@ -499,13 +499,13 @@ static int gpio_fan_get_of_pdata(struct device *dev, return 0; } -static struct of_device_id of_gpio_fan_match[] __devinitdata = { +static struct of_device_id of_gpio_fan_match[] = { { .compatible = "gpio-fan", }, {}, }; #endif /* CONFIG_OF_GPIO */ -static int __devinit gpio_fan_probe(struct platform_device *pdev) +static int gpio_fan_probe(struct platform_device *pdev) { int err; struct gpio_fan_data *fan_data; @@ -581,7 +581,7 @@ err_free_alarm: return err; } -static int __devexit gpio_fan_remove(struct platform_device *pdev) +static int gpio_fan_remove(struct platform_device *pdev) { struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); @@ -626,7 +626,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, - .remove = __devexit_p(gpio_fan_remove), + .remove = gpio_fan_remove, .driver = { .name = "gpio-fan", .pm = GPIO_FAN_PM, diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 9a675efaa78d..2dc37c7c6947 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -220,7 +220,7 @@ static const struct attribute_group hih6130_attr_group = { * device's name. * Returns 0 on success. */ -static int __devinit hih6130_probe(struct i2c_client *client, +static int hih6130_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct hih6130 *hih6130; @@ -263,7 +263,7 @@ fail_remove_sysfs: * hih6130_remove() - remove device * @client: I2C client device */ -static int __devexit hih6130_remove(struct i2c_client *client) +static int hih6130_remove(struct i2c_client *client) { struct hih6130 *hih6130 = i2c_get_clientdata(client); @@ -283,7 +283,7 @@ MODULE_DEVICE_TABLE(i2c, hih6130_id); static struct i2c_driver hih6130_driver = { .driver.name = "hih6130", .probe = hih6130_probe, - .remove = __devexit_p(hih6130_remove), + .remove = hih6130_remove, .id_table = hih6130_id, }; diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 9f26400713f0..89cfd64b3373 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -115,6 +115,12 @@ int vid_from_reg(int val, u8 vrm) return (val < 32) ? 1550 - 25 * val : 775 - (25 * (val - 31)) / 2; + case 26: /* AMD family 10h to 15h, serial VID */ + val &= 0x7f; + if (val >= 0x7c) + return 0; + return DIV_ROUND_CLOSEST(15500 - 125 * val, 10); + case 91: /* VRM 9.1 */ case 90: /* VRM 9.0 */ val &= 0x1f; @@ -195,6 +201,10 @@ static struct vrm_model vrm_models[] = { {X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24}, /* NPT family 0Fh */ {X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25}, /* future fam. 0Fh */ {X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25}, /* NPT family 10h */ + {X86_VENDOR_AMD, 0x11, 0x0, ANY, ANY, 26}, /* family 11h */ + {X86_VENDOR_AMD, 0x12, 0x0, ANY, ANY, 26}, /* family 12h */ + {X86_VENDOR_AMD, 0x14, 0x0, ANY, ANY, 26}, /* family 14h */ + {X86_VENDOR_AMD, 0x15, 0x0, ANY, ANY, 26}, /* family 15h */ {X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82}, /* Pentium Pro, * Pentium II, Xeon, diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index c3c471ca202f..646314f7c839 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -84,19 +84,21 @@ static void __init hwmon_pci_quirks(void) /* Open access to 0x295-0x296 on MSI MS-7031 */ sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); - if (sb && - (sb->subsystem_vendor == 0x1462 && /* MSI */ - sb->subsystem_device == 0x0031)) { /* MS-7031 */ - - pci_read_config_byte(sb, 0x48, &enable); - pci_read_config_word(sb, 0x64, &base); - - if (base == 0 && !(enable & BIT(2))) { - dev_info(&sb->dev, - "Opening wide generic port at 0x295\n"); - pci_write_config_word(sb, 0x64, 0x295); - pci_write_config_byte(sb, 0x48, enable | BIT(2)); + if (sb) { + if (sb->subsystem_vendor == 0x1462 && /* MSI */ + sb->subsystem_device == 0x0031) { /* MS-7031 */ + pci_read_config_byte(sb, 0x48, &enable); + pci_read_config_word(sb, 0x64, &base); + + if (base == 0 && !(enable & BIT(2))) { + dev_info(&sb->dev, + "Opening wide generic port at 0x295\n"); + pci_write_config_word(sb, 0x64, 0x295); + pci_write_config_byte(sb, 0x48, + enable | BIT(2)); + } } + pci_dev_put(sb); } #endif } diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 46141abaafba..b87c2ccee06b 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -260,7 +260,7 @@ static ssize_t show_label(struct device *dev, attr->index & DIMM_MASK); } -static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev) +static int i5k_amb_hwmon_init(struct platform_device *pdev) { int i, j, k, d = 0; u16 c; @@ -406,7 +406,7 @@ exit_remove: return res; } -static int __devinit i5k_amb_add(void) +static int i5k_amb_add(void) { int res = -ENODEV; @@ -425,7 +425,7 @@ err: return res; } -static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data, +static int i5k_find_amb_registers(struct i5k_amb_data *data, unsigned long devid) { struct pci_dev *pcidev; @@ -459,7 +459,7 @@ out: return res; } -static int __devinit i5k_channel_probe(u16 *amb_present, unsigned long dev_id) +static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id) { struct pci_dev *pcidev; u16 val16; @@ -488,14 +488,14 @@ out: static struct { unsigned long err; unsigned long fbd0; -} chipset_ids[] __devinitdata = { +} chipset_ids[] = { { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 }, { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 }, { 0, 0 } }; #ifdef MODULE -static struct pci_device_id i5k_amb_ids[] __devinitdata = { +static struct pci_device_id i5k_amb_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) }, { 0, } @@ -503,7 +503,7 @@ static struct pci_device_id i5k_amb_ids[] __devinitdata = { MODULE_DEVICE_TABLE(pci, i5k_amb_ids); #endif -static int __devinit i5k_amb_probe(struct platform_device *pdev) +static int i5k_amb_probe(struct platform_device *pdev) { struct i5k_amb_data *data; struct resource *reso; @@ -564,7 +564,7 @@ err: return res; } -static int __devexit i5k_amb_remove(struct platform_device *pdev) +static int i5k_amb_remove(struct platform_device *pdev) { int i; struct i5k_amb_data *data = platform_get_drvdata(pdev); @@ -587,7 +587,7 @@ static struct platform_driver i5k_amb_driver = { .name = DRVNAME, }, .probe = i5k_amb_probe, - .remove = __devexit_p(i5k_amb_remove), + .remove = i5k_amb_remove, }; static int __init i5k_amb_init(void) diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c new file mode 100644 index 000000000000..c6fdd5bd395e --- /dev/null +++ b/drivers/hwmon/ina209.c @@ -0,0 +1,636 @@ +/* + * Driver for the Texas Instruments / Burr Brown INA209 + * Bidirectional Current/Power Monitor + * + * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net> + * + * Derived from Ira W. Snyder's original driver submission + * Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca> + * Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu> + * + * Aligned with ina2xx driver + * Copyright (C) 2012 Lothar Felten <l-felten@ti.com> + * Thanks to Jan Volkering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * Datasheet: + * http://www.ti.com/lit/gpn/ina209 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/bug.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> + +#include <linux/platform_data/ina2xx.h> + +/* register definitions */ +#define INA209_CONFIGURATION 0x00 +#define INA209_STATUS 0x01 +#define INA209_STATUS_MASK 0x02 +#define INA209_SHUNT_VOLTAGE 0x03 +#define INA209_BUS_VOLTAGE 0x04 +#define INA209_POWER 0x05 +#define INA209_CURRENT 0x06 +#define INA209_SHUNT_VOLTAGE_POS_PEAK 0x07 +#define INA209_SHUNT_VOLTAGE_NEG_PEAK 0x08 +#define INA209_BUS_VOLTAGE_MAX_PEAK 0x09 +#define INA209_BUS_VOLTAGE_MIN_PEAK 0x0a +#define INA209_POWER_PEAK 0x0b +#define INA209_SHUNT_VOLTAGE_POS_WARN 0x0c +#define INA209_SHUNT_VOLTAGE_NEG_WARN 0x0d +#define INA209_POWER_WARN 0x0e +#define INA209_BUS_VOLTAGE_OVER_WARN 0x0f +#define INA209_BUS_VOLTAGE_UNDER_WARN 0x10 +#define INA209_POWER_OVER_LIMIT 0x11 +#define INA209_BUS_VOLTAGE_OVER_LIMIT 0x12 +#define INA209_BUS_VOLTAGE_UNDER_LIMIT 0x13 +#define INA209_CRITICAL_DAC_POS 0x14 +#define INA209_CRITICAL_DAC_NEG 0x15 +#define INA209_CALIBRATION 0x16 + +#define INA209_REGISTERS 0x17 + +#define INA209_CONFIG_DEFAULT 0x3c47 /* PGA=8, full range */ +#define INA209_SHUNT_DEFAULT 10000 /* uOhm */ + +struct ina209_data { + struct device *hwmon_dev; + + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + u16 regs[INA209_REGISTERS]; /* All chip registers */ + + u16 config_orig; /* Original configuration */ + u16 calibration_orig; /* Original calibration */ + u16 update_interval; +}; + +static struct ina209_data *ina209_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ina209_data *data = i2c_get_clientdata(client); + struct ina209_data *ret = data; + s32 val; + int i; + + mutex_lock(&data->update_lock); + + if (!data->valid || + time_after(jiffies, data->last_updated + data->update_interval)) { + for (i = 0; i < ARRAY_SIZE(data->regs); i++) { + val = i2c_smbus_read_word_swapped(client, i); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->regs[i] = val; + } + data->last_updated = jiffies; + data->valid = true; + } +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +/* + * Read a value from a device register and convert it to the + * appropriate sysfs units + */ +static long ina209_from_reg(const u8 reg, const u16 val) +{ + switch (reg) { + case INA209_SHUNT_VOLTAGE: + case INA209_SHUNT_VOLTAGE_POS_PEAK: + case INA209_SHUNT_VOLTAGE_NEG_PEAK: + case INA209_SHUNT_VOLTAGE_POS_WARN: + case INA209_SHUNT_VOLTAGE_NEG_WARN: + /* LSB=10 uV. Convert to mV. */ + return DIV_ROUND_CLOSEST(val, 100); + + case INA209_BUS_VOLTAGE: + case INA209_BUS_VOLTAGE_MAX_PEAK: + case INA209_BUS_VOLTAGE_MIN_PEAK: + case INA209_BUS_VOLTAGE_OVER_WARN: + case INA209_BUS_VOLTAGE_UNDER_WARN: + case INA209_BUS_VOLTAGE_OVER_LIMIT: + case INA209_BUS_VOLTAGE_UNDER_LIMIT: + /* LSB=4 mV, last 3 bits unused */ + return (val >> 3) * 4; + + case INA209_CRITICAL_DAC_POS: + /* LSB=1 mV, in the upper 8 bits */ + return val >> 8; + + case INA209_CRITICAL_DAC_NEG: + /* LSB=1 mV, in the upper 8 bits */ + return -1 * (val >> 8); + + case INA209_POWER: + case INA209_POWER_PEAK: + case INA209_POWER_WARN: + case INA209_POWER_OVER_LIMIT: + /* LSB=20 mW. Convert to uW */ + return val * 20 * 1000L; + + case INA209_CURRENT: + /* LSB=1 mA (selected). Is in mA */ + return val; + } + + /* programmer goofed */ + WARN_ON_ONCE(1); + return 0; +} + +/* + * Take a value and convert it to register format, clamping the value + * to the appropriate range. + */ +static int ina209_to_reg(u8 reg, u16 old, long val) +{ + switch (reg) { + case INA209_SHUNT_VOLTAGE_POS_WARN: + case INA209_SHUNT_VOLTAGE_NEG_WARN: + /* Limit to +- 320 mV, 10 uV LSB */ + return clamp_val(val, -320, 320) * 100; + + case INA209_BUS_VOLTAGE_OVER_WARN: + case INA209_BUS_VOLTAGE_UNDER_WARN: + case INA209_BUS_VOLTAGE_OVER_LIMIT: + case INA209_BUS_VOLTAGE_UNDER_LIMIT: + /* + * Limit to 0-32000 mV, 4 mV LSB + * + * The last three bits aren't part of the value, but we'll + * preserve them in their original state. + */ + return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3) + | (old & 0x7); + + case INA209_CRITICAL_DAC_NEG: + /* + * Limit to -255-0 mV, 1 mV LSB + * Convert the value to a positive value for the register + * + * The value lives in the top 8 bits only, be careful + * and keep original value of other bits. + */ + return (clamp_val(-val, 0, 255) << 8) | (old & 0xff); + + case INA209_CRITICAL_DAC_POS: + /* + * Limit to 0-255 mV, 1 mV LSB + * + * The value lives in the top 8 bits only, be careful + * and keep original value of other bits. + */ + return (clamp_val(val, 0, 255) << 8) | (old & 0xff); + + case INA209_POWER_WARN: + case INA209_POWER_OVER_LIMIT: + /* 20 mW LSB */ + return DIV_ROUND_CLOSEST(val, 20 * 1000); + } + + /* Other registers are read-only, return access error */ + return -EACCES; +} + +static int ina209_interval_from_reg(u16 reg) +{ + return 68 >> (15 - ((reg >> 3) & 0x0f)); +} + +static u16 ina209_reg_from_interval(u16 config, long interval) +{ + int i, adc; + + if (interval <= 0) { + adc = 8; + } else { + adc = 15; + for (i = 34 + 34 / 2; i; i >>= 1) { + if (i < interval) + break; + adc--; + } + } + return (config & 0xf807) | (adc << 3) | (adc << 7); +} + +static ssize_t ina209_set_interval(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ina209_data *data = ina209_update_device(dev); + long val; + u16 regval; + int ret; + + if (IS_ERR(data)) + return PTR_ERR(data); + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&data->update_lock); + regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION], + val); + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval); + data->regs[INA209_CONFIGURATION] = regval; + data->update_interval = ina209_interval_from_reg(regval); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t ina209_show_interval(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ina209_data *data = i2c_get_clientdata(client); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval); +} + +/* + * History is reset by writing 1 into bit 0 of the respective peak register. + * Since more than one peak register may be affected by the scope of a + * reset_history attribute write, use a bit mask in attr->index to identify + * which registers are affected. + */ +static u16 ina209_reset_history_regs[] = { + INA209_SHUNT_VOLTAGE_POS_PEAK, + INA209_SHUNT_VOLTAGE_NEG_PEAK, + INA209_BUS_VOLTAGE_MAX_PEAK, + INA209_BUS_VOLTAGE_MIN_PEAK, + INA209_POWER_PEAK +}; + +static ssize_t ina209_reset_history(struct device *dev, + struct device_attribute *da, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ina209_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u32 mask = attr->index; + long val; + int i, ret; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&data->update_lock); + for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) { + if (mask & (1 << i)) + i2c_smbus_write_word_swapped(client, + ina209_reset_history_regs[i], 1); + } + data->valid = false; + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t ina209_set_value(struct device *dev, + struct device_attribute *da, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ina209_data *data = ina209_update_device(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int reg = attr->index; + long val; + int ret; + + if (IS_ERR(data)) + return PTR_ERR(data); + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&data->update_lock); + ret = ina209_to_reg(reg, data->regs[reg], val); + if (ret < 0) { + count = ret; + goto abort; + } + i2c_smbus_write_word_swapped(client, reg, ret); + data->regs[reg] = ret; +abort: + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t ina209_show_value(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ina209_data *data = ina209_update_device(dev); + long val; + + if (IS_ERR(data)) + return PTR_ERR(data); + + val = ina209_from_reg(attr->index, data->regs[attr->index]); + return snprintf(buf, PAGE_SIZE, "%ld\n", val); +} + +static ssize_t ina209_show_alarm(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ina209_data *data = ina209_update_device(dev); + const unsigned int mask = attr->index; + u16 status; + + if (IS_ERR(data)) + return PTR_ERR(data); + + status = data->regs[INA209_STATUS]; + + /* + * All alarms are in the INA209_STATUS register. To avoid a long + * switch statement, the mask is passed in attr->index + */ + return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask)); +} + +/* Shunt voltage, history, limits, alarms */ +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL, + INA209_SHUNT_VOLTAGE); +static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL, + INA209_SHUNT_VOLTAGE_POS_PEAK); +static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL, + INA209_SHUNT_VOLTAGE_NEG_PEAK); +static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL, + ina209_reset_history, (1 << 0) | (1 << 1)); +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN); +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN); +static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_CRITICAL_DAC_POS); +static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_CRITICAL_DAC_NEG); + +static SENSOR_DEVICE_ATTR(in0_min_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 11); +static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 12); +static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 6); +static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 7); + +/* Bus voltage, history, limits, alarms */ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL, + INA209_BUS_VOLTAGE); +static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL, + INA209_BUS_VOLTAGE_MAX_PEAK); +static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL, + INA209_BUS_VOLTAGE_MIN_PEAK); +static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL, + ina209_reset_history, (1 << 2) | (1 << 3)); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN); +static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT); +static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT); + +static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 14); +static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 15); +static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 9); +static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 10); + +/* Power */ +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL, + INA209_POWER); +static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value, + NULL, INA209_POWER_PEAK); +static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL, + ina209_reset_history, 1 << 4); +static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_POWER_WARN); +static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value, + ina209_set_value, INA209_POWER_OVER_LIMIT); + +static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 13); +static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL, + 1 << 8); + +/* Current */ +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL, + INA209_CURRENT); + +static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, + ina209_show_interval, ina209_set_interval, 0); + +/* + * Finally, construct an array of pointers to members of the above objects, + * as required for sysfs_create_group() + */ +static struct attribute *ina209_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_input_highest.dev_attr.attr, + &sensor_dev_attr_in0_input_lowest.dev_attr.attr, + &sensor_dev_attr_in0_reset_history.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_crit_max.dev_attr.attr, + &sensor_dev_attr_in0_crit_min.dev_attr.attr, + &sensor_dev_attr_in0_max_alarm.dev_attr.attr, + &sensor_dev_attr_in0_min_alarm.dev_attr.attr, + &sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr, + &sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr, + + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_input_highest.dev_attr.attr, + &sensor_dev_attr_in1_input_lowest.dev_attr.attr, + &sensor_dev_attr_in1_reset_history.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_crit_max.dev_attr.attr, + &sensor_dev_attr_in1_crit_min.dev_attr.attr, + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, + &sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr, + &sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr, + + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_power1_input_highest.dev_attr.attr, + &sensor_dev_attr_power1_reset_history.dev_attr.attr, + &sensor_dev_attr_power1_max.dev_attr.attr, + &sensor_dev_attr_power1_crit.dev_attr.attr, + &sensor_dev_attr_power1_max_alarm.dev_attr.attr, + &sensor_dev_attr_power1_crit_alarm.dev_attr.attr, + + &sensor_dev_attr_curr1_input.dev_attr.attr, + + &sensor_dev_attr_update_interval.dev_attr.attr, + + NULL, +}; + +static const struct attribute_group ina209_group = { + .attrs = ina209_attributes, +}; + +static void ina209_restore_conf(struct i2c_client *client, + struct ina209_data *data) +{ + /* Restore initial configuration */ + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, + data->config_orig); + i2c_smbus_write_word_swapped(client, INA209_CALIBRATION, + data->calibration_orig); +} + +static int ina209_init_client(struct i2c_client *client, + struct ina209_data *data) +{ + struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev); + u32 shunt; + int reg; + + reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION); + if (reg < 0) + return reg; + data->calibration_orig = reg; + + reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION); + if (reg < 0) + return reg; + data->config_orig = reg; + + if (pdata) { + if (pdata->shunt_uohms <= 0) + return -EINVAL; + shunt = pdata->shunt_uohms; + } else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor", + &shunt)) { + if (shunt == 0) + return -EINVAL; + } else { + shunt = data->calibration_orig ? + 40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT; + } + + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, + INA209_CONFIG_DEFAULT); + data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT); + + /* + * Calibrate current LSB to 1mA. Shunt is in uOhms. + * See equation 13 in datasheet. + */ + i2c_smbus_write_word_swapped(client, INA209_CALIBRATION, + clamp_val(40960000 / shunt, 1, 65535)); + + /* Clear status register */ + i2c_smbus_read_word_swapped(client, INA209_STATUS); + + return 0; +} + +static int ina209_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct ina209_data *data; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + ret = ina209_init_client(client, data); + if (ret) + return ret; + + /* Register sysfs hooks */ + ret = sysfs_create_group(&client->dev.kobj, &ina209_group); + if (ret) + goto out_restore_conf; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + goto out_hwmon_device_register; + } + + return 0; + +out_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, &ina209_group); +out_restore_conf: + ina209_restore_conf(client, data); + return ret; +} + +static int ina209_remove(struct i2c_client *client) +{ + struct ina209_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ina209_group); + ina209_restore_conf(client, data); + + return 0; +} + +static const struct i2c_device_id ina209_id[] = { + { "ina209", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ina209_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver ina209_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ina209", + }, + .probe = ina209_probe, + .remove = ina209_remove, + .id_table = ina209_id, +}; + +module_i2c_driver(ina209_driver); + +MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("INA209 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 2b726346f8fa..8e7158c3ad2f 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -302,19 +302,8 @@ static struct i2c_driver ina2xx_driver = { .id_table = ina2xx_id, }; -static int __init ina2xx_init(void) -{ - return i2c_add_driver(&ina2xx_driver); -} - -static void __exit ina2xx_exit(void) -{ - i2c_del_driver(&ina2xx_driver); -} +module_i2c_driver(ina2xx_driver); MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>"); MODULE_DESCRIPTION("ina2xx driver"); MODULE_LICENSE("GPL"); - -module_init(ina2xx_init); -module_exit(ina2xx_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index f1de3979181f..37fc980fde24 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -19,6 +19,8 @@ * IT8726F Super I/O chip w/LPC interface * IT8728F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface + * IT8771E Super I/O chip w/LPC interface + * IT8772E Super I/O chip w/LPC interface * IT8782F Super I/O chip w/LPC interface * IT8783E/F Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F @@ -61,8 +63,8 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782, - it8783 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, + it8772, it8782, it8783 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -140,6 +142,8 @@ static inline void superio_exit(void) #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 +#define IT8771E_DEVID 0x8771 +#define IT8772E_DEVID 0x8772 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 #define IT87_ACT_REG 0x30 @@ -203,6 +207,8 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; +static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; + #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) @@ -226,6 +232,101 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i)) #define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i)) +struct it87_devices { + const char *name; + u16 features; + u8 peci_mask; + u8 old_peci_mask; +}; + +#define FEAT_12MV_ADC (1 << 0) +#define FEAT_NEWER_AUTOPWM (1 << 1) +#define FEAT_OLD_AUTOPWM (1 << 2) +#define FEAT_16BIT_FANS (1 << 3) +#define FEAT_TEMP_OFFSET (1 << 4) +#define FEAT_TEMP_PECI (1 << 5) +#define FEAT_TEMP_OLD_PECI (1 << 6) + +static const struct it87_devices it87_devices[] = { + [it87] = { + .name = "it87", + .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ + }, + [it8712] = { + .name = "it8712", + .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ + }, + [it8716] = { + .name = "it8716", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET, + }, + [it8718] = { + .name = "it8718", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI, + .old_peci_mask = 0x4, + }, + [it8720] = { + .name = "it8720", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI, + .old_peci_mask = 0x4, + }, + [it8721] = { + .name = "it8721", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI, + .peci_mask = 0x05, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, + [it8728] = { + .name = "it8728", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + .peci_mask = 0x07, + }, + [it8771] = { + .name = "it8771", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + /* PECI: guesswork */ + /* 12mV ADC (OHM) */ + /* 16 bit fans (OHM) */ + .peci_mask = 0x07, + }, + [it8772] = { + .name = "it8772", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + /* PECI (coreboot) */ + /* 12mV ADC (HWSensors4, OHM) */ + /* 16 bit fans (HWSensors4, OHM) */ + .peci_mask = 0x07, + }, + [it8782] = { + .name = "it8782", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI, + .old_peci_mask = 0x4, + }, + [it8783] = { + .name = "it8783", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI, + .old_peci_mask = 0x4, + }, +}; + +#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) +#define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) +#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) +#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) +#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) +#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \ + ((data)->peci_mask & (1 << nr))) +#define has_temp_old_peci(data, nr) \ + (((data)->features & FEAT_TEMP_OLD_PECI) && \ + ((data)->old_peci_mask & (1 << nr))) struct it87_sio_data { enum chips type; @@ -249,7 +350,9 @@ struct it87_sio_data { struct it87_data { struct device *hwmon_dev; enum chips type; - u8 revision; + u16 features; + u8 peci_mask; + u8 old_peci_mask; unsigned short addr; const char *name; @@ -258,17 +361,13 @@ struct it87_data { unsigned long last_updated; /* In jiffies */ u16 in_scaled; /* Internal voltage sensors are scaled */ - u8 in[9]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ + u8 in[9][3]; /* [nr][0]=in, [1]=min, [2]=max */ u8 has_fan; /* Bitfield, fans enabled */ - u16 fan[5]; /* Register values, possibly combined */ - u16 fan_min[5]; /* Register values, possibly combined */ + u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */ u8 has_temp; /* Bitfield, temp sensors enabled */ - s8 temp[3]; /* Register value */ - s8 temp_high[3]; /* Register value */ - s8 temp_low[3]; /* Register value */ - u8 sensor; /* Register value */ + s8 temp[3][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */ + u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */ + u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u8 vrm; @@ -296,26 +395,6 @@ struct it87_data { s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ }; -static inline int has_12mv_adc(const struct it87_data *data) -{ - /* - * IT8721F and later have a 12 mV ADC, also with internal scaling - * on selected inputs. - */ - return data->type == it8721 - || data->type == it8728; -} - -static inline int has_newer_autopwm(const struct it87_data *data) -{ - /* - * IT8721F and later have separate registers for the temperature - * mapping and the manual duty cycle. - */ - return data->type == it8721 - || data->type == it8728; -} - static int adc_lsb(const struct it87_data *data, int nr) { int lsb = has_12mv_adc(data) ? 12 : 16; @@ -327,7 +406,7 @@ static int adc_lsb(const struct it87_data *data, int nr) static u8 in_to_reg(const struct it87_data *data, int nr, long val) { val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); - return SENSORS_LIMIT(val, 0, 255); + return clamp_val(val, 0, 255); } static int in_from_reg(const struct it87_data *data, int nr, int val) @@ -339,16 +418,15 @@ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static inline u16 FAN16_TO_REG(long rpm) { if (rpm == 0) return 0xffff; - return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe); + return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \ @@ -357,8 +435,8 @@ static inline u16 FAN16_TO_REG(long rpm) #define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ 1350000 / ((val) * 2)) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \ - ((val) + 500) / 1000), -128, 127)) +#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \ + ((val) + 500) / 1000), -128, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) static u8 pwm_to_reg(const struct it87_data *data, long val) @@ -398,37 +476,8 @@ static const unsigned int pwm_freq[8] = { 750000 / 128, }; -static inline int has_16bit_fans(const struct it87_data *data) -{ - /* - * IT8705F Datasheet 0.4.1, 3h == Version G. - * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. - * These are the first revisions with 16-bit tachometer support. - */ - return (data->type == it87 && data->revision >= 0x03) - || (data->type == it8712 && data->revision >= 0x08) - || data->type == it8716 - || data->type == it8718 - || data->type == it8720 - || data->type == it8721 - || data->type == it8728 - || data->type == it8782 - || data->type == it8783; -} - -static inline int has_old_autopwm(const struct it87_data *data) -{ - /* - * The old automatic fan speed control interface is implemented - * by IT8705F chips up to revision F and IT8712F chips up to - * revision G. - */ - return (data->type == it87 && data->revision < 0x03) - || (data->type == it8712 && data->revision < 0x08); -} - static int it87_probe(struct platform_device *pdev); -static int __devexit it87_remove(struct platform_device *pdev); +static int it87_remove(struct platform_device *pdev); static int it87_read_value(struct it87_data *data, u8 reg); static void it87_write_value(struct it87_data *data, u8 reg, u8 value); @@ -443,63 +492,26 @@ static struct platform_driver it87_driver = { .name = DRVNAME, }, .probe = it87_probe, - .remove = __devexit_p(it87_remove), + .remove = it87_remove, }; static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr])); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index])); } -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = dev_get_drvdata(dev); - unsigned long val; - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->in_min[nr] = in_to_reg(data, nr, val); - it87_write_value(data, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); - mutex_unlock(&data->update_lock); - return count; -} -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); unsigned long val; @@ -508,140 +520,167 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->in_max[nr] = in_to_reg(data, nr, val); - it87_write_value(data, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); + data->in[nr][index] = in_to_reg(data, nr, val); + it87_write_value(data, + index == 1 ? IT87_REG_VIN_MIN(nr) + : IT87_REG_VIN_MAX(nr), + data->in[nr][index]); mutex_unlock(&data->update_lock); return count; } -#define show_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in, NULL, offset); - -#define limit_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - -show_in_offset(0); -limit_in_offset(0); -show_in_offset(1); -limit_in_offset(1); -show_in_offset(2); -limit_in_offset(2); -show_in_offset(3); -limit_in_offset(3); -show_in_offset(4); -limit_in_offset(4); -show_in_offset(5); -limit_in_offset(5); -show_in_offset(6); -limit_in_offset(6); -show_in_offset(7); -limit_in_offset(7); -show_in_offset(8); +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in, + 0, 1); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in, + 0, 2); + +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in, + 1, 1); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in, + 1, 2); + +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in, + 2, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in, + 2, 2); + +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in, + 3, 1); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in, + 3, 2); + +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in, + 4, 1); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in, + 4, 2); + +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in, + 5, 1); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in, + 5, 2); + +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in, + 6, 1); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in, + 6, 2); + +static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0); +static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in, + 7, 1); +static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in, + 7, 2); + +static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0); /* 3 temperatures */ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); } -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); long val; + u8 reg, regval; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; mutex_lock(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); - mutex_unlock(&data->update_lock); - return count; -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = dev_get_drvdata(dev); - long val; - - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; + switch (index) { + default: + case 1: + reg = IT87_REG_TEMP_LOW(nr); + break; + case 2: + reg = IT87_REG_TEMP_HIGH(nr); + break; + case 3: + regval = it87_read_value(data, IT87_REG_BEEP_ENABLE); + if (!(regval & 0x80)) { + regval |= 0x80; + it87_write_value(data, IT87_REG_BEEP_ENABLE, regval); + } + data->valid = 0; + reg = IT87_REG_TEMP_OFFSET[nr]; + break; + } - mutex_lock(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); + data->temp[nr][index] = TEMP_TO_REG(val); + it87_write_value(data, reg, data->temp[nr][index]); mutex_unlock(&data->update_lock); return count; } -#define show_temp_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, - char *buf) + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, 1); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, 2); +static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 0, 3); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, 2); +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 1, 3); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, 1); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, 2); +static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 2, 3); + +static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, + char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); u8 reg = data->sensor; /* In case value is updated while used */ + u8 extra = data->extra; + if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) + || (has_temp_old_peci(data, nr) && (extra & 0x80))) + return sprintf(buf, "6\n"); /* Intel PECI */ if (reg & (1 << nr)) return sprintf(buf, "3\n"); /* thermal diode */ if (reg & (8 << nr)) return sprintf(buf, "4\n"); /* thermistor */ return sprintf(buf, "0\n"); /* disabled */ } -static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct it87_data *data = dev_get_drvdata(dev); long val; - u8 reg; + u8 reg, extra; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; @@ -649,33 +688,45 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, reg = it87_read_value(data, IT87_REG_TEMP_ENABLE); reg &= ~(1 << nr); reg &= ~(8 << nr); + if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6)) + reg &= 0x3f; + extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); + if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6)) + extra &= 0x7f; if (val == 2) { /* backwards compatibility */ - dev_warn(dev, "Sensor type 2 is deprecated, please use 4 " - "instead\n"); + dev_warn(dev, + "Sensor type 2 is deprecated, please use 4 instead\n"); val = 4; } - /* 3 = thermal diode; 4 = thermistor; 0 = disabled */ + /* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */ if (val == 3) reg |= 1 << nr; else if (val == 4) reg |= 8 << nr; + else if (has_temp_peci(data, nr) && val == 6) + reg |= (nr + 1) << 6; + else if (has_temp_old_peci(data, nr) && val == 6) + extra |= 0x80; else if (val != 0) return -EINVAL; mutex_lock(&data->update_lock); data->sensor = reg; + data->extra = extra; it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor); + if (has_temp_old_peci(data, nr)) + it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); data->valid = 0; /* Force cache refresh */ mutex_unlock(&data->update_lock); return count; } -#define show_sensor_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor, set_sensor, offset - 1); -show_sensor_offset(1); -show_sensor_offset(2); -show_sensor_offset(3); +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 0); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 1); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 2); /* 3 Fans */ @@ -692,25 +743,21 @@ static int pwm_mode(const struct it87_data *data, int nr) } static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; + int speed; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr]))); + speed = has_16bit_fans(data) ? + FAN16_FROM_REG(data->fan[nr][index]) : + FAN_FROM_REG(data->fan[nr][index], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", speed); } + static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) { @@ -747,11 +794,13 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", pwm_freq[index]); } -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t set_fan(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); long val; @@ -761,24 +810,36 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - reg = it87_read_value(data, IT87_REG_FAN_DIV); - switch (nr) { - case 0: - data->fan_div[nr] = reg & 0x07; - break; - case 1: - data->fan_div[nr] = (reg >> 3) & 0x07; - break; - case 2: - data->fan_div[nr] = (reg & 0x40) ? 3 : 1; - break; + + if (has_16bit_fans(data)) { + data->fan[nr][index] = FAN16_TO_REG(val); + it87_write_value(data, IT87_REG_FAN_MIN[nr], + data->fan[nr][index] & 0xff); + it87_write_value(data, IT87_REG_FANX_MIN[nr], + data->fan[nr][index] >> 8); + } else { + reg = it87_read_value(data, IT87_REG_FAN_DIV); + switch (nr) { + case 0: + data->fan_div[nr] = reg & 0x07; + break; + case 1: + data->fan_div[nr] = (reg >> 3) & 0x07; + break; + case 2: + data->fan_div[nr] = (reg & 0x40) ? 3 : 1; + break; + } + data->fan[nr][index] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(data, IT87_REG_FAN_MIN[nr], + data->fan[nr][index]); } - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } + static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -797,7 +858,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, old = it87_read_value(data, IT87_REG_FAN_DIV); /* Save fan min limit */ - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr])); switch (nr) { case 0: @@ -818,8 +879,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, it87_write_value(data, IT87_REG_FAN_DIV, val); /* Restore fan min limit */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); + data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]); mutex_unlock(&data->update_lock); return count; @@ -843,8 +904,8 @@ static int check_trip_points(struct device *dev, int nr) } if (err) { - dev_err(dev, "Inconsistent trip points, not switching to " - "automatic mode\n"); + dev_err(dev, + "Inconsistent trip points, not switching to automatic mode\n"); dev_err(dev, "Adjust the trip points and try again\n"); } return err; @@ -1092,118 +1153,106 @@ static ssize_t set_auto_temp(struct device *dev, return count; } -#define show_fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -#define show_pwm_offset(offset) \ -static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm_enable, set_pwm_enable, offset - 1); \ -static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, offset - 1); \ -static DEVICE_ATTR(pwm##offset##_freq, \ - (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \ - show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \ -static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \ - S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 0); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 2); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm, \ - S_IRUGO, show_auto_pwm, NULL, offset - 1, 3); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 0); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 2); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 3); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 4); - -show_pwm_offset(1); -show_pwm_offset(2); -show_pwm_offset(3); - -/* A different set of callbacks for 16-bit fans */ -static ssize_t show_fan16(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr])); -} - -static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr])); -} - -static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = dev_get_drvdata(dev); - long val; - - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN16_TO_REG(val); - it87_write_value(data, IT87_REG_FAN_MIN[nr], - data->fan_min[nr] & 0xff); - it87_write_value(data, IT87_REG_FANX_MIN[nr], - data->fan_min[nr] >> 8); - mutex_unlock(&data->update_lock); - return count; -} - -/* - * We want to use the same sysfs file names as 8-bit fans, but we need - * different variable names, so we have to use SENSOR_ATTR instead of - * SENSOR_DEVICE_ATTR. - */ -#define show_fan16_offset(offset) \ -static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \ - = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan16, NULL, offset - 1); \ -static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ - = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan16_min, set_fan16_min, offset - 1) - -show_fan16_offset(1); -show_fan16_offset(2); -show_fan16_offset(3); -show_fan16_offset(4); -show_fan16_offset(5); +static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 0, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 0); + +static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 1, 1); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 1); + +static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 2, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 2); + +static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 3, 1); + +static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 4, 1); + +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); +static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); +static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 0, 3); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 3); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 4); + +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1); +static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL); +static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 2); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 1, 3); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 2); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 3); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 4); + +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 2); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2); +static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL); +static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 2, 3); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 3); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 4); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, @@ -1471,6 +1520,12 @@ static const struct attribute_group it87_group_temp[3] = { { .attrs = it87_attributes_temp[2] }, }; +static struct attribute *it87_attributes_temp_offset[] = { + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, +}; + static struct attribute *it87_attributes[] = { &dev_attr_alarms.attr, &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, @@ -1500,73 +1555,47 @@ static struct attribute *it87_attributes_temp_beep[] = { &sensor_dev_attr_temp3_beep.dev_attr.attr, }; -static struct attribute *it87_attributes_fan16[5][3+1] = { { - &sensor_dev_attr_fan1_input16.dev_attr.attr, - &sensor_dev_attr_fan1_min16.dev_attr.attr, +static struct attribute *it87_attributes_fan[5][3+1] = { { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan2_input16.dev_attr.attr, - &sensor_dev_attr_fan2_min16.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan3_input16.dev_attr.attr, - &sensor_dev_attr_fan3_min16.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan4_input16.dev_attr.attr, - &sensor_dev_attr_fan4_min16.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan5_input16.dev_attr.attr, - &sensor_dev_attr_fan5_min16.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_alarm.dev_attr.attr, NULL } }; -static const struct attribute_group it87_group_fan16[5] = { - { .attrs = it87_attributes_fan16[0] }, - { .attrs = it87_attributes_fan16[1] }, - { .attrs = it87_attributes_fan16[2] }, - { .attrs = it87_attributes_fan16[3] }, - { .attrs = it87_attributes_fan16[4] }, +static const struct attribute_group it87_group_fan[5] = { + { .attrs = it87_attributes_fan[0] }, + { .attrs = it87_attributes_fan[1] }, + { .attrs = it87_attributes_fan[2] }, + { .attrs = it87_attributes_fan[3] }, + { .attrs = it87_attributes_fan[4] }, }; -static struct attribute *it87_attributes_fan[3][4+1] = { { - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_fan1_min.dev_attr.attr, +static const struct attribute *it87_attributes_fan_div[] = { &sensor_dev_attr_fan1_div.dev_attr.attr, - &sensor_dev_attr_fan1_alarm.dev_attr.attr, - NULL -}, { - &sensor_dev_attr_fan2_input.dev_attr.attr, - &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, - &sensor_dev_attr_fan2_alarm.dev_attr.attr, - NULL -}, { - &sensor_dev_attr_fan3_input.dev_attr.attr, - &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, - &sensor_dev_attr_fan3_alarm.dev_attr.attr, - NULL -} }; - -static const struct attribute_group it87_group_fan[3] = { - { .attrs = it87_attributes_fan[0] }, - { .attrs = it87_attributes_fan[1] }, - { .attrs = it87_attributes_fan[2] }, }; -static const struct attribute_group * -it87_get_fan_group(const struct it87_data *data) -{ - return has_16bit_fans(data) ? it87_group_fan16 : it87_group_fan; -} - static struct attribute *it87_attributes_pwm[3][4+1] = { { &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, @@ -1701,6 +1730,12 @@ static int __init it87_find(unsigned short *address, case IT8728F_DEVID: sio_data->type = it8728; break; + case IT8771E_DEVID: + sio_data->type = it8771; + break; + case IT8772E_DEVID: + sio_data->type = it8772; + break; case IT8782F_DEVID: sio_data->type = it8782; break; @@ -1818,10 +1853,11 @@ static int __init it87_find(unsigned short *address, reg = superio_inb(IT87_SIO_GPIO3_REG); if (sio_data->type == it8721 || sio_data->type == it8728 || + sio_data->type == it8771 || sio_data->type == it8772 || sio_data->type == it8782) { /* * IT8721F/IT8758E, and IT8782F don't have VID pins - * at all, not sure about the IT8728F. + * at all, not sure about the IT8728F and compatibles. */ sio_data->skip_vid = 1; } else { @@ -1875,7 +1911,9 @@ static int __init it87_find(unsigned short *address, if (reg & (1 << 0)) sio_data->internal |= (1 << 0); if ((reg & (1 << 1)) || sio_data->type == it8721 || - sio_data->type == it8728) + sio_data->type == it8728 || + sio_data->type == it8771 || + sio_data->type == it8772) sio_data->internal |= (1 << 1); /* @@ -1925,7 +1963,6 @@ static void it87_remove_files(struct device *dev) { struct it87_data *data = platform_get_drvdata(pdev); struct it87_sio_data *sio_data = dev->platform_data; - const struct attribute_group *fan_group = it87_get_fan_group(data); int i; sysfs_remove_group(&dev->kobj, &it87_group); @@ -1941,6 +1978,9 @@ static void it87_remove_files(struct device *dev) if (!(data->has_temp & (1 << i))) continue; sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); + if (has_temp_offset(data)) + sysfs_remove_file(&dev->kobj, + it87_attributes_temp_offset[i]); if (sio_data->beep_pin) sysfs_remove_file(&dev->kobj, it87_attributes_temp_beep[i]); @@ -1948,10 +1988,13 @@ static void it87_remove_files(struct device *dev) for (i = 0; i < 5; i++) { if (!(data->has_fan & (1 << i))) continue; - sysfs_remove_group(&dev->kobj, &fan_group[i]); + sysfs_remove_group(&dev->kobj, &it87_group_fan[i]); if (sio_data->beep_pin) sysfs_remove_file(&dev->kobj, it87_attributes_fan_beep[i]); + if (i < 3 && !has_16bit_fans(data)) + sysfs_remove_file(&dev->kobj, + it87_attributes_fan_div[i]); } for (i = 0; i < 3; i++) { if (sio_data->skip_pwm & (1 << 0)) @@ -1966,27 +2009,15 @@ static void it87_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &it87_group_label); } -static int __devinit it87_probe(struct platform_device *pdev) +static int it87_probe(struct platform_device *pdev) { struct it87_data *data; struct resource *res; struct device *dev = &pdev->dev; struct it87_sio_data *sio_data = dev->platform_data; - const struct attribute_group *fan_group; int err = 0, i; int enable_pwm_interface; int fan_beep_need_rw; - static const char * const names[] = { - "it87", - "it8712", - "it8716", - "it8718", - "it8720", - "it8721", - "it8728", - "it8782", - "it8783", - }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, @@ -2003,8 +2034,31 @@ static int __devinit it87_probe(struct platform_device *pdev) data->addr = res->start; data->type = sio_data->type; - data->revision = sio_data->revision; - data->name = names[sio_data->type]; + data->features = it87_devices[sio_data->type].features; + data->peci_mask = it87_devices[sio_data->type].peci_mask; + data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask; + data->name = it87_devices[sio_data->type].name; + /* + * IT8705F Datasheet 0.4.1, 3h == Version G. + * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. + * These are the first revisions with 16-bit tachometer support. + */ + switch (data->type) { + case it87: + if (sio_data->revision >= 0x03) { + data->features &= ~FEAT_OLD_AUTOPWM; + data->features |= FEAT_16BIT_FANS; + } + break; + case it8712: + if (sio_data->revision >= 0x08) { + data->features &= ~FEAT_OLD_AUTOPWM; + data->features |= FEAT_16BIT_FANS; + } + break; + default: + break; + } /* Now, we do the remaining detection. */ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) @@ -2068,6 +2122,12 @@ static int __devinit it87_probe(struct platform_device *pdev) err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); if (err) goto error; + if (has_temp_offset(data)) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_temp_offset[i]); + if (err) + goto error; + } if (sio_data->beep_pin) { err = sysfs_create_file(&dev->kobj, it87_attributes_temp_beep[i]); @@ -2077,15 +2137,21 @@ static int __devinit it87_probe(struct platform_device *pdev) } /* Do not create fan files for disabled fans */ - fan_group = it87_get_fan_group(data); fan_beep_need_rw = 1; for (i = 0; i < 5; i++) { if (!(data->has_fan & (1 << i))) continue; - err = sysfs_create_group(&dev->kobj, &fan_group[i]); + err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]); if (err) goto error; + if (i < 3 && !has_16bit_fans(data)) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_fan_div[i]); + if (err) + goto error; + } + if (sio_data->beep_pin) { err = sysfs_create_file(&dev->kobj, it87_attributes_fan_beep[i]); @@ -2158,7 +2224,7 @@ error: return err; } -static int __devexit it87_remove(struct platform_device *pdev) +static int it87_remove(struct platform_device *pdev) { struct it87_data *data = platform_get_drvdata(pdev); @@ -2191,7 +2257,7 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value) } /* Return 1 if and only if the PWM interface is safe to use */ -static int __devinit it87_check_pwm(struct device *dev) +static int it87_check_pwm(struct device *dev) { struct it87_data *data = dev_get_drvdata(dev); /* @@ -2221,8 +2287,8 @@ static int __devinit it87_check_pwm(struct device *dev) * PWM interface). */ if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { - dev_info(dev, "Reconfiguring PWM to " - "active high polarity\n"); + dev_info(dev, + "Reconfiguring PWM to active high polarity\n"); it87_write_value(data, IT87_REG_FAN_CTL, tmp | 0x87); for (i = 0; i < 3; i++) @@ -2232,23 +2298,23 @@ static int __devinit it87_check_pwm(struct device *dev) return 1; } - dev_info(dev, "PWM configuration is " - "too broken to be fixed\n"); + dev_info(dev, + "PWM configuration is too broken to be fixed\n"); } - dev_info(dev, "Detected broken BIOS " - "defaults, disabling PWM interface\n"); + dev_info(dev, + "Detected broken BIOS defaults, disabling PWM interface\n"); return 0; } else if (fix_pwm_polarity) { - dev_info(dev, "PWM configuration looks " - "sane, won't touch\n"); + dev_info(dev, + "PWM configuration looks sane, won't touch\n"); } return 1; } /* Called when we have found a new IT87. */ -static void __devinit it87_init_device(struct platform_device *pdev) +static void it87_init_device(struct platform_device *pdev) { struct it87_sio_data *sio_data = pdev->dev.platform_data; struct it87_data *data = platform_get_drvdata(pdev); @@ -2389,42 +2455,46 @@ static struct it87_data *it87_update_device(struct device *dev) it87_read_value(data, IT87_REG_CONFIG) | 0x40); } for (i = 0; i <= 7; i++) { - data->in[i] = + data->in[i][0] = it87_read_value(data, IT87_REG_VIN(i)); - data->in_min[i] = + data->in[i][1] = it87_read_value(data, IT87_REG_VIN_MIN(i)); - data->in_max[i] = + data->in[i][2] = it87_read_value(data, IT87_REG_VIN_MAX(i)); } /* in8 (battery) has no limit registers */ - data->in[8] = it87_read_value(data, IT87_REG_VIN(8)); + data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8)); for (i = 0; i < 5; i++) { /* Skip disabled fans */ if (!(data->has_fan & (1 << i))) continue; - data->fan_min[i] = + data->fan[i][1] = it87_read_value(data, IT87_REG_FAN_MIN[i]); - data->fan[i] = it87_read_value(data, + data->fan[i][0] = it87_read_value(data, IT87_REG_FAN[i]); /* Add high byte if in 16-bit mode */ if (has_16bit_fans(data)) { - data->fan[i] |= it87_read_value(data, + data->fan[i][0] |= it87_read_value(data, IT87_REG_FANX[i]) << 8; - data->fan_min[i] |= it87_read_value(data, + data->fan[i][1] |= it87_read_value(data, IT87_REG_FANX_MIN[i]) << 8; } } for (i = 0; i < 3; i++) { if (!(data->has_temp & (1 << i))) continue; - data->temp[i] = + data->temp[i][0] = it87_read_value(data, IT87_REG_TEMP(i)); - data->temp_high[i] = - it87_read_value(data, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i] = + data->temp[i][1] = it87_read_value(data, IT87_REG_TEMP_LOW(i)); + data->temp[i][2] = + it87_read_value(data, IT87_REG_TEMP_HIGH(i)); + if (has_temp_offset(data)) + data->temp[i][3] = + it87_read_value(data, + IT87_REG_TEMP_OFFSET[i]); } /* Newer chips don't have clock dividers */ @@ -2448,6 +2518,7 @@ static struct it87_data *it87_update_device(struct device *dev) it87_update_pwm_ctrl(data, i); data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); + data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); /* * The IT8705F does not have VID capability. * The IT8718F and later don't use IT87_REG_VID for the @@ -2549,8 +2620,7 @@ static void __exit sm_it87_exit(void) } -MODULE_AUTHOR("Chris Gauthron, " - "Jean Delvare <khali@linux-fr.org>"); +MODULE_AUTHOR("Chris Gauthron, Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index e21e43c13156..4a58f130fd4e 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -103,6 +103,9 @@ static const unsigned short normal_i2c[] = { #define MCP98243_DEVID 0x2100 #define MCP98243_DEVID_MASK 0xfffc +#define MCP98244_DEVID 0x2200 +#define MCP98244_DEVID_MASK 0xfffc + #define MCP9843_DEVID 0x0000 /* Also matches mcp9805 */ #define MCP9843_DEVID_MASK 0xfffe @@ -147,6 +150,7 @@ static struct jc42_chips jc42_chips[] = { { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK }, { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK }, { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK }, + { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK }, { MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK }, { NXP_MANID, SE97_DEVID, SE97_DEVID_MASK }, { ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK }, @@ -237,9 +241,9 @@ static struct i2c_driver jc42_driver = { static u16 jc42_temp_to_reg(int temp, bool extended) { - int ntemp = SENSORS_LIMIT(temp, - extended ? JC42_TEMP_MIN_EXTENDED : - JC42_TEMP_MIN, JC42_TEMP_MAX); + int ntemp = clamp_val(temp, + extended ? JC42_TEMP_MIN_EXTENDED : + JC42_TEMP_MIN, JC42_TEMP_MAX); /* convert from 0.001 to 0.0625 resolution */ return (ntemp * 2 / 125) & 0x1fff; diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index dee9eec2036e..e0d66b9590ab 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -102,7 +102,7 @@ static const struct attribute_group jz4740_hwmon_attr_group = { .attrs = jz4740_hwmon_attributes, }; -static int __devinit jz4740_hwmon_probe(struct platform_device *pdev) +static int jz4740_hwmon_probe(struct platform_device *pdev) { int ret; struct jz4740_hwmon *hwmon; @@ -172,7 +172,7 @@ err_remove_file: return ret; } -static int __devexit jz4740_hwmon_remove(struct platform_device *pdev) +static int jz4740_hwmon_remove(struct platform_device *pdev) { struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev); @@ -184,7 +184,7 @@ static int __devexit jz4740_hwmon_remove(struct platform_device *pdev) static struct platform_driver jz4740_hwmon_driver = { .probe = jz4740_hwmon_probe, - .remove = __devexit_p(jz4740_hwmon_remove), + .remove = jz4740_hwmon_remove, .driver = { .name = "jz4740-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index f2fe8078633b..e3b037c73a7e 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -95,7 +95,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static bool __devinit has_erratum_319(struct pci_dev *pdev) +static bool has_erratum_319(struct pci_dev *pdev) { u32 pkg_type, reg_dram_cfg; @@ -129,7 +129,7 @@ static bool __devinit has_erratum_319(struct pci_dev *pdev) (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2); } -static int __devinit k10temp_probe(struct pci_dev *pdev, +static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *hwmon_dev; @@ -192,7 +192,7 @@ exit: return err; } -static void __devexit k10temp_remove(struct pci_dev *pdev) +static void k10temp_remove(struct pci_dev *pdev) { hwmon_device_unregister(pci_get_drvdata(pdev)); device_remove_file(&pdev->dev, &dev_attr_name); @@ -219,7 +219,7 @@ static struct pci_driver k10temp_driver = { .name = "k10temp", .id_table = k10temp_id_table, .probe = k10temp_probe, - .remove = __devexit_p(k10temp_remove), + .remove = k10temp_remove, }; module_pci_driver(k10temp_driver); diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index e8c7fb0bbf95..9f3c0aeacdb9 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -142,7 +142,7 @@ static DEFINE_PCI_DEVICE_TABLE(k8temp_ids) = { MODULE_DEVICE_TABLE(pci, k8temp_ids); -static int __devinit is_rev_g_desktop(u8 model) +static int is_rev_g_desktop(u8 model) { u32 brandidx; @@ -173,7 +173,7 @@ static int __devinit is_rev_g_desktop(u8 model) return 1; } -static int __devinit k8temp_probe(struct pci_dev *pdev, +static int k8temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; @@ -304,7 +304,7 @@ exit_remove: return err; } -static void __devexit k8temp_remove(struct pci_dev *pdev) +static void k8temp_remove(struct pci_dev *pdev) { struct k8temp_data *data = pci_get_drvdata(pdev); @@ -324,7 +324,7 @@ static struct pci_driver k8temp_driver = { .name = "k8temp", .id_table = k8temp_ids, .probe = k8temp_probe, - .remove = __devexit_p(k8temp_remove), + .remove = k8temp_remove, }; module_pci_driver(k8temp_driver); diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index 41df29f59b0e..ebbb9f4f27a3 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -422,6 +422,7 @@ static struct attribute *pem_input_attributes[] = { &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, + NULL }; static const struct attribute_group pem_input_group = { @@ -432,6 +433,7 @@ static struct attribute *pem_fan_attributes[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, + NULL }; static const struct attribute_group pem_fan_group = { diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index eed4d9401788..f644a2e57599 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -209,9 +209,9 @@ static inline int lut_temp_to_reg(struct lm63_data *data, long val) { val -= data->temp2_offset; if (data->lut_temp_highres) - return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500); + return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500); else - return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000); + return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000); } /* @@ -415,7 +415,7 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr, return err; reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm1[nr] = data->pwm_highres ? val : @@ -700,7 +700,7 @@ static ssize_t set_update_interval(struct device *dev, return err; mutex_lock(&data->update_lock); - lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); + lm63_set_convrate(client, data, clamp_val(val, 0, 100000)); mutex_unlock(&data->update_lock); return count; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 2d1777a03edb..016efa26ba7c 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -131,7 +131,7 @@ static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); /*----------------------------------------------------------------------*/ -static int __devinit lm70_probe(struct spi_device *spi) +static int lm70_probe(struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; struct lm70 *p_lm70; @@ -178,7 +178,7 @@ out_dev_create_temp_file_failed: return status; } -static int __devexit lm70_remove(struct spi_device *spi) +static int lm70_remove(struct spi_device *spi) { struct lm70 *p_lm70 = spi_get_drvdata(spi); @@ -207,7 +207,7 @@ static struct spi_driver lm70_driver = { }, .id_table = lm70_ids, .probe = lm70_probe, - .remove = __devexit_p(lm70_remove), + .remove = lm70_remove, }; module_spi_driver(lm70_driver); diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 8fa2632cbbaf..9bde9644b102 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -8,6 +8,7 @@ * Guillaume Ligneul <guillaume.ligneul@gmail.com> * Adrien Demarez <adrien.demarez@bolloretelecom.eu> * Jeremy Laine <jeremy.laine@bolloretelecom.eu> + * Chris Verges <kg4ysn@gmail.com> * * This software program is licensed subject to the GNU General Public License * (GPL).Version 2,June 1991, available at @@ -36,11 +37,30 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, #define LM73_ID 0x9001 /* 0x0190, byte-swapped */ #define DRVNAME "lm73" -#define LM73_TEMP_MIN (-40) -#define LM73_TEMP_MAX 150 +#define LM73_TEMP_MIN (-256000 / 250) +#define LM73_TEMP_MAX (255750 / 250) -/*-----------------------------------------------------------------------*/ +#define LM73_CTRL_RES_SHIFT 5 +#define LM73_CTRL_RES_MASK (BIT(5) | BIT(6)) +#define LM73_CTRL_TO_MASK BIT(7) + +#define LM73_CTRL_HI_SHIFT 2 +#define LM73_CTRL_LO_SHIFT 1 + +static const unsigned short lm73_convrates[] = { + 14, /* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */ + 28, /* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */ + 56, /* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */ + 112, /* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */ +}; +struct lm73_data { + struct device *hwmon_dev; + struct mutex lock; + u8 ctrl; /* control register value */ +}; + +/*-----------------------------------------------------------------------*/ static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) @@ -49,16 +69,16 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); long temp; short value; + s32 err; int status = kstrtol(buf, 10, &temp); if (status < 0) return status; /* Write value */ - value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4), - (LM73_TEMP_MAX*4)) << 5; - i2c_smbus_write_word_swapped(client, attr->index, value); - return count; + value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5; + err = i2c_smbus_write_word_swapped(client, attr->index, value); + return (err < 0) ? err : count; } static ssize_t show_temp(struct device *dev, struct device_attribute *da, @@ -66,13 +86,85 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); + int temp; + + s32 err = i2c_smbus_read_word_swapped(client, attr->index); + if (err < 0) + return err; + /* use integer division instead of equivalent right shift to guarantee arithmetic shift and preserve the sign */ - int temp = ((s16) (i2c_smbus_read_word_swapped(client, - attr->index))*250) / 32; - return sprintf(buf, "%d\n", temp); + temp = (((s16) err) * 250) / 32; + return scnprintf(buf, PAGE_SIZE, "%d\n", temp); } +static ssize_t set_convrate(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm73_data *data = i2c_get_clientdata(client); + unsigned long convrate; + s32 err; + int res = 0; + + err = kstrtoul(buf, 10, &convrate); + if (err < 0) + return err; + + /* + * Convert the desired conversion rate into register bits. + * res is already initialized, and everything past the second-to-last + * value in the array is treated as belonging to the last value + * in the array. + */ + while (res < (ARRAY_SIZE(lm73_convrates) - 1) && + convrate > lm73_convrates[res]) + res++; + + mutex_lock(&data->lock); + data->ctrl &= LM73_CTRL_TO_MASK; + data->ctrl |= res << LM73_CTRL_RES_SHIFT; + err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl); + mutex_unlock(&data->lock); + + if (err < 0) + return err; + + return count; +} + +static ssize_t show_convrate(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm73_data *data = i2c_get_clientdata(client); + int res; + + res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT; + return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]); +} + +static ssize_t show_maxmin_alarm(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm73_data *data = i2c_get_clientdata(client); + s32 ctrl; + + mutex_lock(&data->lock); + ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL); + if (ctrl < 0) + goto abort; + data->ctrl = ctrl; + mutex_unlock(&data->lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1); + +abort: + mutex_unlock(&data->lock); + return ctrl; +} /*-----------------------------------------------------------------------*/ @@ -84,13 +176,20 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, LM73_REG_MIN); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, LM73_REG_INPUT); - +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, + show_convrate, set_convrate, 0); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, + show_maxmin_alarm, NULL, LM73_CTRL_HI_SHIFT); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, + show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT); static struct attribute *lm73_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, - + &sensor_dev_attr_update_interval.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, NULL }; @@ -105,23 +204,36 @@ static const struct attribute_group lm73_group = { static int lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct device *hwmon_dev; int status; + struct lm73_data *data; + int ctrl; + + data = devm_kzalloc(&client->dev, sizeof(struct lm73_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL); + if (ctrl < 0) + return ctrl; + data->ctrl = ctrl; /* Register sysfs hooks */ status = sysfs_create_group(&client->dev.kobj, &lm73_group); if (status) return status; - hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(hwmon_dev)) { - status = PTR_ERR(hwmon_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); goto exit_remove; } - i2c_set_clientdata(client, hwmon_dev); dev_info(&client->dev, "%s: sensor '%s'\n", - dev_name(hwmon_dev), client->name); + dev_name(data->hwmon_dev), client->name); return 0; @@ -132,9 +244,9 @@ exit_remove: static int lm73_remove(struct i2c_client *client) { - struct device *hwmon_dev = i2c_get_clientdata(client); + struct lm73_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(hwmon_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm73_group); return 0; } diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h index 89aa9098ba5b..668ff4721323 100644 --- a/drivers/hwmon/lm75.h +++ b/drivers/hwmon/lm75.h @@ -36,7 +36,7 @@ REG: (0.5C/bit, two's complement) << 7 */ static inline u16 LM75_TEMP_TO_REG(long temp) { - int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); ntemp += (ntemp < 0 ? -250 : 250); return (u16)((ntemp / 500) << 7); } diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index f82acf67acf5..f17beb5e6dd6 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -101,7 +101,7 @@ static struct i2c_driver lm77_driver = { */ static inline s16 LM77_TEMP_TO_REG(int temp) { - int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); + int ntemp = clamp_val(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); return (ntemp / 500) * 8; } diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index c6ffafe600ad..483538fa1bd5 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -85,7 +85,7 @@ enum chips { lm78, lm79 }; */ static inline u8 IN_TO_REG(unsigned long val) { - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + unsigned long nval = clamp_val(val, 0, 4080); return (nval + 8) / 16; } #define IN_FROM_REG(val) ((val) * 16) @@ -94,7 +94,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm <= 0) return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static inline int FAN_FROM_REG(u8 val, int div) @@ -108,7 +108,7 @@ static inline int FAN_FROM_REG(u8 val, int div) */ static inline s8 TEMP_TO_REG(int val) { - int nval = SENSORS_LIMIT(val, -128000, 127000) ; + int nval = clamp_val(val, -128000, 127000) ; return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000; } @@ -833,7 +833,7 @@ static struct lm78_data *lm78_update_device(struct device *dev) } #ifdef CONFIG_ISA -static int __devinit lm78_isa_probe(struct platform_device *pdev) +static int lm78_isa_probe(struct platform_device *pdev) { int err; struct lm78_data *data; @@ -886,7 +886,7 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev) return err; } -static int __devexit lm78_isa_remove(struct platform_device *pdev) +static int lm78_isa_remove(struct platform_device *pdev) { struct lm78_data *data = platform_get_drvdata(pdev); @@ -903,7 +903,7 @@ static struct platform_driver lm78_isa_driver = { .name = "lm78", }, .probe = lm78_isa_probe, - .remove = __devexit_p(lm78_isa_remove), + .remove = lm78_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 28a8b71f4571..357fbb998728 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -72,15 +72,15 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, * Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT(((val) + 5) / 10, 0, 255)) +#define IN_TO_REG(val) (clamp_val(((val) + 5) / 10, 0, 255)) #define IN_FROM_REG(val) ((val) * 10) static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ @@ -102,7 +102,7 @@ static inline long TEMP_FROM_REG(u16 temp) #define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ (val) - 0x100 : (val)) * 1000) -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) < 0 ? \ +#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \ ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255) #define DIV_FROM_REG(val) (1 << (val)) diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 9f2dd77e1e0e..47ade8ba152d 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -139,7 +139,7 @@ static const int lm85_scaling[] = { /* .001 Volts */ #define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from)) #define INS_TO_REG(n, val) \ - SENSORS_LIMIT(SCALE(val, lm85_scaling[n], 192), 0, 255) + clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255) #define INSEXT_FROM_REG(n, val, ext) \ SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) @@ -151,19 +151,19 @@ static inline u16 FAN_TO_REG(unsigned long val) { if (!val) return 0xffff; - return SENSORS_LIMIT(5400000 / val, 1, 0xfffe); + return clamp_val(5400000 / val, 1, 0xfffe); } #define FAN_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ 5400000 / (val)) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ - SENSORS_LIMIT(SCALE(val, 1000, 1), -127, 127) + clamp_val(SCALE(val, 1000, 1), -127, 127) #define TEMPEXT_FROM_REG(val, ext) \ SCALE(((val) << 4) + (ext), 16, 1000) #define TEMP_FROM_REG(val) ((val) * 1000) -#define PWM_TO_REG(val) SENSORS_LIMIT(val, 0, 255) +#define PWM_TO_REG(val) clamp_val(val, 0, 255) #define PWM_FROM_REG(val) (val) @@ -258,7 +258,7 @@ static int ZONE_TO_REG(int zone) return i << 5; } -#define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15) +#define HYST_TO_REG(val) clamp_val(((val) + 500) / 1000, 0, 15) #define HYST_FROM_REG(val) ((val) * 1000) /* diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 863412a02bdd..8eeb141c85ac 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -931,7 +931,7 @@ static ssize_t set_update_interval(struct device *dev, return err; mutex_lock(&data->update_lock); - lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); + lm90_set_convrate(client, data, clamp_val(val, 0, 100000)); mutex_unlock(&data->update_lock); return count; diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 1a003f73e4e4..b40f34cdb3ca 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -371,8 +371,8 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg) static u8 LM93_IN_TO_REG(int nr, unsigned val) { /* range limit */ - const long mV = SENSORS_LIMIT(val, - lm93_vin_val_min[nr], lm93_vin_val_max[nr]); + const long mV = clamp_val(val, + lm93_vin_val_min[nr], lm93_vin_val_max[nr]); /* try not to lose too much precision here */ const long uV = mV * 1000; @@ -385,8 +385,8 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val) const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; u8 result = ((uV - intercept + (slope/2)) / slope); - result = SENSORS_LIMIT(result, - lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); + result = clamp_val(result, + lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); return result; } @@ -411,10 +411,10 @@ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) { long uV_offset = vid * 1000 - val * 10000; if (upper) { - uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000); + uV_offset = clamp_val(uV_offset, 12500, 200000); return (u8)((uV_offset / 12500 - 1) << 4); } else { - uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000); + uV_offset = clamp_val(uV_offset, -400000, -25000); return (u8)((uV_offset / -25000 - 1) << 0); } } @@ -437,7 +437,7 @@ static int LM93_TEMP_FROM_REG(u8 reg) */ static u8 LM93_TEMP_TO_REG(long temp) { - int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); + int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); ntemp += (ntemp < 0 ? -500 : 500); return (u8)(ntemp / 1000); } @@ -472,7 +472,7 @@ static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) { int factor = mode ? 5 : 10; - off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN, + off = clamp_val(off, LM93_TEMP_OFFSET_MIN, mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); return (u8)((off + factor/2) / factor); } @@ -620,8 +620,8 @@ static u16 LM93_FAN_TO_REG(long rpm) if (rpm == 0) { count = 0x3fff; } else { - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe); + rpm = clamp_val(rpm, 1, 1000000); + count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe); } regs = count << 2; @@ -692,7 +692,7 @@ static int LM93_RAMP_FROM_REG(u8 reg) */ static u8 LM93_RAMP_TO_REG(int ramp) { - ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); + ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); return (u8)((ramp + 2) / 5); } @@ -702,7 +702,7 @@ static u8 LM93_RAMP_TO_REG(int ramp) */ static u8 LM93_PROCHOT_TO_REG(long prochot) { - prochot = SENSORS_LIMIT(prochot, 0, 255); + prochot = clamp_val(prochot, 0, 255); return (u8)prochot; } @@ -2052,7 +2052,7 @@ static ssize_t store_pwm_auto_channels(struct device *dev, return err; mutex_lock(&data->update_lock); - data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255); + data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255); lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1), data->block9[nr][LM93_PWM_CTL1]); mutex_unlock(&data->update_lock); @@ -2397,7 +2397,7 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev, mutex_lock(&data->update_lock); data->prochot_override = (data->prochot_override & 0xf0) | - SENSORS_LIMIT(val, 0, 15); + clamp_val(val, 0, 15); lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, data->prochot_override); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 2915fd908364..a6c85f0ff8f3 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -259,7 +259,7 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr, val /= 1000; - val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255)); + val = clamp_val(val, 0, (index == 6 ? 127 : 255)); mutex_lock(&data->update_lock); @@ -284,7 +284,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr, val /= 1000; - val = SENSORS_LIMIT(val, 0, 31); + val = clamp_val(val, 0, 31); mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index b4eb0889c465..eda077de8a9f 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -157,7 +157,7 @@ static const struct attribute_group max1110_attr_group = { .attrs = max1110_attributes, }; -static int __devinit setup_transfer(struct max1111_data *data) +static int setup_transfer(struct max1111_data *data) { struct spi_message *m; struct spi_transfer *x; @@ -179,7 +179,7 @@ static int __devinit setup_transfer(struct max1111_data *data) return 0; } -static int __devinit max1111_probe(struct spi_device *spi) +static int max1111_probe(struct spi_device *spi) { enum chips chip = spi_get_device_id(spi)->driver_data; struct max1111_data *data; @@ -256,7 +256,7 @@ err_remove: return err; } -static int __devexit max1111_remove(struct spi_device *spi) +static int max1111_remove(struct spi_device *spi) { struct max1111_data *data = spi_get_drvdata(spi); @@ -283,7 +283,7 @@ static struct spi_driver max1111_driver = { }, .id_table = max1111_ids, .probe = max1111_probe, - .remove = __devexit_p(max1111_remove), + .remove = max1111_remove, }; module_spi_driver(max1111_driver); diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index e0019c69d1bb..2fa2c02f5569 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -118,7 +118,7 @@ static inline int LIMIT_TO_MV(int limit, int range) static inline int MV_TO_LIMIT(int mv, int range) { - return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255); + return clamp_val(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255); } static inline int ADC_TO_CURR(int adc, int gain) diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 666d9f6263eb..a7626358c95d 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -215,7 +215,7 @@ static ssize_t set_temp_max(struct device *dev, return ret; mutex_lock(&data->update_lock); - data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127); + data->temp_max[index] = clamp_val(temp/1000, -128, 127); if (i2c_smbus_write_byte_data(client, MAX1668_REG_LIMH_WR(index), data->temp_max[index])) @@ -240,7 +240,7 @@ static ssize_t set_temp_min(struct device *dev, return ret; mutex_lock(&data->update_lock); - data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127); + data->temp_min[index] = clamp_val(temp/1000, -128, 127); if (i2c_smbus_write_byte_data(client, MAX1668_REG_LIML_WR(index), data->temp_max[index])) diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 6304f2616fa7..b5ebb9198c75 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -257,7 +257,7 @@ static const struct attribute_group max197_sysfs_group = { }, }; -static int __devinit max197_probe(struct platform_device *pdev) +static int max197_probe(struct platform_device *pdev) { int ch, ret; struct max197_data *data; @@ -316,7 +316,7 @@ error: return ret; } -static int __devexit max197_remove(struct platform_device *pdev) +static int max197_remove(struct platform_device *pdev) { struct max197_data *data = platform_get_drvdata(pdev); @@ -339,7 +339,7 @@ static struct platform_driver max197_driver = { .owner = THIS_MODULE, }, .probe = max197_probe, - .remove = __devexit_p(max197_remove), + .remove = max197_remove, .id_table = max197_device_ids, }; module_platform_driver(max197_driver); diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 6e60036abfa7..3e7b4269f5b9 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -74,7 +74,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 }; #define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \ 0 : (rpm_ranges[rpm_range] * 30) / (val)) -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) / 1000, 0, 255) +#define TEMP_LIMIT_TO_REG(val) clamp_val((val) / 1000, 0, 255) /* * Client data (each client gets its own) @@ -312,7 +312,7 @@ static ssize_t set_pwm(struct device *dev, if (res) return res; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm[attr->index] = (u8)(val * 120 / 255); diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 223461a6d70f..57d58cd32206 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -239,7 +239,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255); + data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255); i2c_smbus_write_byte_data(client, attr2->index, data->temp_high[attr2->nr]); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f739f83bafb9..3c16cbd4c002 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -245,7 +245,7 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr, if (err) return err; - rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX); + rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX); /* * Divide the required speed by 60 to get from rpm to rps, then @@ -313,7 +313,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, if (err) return err; - pwm = SENSORS_LIMIT(pwm, 0, 255); + pwm = clamp_val(pwm, 0, 255); mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c new file mode 100644 index 000000000000..bf4aa3777fc1 --- /dev/null +++ b/drivers/hwmon/max6697.c @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2012 Guenter Roeck <linux@roeck-us.net> + * + * based on max1668.c + * Copyright (c) 2011 David George <david.george@ska.ac.za> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/of.h> + +#include <linux/platform_data/max6697.h> + +enum chips { max6581, max6602, max6622, max6636, max6689, max6693, max6694, + max6697, max6698, max6699 }; + +/* Report local sensor as temp1 */ + +static const u8 MAX6697_REG_TEMP[] = { + 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08 }; +static const u8 MAX6697_REG_TEMP_EXT[] = { + 0x57, 0x09, 0x52, 0x53, 0x54, 0x55, 0x56, 0 }; +static const u8 MAX6697_REG_MAX[] = { + 0x17, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18 }; +static const u8 MAX6697_REG_CRIT[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 }; + +/* + * Map device tree / platform data register bit map to chip bit map. + * Applies to alert register and over-temperature register. + */ +#define MAX6697_MAP_BITS(reg) ((((reg) & 0x7e) >> 1) | \ + (((reg) & 0x01) << 6) | ((reg) & 0x80)) + +#define MAX6697_REG_STAT(n) (0x44 + (n)) + +#define MAX6697_REG_CONFIG 0x41 +#define MAX6581_CONF_EXTENDED (1 << 1) +#define MAX6693_CONF_BETA (1 << 2) +#define MAX6697_CONF_RESISTANCE (1 << 3) +#define MAX6697_CONF_TIMEOUT (1 << 5) +#define MAX6697_REG_ALERT_MASK 0x42 +#define MAX6697_REG_OVERT_MASK 0x43 + +#define MAX6581_REG_RESISTANCE 0x4a +#define MAX6581_REG_IDEALITY 0x4b +#define MAX6581_REG_IDEALITY_SELECT 0x4c +#define MAX6581_REG_OFFSET 0x4d +#define MAX6581_REG_OFFSET_SELECT 0x4e + +#define MAX6697_CONV_TIME 156 /* ms per channel, worst case */ + +struct max6697_chip_data { + int channels; + u32 have_ext; + u32 have_crit; + u32 have_fault; + u8 valid_conf; + const u8 *alarm_map; +}; + +struct max6697_data { + struct device *hwmon_dev; + + enum chips type; + const struct max6697_chip_data *chip; + + int update_interval; /* in milli-seconds */ + int temp_offset; /* in degrees C */ + + struct mutex update_lock; + unsigned long last_updated; /* In jiffies */ + bool valid; /* true if following fields are valid */ + + /* 1x local and up to 7x remote */ + u8 temp[8][4]; /* [nr][0]=temp [1]=ext [2]=max [3]=crit */ +#define MAX6697_TEMP_INPUT 0 +#define MAX6697_TEMP_EXT 1 +#define MAX6697_TEMP_MAX 2 +#define MAX6697_TEMP_CRIT 3 + u32 alarms; +}; + +/* Diode fault status bits on MAX6581 are right shifted by one bit */ +static const u8 max6581_alarm_map[] = { + 0, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23 }; + +static const struct max6697_chip_data max6697_chip_data[] = { + [max6581] = { + .channels = 8, + .have_crit = 0xff, + .have_ext = 0x7f, + .have_fault = 0xfe, + .valid_conf = MAX6581_CONF_EXTENDED | MAX6697_CONF_TIMEOUT, + .alarm_map = max6581_alarm_map, + }, + [max6602] = { + .channels = 5, + .have_crit = 0x12, + .have_ext = 0x02, + .have_fault = 0x1e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6622] = { + .channels = 5, + .have_crit = 0x12, + .have_ext = 0x02, + .have_fault = 0x1e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6636] = { + .channels = 7, + .have_crit = 0x72, + .have_ext = 0x02, + .have_fault = 0x7e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6689] = { + .channels = 7, + .have_crit = 0x72, + .have_ext = 0x02, + .have_fault = 0x7e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6693] = { + .channels = 7, + .have_crit = 0x72, + .have_ext = 0x02, + .have_fault = 0x7e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA | + MAX6697_CONF_TIMEOUT, + }, + [max6694] = { + .channels = 5, + .have_crit = 0x12, + .have_ext = 0x02, + .have_fault = 0x1e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA | + MAX6697_CONF_TIMEOUT, + }, + [max6697] = { + .channels = 7, + .have_crit = 0x72, + .have_ext = 0x02, + .have_fault = 0x7e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6698] = { + .channels = 7, + .have_crit = 0x72, + .have_ext = 0x02, + .have_fault = 0x0e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, + [max6699] = { + .channels = 5, + .have_crit = 0x12, + .have_ext = 0x02, + .have_fault = 0x1e, + .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT, + }, +}; + +static struct max6697_data *max6697_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max6697_data *data = i2c_get_clientdata(client); + struct max6697_data *ret = data; + int val; + int i; + u32 alarms; + + mutex_lock(&data->update_lock); + + if (data->valid && + !time_after(jiffies, data->last_updated + + msecs_to_jiffies(data->update_interval))) + goto abort; + + for (i = 0; i < data->chip->channels; i++) { + if (data->chip->have_ext & (1 << i)) { + val = i2c_smbus_read_byte_data(client, + MAX6697_REG_TEMP_EXT[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i][MAX6697_TEMP_EXT] = val; + } + + val = i2c_smbus_read_byte_data(client, MAX6697_REG_TEMP[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i][MAX6697_TEMP_INPUT] = val; + + val = i2c_smbus_read_byte_data(client, MAX6697_REG_MAX[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i][MAX6697_TEMP_MAX] = val; + + if (data->chip->have_crit & (1 << i)) { + val = i2c_smbus_read_byte_data(client, + MAX6697_REG_CRIT[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i][MAX6697_TEMP_CRIT] = val; + } + } + + alarms = 0; + for (i = 0; i < 3; i++) { + val = i2c_smbus_read_byte_data(client, MAX6697_REG_STAT(i)); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + alarms = (alarms << 8) | val; + } + data->alarms = alarms; + data->last_updated = jiffies; + data->valid = true; +abort: + mutex_unlock(&data->update_lock); + + return ret; +} + +static ssize_t show_temp_input(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct max6697_data *data = max6697_update_device(dev); + int temp; + + if (IS_ERR(data)) + return PTR_ERR(data); + + temp = (data->temp[index][MAX6697_TEMP_INPUT] - data->temp_offset) << 3; + temp |= data->temp[index][MAX6697_TEMP_EXT] >> 5; + + return sprintf(buf, "%d\n", temp * 125); +} + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct max6697_data *data = max6697_update_device(dev); + int temp; + + if (IS_ERR(data)) + return PTR_ERR(data); + + temp = data->temp[nr][index]; + temp -= data->temp_offset; + + return sprintf(buf, "%d\n", temp * 1000); +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct max6697_data *data = max6697_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + if (data->chip->alarm_map) + index = data->chip->alarm_map[index]; + + return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1); +} + +static ssize_t set_temp(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct max6697_data *data = i2c_get_clientdata(client); + long temp; + int ret; + + ret = kstrtol(buf, 10, &temp); + if (ret < 0) + return ret; + + mutex_lock(&data->update_lock); + temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset; + temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127); + data->temp[nr][index] = temp; + ret = i2c_smbus_write_byte_data(client, + index == 2 ? MAX6697_REG_MAX[nr] + : MAX6697_REG_CRIT[nr], + temp); + mutex_unlock(&data->update_lock); + + return ret < 0 ? ret : count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3); +static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 3, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 3, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4); +static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 4, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 4, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5); +static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 5, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 5, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_input, NULL, 6); +static SENSOR_DEVICE_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 6, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 6, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_input, NULL, 7); +static SENSOR_DEVICE_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 7, MAX6697_TEMP_MAX); +static SENSOR_DEVICE_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, + 7, MAX6697_TEMP_CRIT); + +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 22); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 18); +static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 19); +static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, show_alarm, NULL, 20); +static SENSOR_DEVICE_ATTR(temp7_max_alarm, S_IRUGO, show_alarm, NULL, 21); +static SENSOR_DEVICE_ATTR(temp8_max_alarm, S_IRUGO, show_alarm, NULL, 23); + +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(temp7_crit_alarm, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(temp8_crit_alarm, S_IRUGO, show_alarm, NULL, 15); + +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7); + +static struct attribute *max6697_attributes[8][7] = { + { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_crit.dev_attr.attr, + &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp6_max.dev_attr.attr, + &sensor_dev_attr_temp6_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp6_crit.dev_attr.attr, + &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp6_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp7_max.dev_attr.attr, + &sensor_dev_attr_temp7_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp7_crit.dev_attr.attr, + &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp7_fault.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp8_max.dev_attr.attr, + &sensor_dev_attr_temp8_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp8_crit.dev_attr.attr, + &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp8_fault.dev_attr.attr, + NULL + } +}; + +static const struct attribute_group max6697_group[8] = { + { .attrs = max6697_attributes[0] }, + { .attrs = max6697_attributes[1] }, + { .attrs = max6697_attributes[2] }, + { .attrs = max6697_attributes[3] }, + { .attrs = max6697_attributes[4] }, + { .attrs = max6697_attributes[5] }, + { .attrs = max6697_attributes[6] }, + { .attrs = max6697_attributes[7] }, +}; + +static void max6697_get_config_of(struct device_node *node, + struct max6697_platform_data *pdata) +{ + int len; + const __be32 *prop; + + prop = of_get_property(node, "smbus-timeout-disable", &len); + if (prop) + pdata->smbus_timeout_disable = true; + prop = of_get_property(node, "extended-range-enable", &len); + if (prop) + pdata->extended_range_enable = true; + prop = of_get_property(node, "beta-compensation-enable", &len); + if (prop) + pdata->beta_compensation = true; + prop = of_get_property(node, "alert-mask", &len); + if (prop && len == sizeof(u32)) + pdata->alert_mask = be32_to_cpu(prop[0]); + prop = of_get_property(node, "over-temperature-mask", &len); + if (prop && len == sizeof(u32)) + pdata->over_temperature_mask = be32_to_cpu(prop[0]); + prop = of_get_property(node, "resistance-cancellation", &len); + if (prop) { + if (len == sizeof(u32)) + pdata->resistance_cancellation = be32_to_cpu(prop[0]); + else + pdata->resistance_cancellation = 0xfe; + } + prop = of_get_property(node, "transistor-ideality", &len); + if (prop && len == 2 * sizeof(u32)) { + pdata->ideality_mask = be32_to_cpu(prop[0]); + pdata->ideality_value = be32_to_cpu(prop[1]); + } +} + +static int max6697_init_chip(struct i2c_client *client) +{ + struct max6697_data *data = i2c_get_clientdata(client); + struct max6697_platform_data *pdata = dev_get_platdata(&client->dev); + struct max6697_platform_data p; + const struct max6697_chip_data *chip = data->chip; + int factor = chip->channels; + int ret, reg; + + /* + * Don't touch configuration if neither platform data nor OF + * configuration was specified. If that is the case, use the + * current chip configuration. + */ + if (!pdata && !client->dev.of_node) { + reg = i2c_smbus_read_byte_data(client, MAX6697_REG_CONFIG); + if (reg < 0) + return reg; + if (data->type == max6581) { + if (reg & MAX6581_CONF_EXTENDED) + data->temp_offset = 64; + reg = i2c_smbus_read_byte_data(client, + MAX6581_REG_RESISTANCE); + if (reg < 0) + return reg; + factor += hweight8(reg); + } else { + if (reg & MAX6697_CONF_RESISTANCE) + factor++; + } + goto done; + } + + if (client->dev.of_node) { + memset(&p, 0, sizeof(p)); + max6697_get_config_of(client->dev.of_node, &p); + pdata = &p; + } + + reg = 0; + if (pdata->smbus_timeout_disable && + (chip->valid_conf & MAX6697_CONF_TIMEOUT)) { + reg |= MAX6697_CONF_TIMEOUT; + } + if (pdata->extended_range_enable && + (chip->valid_conf & MAX6581_CONF_EXTENDED)) { + reg |= MAX6581_CONF_EXTENDED; + data->temp_offset = 64; + } + if (pdata->resistance_cancellation && + (chip->valid_conf & MAX6697_CONF_RESISTANCE)) { + reg |= MAX6697_CONF_RESISTANCE; + factor++; + } + if (pdata->beta_compensation && + (chip->valid_conf & MAX6693_CONF_BETA)) { + reg |= MAX6693_CONF_BETA; + } + + ret = i2c_smbus_write_byte_data(client, MAX6697_REG_CONFIG, reg); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK, + MAX6697_MAP_BITS(pdata->alert_mask)); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK, + MAX6697_MAP_BITS(pdata->over_temperature_mask)); + if (ret < 0) + return ret; + + if (data->type == max6581) { + factor += hweight8(pdata->resistance_cancellation >> 1); + ret = i2c_smbus_write_byte_data(client, MAX6581_REG_RESISTANCE, + pdata->resistance_cancellation >> 1); + if (ret < 0) + return ret; + ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY, + pdata->ideality_mask >> 1); + if (ret < 0) + return ret; + ret = i2c_smbus_write_byte_data(client, + MAX6581_REG_IDEALITY_SELECT, + pdata->ideality_value); + if (ret < 0) + return ret; + } +done: + data->update_interval = factor * MAX6697_CONV_TIME; + return 0; +} + +static void max6697_remove_files(struct i2c_client *client) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(max6697_group); i++) + sysfs_remove_group(&client->dev.kobj, &max6697_group[i]); +} + +static int max6697_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; + struct max6697_data *data; + int i, err; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(struct max6697_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->type = id->driver_data; + data->chip = &max6697_chip_data[data->type]; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + err = max6697_init_chip(client); + if (err) + return err; + + for (i = 0; i < data->chip->channels; i++) { + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][0]); + if (err) + goto error; + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][1]); + if (err) + goto error; + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][2]); + if (err) + goto error; + + if (data->chip->have_crit & (1 << i)) { + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][3]); + if (err) + goto error; + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][4]); + if (err) + goto error; + } + if (data->chip->have_fault & (1 << i)) { + err = sysfs_create_file(&dev->kobj, + max6697_attributes[i][5]); + if (err) + goto error; + } + } + + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto error; + } + + return 0; + +error: + max6697_remove_files(client); + return err; +} + +static int max6697_remove(struct i2c_client *client) +{ + struct max6697_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + max6697_remove_files(client); + + return 0; +} + +static const struct i2c_device_id max6697_id[] = { + { "max6581", max6581 }, + { "max6602", max6602 }, + { "max6622", max6622 }, + { "max6636", max6636 }, + { "max6689", max6689 }, + { "max6693", max6693 }, + { "max6694", max6694 }, + { "max6697", max6697 }, + { "max6698", max6698 }, + { "max6699", max6699 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max6697_id); + +static struct i2c_driver max6697_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "max6697", + }, + .probe = max6697_probe, + .remove = max6697_remove, + .id_table = max6697_id, +}; + +module_i2c_driver(max6697_driver); + +MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("MAX6697 temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index cf47a59657a9..2a7f331cd3c0 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -233,7 +233,7 @@ out_err_create_16chans: return ret; } -static int __devexit mc13783_adc_remove(struct platform_device *pdev) +static int mc13783_adc_remove(struct platform_device *pdev) { struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; @@ -265,7 +265,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); static struct platform_driver mc13783_adc_driver = { - .remove = __devexit_p(mc13783_adc_remove), + .remove = mc13783_adc_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 74a6c58d0218..b5f63f9c0ce1 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -43,7 +43,7 @@ struct ntc_compensation { * The following compensation tables are from the specification of Murata NTC * Thermistors Datasheet */ -const struct ntc_compensation ncpXXwb473[] = { +static const struct ntc_compensation ncpXXwb473[] = { { .temp_C = -40, .ohm = 1747920 }, { .temp_C = -35, .ohm = 1245428 }, { .temp_C = -30, .ohm = 898485 }, @@ -79,7 +79,7 @@ const struct ntc_compensation ncpXXwb473[] = { { .temp_C = 120, .ohm = 1615 }, { .temp_C = 125, .ohm = 1406 }, }; -const struct ntc_compensation ncpXXwl333[] = { +static const struct ntc_compensation ncpXXwl333[] = { { .temp_C = -40, .ohm = 1610154 }, { .temp_C = -35, .ohm = 1130850 }, { .temp_C = -30, .ohm = 802609 }, @@ -309,7 +309,7 @@ static const struct attribute_group ntc_attr_group = { .attrs = ntc_attributes, }; -static int __devinit ntc_thermistor_probe(struct platform_device *pdev) +static int ntc_thermistor_probe(struct platform_device *pdev) { struct ntc_data *data; struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data; @@ -393,7 +393,7 @@ err_after_sysfs: return ret; } -static int __devexit ntc_thermistor_remove(struct platform_device *pdev) +static int ntc_thermistor_remove(struct platform_device *pdev) { struct ntc_data *data = platform_get_drvdata(pdev); @@ -419,7 +419,7 @@ static struct platform_driver ntc_thermistor_driver = { .owner = THIS_MODULE, }, .probe = ntc_thermistor_probe, - .remove = __devexit_p(ntc_thermistor_remove), + .remove = ntc_thermistor_remove, .id_table = ntc_thermistor_id, }; diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 91d5b2a21dd9..e35856bb79b4 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -228,7 +228,7 @@ struct pc87360_data { */ static int pc87360_probe(struct platform_device *pdev); -static int __devexit pc87360_remove(struct platform_device *pdev); +static int pc87360_remove(struct platform_device *pdev); static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, u8 reg); @@ -248,7 +248,7 @@ static struct platform_driver pc87360_driver = { .name = "pc87360", }, .probe = pc87360_probe, - .remove = __devexit_p(pc87360_remove), + .remove = pc87360_remove, }; /* @@ -1221,7 +1221,7 @@ static void pc87360_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); } -static int __devinit pc87360_probe(struct platform_device *pdev) +static int pc87360_probe(struct platform_device *pdev) { int i; struct pc87360_data *data; @@ -1375,7 +1375,7 @@ error: return err; } -static int __devexit pc87360_remove(struct platform_device *pdev) +static int pc87360_remove(struct platform_device *pdev) { struct pc87360_data *data = platform_get_drvdata(pdev); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index f185b1fa53e5..6086ad039d7d 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -956,7 +956,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); * Device detection, attach and detach */ -static int __devinit pc87427_request_regions(struct platform_device *pdev, +static int pc87427_request_regions(struct platform_device *pdev, int count) { struct resource *res; @@ -980,7 +980,7 @@ static int __devinit pc87427_request_regions(struct platform_device *pdev, return 0; } -static void __devinit pc87427_init_device(struct device *dev) +static void pc87427_init_device(struct device *dev) { struct pc87427_sio_data *sio_data = dev->platform_data; struct pc87427_data *data = dev_get_drvdata(dev); @@ -1072,7 +1072,7 @@ static void pc87427_remove_files(struct device *dev) } } -static int __devinit pc87427_probe(struct platform_device *pdev) +static int pc87427_probe(struct platform_device *pdev) { struct pc87427_sio_data *sio_data = pdev->dev.platform_data; struct pc87427_data *data; @@ -1141,7 +1141,7 @@ exit_remove_files: return err; } -static int __devexit pc87427_remove(struct platform_device *pdev) +static int pc87427_remove(struct platform_device *pdev) { struct pc87427_data *data = platform_get_drvdata(pdev); @@ -1158,7 +1158,7 @@ static struct platform_driver pc87427_driver = { .name = DRVNAME, }, .probe = pc87427_probe, - .remove = __devexit_p(pc87427_remove), + .remove = pc87427_remove, }; static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 60745a535821..4f9eb0af5229 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -72,7 +72,7 @@ config SENSORS_MAX34440 default n help If you say yes here you get hardware monitoring support for Maxim - MAX34440, MAX34441, and MAX34446. + MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461. This driver can also be built as a module. If so, the module will be called max34440. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 9652a2c92a24..6d6130752f94 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -59,10 +59,10 @@ enum chips { ltc2978, ltc3880 }; struct ltc2978_data { enum chips id; int vin_min, vin_max; - int temp_min, temp_max; + int temp_min, temp_max[2]; int vout_min[8], vout_max[8]; int iout_max[2]; - int temp2_max[2]; + int temp2_max; struct pmbus_driver_info info; }; @@ -113,9 +113,10 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, ret = pmbus_read_word_data(client, page, LTC2978_MFR_TEMPERATURE_PEAK); if (ret >= 0) { - if (lin11_to_val(ret) > lin11_to_val(data->temp_max)) - data->temp_max = ret; - ret = data->temp_max; + if (lin11_to_val(ret) + > lin11_to_val(data->temp_max[page])) + data->temp_max[page] = ret; + ret = data->temp_max[page]; } break; case PMBUS_VIRT_RESET_VOUT_HISTORY: @@ -204,10 +205,9 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, page, LTC3880_MFR_TEMPERATURE2_PEAK); if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->temp2_max[page])) - data->temp2_max[page] = ret; - ret = data->temp2_max[page]; + if (lin11_to_val(ret) > lin11_to_val(data->temp2_max)) + data->temp2_max = ret; + ret = data->temp2_max; } break; case PMBUS_VIRT_READ_VIN_MIN: @@ -248,11 +248,11 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, switch (reg) { case PMBUS_VIRT_RESET_IOUT_HISTORY: - data->iout_max[page] = 0x7fff; + data->iout_max[page] = 0x7c00; ret = ltc2978_clear_peaks(client, page, data->id); break; case PMBUS_VIRT_RESET_TEMP2_HISTORY: - data->temp2_max[page] = 0x7fff; + data->temp2_max = 0x7c00; ret = ltc2978_clear_peaks(client, page, data->id); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: @@ -262,12 +262,12 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, break; case PMBUS_VIRT_RESET_VIN_HISTORY: data->vin_min = 0x7bff; - data->vin_max = 0; + data->vin_max = 0x7c00; ret = ltc2978_clear_peaks(client, page, data->id); break; case PMBUS_VIRT_RESET_TEMP_HISTORY: data->temp_min = 0x7bff; - data->temp_max = 0x7fff; + data->temp_max[page] = 0x7c00; ret = ltc2978_clear_peaks(client, page, data->id); break; default: @@ -321,12 +321,14 @@ static int ltc2978_probe(struct i2c_client *client, info = &data->info; info->write_word_data = ltc2978_write_word_data; - data->vout_min[0] = 0xffff; data->vin_min = 0x7bff; + data->vin_max = 0x7c00; data->temp_min = 0x7bff; - data->temp_max = 0x7fff; + for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) + data->temp_max[i] = 0x7c00; + data->temp2_max = 0x7c00; - switch (id->driver_data) { + switch (data->id) { case ltc2978: info->read_word_data = ltc2978_read_word_data; info->pages = 8; @@ -336,7 +338,6 @@ static int ltc2978_probe(struct i2c_client *client, for (i = 1; i < 8; i++) { info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; - data->vout_min[i] = 0xffff; } break; case ltc3880: @@ -352,11 +353,14 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - data->vout_min[1] = 0xffff; + data->iout_max[0] = 0x7c00; + data->iout_max[1] = 0x7c00; break; default: return -ENODEV; } + for (i = 0; i < info->pages; i++) + data->vout_min[i] = 0xffff; return pmbus_do_probe(client, id, info); } diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 2ada7b021fbe..7e930c3ce1ab 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -2,6 +2,7 @@ * Hardware monitoring driver for Maxim MAX34440/MAX34441 * * Copyright (c) 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +26,7 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { max34440, max34441, max34446 }; +enum chips { max34440, max34441, max34446, max34460, max34461 }; #define MAX34440_MFR_VOUT_PEAK 0xd4 #define MAX34440_MFR_IOUT_PEAK 0xd5 @@ -87,7 +88,8 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) MAX34446_MFR_POUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_AVG: - if (data->id != max34446) + if (data->id != max34446 && data->id != max34460 && + data->id != max34461) return -ENXIO; ret = pmbus_read_word_data(client, page, MAX34446_MFR_TEMPERATURE_AVG); @@ -322,6 +324,73 @@ static struct pmbus_driver_info max34440_info[] = { .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, + [max34460] = { + .pages = 18, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 2, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .read_byte_data = max34440_read_byte_data, + .read_word_data = max34440_read_word_data, + .write_word_data = max34440_write_word_data, + }, + [max34461] = { + .pages = 23, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 2, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + /* page 16 is reserved */ + .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .read_byte_data = max34440_read_byte_data, + .read_word_data = max34440_read_word_data, + .write_word_data = max34440_write_word_data, + }, }; static int max34440_probe(struct i2c_client *client, @@ -343,6 +412,8 @@ static const struct i2c_device_id max34440_id[] = { {"max34440", max34440}, {"max34441", max34441}, {"max34446", max34446}, + {"max34460", max34460}, + {"max34461", max34461}, {} }; MODULE_DEVICE_TABLE(i2c, max34440_id); diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 3fe03dc47eb7..fa9beb3eb60c 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -2,6 +2,7 @@ * pmbus.h - Common defines and structures for PMBus devices * * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -177,6 +178,13 @@ #define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28) #define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29) +#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 30) +#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 31) +#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 32) +#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33) +#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34) +#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35) + /* * CAPABILITY */ @@ -317,6 +325,8 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_STATUS_TEMP (1 << 15) #define PMBUS_HAVE_STATUS_FAN12 (1 << 16) #define PMBUS_HAVE_STATUS_FAN34 (1 << 17) +#define PMBUS_HAVE_VMON (1 << 18) +#define PMBUS_HAVE_STATUS_VMON (1 << 19) enum pmbus_data_format { linear = 0, direct, vid }; @@ -359,6 +369,7 @@ struct pmbus_driver_info { /* Function declarations */ +void pmbus_clear_cache(struct i2c_client *client); int pmbus_set_page(struct i2c_client *client, u8 page); int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 7d19b1bb9ce6..9add60920ac0 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2,6 +2,7 @@ * Hardware monitoring driver for PMBus devices * * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,45 +32,10 @@ #include "pmbus.h" /* - * Constants needed to determine number of sensors, booleans, and labels. + * Number of additional attribute pointers to allocate + * with each call to krealloc */ -#define PMBUS_MAX_INPUT_SENSORS 22 /* 10*volt, 7*curr, 5*power */ -#define PMBUS_VOUT_SENSORS_PER_PAGE 9 /* input, min, max, lcrit, - crit, lowest, highest, avg, - reset */ -#define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit, - lowest, highest, avg, - reset */ -#define PMBUS_POUT_SENSORS_PER_PAGE 7 /* input, cap, max, crit, - * highest, avg, reset - */ -#define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */ -#define PMBUS_MAX_SENSORS_PER_TEMP 9 /* input, min, max, lcrit, - * crit, lowest, highest, avg, - * reset - */ - -#define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm, - lcrit_alarm, crit_alarm; - c: alarm, crit_alarm; - p: crit_alarm */ -#define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm, - lcrit_alarm, crit_alarm */ -#define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm, - crit_alarm */ -#define PMBUS_POUT_BOOLEANS_PER_PAGE 3 /* cap_alarm, alarm, crit_alarm - */ -#define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */ -#define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm, - lcrit_alarm, crit_alarm */ - -#define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */ - -/* - * status, status_vout, status_iout, status_fans, status_fan34, and status_temp - * are paged. status_input is unpaged. - */ -#define PB_NUM_STATUS_REG (PMBUS_PAGES * 6 + 1) +#define PMBUS_ATTR_ALLOC_SIZE 32 /* * Index into status register array, per status register group @@ -79,14 +45,18 @@ #define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) #define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) #define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) -#define PB_STATUS_INPUT_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) -#define PB_STATUS_TEMP_BASE (PB_STATUS_INPUT_BASE + 1) +#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) +#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES) +#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1) + +#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1) #define PMBUS_NAME_SIZE 24 struct pmbus_sensor { + struct pmbus_sensor *next; char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ - struct sensor_device_attribute attribute; + struct device_attribute attribute; u8 page; /* page number */ u16 reg; /* register */ enum pmbus_sensor_classes class; /* sensor class */ @@ -94,19 +64,28 @@ struct pmbus_sensor { int data; /* Sensor data. Negative if there was a read error */ }; +#define to_pmbus_sensor(_attr) \ + container_of(_attr, struct pmbus_sensor, attribute) struct pmbus_boolean { char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ struct sensor_device_attribute attribute; + struct pmbus_sensor *s1; + struct pmbus_sensor *s2; }; +#define to_pmbus_boolean(_attr) \ + container_of(_attr, struct pmbus_boolean, attribute) struct pmbus_label { char name[PMBUS_NAME_SIZE]; /* sysfs label name */ - struct sensor_device_attribute attribute; + struct device_attribute attribute; char label[PMBUS_NAME_SIZE]; /* label */ }; +#define to_pmbus_label(_attr) \ + container_of(_attr, struct pmbus_label, attribute) struct pmbus_data { + struct device *dev; struct device *hwmon_dev; u32 flags; /* from platform data */ @@ -117,29 +96,9 @@ struct pmbus_data { int max_attributes; int num_attributes; - struct attribute **attributes; struct attribute_group group; - /* - * Sensors cover both sensor and limit registers. - */ - int max_sensors; - int num_sensors; struct pmbus_sensor *sensors; - /* - * Booleans are used for alarms. - * Values are determined from status registers. - */ - int max_booleans; - int num_booleans; - struct pmbus_boolean *booleans; - /* - * Labels are used to map generic names (e.g., "in1") - * to PMBus specific names (e.g., "vin" or "vout1"). - */ - int max_labels; - int num_labels; - struct pmbus_label *labels; struct mutex update_lock; bool valid; @@ -150,10 +109,19 @@ struct pmbus_data { * so we keep them all together. */ u8 status[PB_NUM_STATUS_REG]; + u8 status_register; u8 currpage; }; +void pmbus_clear_cache(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + data->valid = false; +} +EXPORT_SYMBOL_GPL(pmbus_clear_cache); + int pmbus_set_page(struct i2c_client *client, u8 page) { struct pmbus_data *data = i2c_get_clientdata(client); @@ -318,9 +286,10 @@ EXPORT_SYMBOL_GPL(pmbus_clear_faults); static int pmbus_check_status_cml(struct i2c_client *client) { + struct pmbus_data *data = i2c_get_clientdata(client); int status, status2; - status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE); + status = _pmbus_read_byte_data(client, -1, data->status_register); if (status < 0 || (status & PB_STATUS_CML)) { status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) @@ -329,29 +298,30 @@ static int pmbus_check_status_cml(struct i2c_client *client) return 0; } -bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) +static bool pmbus_check_register(struct i2c_client *client, + int (*func)(struct i2c_client *client, + int page, int reg), + int page, int reg) { int rv; struct pmbus_data *data = i2c_get_clientdata(client); - rv = _pmbus_read_byte_data(client, page, reg); + rv = func(client, page, reg); if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) rv = pmbus_check_status_cml(client); pmbus_clear_fault_page(client, -1); return rv >= 0; } + +bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) +{ + return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); +} EXPORT_SYMBOL_GPL(pmbus_check_byte_register); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) { - int rv; - struct pmbus_data *data = i2c_get_clientdata(client); - - rv = _pmbus_read_word_data(client, page, reg); - if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) - rv = pmbus_check_status_cml(client); - pmbus_clear_fault_page(client, -1); - return rv >= 0; + return pmbus_check_register(client, _pmbus_read_word_data, page, reg); } EXPORT_SYMBOL_GPL(pmbus_check_word_register); @@ -363,53 +333,43 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_get_driver_info); +static struct _pmbus_status { + u32 func; + u16 base; + u16 reg; +} pmbus_status[] = { + { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT }, + { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT }, + { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE, + PMBUS_STATUS_TEMPERATURE }, + { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 }, + { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 }, +}; + static struct pmbus_data *pmbus_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct pmbus_data *data = i2c_get_clientdata(client); const struct pmbus_driver_info *info = data->info; + struct pmbus_sensor *sensor; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i; + int i, j; - for (i = 0; i < info->pages; i++) + for (i = 0; i < info->pages; i++) { data->status[PB_STATUS_BASE + i] = _pmbus_read_byte_data(client, i, - PMBUS_STATUS_BYTE); - for (i = 0; i < info->pages; i++) { - if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT)) - continue; - data->status[PB_STATUS_VOUT_BASE + i] - = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT); - } - for (i = 0; i < info->pages; i++) { - if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT)) - continue; - data->status[PB_STATUS_IOUT_BASE + i] - = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT); - } - for (i = 0; i < info->pages; i++) { - if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP)) - continue; - data->status[PB_STATUS_TEMP_BASE + i] - = _pmbus_read_byte_data(client, i, - PMBUS_STATUS_TEMPERATURE); - } - for (i = 0; i < info->pages; i++) { - if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12)) - continue; - data->status[PB_STATUS_FAN_BASE + i] - = _pmbus_read_byte_data(client, i, - PMBUS_STATUS_FAN_12); - } - - for (i = 0; i < info->pages; i++) { - if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34)) - continue; - data->status[PB_STATUS_FAN34_BASE + i] - = _pmbus_read_byte_data(client, i, - PMBUS_STATUS_FAN_34); + data->status_register); + for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { + struct _pmbus_status *s = &pmbus_status[j]; + + if (!(info->func[i] & s->func)) + continue; + data->status[s->base + i] + = _pmbus_read_byte_data(client, i, + s->reg); + } } if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) @@ -417,9 +377,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) = _pmbus_read_byte_data(client, 0, PMBUS_STATUS_INPUT); - for (i = 0; i < data->num_sensors; i++) { - struct pmbus_sensor *sensor = &data->sensors[i]; + if (info->func[0] & PMBUS_HAVE_STATUS_VMON) + data->status[PB_STATUS_VMON_BASE] + = _pmbus_read_byte_data(client, 0, + PMBUS_VIRT_STATUS_VMON); + for (sensor = data->sensors; sensor; sensor = sensor->next) { if (!data->valid || sensor->update) sensor->data = _pmbus_read_word_data(client, @@ -657,7 +620,7 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, static u16 pmbus_data2reg_vid(struct pmbus_data *data, enum pmbus_sensor_classes class, long val) { - val = SENSORS_LIMIT(val, 500, 1600); + val = clamp_val(val, 500, 1600); return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); } @@ -684,25 +647,20 @@ static u16 pmbus_data2reg(struct pmbus_data *data, /* * Return boolean calculated from converted data. - * <index> defines a status register index and mask, and optionally - * two sensor indexes. - * The upper half-word references the two sensors, - * two sensor indices. - * The upper half-word references the two optional sensors, - * the lower half word references status register and mask. - * The function returns true if (status[reg] & mask) is true and, - * if specified, if v1 >= v2. - * To determine if an object exceeds upper limits, specify <v, limit>. - * To determine if an object exceeds lower limits, specify <limit, v>. + * <index> defines a status register index and mask. + * The mask is in the lower 8 bits, the register index is in bits 8..23. * - * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of - * index are set. s1 and s2 (the sensor index values) are zero in this case. - * The function returns true if (status[reg] & mask) is true. + * The associated pmbus_boolean structure contains optional pointers to two + * sensor attributes. If specified, those attributes are compared against each + * other to determine if a limit has been exceeded. * - * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against - * a specified limit has to be performed to determine the boolean result. + * If the sensor attribute pointers are NULL, the function returns true if + * (status[reg] & mask) is true. + * + * If sensor attribute pointers are provided, a comparison against a specified + * limit has to be performed to determine the boolean result. * In this case, the function returns true if v1 >= v2 (where v1 and v2 are - * sensor values referenced by sensor indices s1 and s2). + * sensor values referenced by sensor attribute pointers s1 and s2). * * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>. * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>. @@ -710,11 +668,12 @@ static u16 pmbus_data2reg(struct pmbus_data *data, * If a negative value is stored in any of the referenced registers, this value * reflects an error code which will be returned. */ -static int pmbus_get_boolean(struct pmbus_data *data, int index) +static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, + int index) { - u8 s1 = (index >> 24) & 0xff; - u8 s2 = (index >> 16) & 0xff; - u8 reg = (index >> 8) & 0xff; + struct pmbus_sensor *s1 = b->s1; + struct pmbus_sensor *s2 = b->s2; + u16 reg = (index >> 8) & 0xffff; u8 mask = index & 0xff; int ret, status; u8 regval; @@ -724,21 +683,21 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index) return status; regval = status & mask; - if (!s1 && !s2) + if (!s1 && !s2) { ret = !!regval; - else { + } else if (!s1 || !s2) { + BUG(); + return 0; + } else { long v1, v2; - struct pmbus_sensor *sensor1, *sensor2; - sensor1 = &data->sensors[s1]; - if (sensor1->data < 0) - return sensor1->data; - sensor2 = &data->sensors[s2]; - if (sensor2->data < 0) - return sensor2->data; + if (s1->data < 0) + return s1->data; + if (s2->data < 0) + return s2->data; - v1 = pmbus_reg2data(data, sensor1); - v2 = pmbus_reg2data(data, sensor2); + v1 = pmbus_reg2data(data, s1); + v2 = pmbus_reg2data(data, s2); ret = !!(regval && v1 >= v2); } return ret; @@ -748,23 +707,22 @@ static ssize_t pmbus_show_boolean(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct pmbus_boolean *boolean = to_pmbus_boolean(attr); struct pmbus_data *data = pmbus_update_device(dev); int val; - val = pmbus_get_boolean(data, attr->index); + val = pmbus_get_boolean(data, boolean, attr->index); if (val < 0) return val; return snprintf(buf, PAGE_SIZE, "%d\n", val); } static ssize_t pmbus_show_sensor(struct device *dev, - struct device_attribute *da, char *buf) + struct device_attribute *devattr, char *buf) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct pmbus_data *data = pmbus_update_device(dev); - struct pmbus_sensor *sensor; + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); - sensor = &data->sensors[attr->index]; if (sensor->data < 0) return sensor->data; @@ -775,10 +733,9 @@ static ssize_t pmbus_set_sensor(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct pmbus_data *data = i2c_get_clientdata(client); - struct pmbus_sensor *sensor = &data->sensors[attr->index]; + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); ssize_t rv = count; long val = 0; int ret; @@ -793,7 +750,7 @@ static ssize_t pmbus_set_sensor(struct device *dev, if (ret < 0) rv = ret; else - data->sensors[attr->index].data = regval; + sensor->data = regval; mutex_unlock(&data->update_lock); return rv; } @@ -801,102 +758,132 @@ static ssize_t pmbus_set_sensor(struct device *dev, static ssize_t pmbus_show_label(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct pmbus_data *data = i2c_get_clientdata(client); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct pmbus_label *label = to_pmbus_label(da); - return snprintf(buf, PAGE_SIZE, "%s\n", - data->labels[attr->index].label); + return snprintf(buf, PAGE_SIZE, "%s\n", label->label); } -#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set) \ -do { \ - struct sensor_device_attribute *a \ - = &data->_type##s[data->num_##_type##s].attribute; \ - BUG_ON(data->num_attributes >= data->max_attributes); \ - sysfs_attr_init(&a->dev_attr.attr); \ - a->dev_attr.attr.name = _name; \ - a->dev_attr.attr.mode = _mode; \ - a->dev_attr.show = _show; \ - a->dev_attr.store = _set; \ - a->index = _idx; \ - data->attributes[data->num_attributes] = &a->dev_attr.attr; \ - data->num_attributes++; \ -} while (0) - -#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx) \ - PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type, \ - pmbus_show_##_type, NULL) - -#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx) \ - PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type, \ - pmbus_show_##_type, pmbus_set_##_type) - -static void pmbus_add_boolean(struct pmbus_data *data, - const char *name, const char *type, int seq, - int idx) +static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) { - struct pmbus_boolean *boolean; - - BUG_ON(data->num_booleans >= data->max_booleans); - - boolean = &data->booleans[data->num_booleans]; + if (data->num_attributes >= data->max_attributes - 1) { + int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; + void *new_attrs = krealloc(data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + data->max_attributes = new_max_attrs; + } - snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", - name, seq, type); - PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx); - data->num_booleans++; + data->group.attrs[data->num_attributes++] = attr; + data->group.attrs[data->num_attributes] = NULL; + return 0; } -static void pmbus_add_boolean_reg(struct pmbus_data *data, - const char *name, const char *type, - int seq, int reg, int bit) +static void pmbus_dev_attr_init(struct device_attribute *dev_attr, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) { - pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit); + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = mode; + dev_attr->show = show; + dev_attr->store = store; } -static void pmbus_add_boolean_cmp(struct pmbus_data *data, - const char *name, const char *type, - int seq, int i1, int i2, int reg, int mask) +static void pmbus_attr_init(struct sensor_device_attribute *a, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count), + int idx) { - pmbus_add_boolean(data, name, type, seq, - (i1 << 24) | (i2 << 16) | (reg << 8) | mask); + pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store); + a->index = idx; } -static void pmbus_add_sensor(struct pmbus_data *data, +static int pmbus_add_boolean(struct pmbus_data *data, const char *name, const char *type, int seq, - int page, int reg, enum pmbus_sensor_classes class, - bool update, bool readonly) + struct pmbus_sensor *s1, + struct pmbus_sensor *s2, + u16 reg, u8 mask) +{ + struct pmbus_boolean *boolean; + struct sensor_device_attribute *a; + + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); + if (!boolean) + return -ENOMEM; + + a = &boolean->attribute; + + snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", + name, seq, type); + boolean->s1 = s1; + boolean->s2 = s2; + pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL, + (reg << 8) | mask); + + return pmbus_add_attribute(data, &a->dev_attr.attr); +} + +static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, + const char *name, const char *type, + int seq, int page, int reg, + enum pmbus_sensor_classes class, + bool update, bool readonly) { struct pmbus_sensor *sensor; + struct device_attribute *a; - BUG_ON(data->num_sensors >= data->max_sensors); + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; - sensor = &data->sensors[data->num_sensors]; snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", name, seq, type); sensor->page = page; sensor->reg = reg; sensor->class = class; sensor->update = update; - if (readonly) - PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, - data->num_sensors); - else - PMBUS_ADD_SET_ATTR(data, sensor->name, sensor, - data->num_sensors); - data->num_sensors++; + pmbus_dev_attr_init(a, sensor->name, + readonly ? S_IRUGO : S_IRUGO | S_IWUSR, + pmbus_show_sensor, pmbus_set_sensor); + + if (pmbus_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; } -static void pmbus_add_label(struct pmbus_data *data, - const char *name, int seq, - const char *lstring, int index) +static int pmbus_add_label(struct pmbus_data *data, + const char *name, int seq, + const char *lstring, int index) { struct pmbus_label *label; + struct device_attribute *a; - BUG_ON(data->num_labels >= data->max_labels); + label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); + if (!label) + return -ENOMEM; + + a = &label->attribute; - label = &data->labels[data->num_labels]; snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); if (!index) strncpy(label->label, lstring, sizeof(label->label) - 1); @@ -904,65 +891,8 @@ static void pmbus_add_label(struct pmbus_data *data, snprintf(label->label, sizeof(label->label), "%s%d", lstring, index); - PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels); - data->num_labels++; -} - -/* - * Determine maximum number of sensors, booleans, and labels. - * To keep things simple, only make a rough high estimate. - */ -static void pmbus_find_max_attr(struct i2c_client *client, - struct pmbus_data *data) -{ - const struct pmbus_driver_info *info = data->info; - int page, max_sensors, max_booleans, max_labels; - - max_sensors = PMBUS_MAX_INPUT_SENSORS; - max_booleans = PMBUS_MAX_INPUT_BOOLEANS; - max_labels = PMBUS_MAX_INPUT_LABELS; - - for (page = 0; page < info->pages; page++) { - if (info->func[page] & PMBUS_HAVE_VOUT) { - max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE; - max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE; - max_labels++; - } - if (info->func[page] & PMBUS_HAVE_IOUT) { - max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE; - max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE; - max_labels++; - } - if (info->func[page] & PMBUS_HAVE_POUT) { - max_sensors += PMBUS_POUT_SENSORS_PER_PAGE; - max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE; - max_labels++; - } - if (info->func[page] & PMBUS_HAVE_FAN12) { - max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; - max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; - } - if (info->func[page] & PMBUS_HAVE_FAN34) { - max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; - max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; - } - if (info->func[page] & PMBUS_HAVE_TEMP) { - max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; - max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; - } - if (info->func[page] & PMBUS_HAVE_TEMP2) { - max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; - max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; - } - if (info->func[page] & PMBUS_HAVE_TEMP3) { - max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; - max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; - } - } - data->max_sensors = max_sensors; - data->max_booleans = max_booleans; - data->max_labels = max_labels; - data->max_attributes = max_sensors + max_booleans + max_labels; + pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL); + return pmbus_add_attribute(data, &a->attr); } /* @@ -975,12 +905,12 @@ static void pmbus_find_max_attr(struct i2c_client *client, */ struct pmbus_limit_attr { u16 reg; /* Limit register */ + u16 sbit; /* Alarm attribute status bit */ bool update; /* True if register needs updates */ bool low; /* True if low limit; for limits with compare functions only */ const char *attr; /* Attribute name */ const char *alarm; /* Alarm attribute name */ - u32 sbit; /* Alarm attribute status bit */ }; /* @@ -988,7 +918,9 @@ struct pmbus_limit_attr { * description includes a reference to the associated limit attributes. */ struct pmbus_sensor_attr { - u8 reg; /* sensor register */ + u16 reg; /* sensor register */ + u8 gbit; /* generic status bit */ + u8 nlimit; /* # of limit registers */ enum pmbus_sensor_classes class;/* sensor class */ const char *label; /* sensor label */ bool paged; /* true if paged sensor */ @@ -997,47 +929,47 @@ struct pmbus_sensor_attr { u32 func; /* sensor mask */ u32 sfunc; /* sensor status mask */ int sbase; /* status base register */ - u32 gbit; /* generic status bit */ const struct pmbus_limit_attr *limit;/* limit registers */ - int nlimit; /* # of limit registers */ }; /* * Add a set of limit attributes and, if supported, the associated * alarm attributes. + * returns 0 if no alarm register found, 1 if an alarm register was found, + * < 0 on errors. */ -static bool pmbus_add_limit_attrs(struct i2c_client *client, - struct pmbus_data *data, - const struct pmbus_driver_info *info, - const char *name, int index, int page, - int cbase, - const struct pmbus_sensor_attr *attr) +static int pmbus_add_limit_attrs(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, int index, int page, + struct pmbus_sensor *base, + const struct pmbus_sensor_attr *attr) { const struct pmbus_limit_attr *l = attr->limit; int nlimit = attr->nlimit; - bool have_alarm = false; - int i, cindex; + int have_alarm = 0; + int i, ret; + struct pmbus_sensor *curr; for (i = 0; i < nlimit; i++) { if (pmbus_check_word_register(client, page, l->reg)) { - cindex = data->num_sensors; - pmbus_add_sensor(data, name, l->attr, index, page, - l->reg, attr->class, - attr->update || l->update, - false); + curr = pmbus_add_sensor(data, name, l->attr, index, + page, l->reg, attr->class, + attr->update || l->update, + false); + if (!curr) + return -ENOMEM; if (l->sbit && (info->func[page] & attr->sfunc)) { - if (attr->compare) { - pmbus_add_boolean_cmp(data, name, - l->alarm, index, - l->low ? cindex : cbase, - l->low ? cbase : cindex, - attr->sbase + page, l->sbit); - } else { - pmbus_add_boolean_reg(data, name, - l->alarm, index, - attr->sbase + page, l->sbit); - } - have_alarm = true; + ret = pmbus_add_boolean(data, name, + l->alarm, index, + attr->compare ? l->low ? curr : base + : NULL, + attr->compare ? l->low ? base : curr + : NULL, + attr->sbase + page, l->sbit); + if (ret) + return ret; + have_alarm = 1; } } l++; @@ -1045,45 +977,59 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client, return have_alarm; } -static void pmbus_add_sensor_attrs_one(struct i2c_client *client, - struct pmbus_data *data, - const struct pmbus_driver_info *info, - const char *name, - int index, int page, - const struct pmbus_sensor_attr *attr) +static int pmbus_add_sensor_attrs_one(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, + int index, int page, + const struct pmbus_sensor_attr *attr) { - bool have_alarm; - int cbase = data->num_sensors; - - if (attr->label) - pmbus_add_label(data, name, index, attr->label, - attr->paged ? page + 1 : 0); - pmbus_add_sensor(data, name, "input", index, page, attr->reg, - attr->class, true, true); + struct pmbus_sensor *base; + int ret; + + if (attr->label) { + ret = pmbus_add_label(data, name, index, attr->label, + attr->paged ? page + 1 : 0); + if (ret) + return ret; + } + base = pmbus_add_sensor(data, name, "input", index, page, attr->reg, + attr->class, true, true); + if (!base) + return -ENOMEM; if (attr->sfunc) { - have_alarm = pmbus_add_limit_attrs(client, data, info, name, - index, page, cbase, attr); + ret = pmbus_add_limit_attrs(client, data, info, name, + index, page, base, attr); + if (ret < 0) + return ret; /* * Add generic alarm attribute only if there are no individual * alarm attributes, if there is a global alarm bit, and if * the generic status register for this page is accessible. */ - if (!have_alarm && attr->gbit && - pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE)) - pmbus_add_boolean_reg(data, name, "alarm", index, - PB_STATUS_BASE + page, - attr->gbit); + if (!ret && attr->gbit && + pmbus_check_byte_register(client, page, + data->status_register)) { + ret = pmbus_add_boolean(data, name, "alarm", index, + NULL, NULL, + PB_STATUS_BASE + page, + attr->gbit); + if (ret) + return ret; + } } + return 0; } -static void pmbus_add_sensor_attrs(struct i2c_client *client, - struct pmbus_data *data, - const char *name, - const struct pmbus_sensor_attr *attrs, - int nattrs) +static int pmbus_add_sensor_attrs(struct i2c_client *client, + struct pmbus_data *data, + const char *name, + const struct pmbus_sensor_attr *attrs, + int nattrs) { const struct pmbus_driver_info *info = data->info; int index, i; + int ret; index = 1; for (i = 0; i < nattrs; i++) { @@ -1093,12 +1039,16 @@ static void pmbus_add_sensor_attrs(struct i2c_client *client, for (page = 0; page < pages; page++) { if (!(info->func[page] & attrs->func)) continue; - pmbus_add_sensor_attrs_one(client, data, info, name, - index, page, attrs); + ret = pmbus_add_sensor_attrs_one(client, data, info, + name, index, page, + attrs); + if (ret) + return ret; index++; } attrs++; } + return 0; } static const struct pmbus_limit_attr vin_limit_attrs[] = { @@ -1140,6 +1090,30 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, }; +static const struct pmbus_limit_attr vmon_limit_attrs[] = { + { + .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + } +}; + static const struct pmbus_limit_attr vout_limit_attrs[] = { { .reg = PMBUS_VOUT_UV_WARN_LIMIT, @@ -1191,6 +1165,15 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .limit = vin_limit_attrs, .nlimit = ARRAY_SIZE(vin_limit_attrs), }, { + .reg = PMBUS_VIRT_READ_VMON, + .class = PSC_VOLTAGE_IN, + .label = "vmon", + .func = PMBUS_HAVE_VMON, + .sfunc = PMBUS_HAVE_STATUS_VMON, + .sbase = PB_STATUS_VMON_BASE, + .limit = vmon_limit_attrs, + .nlimit = ARRAY_SIZE(vmon_limit_attrs), + }, { .reg = PMBUS_READ_VCAP, .class = PSC_VOLTAGE_IN, .label = "vcap", @@ -1553,12 +1536,13 @@ static const u32 pmbus_fan_status_flags[] = { }; /* Fans */ -static void pmbus_add_fan_attributes(struct i2c_client *client, - struct pmbus_data *data) +static int pmbus_add_fan_attributes(struct i2c_client *client, + struct pmbus_data *data) { const struct pmbus_driver_info *info = data->info; int index = 1; int page; + int ret; for (page = 0; page < info->pages; page++) { int f; @@ -1584,9 +1568,10 @@ static void pmbus_add_fan_attributes(struct i2c_client *client, (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) continue; - pmbus_add_sensor(data, "fan", "input", index, page, - pmbus_fan_registers[f], PSC_FAN, true, - true); + if (pmbus_add_sensor(data, "fan", "input", index, + page, pmbus_fan_registers[f], + PSC_FAN, true, true) == NULL) + return -ENOMEM; /* * Each fan status register covers multiple fans, @@ -1601,39 +1586,55 @@ static void pmbus_add_fan_attributes(struct i2c_client *client, base = PB_STATUS_FAN34_BASE + page; else base = PB_STATUS_FAN_BASE + page; - pmbus_add_boolean_reg(data, "fan", "alarm", - index, base, + ret = pmbus_add_boolean(data, "fan", + "alarm", index, NULL, NULL, base, PB_FAN_FAN1_WARNING >> (f & 1)); - pmbus_add_boolean_reg(data, "fan", "fault", - index, base, + if (ret) + return ret; + ret = pmbus_add_boolean(data, "fan", + "fault", index, NULL, NULL, base, PB_FAN_FAN1_FAULT >> (f & 1)); + if (ret) + return ret; } index++; } } + return 0; } -static void pmbus_find_attributes(struct i2c_client *client, - struct pmbus_data *data) +static int pmbus_find_attributes(struct i2c_client *client, + struct pmbus_data *data) { + int ret; + /* Voltage sensors */ - pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, - ARRAY_SIZE(voltage_attributes)); + ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, + ARRAY_SIZE(voltage_attributes)); + if (ret) + return ret; /* Current sensors */ - pmbus_add_sensor_attrs(client, data, "curr", current_attributes, - ARRAY_SIZE(current_attributes)); + ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes, + ARRAY_SIZE(current_attributes)); + if (ret) + return ret; /* Power sensors */ - pmbus_add_sensor_attrs(client, data, "power", power_attributes, - ARRAY_SIZE(power_attributes)); + ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes, + ARRAY_SIZE(power_attributes)); + if (ret) + return ret; /* Temperature sensors */ - pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, - ARRAY_SIZE(temp_attributes)); + ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, + ARRAY_SIZE(temp_attributes)); + if (ret) + return ret; /* Fans */ - pmbus_add_fan_attributes(client, data); + ret = pmbus_add_fan_attributes(client, data); + return ret; } /* @@ -1672,127 +1673,119 @@ static int pmbus_identify_common(struct i2c_client *client, } } - /* Determine maximum number of sensors, booleans, and labels */ - pmbus_find_max_attr(client, data); pmbus_clear_fault_page(client, 0); return 0; } -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info) +static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, + struct pmbus_driver_info *info) { - const struct pmbus_platform_data *pdata = client->dev.platform_data; - struct pmbus_data *data; + struct device *dev = &client->dev; int ret; - if (!info) { - dev_err(&client->dev, "Missing chip information"); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE - | I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; - - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&client->dev, "No memory to allocate driver data\n"); - return -ENOMEM; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - /* Bail out if PMBus status register does not exist. */ - if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) { - dev_err(&client->dev, "PMBus status register not found\n"); - return -ENODEV; + /* + * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try + * to use PMBUS_STATUS_WORD instead if that is the case. + * Bail out if both registers are not supported. + */ + data->status_register = PMBUS_STATUS_BYTE; + ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); + if (ret < 0 || ret == 0xff) { + data->status_register = PMBUS_STATUS_WORD; + ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); + if (ret < 0 || ret == 0xffff) { + dev_err(dev, "PMBus status register not found\n"); + return -ENODEV; + } } - if (pdata) - data->flags = pdata->flags; - data->info = info; - pmbus_clear_faults(client); if (info->identify) { ret = (*info->identify)(client, info); if (ret < 0) { - dev_err(&client->dev, "Chip identification failed\n"); + dev_err(dev, "Chip identification failed\n"); return ret; } } if (info->pages <= 0 || info->pages > PMBUS_PAGES) { - dev_err(&client->dev, "Bad number of PMBus pages: %d\n", - info->pages); + dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages); return -ENODEV; } ret = pmbus_identify_common(client, data); if (ret < 0) { - dev_err(&client->dev, "Failed to identify chip capabilities\n"); + dev_err(dev, "Failed to identify chip capabilities\n"); return ret; } + return 0; +} - ret = -ENOMEM; - data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor) - * data->max_sensors, GFP_KERNEL); - if (!data->sensors) { - dev_err(&client->dev, "No memory to allocate sensor data\n"); - return -ENOMEM; - } +int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, + struct pmbus_driver_info *info) +{ + struct device *dev = &client->dev; + const struct pmbus_platform_data *pdata = dev->platform_data; + struct pmbus_data *data; + int ret; - data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean) - * data->max_booleans, GFP_KERNEL); - if (!data->booleans) { - dev_err(&client->dev, "No memory to allocate boolean data\n"); - return -ENOMEM; - } + if (!info) + return -ENODEV; - data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label) - * data->max_labels, GFP_KERNEL); - if (!data->labels) { - dev_err(&client->dev, "No memory to allocate label data\n"); - return -ENOMEM; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE + | I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; - data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *) - * data->max_attributes, GFP_KERNEL); - if (!data->attributes) { - dev_err(&client->dev, "No memory to allocate attribute data\n"); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - } - pmbus_find_attributes(client, data); + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->dev = dev; + + if (pdata) + data->flags = pdata->flags; + data->info = info; + + ret = pmbus_init_common(client, data, info); + if (ret < 0) + return ret; + + ret = pmbus_find_attributes(client, data); + if (ret) + goto out_kfree; /* * If there are no attributes, something is wrong. * Bail out instead of trying to register nothing. */ if (!data->num_attributes) { - dev_err(&client->dev, "No attributes found\n"); - return -ENODEV; + dev_err(dev, "No attributes found\n"); + ret = -ENODEV; + goto out_kfree; } /* Register sysfs hooks */ - data->group.attrs = data->attributes; - ret = sysfs_create_group(&client->dev.kobj, &data->group); + ret = sysfs_create_group(&dev->kobj, &data->group); if (ret) { - dev_err(&client->dev, "Failed to create sysfs entries\n"); - return ret; + dev_err(dev, "Failed to create sysfs entries\n"); + goto out_kfree; } - data->hwmon_dev = hwmon_device_register(&client->dev); + data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { ret = PTR_ERR(data->hwmon_dev); - dev_err(&client->dev, "Failed to register hwmon device\n"); + dev_err(dev, "Failed to register hwmon device\n"); goto out_hwmon_device_register; } return 0; out_hwmon_device_register: - sysfs_remove_group(&client->dev.kobj, &data->group); + sysfs_remove_group(&dev->kobj, &data->group); +out_kfree: + kfree(data->group.attrs); return ret; } EXPORT_SYMBOL_GPL(pmbus_do_probe); @@ -1802,6 +1795,7 @@ int pmbus_do_remove(struct i2c_client *client) struct pmbus_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->group); + kfree(data->group.attrs); return 0; } EXPORT_SYMBOL_GPL(pmbus_do_remove); diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index fc5eed8e85bb..819644121259 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -2,6 +2,7 @@ * Hardware monitoring driver for ZL6100 and compatibles * * Copyright (c) 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,12 +46,87 @@ struct zl6100_data { #define ZL6100_MFR_XTEMP_ENABLE (1 << 7) +#define MFR_VMON_OV_FAULT_LIMIT 0xf5 +#define MFR_VMON_UV_FAULT_LIMIT 0xf6 +#define MFR_READ_VMON 0xf7 + +#define VMON_UV_WARNING (1 << 5) +#define VMON_OV_WARNING (1 << 4) +#define VMON_UV_FAULT (1 << 1) +#define VMON_OV_FAULT (1 << 0) + #define ZL6100_WAIT_TIME 1000 /* uS */ static ushort delay = ZL6100_WAIT_TIME; module_param(delay, ushort, 0644); MODULE_PARM_DESC(delay, "Delay between chip accesses in uS"); +/* Convert linear sensor value to milli-units */ +static long zl6100_l2d(s16 l) +{ + s16 exponent; + s32 mantissa; + long val; + + exponent = l >> 11; + mantissa = ((s16)((l & 0x7ff) << 5)) >> 5; + + val = mantissa; + + /* scale result to milli-units */ + val = val * 1000L; + + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + return val; +} + +#define MAX_MANTISSA (1023 * 1000) +#define MIN_MANTISSA (511 * 1000) + +static u16 zl6100_d2l(long val) +{ + s16 exponent = 0, mantissa; + bool negative = false; + + /* simple case */ + if (val == 0) + return 0; + + if (val < 0) { + negative = true; + val = -val; + } + + /* Reduce large mantissa until it fits into 10 bit */ + while (val >= MAX_MANTISSA && exponent < 15) { + exponent++; + val >>= 1; + } + /* Increase small mantissa to improve precision */ + while (val < MIN_MANTISSA && exponent > -15) { + exponent--; + val <<= 1; + } + + /* Convert mantissa from milli-units to units */ + mantissa = DIV_ROUND_CLOSEST(val, 1000); + + /* Ensure that resulting number is within range */ + if (mantissa > 0x3ff) + mantissa = 0x3ff; + + /* restore sign */ + if (negative) + mantissa = -mantissa; + + /* Convert to 5 bit exponent, 11 bit mantissa */ + return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); +} + /* Some chips need a delay between accesses */ static inline void zl6100_wait(const struct zl6100_data *data) { @@ -65,9 +141,9 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct zl6100_data *data = to_zl6100_data(info); - int ret; + int ret, vreg; - if (page || reg >= PMBUS_VIRT_BASE) + if (page > 0) return -ENXIO; if (data->id == zl2005) { @@ -83,9 +159,39 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) } } + switch (reg) { + case PMBUS_VIRT_READ_VMON: + vreg = MFR_READ_VMON; + break; + case PMBUS_VIRT_VMON_OV_WARN_LIMIT: + case PMBUS_VIRT_VMON_OV_FAULT_LIMIT: + vreg = MFR_VMON_OV_FAULT_LIMIT; + break; + case PMBUS_VIRT_VMON_UV_WARN_LIMIT: + case PMBUS_VIRT_VMON_UV_FAULT_LIMIT: + vreg = MFR_VMON_UV_FAULT_LIMIT; + break; + default: + if (reg >= PMBUS_VIRT_BASE) + return -ENXIO; + vreg = reg; + break; + } + zl6100_wait(data); - ret = pmbus_read_word_data(client, page, reg); + ret = pmbus_read_word_data(client, page, vreg); data->access = ktime_get(); + if (ret < 0) + return ret; + + switch (reg) { + case PMBUS_VIRT_VMON_OV_WARN_LIMIT: + ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10)); + break; + case PMBUS_VIRT_VMON_UV_WARN_LIMIT: + ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10)); + break; + } return ret; } @@ -94,13 +200,35 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct zl6100_data *data = to_zl6100_data(info); - int ret; + int ret, status; if (page > 0) return -ENXIO; zl6100_wait(data); - ret = pmbus_read_byte_data(client, page, reg); + + switch (reg) { + case PMBUS_VIRT_STATUS_VMON: + ret = pmbus_read_byte_data(client, 0, + PMBUS_STATUS_MFR_SPECIFIC); + if (ret < 0) + break; + + status = 0; + if (ret & VMON_UV_WARNING) + status |= PB_VOLTAGE_UV_WARNING; + if (ret & VMON_OV_WARNING) + status |= PB_VOLTAGE_OV_WARNING; + if (ret & VMON_UV_FAULT) + status |= PB_VOLTAGE_UV_FAULT; + if (ret & VMON_OV_FAULT) + status |= PB_VOLTAGE_OV_FAULT; + ret = status; + break; + default: + ret = pmbus_read_byte_data(client, page, reg); + break; + } data->access = ktime_get(); return ret; @@ -111,13 +239,38 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg, { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct zl6100_data *data = to_zl6100_data(info); - int ret; + int ret, vreg; - if (page || reg >= PMBUS_VIRT_BASE) + if (page > 0) return -ENXIO; + switch (reg) { + case PMBUS_VIRT_VMON_OV_WARN_LIMIT: + word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9)); + vreg = MFR_VMON_OV_FAULT_LIMIT; + pmbus_clear_cache(client); + break; + case PMBUS_VIRT_VMON_OV_FAULT_LIMIT: + vreg = MFR_VMON_OV_FAULT_LIMIT; + pmbus_clear_cache(client); + break; + case PMBUS_VIRT_VMON_UV_WARN_LIMIT: + word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11)); + vreg = MFR_VMON_UV_FAULT_LIMIT; + pmbus_clear_cache(client); + break; + case PMBUS_VIRT_VMON_UV_FAULT_LIMIT: + vreg = MFR_VMON_UV_FAULT_LIMIT; + pmbus_clear_cache(client); + break; + default: + if (reg >= PMBUS_VIRT_BASE) + return -ENXIO; + vreg = reg; + } + zl6100_wait(data); - ret = pmbus_write_word_data(client, page, reg, word); + ret = pmbus_write_word_data(client, page, vreg, word); data->access = ktime_get(); return ret; @@ -225,6 +378,13 @@ static int zl6100_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + /* + * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage + * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon. + */ + if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117) + info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON; + ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG); if (ret < 0) return ret; diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index bcecd025fcc4..ff2ae0252a48 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -275,7 +275,7 @@ static void s3c_hwmon_remove_attr(struct device *dev, * s3c_hwmon_probe - device probe entry. * @dev: The device being probed. */ -static int __devinit s3c_hwmon_probe(struct platform_device *dev) +static int s3c_hwmon_probe(struct platform_device *dev) { struct s3c_hwmon_pdata *pdata = dev->dev.platform_data; struct s3c_hwmon *hwmon; @@ -364,7 +364,7 @@ static int __devinit s3c_hwmon_probe(struct platform_device *dev) return ret; } -static int __devexit s3c_hwmon_remove(struct platform_device *dev) +static int s3c_hwmon_remove(struct platform_device *dev) { struct s3c_hwmon *hwmon = platform_get_drvdata(dev); int i; @@ -386,7 +386,7 @@ static struct platform_driver s3c_hwmon_driver = { .owner = THIS_MODULE, }, .probe = s3c_hwmon_probe, - .remove = __devexit_p(s3c_hwmon_remove), + .remove = s3c_hwmon_remove, }; module_platform_driver(s3c_hwmon_driver); diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 49f6230bdcf1..0cc99fd83e8e 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -153,7 +153,7 @@ abort: return ret; } -static int __devinit sch5627_read_limits(struct sch5627_data *data) +static int sch5627_read_limits(struct sch5627_data *data) { int i, val; @@ -465,7 +465,7 @@ static int sch5627_remove(struct platform_device *pdev) return 0; } -static int __devinit sch5627_probe(struct platform_device *pdev) +static int sch5627_probe(struct platform_device *pdev) { struct sch5627_data *data; int err, build_code, build_id, hwmon_rev, val; diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 517118016192..547b5c952eff 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -405,7 +405,7 @@ static int sch5636_remove(struct platform_device *pdev) return 0; } -static int __devinit sch5636_probe(struct platform_device *pdev) +static int sch5636_probe(struct platform_device *pdev) { struct sch5636_data *data; int i, err, val, revision[2]; diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 07a0c1a0b84d..2507f902fb7a 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -139,12 +139,12 @@ static const u8 sht15_crc8_table[] = { * @reg: associated regulator (if specified). * @nb: notifier block to handle notifications of voltage * changes. - * @supply_uV: local copy of supply voltage used to allow use of + * @supply_uv: local copy of supply voltage used to allow use of * regulator consumer if available. - * @supply_uV_valid: indicates that an updated value has not yet been + * @supply_uv_valid: indicates that an updated value has not yet been * obtained from the regulator and so any calculations * based upon it will be invalid. - * @update_supply_work: work struct that is used to update the supply_uV. + * @update_supply_work: work struct that is used to update the supply_uv. * @interrupt_handled: flag used to indicate a handler has been scheduled. */ struct sht15_data { @@ -166,8 +166,8 @@ struct sht15_data { struct device *hwmon_dev; struct regulator *reg; struct notifier_block nb; - int supply_uV; - bool supply_uV_valid; + int supply_uv; + bool supply_uv_valid; struct work_struct update_supply_work; atomic_t interrupt_handled; }; @@ -212,11 +212,13 @@ static u8 sht15_crc8(struct sht15_data *data, * * This implements section 3.4 of the data sheet */ -static void sht15_connection_reset(struct sht15_data *data) +static int sht15_connection_reset(struct sht15_data *data) { - int i; + int i, err; - gpio_direction_output(data->pdata->gpio_data, 1); + err = gpio_direction_output(data->pdata->gpio_data, 1); + if (err) + return err; ndelay(SHT15_TSCKL); gpio_set_value(data->pdata->gpio_sck, 0); ndelay(SHT15_TSCKL); @@ -226,6 +228,7 @@ static void sht15_connection_reset(struct sht15_data *data) gpio_set_value(data->pdata->gpio_sck, 0); ndelay(SHT15_TSCKL); } + return 0; } /** @@ -251,10 +254,14 @@ static inline void sht15_send_bit(struct sht15_data *data, int val) * conservative ones used in implementation. This implements * figure 12 on the data sheet. */ -static void sht15_transmission_start(struct sht15_data *data) +static int sht15_transmission_start(struct sht15_data *data) { + int err; + /* ensure data is high and output */ - gpio_direction_output(data->pdata->gpio_data, 1); + err = gpio_direction_output(data->pdata->gpio_data, 1); + if (err) + return err; ndelay(SHT15_TSU); gpio_set_value(data->pdata->gpio_sck, 0); ndelay(SHT15_TSCKL); @@ -270,6 +277,7 @@ static void sht15_transmission_start(struct sht15_data *data) ndelay(SHT15_TSU); gpio_set_value(data->pdata->gpio_sck, 0); ndelay(SHT15_TSCKL); + return 0; } /** @@ -293,13 +301,19 @@ static void sht15_send_byte(struct sht15_data *data, u8 byte) */ static int sht15_wait_for_response(struct sht15_data *data) { - gpio_direction_input(data->pdata->gpio_data); + int err; + + err = gpio_direction_input(data->pdata->gpio_data); + if (err) + return err; gpio_set_value(data->pdata->gpio_sck, 1); ndelay(SHT15_TSCKH); if (gpio_get_value(data->pdata->gpio_data)) { gpio_set_value(data->pdata->gpio_sck, 0); dev_err(data->dev, "Command not acknowledged\n"); - sht15_connection_reset(data); + err = sht15_connection_reset(data); + if (err) + return err; return -EIO; } gpio_set_value(data->pdata->gpio_sck, 0); @@ -317,12 +331,13 @@ static int sht15_wait_for_response(struct sht15_data *data) */ static int sht15_send_cmd(struct sht15_data *data, u8 cmd) { - int ret = 0; + int err; - sht15_transmission_start(data); + err = sht15_transmission_start(data); + if (err) + return err; sht15_send_byte(data, cmd); - ret = sht15_wait_for_response(data); - return ret; + return sht15_wait_for_response(data); } /** @@ -352,9 +367,13 @@ static int sht15_soft_reset(struct sht15_data *data) * Each byte of data is acknowledged by pulling the data line * low for one clock pulse. */ -static void sht15_ack(struct sht15_data *data) +static int sht15_ack(struct sht15_data *data) { - gpio_direction_output(data->pdata->gpio_data, 0); + int err; + + err = gpio_direction_output(data->pdata->gpio_data, 0); + if (err) + return err; ndelay(SHT15_TSU); gpio_set_value(data->pdata->gpio_sck, 1); ndelay(SHT15_TSU); @@ -362,7 +381,7 @@ static void sht15_ack(struct sht15_data *data) ndelay(SHT15_TSU); gpio_set_value(data->pdata->gpio_data, 1); - gpio_direction_input(data->pdata->gpio_data); + return gpio_direction_input(data->pdata->gpio_data); } /** @@ -371,14 +390,19 @@ static void sht15_ack(struct sht15_data *data) * * This is basically a NAK (single clock pulse, data high). */ -static void sht15_end_transmission(struct sht15_data *data) +static int sht15_end_transmission(struct sht15_data *data) { - gpio_direction_output(data->pdata->gpio_data, 1); + int err; + + err = gpio_direction_output(data->pdata->gpio_data, 1); + if (err) + return err; ndelay(SHT15_TSU); gpio_set_value(data->pdata->gpio_sck, 1); ndelay(SHT15_TSCKH); gpio_set_value(data->pdata->gpio_sck, 0); ndelay(SHT15_TSCKL); + return 0; } /** @@ -410,17 +434,19 @@ static u8 sht15_read_byte(struct sht15_data *data) */ static int sht15_send_status(struct sht15_data *data, u8 status) { - int ret; - - ret = sht15_send_cmd(data, SHT15_WRITE_STATUS); - if (ret) - return ret; - gpio_direction_output(data->pdata->gpio_data, 1); + int err; + + err = sht15_send_cmd(data, SHT15_WRITE_STATUS); + if (err) + return err; + err = gpio_direction_output(data->pdata->gpio_data, 1); + if (err) + return err; ndelay(SHT15_TSU); sht15_send_byte(data, status); - ret = sht15_wait_for_response(data); - if (ret) - return ret; + err = sht15_wait_for_response(data); + if (err) + return err; data->val_status = status; return 0; @@ -446,7 +472,7 @@ static int sht15_update_status(struct sht15_data *data) || !data->status_valid) { ret = sht15_send_cmd(data, SHT15_READ_STATUS); if (ret) - goto error_ret; + goto unlock; status = sht15_read_byte(data); if (data->checksumming) { @@ -458,7 +484,9 @@ static int sht15_update_status(struct sht15_data *data) == dev_checksum); } - sht15_end_transmission(data); + ret = sht15_end_transmission(data); + if (ret) + goto unlock; /* * Perform checksum validation on the received data. @@ -469,27 +497,27 @@ static int sht15_update_status(struct sht15_data *data) previous_config = data->val_status & 0x07; ret = sht15_soft_reset(data); if (ret) - goto error_ret; + goto unlock; if (previous_config) { ret = sht15_send_status(data, previous_config); if (ret) { dev_err(data->dev, "CRC validation failed, unable " "to restore device settings\n"); - goto error_ret; + goto unlock; } } ret = -EAGAIN; - goto error_ret; + goto unlock; } data->val_status = status; data->status_valid = true; data->last_status = jiffies; } -error_ret: - mutex_unlock(&data->read_lock); +unlock: + mutex_unlock(&data->read_lock); return ret; } @@ -511,7 +539,9 @@ static int sht15_measurement(struct sht15_data *data, if (ret) return ret; - gpio_direction_input(data->pdata->gpio_data); + ret = gpio_direction_input(data->pdata->gpio_data); + if (ret) + return ret; atomic_set(&data->interrupt_handled, 0); enable_irq(gpio_to_irq(data->pdata->gpio_data)); @@ -524,9 +554,14 @@ static int sht15_measurement(struct sht15_data *data, ret = wait_event_timeout(data->wait_queue, (data->state == SHT15_READING_NOTHING), msecs_to_jiffies(timeout_msecs)); - if (ret == 0) {/* timeout occurred */ + if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */ + data->state = SHT15_READING_NOTHING; + return -EIO; + } else if (ret == 0) { /* timeout occurred */ disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); - sht15_connection_reset(data); + ret = sht15_connection_reset(data); + if (ret) + return ret; return -ETIME; } @@ -570,17 +605,17 @@ static int sht15_update_measurements(struct sht15_data *data) data->state = SHT15_READING_HUMID; ret = sht15_measurement(data, SHT15_MEASURE_RH, 160); if (ret) - goto error_ret; + goto unlock; data->state = SHT15_READING_TEMP; ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400); if (ret) - goto error_ret; + goto unlock; data->measurements_valid = true; data->last_measurement = jiffies; } -error_ret: - mutex_unlock(&data->read_lock); +unlock: + mutex_unlock(&data->read_lock); return ret; } @@ -598,8 +633,8 @@ static inline int sht15_calc_temp(struct sht15_data *data) for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--) /* Find pointer to interpolate */ - if (data->supply_uV > temppoints[i - 1].vdd) { - d1 = (data->supply_uV - temppoints[i - 1].vdd) + if (data->supply_uv > temppoints[i - 1].vdd) { + d1 = (data->supply_uv - temppoints[i - 1].vdd) * (temppoints[i].d1 - temppoints[i - 1].d1) / (temppoints[i].vdd - temppoints[i - 1].vdd) + temppoints[i - 1].d1; @@ -818,7 +853,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) /* Read the data back from the device */ val = sht15_read_byte(data); val <<= 8; - sht15_ack(data); + if (sht15_ack(data)) + goto wakeup; val |= sht15_read_byte(data); if (data->checksumming) { @@ -826,7 +862,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) * Ask the device for a checksum and read it back. * Note: the device sends the checksum byte reversed. */ - sht15_ack(data); + if (sht15_ack(data)) + goto wakeup; dev_checksum = sht15_reverse(sht15_read_byte(data)); checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; @@ -837,7 +874,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) } /* Tell the device we are done */ - sht15_end_transmission(data); + if (sht15_end_transmission(data)) + goto wakeup; switch (data->state) { case SHT15_READING_TEMP: @@ -851,6 +889,7 @@ static void sht15_bh_read_data(struct work_struct *work_s) } data->state = SHT15_READING_NOTHING; +wakeup: wake_up(&data->wait_queue); } @@ -859,7 +898,7 @@ static void sht15_update_voltage(struct work_struct *work_s) struct sht15_data *data = container_of(work_s, struct sht15_data, update_supply_work); - data->supply_uV = regulator_get_voltage(data->reg); + data->supply_uv = regulator_get_voltage(data->reg); } /** @@ -878,13 +917,13 @@ static int sht15_invalidate_voltage(struct notifier_block *nb, struct sht15_data *data = container_of(nb, struct sht15_data, nb); if (event == REGULATOR_EVENT_VOLTAGE_CHANGE) - data->supply_uV_valid = false; + data->supply_uv_valid = false; schedule_work(&data->update_supply_work); return NOTIFY_OK; } -static int __devinit sht15_probe(struct platform_device *pdev) +static int sht15_probe(struct platform_device *pdev) { int ret; struct sht15_data *data; @@ -906,7 +945,7 @@ static int __devinit sht15_probe(struct platform_device *pdev) return -EINVAL; } data->pdata = pdev->dev.platform_data; - data->supply_uV = data->pdata->supply_mv * 1000; + data->supply_uv = data->pdata->supply_mv * 1000; if (data->pdata->checksum) data->checksumming = true; if (data->pdata->no_otp_reload) @@ -924,9 +963,15 @@ static int __devinit sht15_probe(struct platform_device *pdev) voltage = regulator_get_voltage(data->reg); if (voltage) - data->supply_uV = voltage; + data->supply_uv = voltage; + + ret = regulator_enable(data->reg); + if (ret != 0) { + dev_err(&pdev->dev, + "failed to enable regulator: %d\n", ret); + return ret; + } - regulator_enable(data->reg); /* * Setup a notifier block to update this if another device * causes the voltage to change @@ -942,17 +987,17 @@ static int __devinit sht15_probe(struct platform_device *pdev) } /* Try requesting the GPIOs */ - ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck"); + ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck, + GPIOF_OUT_INIT_LOW, "SHT15 sck"); if (ret) { - dev_err(&pdev->dev, "gpio request failed\n"); + dev_err(&pdev->dev, "clock line GPIO request failed\n"); goto err_release_reg; } - gpio_direction_output(data->pdata->gpio_sck, 0); ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data, "SHT15 data"); if (ret) { - dev_err(&pdev->dev, "gpio request failed\n"); + dev_err(&pdev->dev, "data line GPIO request failed\n"); goto err_release_reg; } @@ -966,7 +1011,9 @@ static int __devinit sht15_probe(struct platform_device *pdev) goto err_release_reg; } disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); - sht15_connection_reset(data); + ret = sht15_connection_reset(data); + if (ret) + goto err_release_reg; ret = sht15_soft_reset(data); if (ret) goto err_release_reg; @@ -1002,7 +1049,7 @@ err_release_reg: return ret; } -static int __devexit sht15_remove(struct platform_device *pdev) +static int sht15_remove(struct platform_device *pdev) { struct sht15_data *data = platform_get_drvdata(pdev); @@ -1043,7 +1090,7 @@ static struct platform_driver sht15_driver = { .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = __devexit_p(sht15_remove), + .remove = sht15_remove, .id_table = sht15_device_ids, }; module_platform_driver(sht15_driver); diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 5f67546950b1..2e9f9570b6f8 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -187,7 +187,7 @@ static const struct attribute_group sht21_attr_group = { * device's name. * Returns 0 on success. */ -static int __devinit sht21_probe(struct i2c_client *client, +static int sht21_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sht21 *sht21; @@ -233,7 +233,7 @@ fail_remove_sysfs: * sht21_remove() - remove device * @client: I2C client device */ -static int __devexit sht21_remove(struct i2c_client *client) +static int sht21_remove(struct i2c_client *client) { struct sht21 *sht21 = i2c_get_clientdata(client); @@ -253,7 +253,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id); static struct i2c_driver sht21_driver = { .driver.name = "sht21", .probe = sht21_probe, - .remove = __devexit_p(sht21_remove), + .remove = sht21_remove, .id_table = sht21_id, }; diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 8275f0e14eb7..c35847a1a0a3 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -132,7 +132,7 @@ static struct platform_device *pdev; */ static inline u8 IN_TO_REG(unsigned long val) { - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + unsigned long nval = clamp_val(val, 0, 4080); return (nval + 8) / 16; } #define IN_FROM_REG(val) ((val) * 16) @@ -141,7 +141,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm <= 0) return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static inline int FAN_FROM_REG(u8 val, int div) @@ -159,7 +159,7 @@ static inline int TEMP_FROM_REG(s8 val) } static inline s8 TEMP_TO_REG(int val) { - int nval = SENSORS_LIMIT(val, -54120, 157530) ; + int nval = clamp_val(val, -54120, 157530) ; return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830; } @@ -204,7 +204,7 @@ struct sis5595_data { static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ static int sis5595_probe(struct platform_device *pdev); -static int __devexit sis5595_remove(struct platform_device *pdev); +static int sis5595_remove(struct platform_device *pdev); static int sis5595_read_value(struct sis5595_data *data, u8 reg); static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value); @@ -217,7 +217,7 @@ static struct platform_driver sis5595_driver = { .name = "sis5595", }, .probe = sis5595_probe, - .remove = __devexit_p(sis5595_remove), + .remove = sis5595_remove, }; /* 4 Voltages */ @@ -583,7 +583,7 @@ static const struct attribute_group sis5595_group_temp1 = { }; /* This is called when the module is loaded */ -static int __devinit sis5595_probe(struct platform_device *pdev) +static int sis5595_probe(struct platform_device *pdev) { int err = 0; int i; @@ -659,7 +659,7 @@ exit_remove_files: return err; } -static int __devexit sis5595_remove(struct platform_device *pdev) +static int sis5595_remove(struct platform_device *pdev) { struct sis5595_data *data = platform_get_drvdata(pdev); @@ -693,7 +693,7 @@ static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value) } /* Called when we have found a new SIS5595. */ -static void __devinit sis5595_init_device(struct sis5595_data *data) +static void sis5595_init_device(struct sis5595_data *data) { u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG); if (!(config & 0x01)) @@ -758,7 +758,7 @@ static DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = { MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); -static int blacklist[] __devinitdata = { +static int blacklist[] = { PCI_DEVICE_ID_SI_540, PCI_DEVICE_ID_SI_550, PCI_DEVICE_ID_SI_630, @@ -774,7 +774,7 @@ static int blacklist[] __devinitdata = { PCI_DEVICE_ID_SI_5598, 0 }; -static int __devinit sis5595_device_add(unsigned short address) +static int sis5595_device_add(unsigned short address) { struct resource res = { .start = address, @@ -815,7 +815,7 @@ exit: return err; } -static int __devinit sis5595_pci_probe(struct pci_dev *dev, +static int sis5595_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 65b07de11a0f..81348fadf3b6 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -228,7 +228,7 @@ static const struct attribute_group smsc47b397_group = { .attrs = smsc47b397_attributes, }; -static int __devexit smsc47b397_remove(struct platform_device *pdev) +static int smsc47b397_remove(struct platform_device *pdev) { struct smsc47b397_data *data = platform_get_drvdata(pdev); @@ -246,10 +246,10 @@ static struct platform_driver smsc47b397_driver = { .name = DRVNAME, }, .probe = smsc47b397_probe, - .remove = __devexit_p(smsc47b397_remove), + .remove = smsc47b397_remove, }; -static int __devinit smsc47b397_probe(struct platform_device *pdev) +static int smsc47b397_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct smsc47b397_data *data; diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index dba0c567e7a1..6d8255ccf07a 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -326,7 +326,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute /* Preserve fan min */ tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + new_div / 2) / new_div; - data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); + data->fan_preload[nr] = clamp_val(tmp, 0, 191); smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], data->fan_preload[nr]); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 36a3478d0799..efee4c59239f 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -77,7 +77,7 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n) static inline u8 IN_TO_REG(unsigned long val, int n) { - return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); + return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255); } /* @@ -86,7 +86,7 @@ static inline u8 IN_TO_REG(unsigned long val, int n) */ static inline s8 TEMP_TO_REG(int val) { - return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000); + return clamp_val(SCALE(val, 1, 1000), -128000, 127000); } static inline int TEMP_FROM_REG(s8 val) diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 3c2c48d904e6..4b59eb53b18a 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -134,7 +134,7 @@ static ssize_t set_analog_out(struct device *dev, return err; mutex_lock(&data->update_lock); - data->analog_out = SENSORS_LIMIT(tmp, 0, 255); + data->analog_out = clamp_val(tmp, 0, 255); i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, data->analog_out); @@ -187,7 +187,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127); + data->temp_min[nr] = clamp_val(val / 1000, -128, 127); i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr], data->temp_min[nr]); mutex_unlock(&data->update_lock); @@ -216,7 +216,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127); + data->temp_max[nr] = clamp_val(val / 1000, -128, 127); i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr], data->temp_max[nr]); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index b8777e54190a..523dd89ba498 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -115,7 +115,7 @@ static ssize_t tmp102_set_temp(struct device *dev, if (kstrtol(buf, 10, &val) < 0) return -EINVAL; - val = SENSORS_LIMIT(val, -256000, 255000); + val = clamp_val(val, -256000, 255000); mutex_lock(&tmp102->lock); tmp102->temp[sda->index] = val; @@ -147,7 +147,7 @@ static const struct attribute_group tmp102_attr_group = { #define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) -static int __devinit tmp102_probe(struct i2c_client *client, +static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tmp102 *tmp102; @@ -216,7 +216,7 @@ fail_restore_config: return status; } -static int __devexit tmp102_remove(struct i2c_client *client) +static int tmp102_remove(struct i2c_client *client) { struct tmp102 *tmp102 = i2c_get_clientdata(client); @@ -283,7 +283,7 @@ static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.pm = TMP102_DEV_PM_OPS, .probe = tmp102_probe, - .remove = __devexit_p(tmp102_remove), + .remove = tmp102_remove, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index e62054875164..c85f6967ccc3 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -142,10 +142,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config) static u16 tmp401_temp_to_register(long temp, u8 config) { if (config & TMP401_CONFIG_RANGE) { - temp = SENSORS_LIMIT(temp, -64000, 191000); + temp = clamp_val(temp, -64000, 191000); temp += 64000; } else - temp = SENSORS_LIMIT(temp, 0, 127000); + temp = clamp_val(temp, 0, 127000); return (temp * 160 + 312) / 625; } @@ -163,10 +163,10 @@ static int tmp401_crit_register_to_temp(u8 reg, u8 config) static u8 tmp401_crit_temp_to_register(long temp, u8 config) { if (config & TMP401_CONFIG_RANGE) { - temp = SENSORS_LIMIT(temp, -64000, 191000); + temp = clamp_val(temp, -64000, 191000); temp += 64000; } else - temp = SENSORS_LIMIT(temp, 0, 127000); + temp = clamp_val(temp, 0, 127000); return (temp + 500) / 1000; } @@ -417,14 +417,14 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute return -EINVAL; if (data->config & TMP401_CONFIG_RANGE) - val = SENSORS_LIMIT(val, -64000, 191000); + val = clamp_val(val, -64000, 191000); else - val = SENSORS_LIMIT(val, 0, 127000); + val = clamp_val(val, 0, 127000); mutex_lock(&data->update_lock); temp = tmp401_crit_register_to_temp(data->temp_crit[index], data->config); - val = SENSORS_LIMIT(val, temp - 255000, temp); + val = clamp_val(val, temp - 255000, temp); reg = ((temp - val) + 500) / 1000; i2c_smbus_write_byte_data(to_i2c_client(dev), diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 1a174f0a3cde..6c6d440bb2dd 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -96,7 +96,7 @@ static const struct attribute_group twl4030_madc_group = { .attrs = twl4030_madc_attributes, }; -static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) +static int twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; struct device *hwmon; @@ -120,7 +120,7 @@ err_sysfs: return ret; } -static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev) +static int twl4030_madc_hwmon_remove(struct platform_device *pdev) { hwmon_device_unregister(&pdev->dev); sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group); @@ -130,7 +130,7 @@ static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev) static struct platform_driver twl4030_madc_hwmon_driver = { .probe = twl4030_madc_hwmon_probe, - .remove = __exit_p(twl4030_madc_hwmon_remove), + .remove = twl4030_madc_hwmon_remove, .driver = { .name = "twl4030_madc_hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 44136bb6d045..fb3e69341c1b 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -250,7 +250,7 @@ static const struct attribute_group env_group = { .attrs = env_attributes, }; -static int __devinit env_probe(struct platform_device *op) +static int env_probe(struct platform_device *op) { struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); int err = -ENOMEM; @@ -291,7 +291,7 @@ out_free: goto out; } -static int __devexit env_remove(struct platform_device *op) +static int env_remove(struct platform_device *op) { struct env *p = platform_get_drvdata(op); @@ -321,7 +321,7 @@ static struct platform_driver env_driver = { .of_match_table = env_match, }, .probe = env_probe, - .remove = __devexit_p(env_remove), + .remove = env_remove, }; module_platform_driver(env_driver); diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c new file mode 100644 index 000000000000..d867e6bb2be1 --- /dev/null +++ b/drivers/hwmon/vexpress.c @@ -0,0 +1,230 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#define DRVNAME "vexpress-hwmon" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/vexpress.h> + +struct vexpress_hwmon_data { + struct device *hwmon_dev; + struct vexpress_config_func *func; +}; + +static ssize_t vexpress_hwmon_name_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + const char *compatible = of_get_property(dev->of_node, "compatible", + NULL); + + return sprintf(buffer, "%s\n", compatible); +} + +static ssize_t vexpress_hwmon_label_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + const char *label = of_get_property(dev->of_node, "label", NULL); + + if (!label) + return -ENOENT; + + return snprintf(buffer, PAGE_SIZE, "%s\n", label); +} + +static ssize_t vexpress_hwmon_u32_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct vexpress_hwmon_data *data = dev_get_drvdata(dev); + int err; + u32 value; + + err = vexpress_config_read(data->func, 0, &value); + if (err) + return err; + + return snprintf(buffer, PAGE_SIZE, "%u\n", value / + to_sensor_dev_attr(dev_attr)->index); +} + +static ssize_t vexpress_hwmon_u64_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct vexpress_hwmon_data *data = dev_get_drvdata(dev); + int err; + u32 value_hi, value_lo; + + err = vexpress_config_read(data->func, 0, &value_lo); + if (err) + return err; + + err = vexpress_config_read(data->func, 1, &value_hi); + if (err) + return err; + + return snprintf(buffer, PAGE_SIZE, "%llu\n", + div_u64(((u64)value_hi << 32) | value_lo, + to_sensor_dev_attr(dev_attr)->index)); +} + +static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); + +#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \ +struct attribute *vexpress_hwmon_attrs_##_name[] = { \ + &dev_attr_name.attr, \ + &dev_attr_##_label_attr.attr, \ + &sensor_dev_attr_##_input_attr.dev_attr.attr, \ + NULL \ +} + +#if !defined(CONFIG_REGULATOR_VEXPRESS) +static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input); +static struct attribute_group vexpress_hwmon_group_volt = { + .attrs = vexpress_hwmon_attrs_volt, +}; +#endif + +static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input); +static struct attribute_group vexpress_hwmon_group_amp = { + .attrs = vexpress_hwmon_attrs_amp, +}; + +static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input); +static struct attribute_group vexpress_hwmon_group_temp = { + .attrs = vexpress_hwmon_attrs_temp, +}; + +static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1); +static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input); +static struct attribute_group vexpress_hwmon_group_power = { + .attrs = vexpress_hwmon_attrs_power, +}; + +static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show, + NULL, 1); +static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input); +static struct attribute_group vexpress_hwmon_group_energy = { + .attrs = vexpress_hwmon_attrs_energy, +}; + +static struct of_device_id vexpress_hwmon_of_match[] = { +#if !defined(CONFIG_REGULATOR_VEXPRESS) + { + .compatible = "arm,vexpress-volt", + .data = &vexpress_hwmon_group_volt, + }, +#endif + { + .compatible = "arm,vexpress-amp", + .data = &vexpress_hwmon_group_amp, + }, { + .compatible = "arm,vexpress-temp", + .data = &vexpress_hwmon_group_temp, + }, { + .compatible = "arm,vexpress-power", + .data = &vexpress_hwmon_group_power, + }, { + .compatible = "arm,vexpress-energy", + .data = &vexpress_hwmon_group_energy, + }, + {} +}; +MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match); + +static int vexpress_hwmon_probe(struct platform_device *pdev) +{ + int err; + const struct of_device_id *match; + struct vexpress_hwmon_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + platform_set_drvdata(pdev, data); + + match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + data->func = vexpress_config_func_get_by_dev(&pdev->dev); + if (!data->func) + return -ENODEV; + + err = sysfs_create_group(&pdev->dev.kobj, match->data); + if (err) + goto error; + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto error; + } + + return 0; + +error: + sysfs_remove_group(&pdev->dev.kobj, match->data); + vexpress_config_func_put(data->func); + return err; +} + +static int vexpress_hwmon_remove(struct platform_device *pdev) +{ + struct vexpress_hwmon_data *data = platform_get_drvdata(pdev); + const struct of_device_id *match; + + hwmon_device_unregister(data->hwmon_dev); + + match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); + sysfs_remove_group(&pdev->dev.kobj, match->data); + + vexpress_config_func_put(data->func); + + return 0; +} + +static struct platform_driver vexpress_hwmon_driver = { + .probe = vexpress_hwmon_probe, + .remove = vexpress_hwmon_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = vexpress_hwmon_of_match, + }, +}; + +module_platform_driver(vexpress_hwmon_driver); + +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); +MODULE_DESCRIPTION("Versatile Express hwmon sensors driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vexpress-hwmon"); diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 4cddee04f2e6..76f157b568ed 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -121,7 +121,7 @@ static const struct attribute_group via_cputemp_group = { /* Optional attributes */ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_cpu_vid, NULL); -static int __devinit via_cputemp_probe(struct platform_device *pdev) +static int via_cputemp_probe(struct platform_device *pdev) { struct via_cputemp_data *data; struct cpuinfo_x86 *c = &cpu_data(pdev->id); @@ -192,7 +192,7 @@ exit_remove: return err; } -static int __devexit via_cputemp_remove(struct platform_device *pdev) +static int via_cputemp_remove(struct platform_device *pdev) { struct via_cputemp_data *data = platform_get_drvdata(pdev); @@ -209,7 +209,7 @@ static struct platform_driver via_cputemp_driver = { .name = DRVNAME, }, .probe = via_cputemp_probe, - .remove = __devexit_p(via_cputemp_remove), + .remove = via_cputemp_remove, }; struct pdev_entry { diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 299399aa30fe..3123b30208c5 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -135,17 +135,14 @@ static inline u8 IN_TO_REG(long val, int inNum) * for the constants. */ if (inNum <= 1) - return (u8) - SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); + return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255); else if (inNum == 2) - return (u8) - SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); + return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255); else if (inNum == 3) - return (u8) - SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); + return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255); else - return (u8) - SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); + return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0, + 255); } static inline long IN_FROM_REG(u8 val, int inNum) @@ -175,8 +172,8 @@ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255); } #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \ @@ -339,7 +336,7 @@ struct via686a_data { static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ static int via686a_probe(struct platform_device *pdev); -static int __devexit via686a_remove(struct platform_device *pdev); +static int via686a_remove(struct platform_device *pdev); static inline int via686a_read_value(struct via686a_data *data, u8 reg) { @@ -677,12 +674,12 @@ static struct platform_driver via686a_driver = { .name = "via686a", }, .probe = via686a_probe, - .remove = __devexit_p(via686a_remove), + .remove = via686a_remove, }; /* This is called when the module is loaded */ -static int __devinit via686a_probe(struct platform_device *pdev) +static int via686a_probe(struct platform_device *pdev) { struct via686a_data *data; struct resource *res; @@ -728,7 +725,7 @@ exit_remove_files: return err; } -static int __devexit via686a_remove(struct platform_device *pdev) +static int via686a_remove(struct platform_device *pdev) { struct via686a_data *data = platform_get_drvdata(pdev); @@ -745,7 +742,7 @@ static void via686a_update_fan_div(struct via686a_data *data) data->fan_div[1] = reg >> 6; } -static void __devinit via686a_init_device(struct via686a_data *data) +static void via686a_init_device(struct via686a_data *data) { u8 reg; @@ -833,7 +830,7 @@ static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = { }; MODULE_DEVICE_TABLE(pci, via686a_pci_ids); -static int __devinit via686a_device_add(unsigned short address) +static int via686a_device_add(unsigned short address) { struct resource res = { .start = address, @@ -874,7 +871,7 @@ exit: return err; } -static int __devinit via686a_pci_probe(struct pci_dev *dev, +static int via686a_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address, val; diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index f2c61153dba9..dcc62f80f67b 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -158,7 +158,7 @@ struct vt1211_data { #define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \ (((reg) - 3) * 15882 + 479) / 958 : \ (((reg) - 3) * 10000 + 479) / 958) -#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \ +#define IN_TO_REG(ix, val) (clamp_val((ix) == 5 ? \ ((val) * 958 + 7941) / 15882 + 3 : \ ((val) * 958 + 5000) / 10000 + 3, 0, 255)) @@ -173,7 +173,7 @@ struct vt1211_data { (ix) == 1 ? (reg) < 51 ? 0 : \ ((reg) - 51) * 1000 : \ ((253 - (reg)) * 2200 + 105) / 210) -#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \ +#define TEMP_TO_REG(ix, val) clamp_val( \ ((ix) == 0 ? ((val) + 500) / 1000 : \ (ix) == 1 ? ((val) + 500) / 1000 + 51 : \ 253 - ((val) * 210 + 1100) / 2200), 0, 255) @@ -183,7 +183,7 @@ struct vt1211_data { #define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \ 1310720 / (reg) / DIV_FROM_REG(div)) #define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \ - SENSORS_LIMIT((1310720 / (val) / \ + clamp_val((1310720 / (val) / \ DIV_FROM_REG(div)), 1, 254)) /* --------------------------------------------------------------------- @@ -687,7 +687,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->fan_ctl)); break; case SHOW_SET_PWM_FREQ: - val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000); + val = 135000 / clamp_val(val, 135000 >> 7, 135000); /* calculate tmp = log2(val) */ tmp = 0; for (val >>= 1; val > 0; val >>= 1) @@ -845,7 +845,7 @@ static ssize_t set_pwm_auto_point_pwm(struct device *dev, return err; mutex_lock(&data->update_lock); - data->pwm_auto_pwm[ix][ap] = SENSORS_LIMIT(val, 0, 255); + data->pwm_auto_pwm[ix][ap] = clamp_val(val, 0, 255); vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap), data->pwm_auto_pwm[ix][ap]); mutex_unlock(&data->update_lock); @@ -1086,7 +1086,7 @@ static struct device_attribute vt1211_sysfs_misc[] = { * Device registration and initialization * --------------------------------------------------------------------- */ -static void __devinit vt1211_init_device(struct vt1211_data *data) +static void vt1211_init_device(struct vt1211_data *data) { /* set VRM */ data->vrm = vid_which_vrm(); @@ -1141,7 +1141,7 @@ static void vt1211_remove_sysfs(struct platform_device *pdev) device_remove_file(dev, &vt1211_sysfs_misc[i]); } -static int __devinit vt1211_probe(struct platform_device *pdev) +static int vt1211_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct vt1211_data *data; @@ -1217,7 +1217,7 @@ EXIT_DEV_REMOVE_SILENT: return err; } -static int __devexit vt1211_remove(struct platform_device *pdev) +static int vt1211_remove(struct platform_device *pdev) { struct vt1211_data *data = platform_get_drvdata(pdev); @@ -1233,7 +1233,7 @@ static struct platform_driver vt1211_driver = { .name = DRVNAME, }, .probe = vt1211_probe, - .remove = __devexit_p(vt1211_remove), + .remove = vt1211_remove, }; static int __init vt1211_device_add(unsigned short address) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 84e3dc5e3a83..988a2a796764 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -147,7 +147,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 0; - return SENSORS_LIMIT(1310720 / (rpm * div), 1, 255); + return clamp_val(1310720 / (rpm * div), 1, 255); } #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div))) @@ -176,7 +176,7 @@ struct vt8231_data { static struct pci_dev *s_bridge; static int vt8231_probe(struct platform_device *pdev); -static int __devexit vt8231_remove(struct platform_device *pdev); +static int vt8231_remove(struct platform_device *pdev); static struct vt8231_data *vt8231_update_device(struct device *dev); static void vt8231_init_device(struct vt8231_data *data); @@ -236,7 +236,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); + data->in_min[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255); vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]); mutex_unlock(&data->update_lock); return count; @@ -256,7 +256,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); + data->in_max[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255); vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]); mutex_unlock(&data->update_lock); return count; @@ -302,8 +302,8 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, - 0, 255); + data->in_min[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3, + 0, 255); vt8231_write_value(data, regvoltmin[5], data->in_min[5]); mutex_unlock(&data->update_lock); return count; @@ -321,8 +321,8 @@ static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, - 0, 255); + data->in_max[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3, + 0, 255); vt8231_write_value(data, regvoltmax[5], data->in_max[5]); mutex_unlock(&data->update_lock); return count; @@ -380,7 +380,7 @@ static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); + data->temp_max[0] = clamp_val((val + 500) / 1000, 0, 255); vt8231_write_value(data, regtempmax[0], data->temp_max[0]); mutex_unlock(&data->update_lock); return count; @@ -397,7 +397,7 @@ static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); + data->temp_min[0] = clamp_val((val + 500) / 1000, 0, 255); vt8231_write_value(data, regtempmin[0], data->temp_min[0]); mutex_unlock(&data->update_lock); return count; @@ -444,7 +444,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); + data->temp_max[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255); vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]); mutex_unlock(&data->update_lock); return count; @@ -463,7 +463,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); + data->temp_min[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255); vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]); mutex_unlock(&data->update_lock); return count; @@ -762,7 +762,7 @@ static struct platform_driver vt8231_driver = { .name = "vt8231", }, .probe = vt8231_probe, - .remove = __devexit_p(vt8231_remove), + .remove = vt8231_remove, }; static DEFINE_PCI_DEVICE_TABLE(vt8231_pci_ids) = { @@ -772,7 +772,7 @@ static DEFINE_PCI_DEVICE_TABLE(vt8231_pci_ids) = { MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); -static int __devinit vt8231_pci_probe(struct pci_dev *dev, +static int vt8231_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); static struct pci_driver vt8231_pci_driver = { @@ -851,7 +851,7 @@ exit_remove_files: return err; } -static int __devexit vt8231_remove(struct platform_device *pdev) +static int vt8231_remove(struct platform_device *pdev) { struct vt8231_data *data = platform_get_drvdata(pdev); int i; @@ -943,7 +943,7 @@ static struct vt8231_data *vt8231_update_device(struct device *dev) return data; } -static int __devinit vt8231_device_add(unsigned short address) +static int vt8231_device_add(unsigned short address) { struct resource res = { .start = address, @@ -984,7 +984,7 @@ exit: return err; } -static int __devinit vt8231_pci_probe(struct pci_dev *dev, +static int vt8231_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address, val; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 1821b7423d5b..0a89211c25f6 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1,7 +1,7 @@ /* * w83627ehf - Driver for the hardware monitoring functionality of * the Winbond W83627EHF Super-I/O chip - * Copyright (C) 2005-2011 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org> * Copyright (C) 2006 Yuan Mu (Winbond), * Rudolf Marek <r.marek@assembler.cz> * David Hubbard <david.c.hubbard@gmail.com> @@ -354,8 +354,8 @@ static inline unsigned int step_time_from_reg(u8 reg, u8 mode) static inline u8 step_time_to_reg(unsigned int msec, u8 mode) { - return SENSORS_LIMIT((mode ? (msec + 50) / 100 : - (msec + 200) / 400), 1, 255); + return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400), + 1, 255); } static unsigned int fan_from_reg8(u16 reg, unsigned int divreg) @@ -414,8 +414,7 @@ static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in) static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in) { - return SENSORS_LIMIT(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, - 255); + return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255); } /* @@ -502,6 +501,13 @@ struct w83627ehf_data { u16 have_temp_offset; u8 in6_skip:1; u8 temp3_val_only:1; + +#ifdef CONFIG_PM + /* Remember extra register values over suspend/resume */ + u8 vbat; + u8 fandiv1; + u8 fandiv2; +#endif }; struct w83627ehf_sio_data { @@ -898,6 +904,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) data->temp_max_hyst[i] = w83627ehf_read_temp(data, data->reg_temp_hyst[i]); + if (i > 2) + continue; if (data->have_temp_offset & (1 << i)) data->temp_offset[i] = w83627ehf_read_value(data, @@ -1258,7 +1266,7 @@ store_temp_offset(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), -128, 127); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); mutex_lock(&data->update_lock); data->temp_offset[nr] = val; @@ -1426,7 +1434,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm[nr] = val; @@ -1505,7 +1513,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 127); mutex_lock(&data->update_lock); data->target_temp[nr] = val; @@ -1531,7 +1539,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, return err; /* Limit the temp to 0C - 15C */ - val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 15); mutex_lock(&data->update_lock); if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { @@ -1630,7 +1638,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ err = kstrtoul(buf, 10, &val); \ if (err < 0) \ return err; \ - val = SENSORS_LIMIT(val, 1, 255); \ + val = clamp_val(val, 1, 255); \ mutex_lock(&data->update_lock); \ data->reg[nr] = val; \ w83627ehf_write_value(data, data->REG_##REG[nr], val); \ @@ -1866,7 +1874,7 @@ static void w83627ehf_device_remove_files(struct device *dev) } /* Get the monitoring functions started */ -static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, +static inline void w83627ehf_init_device(struct w83627ehf_data *data, enum kinds kind) { int i; @@ -1952,7 +1960,7 @@ static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, data->reg_temp_config[r2] = tmp; } -static void __devinit +static void w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp) { int i; @@ -1965,7 +1973,7 @@ w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp) } } -static void __devinit +static void w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, struct w83627ehf_data *data) { @@ -2054,7 +2062,7 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, } } -static int __devinit w83627ehf_probe(struct platform_device *pdev) +static int w83627ehf_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct w83627ehf_sio_data *sio_data = dev->platform_data; @@ -2083,6 +2091,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) mutex_init(&data->lock); mutex_init(&data->update_lock); data->name = w83627ehf_device_names[sio_data->kind]; + data->bank = 0xff; /* Force initial bank selection */ platform_set_drvdata(pdev, data); /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ @@ -2595,7 +2604,7 @@ exit: return err; } -static int __devexit w83627ehf_remove(struct platform_device *pdev) +static int w83627ehf_remove(struct platform_device *pdev) { struct w83627ehf_data *data = platform_get_drvdata(pdev); @@ -2607,13 +2616,101 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int w83627ehf_suspend(struct device *dev) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + struct w83627ehf_sio_data *sio_data = dev->platform_data; + + mutex_lock(&data->update_lock); + data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT); + if (sio_data->kind == nct6775) { + data->fandiv1 = w83627ehf_read_value(data, NCT6775_REG_FANDIV1); + data->fandiv2 = w83627ehf_read_value(data, NCT6775_REG_FANDIV2); + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int w83627ehf_resume(struct device *dev) +{ + struct w83627ehf_data *data = dev_get_drvdata(dev); + struct w83627ehf_sio_data *sio_data = dev->platform_data; + int i; + + mutex_lock(&data->update_lock); + data->bank = 0xff; /* Force initial bank selection */ + + /* Restore limits */ + for (i = 0; i < data->in_num; i++) { + if ((i == 6) && data->in6_skip) + continue; + + w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i), + data->in_min[i]); + w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i), + data->in_max[i]); + } + + for (i = 0; i < 5; i++) { + if (!(data->has_fan_min & (1 << i))) + continue; + + w83627ehf_write_value(data, data->REG_FAN_MIN[i], + data->fan_min[i]); + } + + for (i = 0; i < NUM_REG_TEMP; i++) { + if (!(data->have_temp & (1 << i))) + continue; + + if (data->reg_temp_over[i]) + w83627ehf_write_temp(data, data->reg_temp_over[i], + data->temp_max[i]); + if (data->reg_temp_hyst[i]) + w83627ehf_write_temp(data, data->reg_temp_hyst[i], + data->temp_max_hyst[i]); + if (i > 2) + continue; + if (data->have_temp_offset & (1 << i)) + w83627ehf_write_value(data, + W83627EHF_REG_TEMP_OFFSET[i], + data->temp_offset[i]); + } + + /* Restore other settings */ + w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat); + if (sio_data->kind == nct6775) { + w83627ehf_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1); + w83627ehf_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2); + } + + /* Force re-reading all values */ + data->valid = 0; + mutex_unlock(&data->update_lock); + + return 0; +} + +static const struct dev_pm_ops w83627ehf_dev_pm_ops = { + .suspend = w83627ehf_suspend, + .resume = w83627ehf_resume, +}; + +#define W83627EHF_DEV_PM_OPS (&w83627ehf_dev_pm_ops) +#else +#define W83627EHF_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + static struct platform_driver w83627ehf_driver = { .driver = { .owner = THIS_MODULE, .name = DRVNAME, + .pm = W83627EHF_DEV_PM_OPS, }, .probe = w83627ehf_probe, - .remove = __devexit_p(w83627ehf_remove), + .remove = w83627ehf_remove, }; /* w83627ehf_find() looks for a '627 in the Super-I/O config space */ diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 5b1a6a666441..3b9ef2d23452 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -5,7 +5,7 @@ * Philip Edelbrock <phil@netroedge.com>, * and Mark Studebaker <mdsxyz123@yahoo.com> * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> - * Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> + * Copyright (c) 2007 - 1012 Jean Delvare <khali@linux-fr.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) * w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) * w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) @@ -254,16 +254,15 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; * these macros are called: arguments may be evaluated more than once. * Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255)) #define IN_FROM_REG(val) ((val) * 16) static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define TEMP_MIN (-128000) @@ -275,9 +274,9 @@ static inline u8 FAN_TO_REG(long rpm, int div) */ static u8 TEMP_TO_REG(long temp) { - int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); - return (u8)(ntemp / 1000); + int ntemp = clamp_val(temp, TEMP_MIN, TEMP_MAX); + ntemp += (ntemp < 0 ? -500 : 500); + return (u8)(ntemp / 1000); } static int TEMP_FROM_REG(u8 reg) @@ -287,7 +286,7 @@ static int TEMP_FROM_REG(u8 reg) #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) +#define PWM_TO_REG(val) (clamp_val((val), 0, 255)) static inline unsigned long pwm_freq_from_reg_627hf(u8 reg) { @@ -342,7 +341,7 @@ static inline u8 pwm_freq_to_reg(unsigned long val) static inline u8 DIV_TO_REG(long val) { int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; + val = clamp_val(val, 1, 128) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; @@ -389,11 +388,17 @@ struct w83627hf_data { */ u8 vrm; u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ + +#ifdef CONFIG_PM + /* Remember extra register values over suspend/resume */ + u8 scfg1; + u8 scfg2; +#endif }; static int w83627hf_probe(struct platform_device *pdev); -static int __devexit w83627hf_remove(struct platform_device *pdev); +static int w83627hf_remove(struct platform_device *pdev); static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); @@ -401,13 +406,80 @@ static void w83627hf_update_fan_div(struct w83627hf_data *data); static struct w83627hf_data *w83627hf_update_device(struct device *dev); static void w83627hf_init_device(struct platform_device *pdev); +#ifdef CONFIG_PM +static int w83627hf_suspend(struct device *dev) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + + mutex_lock(&data->update_lock); + data->scfg1 = w83627hf_read_value(data, W83781D_REG_SCFG1); + data->scfg2 = w83627hf_read_value(data, W83781D_REG_SCFG2); + mutex_unlock(&data->update_lock); + + return 0; +} + +static int w83627hf_resume(struct device *dev) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + int i, num_temps = (data->type == w83697hf) ? 2 : 3; + + /* Restore limits */ + mutex_lock(&data->update_lock); + for (i = 0; i <= 8; i++) { + /* skip missing sensors */ + if (((data->type == w83697hf) && (i == 1)) || + ((data->type != w83627hf && data->type != w83697hf) + && (i == 5 || i == 6))) + continue; + w83627hf_write_value(data, W83781D_REG_IN_MAX(i), + data->in_max[i]); + w83627hf_write_value(data, W83781D_REG_IN_MIN(i), + data->in_min[i]); + } + for (i = 0; i <= 2; i++) + w83627hf_write_value(data, W83627HF_REG_FAN_MIN(i), + data->fan_min[i]); + for (i = 0; i < num_temps; i++) { + w83627hf_write_value(data, w83627hf_reg_temp_over[i], + data->temp_max[i]); + w83627hf_write_value(data, w83627hf_reg_temp_hyst[i], + data->temp_max_hyst[i]); + } + + /* Fixup BIOS bugs */ + if (data->type == w83627thf || data->type == w83637hf || + data->type == w83687thf) + w83627hf_write_value(data, W83627THF_REG_VRM_OVT_CFG, + data->vrm_ovt); + w83627hf_write_value(data, W83781D_REG_SCFG1, data->scfg1); + w83627hf_write_value(data, W83781D_REG_SCFG2, data->scfg2); + + /* Force re-reading all values */ + data->valid = 0; + mutex_unlock(&data->update_lock); + + return 0; +} + +static const struct dev_pm_ops w83627hf_dev_pm_ops = { + .suspend = w83627hf_suspend, + .resume = w83627hf_resume, +}; + +#define W83627HF_DEV_PM_OPS (&w83627hf_dev_pm_ops) +#else +#define W83627HF_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + static struct platform_driver w83627hf_driver = { .driver = { .owner = THIS_MODULE, .name = DRVNAME, + .pm = W83627HF_DEV_PM_OPS, }, .probe = w83627hf_probe, - .remove = __devexit_p(w83627hf_remove), + .remove = w83627hf_remove, }; static ssize_t @@ -541,8 +613,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a /* use VRM9 calculation */ data->in_min[0] = - SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0, - 255); + clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255); else /* use VRM8 (standard) calculation */ data->in_min[0] = IN_TO_REG(val); @@ -571,8 +642,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a /* use VRM9 calculation */ data->in_max[0] = - SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0, - 255); + clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255); else /* use VRM8 (standard) calculation */ data->in_max[0] = IN_TO_REG(val); @@ -1342,7 +1412,7 @@ static const struct attribute_group w83627hf_group_opt = { .attrs = w83627hf_attributes_opt, }; -static int __devinit w83627hf_probe(struct platform_device *pdev) +static int w83627hf_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct w83627hf_sio_data *sio_data = dev->platform_data; @@ -1508,7 +1578,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) return err; } -static int __devexit w83627hf_remove(struct platform_device *pdev) +static int w83627hf_remove(struct platform_device *pdev) { struct w83627hf_data *data = platform_get_drvdata(pdev); @@ -1564,7 +1634,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) return res; } -static int __devinit w83627thf_read_gpio5(struct platform_device *pdev) +static int w83627thf_read_gpio5(struct platform_device *pdev) { struct w83627hf_sio_data *sio_data = pdev->dev.platform_data; int res = 0xff, sel; @@ -1597,7 +1667,7 @@ exit: return res; } -static int __devinit w83687thf_read_vid(struct platform_device *pdev) +static int w83687thf_read_vid(struct platform_device *pdev) { struct w83627hf_sio_data *sio_data = pdev->dev.platform_data; int res = 0xff; @@ -1649,7 +1719,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) return 0; } -static void __devinit w83627hf_init_device(struct platform_device *pdev) +static void w83627hf_init_device(struct platform_device *pdev) { struct w83627hf_data *data = platform_get_drvdata(pdev); int i; @@ -1659,8 +1729,10 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) /* Minimize conflicts with other winbond i2c-only clients... */ /* disable i2c subclients... how to disable main i2c client?? */ /* force i2c address to relatively uncommon address */ - w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); + if (type == w83627hf) { + w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); + w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); + } /* Read VID only once */ if (type == w83627hf || type == w83637hf) { diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 5a5046d94c3e..aeec5b1d81c9 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -24,7 +24,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * as99127f 7 3 0 3 0x31 0x12c3 yes no * as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no * w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes @@ -159,7 +159,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; #define W83781D_DEFAULT_BETA 3435 /* Conversions */ -#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255) +#define IN_TO_REG(val) clamp_val(((val) + 8) / 16, 0, 255) #define IN_FROM_REG(val) ((val) * 16) static inline u8 @@ -167,8 +167,8 @@ FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static inline long @@ -181,7 +181,7 @@ FAN_FROM_REG(u8 val, int div) return 1350000 / (val * div); } -#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128) +#define TEMP_TO_REG(val) clamp_val((val) / 1000, -127, 128) #define TEMP_FROM_REG(val) ((val) * 1000) #define BEEP_MASK_FROM_REG(val, type) ((type) == as99127f ? \ @@ -195,9 +195,8 @@ static inline u8 DIV_TO_REG(long val, enum chips type) { int i; - val = SENSORS_LIMIT(val, 1, - ((type == w83781d - || type == as99127f) ? 8 : 128)) >> 1; + val = clamp_val(val, 1, + ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; @@ -443,7 +442,7 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; - data->vrm = SENSORS_LIMIT(val, 0, 255); + data->vrm = clamp_val(val, 0, 255); return count; } @@ -730,7 +729,7 @@ store_pwm(struct device *dev, struct device_attribute *da, const char *buf, return err; mutex_lock(&data->update_lock); - data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + data->pwm[nr] = clamp_val(val, 0, 255); w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]); mutex_unlock(&data->update_lock); return count; @@ -1764,7 +1763,7 @@ w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value) return 0; } -static int __devinit +static int w83781d_isa_probe(struct platform_device *pdev) { int err, reg; @@ -1824,7 +1823,7 @@ w83781d_isa_probe(struct platform_device *pdev) return err; } -static int __devexit +static int w83781d_isa_remove(struct platform_device *pdev) { struct w83781d_data *data = platform_get_drvdata(pdev); @@ -1842,7 +1841,7 @@ static struct platform_driver w83781d_isa_driver = { .name = "w83781d", }, .probe = w83781d_isa_probe, - .remove = __devexit_p(w83781d_isa_remove), + .remove = w83781d_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 39ab7bcc616e..38dddddf8875 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -22,7 +22,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83791d 10 5 5 3 0x71 0x5ca3 yes no * * The w83791d chip appears to be part way between the 83781d and the @@ -220,15 +220,15 @@ static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value) * in mV as would be measured on the chip input pin, need to just * multiply/divide by 16 to translate from/to register values. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255)) +#define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255)) #define IN_FROM_REG(val) ((val) * 16) static u8 fan_to_reg(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ @@ -273,7 +273,7 @@ static u8 div_to_reg(int nr, long val) int i; /* fan divisors max out at 128 */ - val = SENSORS_LIMIT(val, 1, 128) >> 1; + val = clamp_val(val, 1, 128) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; @@ -747,7 +747,7 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + data->pwm[nr] = clamp_val(val, 0, 255); w83791d_write(client, W83791D_REG_PWM[nr], data->pwm[nr]); mutex_unlock(&data->update_lock); return count; diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 053645279f38..5cb83ddf2cc6 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -31,7 +31,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83792d 9 7 7 3 0x7a 0x5ca3 yes no */ @@ -235,8 +235,8 @@ FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ @@ -244,16 +244,15 @@ FAN_TO_REG(long rpm, int div) 1350000 / ((val) * (div)))) /* for temp1 */ -#define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) +#define TEMP1_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \ + : (val)) / 1000, 0, 0xff)) #define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) /* for temp2 and temp3, because they need additional resolution */ #define TEMP_ADD_FROM_REG(val1, val2) \ ((((val1) & 0x80 ? (val1)-0x100 \ : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0)) #define TEMP_ADD_TO_REG_HIGH(val) \ - (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) + (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 : (val)) / 1000, 0, 0xff)) #define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00) #define DIV_FROM_REG(val) (1 << (val)) @@ -262,7 +261,7 @@ static inline u8 DIV_TO_REG(long val) { int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; + val = clamp_val(val, 1, 128) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; @@ -397,7 +396,7 @@ static ssize_t store_in_##reg(struct device *dev, \ if (err) \ return err; \ mutex_lock(&data->update_lock); \ - data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val) / 4, 0, 255); \ + data->in_##reg[nr] = clamp_val(IN_TO_REG(nr, val) / 4, 0, 255); \ w83792d_write_value(client, W83792D_REG_IN_##REG[nr], \ data->in_##reg[nr]); \ mutex_unlock(&data->update_lock); \ @@ -645,7 +644,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; - val = SENSORS_LIMIT(val, 0, 255) >> 4; + val = clamp_val(val, 0, 255) >> 4; mutex_lock(&data->update_lock); val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0; @@ -799,7 +798,7 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80; - data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255); + data->thermal_cruise[nr] = clamp_val(target_tmp, 0, 255); w83792d_write_value(client, W83792D_REG_THERMAL[nr], (data->thermal_cruise[nr]) | target_mask); mutex_unlock(&data->update_lock); @@ -837,7 +836,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); tol_mask = w83792d_read_value(client, W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0); - tol_tmp = SENSORS_LIMIT(val, 0, 15); + tol_tmp = clamp_val(val, 0, 15); tol_tmp &= 0x0f; data->tolerance[nr] = tol_tmp; if (nr == 1) @@ -881,7 +880,7 @@ store_sf2_point(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127); + data->sf2_points[index][nr] = clamp_val(val, 0, 127); mask_tmp = w83792d_read_value(client, W83792D_REG_POINTS[index][nr]) & 0x80; w83792d_write_value(client, W83792D_REG_POINTS[index][nr], @@ -923,7 +922,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15); + data->sf2_levels[index][nr] = clamp_val((val * 15) / 100, 0, 15); mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr]) & ((nr == 3) ? 0xf0 : 0x0f); if (nr == 3) diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 99799fd1d917..660427520c53 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -191,7 +191,7 @@ static inline u16 FAN_TO_REG(long rpm) { if (rpm <= 0) return 0x0fff; - return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); + return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); } static inline unsigned long TIME_FROM_REG(u8 reg) @@ -201,7 +201,7 @@ static inline unsigned long TIME_FROM_REG(u8 reg) static inline u8 TIME_TO_REG(unsigned long val) { - return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); + return clamp_val((val + 50) / 100, 0, 0xff); } static inline long TEMP_FROM_REG(s8 reg) @@ -211,7 +211,7 @@ static inline long TEMP_FROM_REG(s8 reg) static inline s8 TEMP_TO_REG(long val, s8 min, s8 max) { - return SENSORS_LIMIT((val + (val < 0 ? -500 : 500)) / 1000, min, max); + return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max); } struct w83793_data { @@ -558,7 +558,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index), val); } else { - val = SENSORS_LIMIT(val, 0, 0xff) >> 2; + val = clamp_val(val, 0, 0xff) >> 2; data->pwm[index][nr] = w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0; data->pwm[index][nr] |= val; @@ -739,7 +739,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, if (nr == SETUP_PWM_DEFAULT) { data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0; - data->pwm_default |= SENSORS_LIMIT(val, 0, 0xff) >> 2; + data->pwm_default |= clamp_val(val, 0, 0xff) >> 2; w83793_write_value(client, W83793_REG_PWM_DEFAULT, data->pwm_default); } else if (nr == SETUP_PWM_UPTIME) { @@ -838,7 +838,7 @@ store_sf_ctrl(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); if (nr == TEMP_FAN_MAP) { - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val); data->temp_fan_map[index] = val; } else if (nr == TEMP_PWM_ENABLE) { @@ -907,7 +907,7 @@ store_sf2_pwm(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; - val = SENSORS_LIMIT(val, 0, 0xff) >> 2; + val = clamp_val(val, 0, 0xff) >> 2; mutex_lock(&data->update_lock); data->sf2_pwm[index][nr] = @@ -1003,9 +1003,9 @@ store_in(struct device *dev, struct device_attribute *attr, /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */ if (nr == 1 || nr == 2) val -= scale_in_add[index] / scale_in[index]; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); } else { - val = SENSORS_LIMIT(val, 0, 0x3FF); + val = clamp_val(val, 0, 0x3FF); data->in_low_bits[nr] = w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]); data->in_low_bits[nr] &= ~(0x03 << (2 * index)); diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 55a4f4894531..e226096148eb 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -262,7 +262,7 @@ static inline u16 fan_to_reg(long rpm) { if (rpm <= 0) return 0x0fff; - return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); + return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); } static inline unsigned long time_from_reg(u8 reg) @@ -272,7 +272,7 @@ static inline unsigned long time_from_reg(u8 reg) static inline u8 time_to_reg(unsigned long val) { - return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); + return clamp_val((val + 50) / 100, 0, 0xff); } static inline long temp_from_reg(s8 reg) @@ -282,7 +282,7 @@ static inline long temp_from_reg(s8 reg) static inline s8 temp_to_reg(long val, s8 min, s8 max) { - return SENSORS_LIMIT(val / 1000, min, max); + return clamp_val(val / 1000, min, max); } static const u16 pwm_freq_cksel0[16] = { @@ -319,7 +319,7 @@ static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) /* Best fit for cksel = 1 */ base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); - reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); + reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); best1 = base_clock / reg1; reg1 = 0x80 | (reg1 - 1); @@ -889,7 +889,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, val = pwm_freq_to_reg(val, data->clkin); break; default: - val = SENSORS_LIMIT(val, 0, 0xff); + val = clamp_val(val, 0, 0xff); break; } w83795_write(client, W83795_REG_PWM(index, nr), val); @@ -1126,7 +1126,7 @@ store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, break; case TEMP_PWM_FAN_MAP: mutex_lock(&data->update_lock); - tmp = SENSORS_LIMIT(tmp, 0, 0xff); + tmp = clamp_val(tmp, 0, 0xff); w83795_write(client, W83795_REG_TFMR(index), tmp); data->pwm_tfmr[index] = tmp; mutex_unlock(&data->update_lock); @@ -1177,13 +1177,13 @@ store_fanin(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); switch (nr) { case FANIN_TARGET: - val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); + val = fan_to_reg(clamp_val(val, 0, 0xfff)); w83795_write(client, W83795_REG_FTSH(index), val >> 4); w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); data->target_speed[index] = val; break; case FANIN_TOL: - val = SENSORS_LIMIT(val, 0, 0x3f); + val = clamp_val(val, 0, 0x3f); w83795_write(client, W83795_REG_TFTS, val); data->tol_speed = val; break; @@ -1227,22 +1227,22 @@ store_temp_pwm(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); switch (nr) { case TEMP_PWM_TTTI: - val = SENSORS_LIMIT(val, 0, 0x7f); + val = clamp_val(val, 0, 0x7f); w83795_write(client, W83795_REG_TTTI(index), val); break; case TEMP_PWM_CTFS: - val = SENSORS_LIMIT(val, 0, 0x7f); + val = clamp_val(val, 0, 0x7f); w83795_write(client, W83795_REG_CTFS(index), val); break; case TEMP_PWM_HCT: - val = SENSORS_LIMIT(val, 0, 0x0f); + val = clamp_val(val, 0, 0x0f); tmp = w83795_read(client, W83795_REG_HT(index)); tmp &= 0x0f; tmp |= (val << 4) & 0xf0; w83795_write(client, W83795_REG_HT(index), tmp); break; case TEMP_PWM_HOT: - val = SENSORS_LIMIT(val, 0, 0x0f); + val = clamp_val(val, 0, 0x0f); tmp = w83795_read(client, W83795_REG_HT(index)); tmp &= 0xf0; tmp |= val & 0x0f; @@ -1541,7 +1541,7 @@ store_in(struct device *dev, struct device_attribute *attr, if ((index >= 17) && !((data->has_gain >> (index - 17)) & 1)) val /= 8; - val = SENSORS_LIMIT(val, 0, 0x3FF); + val = clamp_val(val, 0, 0x3FF); mutex_lock(&data->update_lock); lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; @@ -1596,7 +1596,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, switch (nr) { case SETUP_PWM_DEFAULT: - val = SENSORS_LIMIT(val, 0, 0xff); + val = clamp_val(val, 0, 0xff); break; case SETUP_PWM_UPTIME: case SETUP_PWM_DOWNTIME: diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index f0e8286c3c70..edb06cda5a68 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -20,7 +20,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no */ @@ -86,8 +86,8 @@ FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ @@ -95,9 +95,8 @@ FAN_TO_REG(long rpm, int div) 1350000 / ((val) * (div)))) /* for temp */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? \ - (val) + 0x100 * 1000 \ - : (val)) / 1000, 0, 0xff)) +#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \ + : (val)) / 1000, 0, 0xff)) #define TEMP_FROM_REG(val) (((val) & 0x80 ? \ (val) - 0x100 : (val)) * 1000) @@ -106,7 +105,7 @@ FAN_TO_REG(long rpm, int div) * in mV as would be measured on the chip input pin, need to just * multiply/divide by 8 to translate from/to register values. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) +#define IN_TO_REG(val) (clamp_val((((val) + 4) / 8), 0, 255)) #define IN_FROM_REG(val) ((val) * 8) #define DIV_FROM_REG(val) (1 << (val)) @@ -115,7 +114,7 @@ static inline u8 DIV_TO_REG(long val) { int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; + val = clamp_val(val, 1, 128) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; @@ -481,7 +480,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; - val = SENSORS_LIMIT(val, 0, 255); + val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); data->pwm[nr] = val; @@ -564,7 +563,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); tol_mask = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0); - tol_tmp = SENSORS_LIMIT(val, 0, 15); + tol_tmp = clamp_val(val, 0, 15); tol_tmp &= 0x0f; data->tolerance[nr] = tol_tmp; if (nr == 1) diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c index d0db1f2738fb..df6ceaf8d58a 100644 --- a/drivers/hwmon/wm831x-hwmon.c +++ b/drivers/hwmon/wm831x-hwmon.c @@ -157,7 +157,7 @@ static const struct attribute_group wm831x_attr_group = { .attrs = wm831x_attributes, }; -static int __devinit wm831x_hwmon_probe(struct platform_device *pdev) +static int wm831x_hwmon_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_hwmon *hwmon; @@ -189,7 +189,7 @@ err_sysfs: return ret; } -static int __devexit wm831x_hwmon_remove(struct platform_device *pdev) +static int wm831x_hwmon_remove(struct platform_device *pdev) { struct wm831x_hwmon *hwmon = platform_get_drvdata(pdev); @@ -201,7 +201,7 @@ static int __devexit wm831x_hwmon_remove(struct platform_device *pdev) static struct platform_driver wm831x_hwmon_driver = { .probe = wm831x_hwmon_probe, - .remove = __devexit_p(wm831x_hwmon_remove), + .remove = wm831x_hwmon_remove, .driver = { .name = "wm831x-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c index b955756bdb42..64bf75c9442b 100644 --- a/drivers/hwmon/wm8350-hwmon.c +++ b/drivers/hwmon/wm8350-hwmon.c @@ -91,7 +91,7 @@ static const struct attribute_group wm8350_attr_group = { .attrs = wm8350_attributes, }; -static int __devinit wm8350_hwmon_probe(struct platform_device *pdev) +static int wm8350_hwmon_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); int ret; @@ -114,7 +114,7 @@ err: return ret; } -static int __devexit wm8350_hwmon_remove(struct platform_device *pdev) +static int wm8350_hwmon_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); @@ -126,7 +126,7 @@ static int __devexit wm8350_hwmon_remove(struct platform_device *pdev) static struct platform_driver wm8350_hwmon_driver = { .probe = wm8350_hwmon_probe, - .remove = __devexit_p(wm8350_hwmon_remove), + .remove = wm8350_hwmon_remove, .driver = { .name = "wm8350-hwmon", .owner = THIS_MODULE, |