diff options
Diffstat (limited to 'drivers/hwmon')
71 files changed, 5404 insertions, 2774 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5ce43d8dfa9..02d3d85829f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -111,22 +111,6 @@ config SENSORS_AD7418 This driver can also be built as a module. If so, the module will be called ad7418. -config SENSORS_ADCXX - tristate "National Semiconductor ADCxxxSxxx" - depends on SPI_MASTER - help - If you say yes here you get support for the National Semiconductor - ADC<bb><c>S<sss> chip family, where - * bb is the resolution in number of bits (8, 10, 12) - * c is the number of channels (1, 2, 4, 8) - * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 - kSPS and 101 for 1 MSPS) - - Examples : ADC081S101, ADC124S501, ... - - This driver can also be built as a module. If so, the module - will be called adcxx. - config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" depends on I2C @@ -296,8 +280,8 @@ config SENSORS_K10TEMP If you say yes here you get support for the temperature sensor(s) inside your CPU. Supported are later revisions of the AMD Family 10h and all revisions of the AMD Family 11h, - 12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity) and - 16h (Kabini) microarchitectures. + 12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri) and + 16h (Kabini/Mullins) microarchitectures. This driver can also be built as a module. If so, the module will be called k10temp. @@ -312,6 +296,31 @@ config SENSORS_FAM15H_POWER This driver can also be built as a module. If so, the module will be called fam15h_power. +config SENSORS_APPLESMC + tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" + depends on INPUT && X86 + select NEW_LEDS + select LEDS_CLASS + select INPUT_POLLDEV + default n + help + This driver provides support for the Apple System Management + Controller, which provides an accelerometer (Apple Sudden Motion + Sensor), light sensors, temperature sensors, keyboard backlight + control and fan control. + + Only Intel-based Apple's computers are supported (MacBook Pro, + MacBook, MacMini). + + Data from the different sensors, keyboard backlight control and fan + control are accessible via sysfs. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. + + Say Y here if you have an applicable laptop and want to experience + the awesome power of applesmc. + config SENSORS_ASB100 tristate "Asus ASB100 Bach" depends on X86 && I2C @@ -435,6 +444,12 @@ config SENSORS_F75375S This driver can also be built as a module. If so, the module will be called f75375s. +config SENSORS_MC13783_ADC + tristate "Freescale MC13783/MC13892 ADC" + depends on MFD_MC13XXX + help + Support for the A/D converter on MC13783 and MC13892 PMIC. + config SENSORS_FSCHMD tristate "Fujitsu Siemens Computers sensor chips" depends on X86 && I2C @@ -451,26 +466,6 @@ config SENSORS_FSCHMD This driver can also be built as a module. If so, the module will be called fschmd. -config SENSORS_G760A - tristate "GMT G760A" - depends on I2C - help - If you say yes here you get support for Global Mixed-mode - Technology Inc G760A fan speed PWM controller chips. - - This driver can also be built as a module. If so, the module - will be called g760a. - -config SENSORS_G762 - tristate "GMT G762 and G763" - depends on I2C - help - If you say yes here you get support for Global Mixed-mode - Technology Inc G762 and G763 fan speed PWM controller chips. - - This driver can also be built as a module. If so, the module - will be called g762. - config SENSORS_GL518SM tristate "Genesys Logic GL518SM" depends on I2C @@ -492,6 +487,26 @@ config SENSORS_GL520SM This driver can also be built as a module. If so, the module will be called gl520sm. +config SENSORS_G760A + tristate "GMT G760A" + depends on I2C + help + If you say yes here you get support for Global Mixed-mode + Technology Inc G760A fan speed PWM controller chips. + + This driver can also be built as a module. If so, the module + will be called g760a. + +config SENSORS_G762 + tristate "GMT G762 and G763" + depends on I2C + help + If you say yes here you get support for Global Mixed-mode + Technology Inc G762 and G763 fan speed PWM controller chips. + + This driver can also be built as a module. If so, the module + will be called g762. + config SENSORS_GPIO_FAN tristate "GPIO fan" depends on GPIOLIB @@ -511,24 +526,6 @@ config SENSORS_HIH6130 This driver can also be built as a module. If so, the module will be called hih6130. -config SENSORS_HTU21 - tristate "Measurement Specialties HTU21D humidity/temperature sensors" - depends on I2C - help - If you say yes here you get support for the Measurement Specialties - HTU21D humidity and temperature sensors. - - This driver can also be built as a module. If so, the module - will be called htu21. - -config SENSORS_CORETEMP - tristate "Intel Core/Core2/Atom temperature sensor" - 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 - are supported. Check Documentation/hwmon/coretemp for details. - config SENSORS_IBMAEM tristate "IBM Active Energy Manager temperature/power sensors and control" select IPMI_SI @@ -566,6 +563,14 @@ config SENSORS_IIO_HWMON for those channels specified in the map. This map can be provided either via platform data or the device tree bindings. +config SENSORS_CORETEMP + tristate "Intel Core/Core2/Atom temperature sensor" + 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 + are supported. Check Documentation/hwmon/coretemp for details. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" depends on !PPC @@ -614,6 +619,219 @@ config SENSORS_LINEAGE This driver can also be built as a module. If so, the module will be called lineage-pem. +config SENSORS_LTC2945 + tristate "Linear Technology LTC2945" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for Linear Technology LTC2945 + I2C System Monitor. + + This driver can also be built as a module. If so, the module will + be called ltc2945. + +config SENSORS_LTC4151 + tristate "Linear Technology LTC4151" + depends on I2C + default n + help + If you say yes here you get support for Linear Technology LTC4151 + High Voltage I2C Current and Voltage Monitor interface. + + This driver can also be built as a module. If so, the module will + be called ltc4151. + +config SENSORS_LTC4215 + tristate "Linear Technology LTC4215" + depends on I2C + default n + help + If you say yes here you get support for Linear Technology LTC4215 + Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4215. + +config SENSORS_LTC4222 + tristate "Linear Technology LTC4222" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for Linear Technology LTC4222 + Dual Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4222. + +config SENSORS_LTC4245 + tristate "Linear Technology LTC4245" + depends on I2C + default n + help + If you say yes here you get support for Linear Technology LTC4245 + Multiple Supply Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4245. + +config SENSORS_LTC4260 + tristate "Linear Technology LTC4260" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for Linear Technology LTC4260 + Positive Voltage Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4260. + +config SENSORS_LTC4261 + tristate "Linear Technology LTC4261" + depends on I2C + default n + help + If you say yes here you get support for Linear Technology LTC4261 + Negative Voltage Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4261. + +config SENSORS_MAX1111 + tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles" + depends on SPI_MASTER + help + Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113 + ADC chips. + + This driver can also be built as a module. If so, the module + will be called max1111. + +config SENSORS_MAX16065 + tristate "Maxim MAX16065 System Manager and compatibles" + depends on I2C + help + If you say yes here you get support for hardware monitoring + capabilities of the following Maxim System Manager chips. + MAX16065 + MAX16066 + MAX16067 + MAX16068 + MAX16070 + MAX16071 + + This driver can also be built as a module. If so, the module + will be called max16065. + +config SENSORS_MAX1619 + tristate "Maxim MAX1619 sensor chip" + depends on I2C + help + If you say yes here you get support for MAX1619 sensor chip. + + This driver can also be built as a module. If so, the module + will be called max1619. + +config SENSORS_MAX1668 + tristate "Maxim MAX1668 and compatibles" + depends on I2C + help + If you say yes here you get support for MAX1668, MAX1989 and + MAX1805 chips. + + This driver can also be built as a module. If so, the module + will be called max1668. + +config SENSORS_MAX197 + tristate "Maxim MAX197 and compatibles" + help + Support for the Maxim MAX197 A/D converter. + Support will include, but not be limited to, MAX197, and MAX199. + + This driver can also be built as a module. If so, the module + will be called max197. + +config SENSORS_MAX6639 + tristate "Maxim MAX6639 sensor chip" + depends on I2C + help + If you say yes here you get support for the MAX6639 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called max6639. + +config SENSORS_MAX6642 + tristate "Maxim MAX6642 sensor chip" + depends on I2C + help + If you say yes here you get support for MAX6642 sensor chip. + MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor + with Overtemperature Alarm from Maxim. + + This driver can also be built as a module. If so, the module + will be called max6642. + +config SENSORS_MAX6650 + tristate "Maxim MAX6650 sensor chip" + depends on I2C + help + If you say yes here you get support for the MAX6650 / MAX6651 + sensor chips. + + 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_HTU21 + tristate "Measurement Specialties HTU21D humidity/temperature sensors" + depends on I2C + help + If you say yes here you get support for the Measurement Specialties + HTU21D humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called htu21. + +config SENSORS_MCP3021 + tristate "Microchip MCP3021 and compatibles" + depends on I2C + help + If you say yes here you get support for MCP3021 and MCP3221. + The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221 + with 12-bit resolution. + + This driver can also be built as a module. If so, the module + will be called mcp3021. + +config SENSORS_ADCXX + tristate "National Semiconductor ADCxxxSxxx" + depends on SPI_MASTER + help + If you say yes here you get support for the National Semiconductor + ADC<bb><c>S<sss> chip family, where + * bb is the resolution in number of bits (8, 10, 12) + * c is the number of channels (1, 2, 4, 8) + * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 + kSPS and 101 for 1 MSPS) + + Examples : ADC081S101, ADC124S501, ... + + This driver can also be built as a module. If so, the module + will be called adcxx. + config SENSORS_LM63 tristate "National Semiconductor LM63 and compatibles" depends on I2C @@ -776,50 +994,6 @@ config SENSORS_LM93 This driver can also be built as a module. If so, the module will be called lm93. -config SENSORS_LTC4151 - tristate "Linear Technology LTC4151" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4151 - High Voltage I2C Current and Voltage Monitor interface. - - This driver can also be built as a module. If so, the module will - be called ltc4151. - -config SENSORS_LTC4215 - tristate "Linear Technology LTC4215" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4215 - Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4215. - -config SENSORS_LTC4245 - tristate "Linear Technology LTC4245" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4245 - Multiple Supply Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4245. - -config SENSORS_LTC4261 - tristate "Linear Technology LTC4261" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4261 - Negative Voltage Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4261. - config SENSORS_LM95234 tristate "National Semiconductor LM95234" depends on I2C @@ -849,167 +1023,71 @@ config SENSORS_LM95245 This driver can also be built as a module. If so, the module will be called lm95245. -config SENSORS_MAX1111 - tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles" - depends on SPI_MASTER - help - Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113 - ADC chips. - - This driver can also be built as a module. If so, the module - will be called max1111. - -config SENSORS_MAX16065 - tristate "Maxim MAX16065 System Manager and compatibles" - depends on I2C - help - If you say yes here you get support for hardware monitoring - capabilities of the following Maxim System Manager chips. - MAX16065 - MAX16066 - MAX16067 - MAX16068 - MAX16070 - MAX16071 - - This driver can also be built as a module. If so, the module - will be called max16065. - -config SENSORS_MAX1619 - tristate "Maxim MAX1619 sensor chip" - depends on I2C - help - If you say yes here you get support for MAX1619 sensor chip. - - This driver can also be built as a module. If so, the module - will be called max1619. - -config SENSORS_MAX1668 - tristate "Maxim MAX1668 and compatibles" - depends on I2C - help - If you say yes here you get support for MAX1668, MAX1989 and - MAX1805 chips. - - This driver can also be built as a module. If so, the module - will be called max1668. - -config SENSORS_MAX197 - tristate "Maxim MAX197 and compatibles" - help - Support for the Maxim MAX197 A/D converter. - Support will include, but not be limited to, MAX197, and MAX199. - - This driver can also be built as a module. If so, the module - will be called max197. - -config SENSORS_MAX6639 - tristate "Maxim MAX6639 sensor chip" - depends on I2C - help - If you say yes here you get support for the MAX6639 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called max6639. - -config SENSORS_MAX6642 - tristate "Maxim MAX6642 sensor chip" - depends on I2C - help - If you say yes here you get support for MAX6642 sensor chip. - MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor - with Overtemperature Alarm from Maxim. - - This driver can also be built as a module. If so, the module - will be called max6642. - -config SENSORS_MAX6650 - tristate "Maxim MAX6650 sensor chip" - depends on I2C - help - If you say yes here you get support for the MAX6650 / MAX6651 - sensor chips. - - 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 +config SENSORS_PC87360 + tristate "National Semiconductor PC87360 family" + depends on !PPC + select HWMON_VID help - If you say yes here you get support for MCP3021 and MCP3221. - The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221 - with 12-bit resolution. + If you say yes here you get access to the hardware monitoring + functions of the National Semiconductor PC8736x Super-I/O chips. + The PC87360, PC87363 and PC87364 only have fan monitoring and + control. The PC87365 and PC87366 additionally have voltage and + temperature monitoring. This driver can also be built as a module. If so, the module - will be called mcp3021. + will be called pc87360. -config SENSORS_NCT6775 - tristate "Nuvoton NCT6775F and compatibles" +config SENSORS_PC87427 + tristate "National Semiconductor PC87427" depends on !PPC - select HWMON_VID help - If you say yes here you get support for the hardware monitoring - functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D - and compatible Super-I/O chips. This driver replaces the - w83627ehf driver for NCT6775F and NCT6776F. + If you say yes here you get access to the hardware monitoring + functions of the National Semiconductor PC87427 Super-I/O chip. + The chip has two distinct logical devices, one for fan speed + monitoring and control, and one for voltage and temperature + monitoring. Fan speed monitoring and control are supported, as + well as temperature monitoring. Voltages aren't supported yet. This driver can also be built as a module. If so, the module - will be called nct6775. + will be called pc87427. config SENSORS_NTC_THERMISTOR - tristate "NTC thermistor support" - depends on (!OF && !IIO) || (OF && IIO) + tristate "NTC thermistor support from Murata" + depends on !OF || IIO=n || IIO help This driver supports NTC thermistors sensor reading and its interpretation. The driver can also monitor the temperature and send notifications about the temperature. Currently, this driver supports - NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333. + NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333 + from Murata. This driver can also be built as a module. If so, the module will be called ntc-thermistor. -config SENSORS_PC87360 - tristate "National Semiconductor PC87360 family" +config SENSORS_NCT6683 + tristate "Nuvoton NCT6683D" depends on !PPC - select HWMON_VID help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC8736x Super-I/O chips. - The PC87360, PC87363 and PC87364 only have fan monitoring and - control. The PC87365 and PC87366 additionally have voltage and - temperature monitoring. + If you say yes here you get support for the hardware monitoring + functionality of the Nuvoton NCT6683D eSIO chip. This driver can also be built as a module. If so, the module - will be called pc87360. + will be called nct6683. -config SENSORS_PC87427 - tristate "National Semiconductor PC87427" +config SENSORS_NCT6775 + tristate "Nuvoton NCT6775F and compatibles" depends on !PPC + select HWMON_VID help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC87427 Super-I/O chip. - The chip has two distinct logical devices, one for fan speed - monitoring and control, and one for voltage and temperature - monitoring. Fan speed monitoring and control are supported, as - well as temperature monitoring. Voltages aren't supported yet. + If you say yes here you get support for the hardware monitoring + functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D + and compatible Super-I/O chips. This driver replaces the + w83627ehf driver for NCT6775F and NCT6776F. This driver can also be built as a module. If so, the module - will be called pc87427. + will be called nct6775. config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" @@ -1047,6 +1125,16 @@ config SENSORS_SHT21 This driver can also be built as a module. If so, the module will be called sht21. +config SENSORS_SHTC1 + tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." + depends on I2C + help + If you say yes here you get support for the Sensiron SHTC1 and SHTW1 + humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called shtc1. + config SENSORS_S3C tristate "Samsung built-in ADC" depends on S3C_ADC @@ -1074,21 +1162,6 @@ config SENSORS_SIS5595 This driver can also be built as a module. If so, the module will be called sis5595. -config SENSORS_SMM665 - tristate "Summit Microelectronics SMM665" - depends on I2C - default n - help - If you say yes here you get support for the hardware monitoring - features of the Summit Microelectronics SMM665/SMM665B Six-Channel - Active DC Output Controller / Monitor. - - Other supported chips are SMM465, SMM665C, SMM764, and SMM766. - Support for those chips is untested. - - This driver can also be built as a module. If so, the module will - be called smm665. - config SENSORS_DME1737 tristate "SMSC DME1737, SCH311x and compatibles" depends on I2C && !PPC @@ -1104,6 +1177,7 @@ config SENSORS_DME1737 config SENSORS_EMC1403 tristate "SMSC EMC1403/23 thermal sensor" depends on I2C + select REGMAP_I2C help If you say yes here you get support for the SMSC EMC1403/23 temperature monitoring chip. @@ -1210,6 +1284,31 @@ config SENSORS_SCH5636 This driver can also be built as a module. If so, the module will be called sch5636. +config SENSORS_SMM665 + tristate "Summit Microelectronics SMM665" + depends on I2C + default n + help + If you say yes here you get support for the hardware monitoring + features of the Summit Microelectronics SMM665/SMM665B Six-Channel + Active DC Output Controller / Monitor. + + Other supported chips are SMM465, SMM665C, SMM764, and SMM766. + Support for those chips is untested. + + This driver can also be built as a module. If so, the module will + be called smm665. + +config SENSORS_ADC128D818 + tristate "Texas Instruments ADC128D818" + depends on I2C + help + If you say yes here you get support for the Texas Instruments + ADC128D818 System Monitor with Temperature Sensor chip. + + This driver can also be built as a module. If so, the module + will be called adc128d818. + config SENSORS_ADS1015 tristate "Texas Instruments ADS1015" depends on I2C @@ -1525,37 +1624,6 @@ config SENSORS_ULTRA45 This driver provides support for the Ultra45 workstation environmental sensors. -config SENSORS_APPLESMC - tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" - depends on INPUT && X86 - select NEW_LEDS - select LEDS_CLASS - select INPUT_POLLDEV - default n - help - This driver provides support for the Apple System Management - Controller, which provides an accelerometer (Apple Sudden Motion - Sensor), light sensors, temperature sensors, keyboard backlight - control and fan control. - - Only Intel-based Apple's computers are supported (MacBook Pro, - MacBook, MacMini). - - Data from the different sensors, keyboard backlight control and fan - control are accessible via sysfs. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. - - Say Y here if you have an applicable laptop and want to experience - the awesome power of applesmc. - -config SENSORS_MC13783_ADC - tristate "Freescale MC13783/MC13892 ADC" - depends on MFD_MC13XXX - help - Support for the A/D converter on MC13783 and MC13892 PMIC. - if ACPI comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index ec7cde06eb5..3dc0f02f71d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o obj-$(CONFIG_SENSORS_AD7314) += ad7314.o obj-$(CONFIG_SENSORS_AD7414) += ad7414.o obj-$(CONFIG_SENSORS_AD7418) += ad7418.o +obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o @@ -95,9 +96,12 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o obj-$(CONFIG_SENSORS_LM95234) += lm95234.o obj-$(CONFIG_SENSORS_LM95241) += lm95241.o obj-$(CONFIG_SENSORS_LM95245) += lm95245.o +obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o +obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o +obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o obj-$(CONFIG_SENSORS_MAX1111) += max1111.o obj-$(CONFIG_SENSORS_MAX16065) += max16065.o @@ -110,6 +114,7 @@ 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_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o @@ -121,6 +126,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o +obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c new file mode 100644 index 00000000000..0625e50d7a6 --- /dev/null +++ b/drivers/hwmon/adc128d818.c @@ -0,0 +1,491 @@ +/* + * Driver for TI ADC128D818 System Monitor with Temperature Sensor + * + * Copyright (c) 2014 Guenter Roeck + * + * Derived from lm80.c + * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + * and Philip Edelbrock <phil@netroedge.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. + * + * 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/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/regulator/consumer.h> +#include <linux/mutex.h> + +/* Addresses to scan + * The chip also supports addresses 0x35..0x37. Don't scan those addresses + * since they are also used by some EEPROMs, which may result in false + * positives. + */ +static const unsigned short normal_i2c[] = { + 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; + +/* registers */ +#define ADC128_REG_IN_MAX(nr) (0x2a + (nr) * 2) +#define ADC128_REG_IN_MIN(nr) (0x2b + (nr) * 2) +#define ADC128_REG_IN(nr) (0x20 + (nr)) + +#define ADC128_REG_TEMP 0x27 +#define ADC128_REG_TEMP_MAX 0x38 +#define ADC128_REG_TEMP_HYST 0x39 + +#define ADC128_REG_CONFIG 0x00 +#define ADC128_REG_ALARM 0x01 +#define ADC128_REG_MASK 0x03 +#define ADC128_REG_CONV_RATE 0x07 +#define ADC128_REG_ONESHOT 0x09 +#define ADC128_REG_SHUTDOWN 0x0a +#define ADC128_REG_CONFIG_ADV 0x0b +#define ADC128_REG_BUSY_STATUS 0x0c + +#define ADC128_REG_MAN_ID 0x3e +#define ADC128_REG_DEV_ID 0x3f + +struct adc128_data { + struct i2c_client *client; + struct regulator *regulator; + int vref; /* Reference voltage in mV */ + struct mutex update_lock; + bool valid; /* true if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 in[3][7]; /* Register value, normalized to 12 bit + * 0: input voltage + * 1: min limit + * 2: max limit + */ + s16 temp[3]; /* Register value, normalized to 9 bit + * 0: sensor 1: limit 2: hyst + */ + u8 alarms; /* alarm register value */ +}; + +static struct adc128_data *adc128_update_device(struct device *dev) +{ + struct adc128_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct adc128_data *ret = data; + int i, rv; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + for (i = 0; i < 7; i++) { + rv = i2c_smbus_read_word_swapped(client, + ADC128_REG_IN(i)); + if (rv < 0) + goto abort; + data->in[0][i] = rv >> 4; + + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_IN_MIN(i)); + if (rv < 0) + goto abort; + data->in[1][i] = rv << 4; + + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_IN_MAX(i)); + if (rv < 0) + goto abort; + data->in[2][i] = rv << 4; + } + + rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP); + if (rv < 0) + goto abort; + data->temp[0] = rv >> 7; + + rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX); + if (rv < 0) + goto abort; + data->temp[1] = rv << 1; + + rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST); + if (rv < 0) + goto abort; + data->temp[2] = rv << 1; + + rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM); + if (rv < 0) + goto abort; + data->alarms |= rv; + + data->last_updated = jiffies; + data->valid = true; + } + goto done; + +abort: + ret = ERR_PTR(rv); + data->valid = false; +done: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adc128_data *data = adc128_update_device(dev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + int val; + + if (IS_ERR(data)) + return PTR_ERR(data); + + val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095); + return sprintf(buf, "%d\n", val); +} + +static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adc128_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + u8 reg, regval; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + mutex_lock(&data->update_lock); + /* 10 mV LSB on limit registers */ + regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255); + data->in[index][nr] = regval << 4; + reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr); + i2c_smbus_write_byte_data(data->client, reg, regval); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t adc128_show_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adc128_data *data = adc128_update_device(dev); + int index = to_sensor_dev_attr(attr)->index; + int temp; + + if (IS_ERR(data)) + return PTR_ERR(data); + + temp = (data->temp[index] << 7) >> 7; /* sign extend */ + return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */ +} + +static ssize_t adc128_set_temp(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adc128_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + long val; + int err; + s8 regval; + + err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + mutex_lock(&data->update_lock); + regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); + data->temp[index] = regval << 1; + i2c_smbus_write_byte_data(data->client, + index == 1 ? ADC128_REG_TEMP_MAX + : ADC128_REG_TEMP_HYST, + regval); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t adc128_show_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adc128_data *data = adc128_update_device(dev); + int mask = 1 << to_sensor_dev_attr(attr)->index; + u8 alarms; + + if (IS_ERR(data)) + return PTR_ERR(data); + + /* + * Clear an alarm after reporting it to user space. If it is still + * active, the next update sequence will set the alarm bit again. + */ + alarms = data->alarms; + data->alarms &= ~mask; + + return sprintf(buf, "%u\n", !!(alarms & mask)); +} + +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, + adc128_show_in, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 0, 1); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 0, 2); + +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, + adc128_show_in, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 1, 1); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 1, 2); + +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, + adc128_show_in, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 2, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 2, 2); + +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, + adc128_show_in, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 3, 1); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 3, 2); + +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, + adc128_show_in, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 4, 1); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 4, 2); + +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, + adc128_show_in, NULL, 5, 0); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 5, 1); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 5, 2); + +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, + adc128_show_in, NULL, 6, 0); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 6, 1); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 6, 2); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + adc128_show_temp, adc128_set_temp, 1); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + adc128_show_temp, adc128_set_temp, 2); + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7); + +static struct attribute *adc128_attrs[] = { + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(adc128); + +static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info) +{ + int man_id, dev_id; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID); + dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID); + if (man_id != 0x01 || dev_id != 0x09) + return -ENODEV; + + /* Check unused bits for confirmation */ + if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4) + return -ENODEV; + if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe) + return -ENODEV; + if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe) + return -ENODEV; + if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe) + return -ENODEV; + if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8) + return -ENODEV; + if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc) + return -ENODEV; + + strlcpy(info->type, "adc128d818", I2C_NAME_SIZE); + + return 0; +} + +static int adc128_init_client(struct adc128_data *data) +{ + struct i2c_client *client = data->client; + int err; + + /* + * Reset chip to defaults. + * This makes most other initializations unnecessary. + */ + err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80); + if (err) + return err; + + /* Start monitoring */ + err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01); + if (err) + return err; + + /* If external vref is selected, configure the chip to use it */ + if (data->regulator) { + err = i2c_smbus_write_byte_data(client, + ADC128_REG_CONFIG_ADV, 0x01); + if (err) + return err; + } + + return 0; +} + +static int adc128_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct regulator *regulator; + struct device *hwmon_dev; + struct adc128_data *data; + int err, vref; + + data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* vref is optional. If specified, is used as chip reference voltage */ + regulator = devm_regulator_get_optional(dev, "vref"); + if (!IS_ERR(regulator)) { + data->regulator = regulator; + err = regulator_enable(regulator); + if (err < 0) + return err; + vref = regulator_get_voltage(regulator); + if (vref < 0) { + err = vref; + goto error; + } + data->vref = DIV_ROUND_CLOSEST(vref, 1000); + } else { + data->vref = 2560; /* 2.56V, in mV */ + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* Initialize the chip */ + err = adc128_init_client(data); + if (err < 0) + goto error; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, adc128_groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto error; + } + + return 0; + +error: + if (data->regulator) + regulator_disable(data->regulator); + return err; +} + +static int adc128_remove(struct i2c_client *client) +{ + struct adc128_data *data = i2c_get_clientdata(client); + + if (data->regulator) + regulator_disable(data->regulator); + + return 0; +} + +static const struct i2c_device_id adc128_id[] = { + { "adc128d818", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adc128_id); + +static struct i2c_driver adc128_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "adc128d818", + }, + .probe = adc128_probe, + .remove = adc128_remove, + .id_table = adc128_id, + .detect = adc128_detect, + .address_list = normal_i2c, +}; + +module_i2c_driver(adc128_driver); + +MODULE_AUTHOR("Guenter Roeck"); +MODULE_DESCRIPTION("Driver for ADC128D818"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 29dd9f746df..d74241bb278 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -79,9 +79,11 @@ enum chips { /* Each client has this additional data */ struct adm1021_data { - struct device *hwmon_dev; + struct i2c_client *client; enum chips type; + const struct attribute_group *groups[3]; + struct mutex update_lock; char valid; /* !=0 if following fields are valid */ char low_power; /* !=0 if device in low power mode */ @@ -101,7 +103,6 @@ static int adm1021_probe(struct i2c_client *client, static int adm1021_detect(struct i2c_client *client, struct i2c_board_info *info); static void adm1021_init_client(struct i2c_client *client); -static int adm1021_remove(struct i2c_client *client); static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ @@ -128,7 +129,6 @@ static struct i2c_driver adm1021_driver = { .name = "adm1021", }, .probe = adm1021_probe, - .remove = adm1021_remove, .id_table = adm1021_id, .detect = adm1021_detect, .address_list = normal_i2c, @@ -182,10 +182,10 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, size_t count) { int index = to_sensor_dev_attr(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long temp; - int err; + int reg_val, err; err = kstrtol(buf, 10, &temp); if (err) @@ -193,10 +193,11 @@ static ssize_t set_temp_max(struct device *dev, temp /= 1000; mutex_lock(&data->update_lock); - data->temp_max[index] = clamp_val(temp, -128, 127); + reg_val = clamp_val(temp, -128, 127); + data->temp_max[index] = reg_val * 1000; if (!read_only) i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index), - data->temp_max[index]); + reg_val); mutex_unlock(&data->update_lock); return count; @@ -207,10 +208,10 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, size_t count) { int index = to_sensor_dev_attr(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long temp; - int err; + int reg_val, err; err = kstrtol(buf, 10, &temp); if (err) @@ -218,10 +219,11 @@ static ssize_t set_temp_min(struct device *dev, temp /= 1000; mutex_lock(&data->update_lock); - data->temp_min[index] = clamp_val(temp, -128, 127); + reg_val = clamp_val(temp, -128, 127); + data->temp_min[index] = reg_val * 1000; if (!read_only) i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index), - data->temp_min[index]); + reg_val); mutex_unlock(&data->update_lock); return count; @@ -238,8 +240,8 @@ static ssize_t set_low_power(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; char low_power; unsigned long val; int err; @@ -412,15 +414,15 @@ static int adm1021_detect(struct i2c_client *client, static int adm1021_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct adm1021_data *data; - int err; + struct device *hwmon_dev; - data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct adm1021_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; data->type = id->driver_data; mutex_init(&data->update_lock); @@ -428,29 +430,14 @@ static int adm1021_probe(struct i2c_client *client, if (data->type != lm84 && !read_only) adm1021_init_client(client); - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &adm1021_group); - if (err) - return err; + data->groups[0] = &adm1021_group; + if (data->type != lm84) + data->groups[1] = &adm1021_min_group; - if (data->type != lm84) { - err = sysfs_create_group(&client->dev.kobj, &adm1021_min_group); - if (err) - goto error; - } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error; - } - - return 0; - -error: - sysfs_remove_group(&client->dev.kobj, &adm1021_min_group); - sysfs_remove_group(&client->dev.kobj, &adm1021_group); - return err; + return PTR_ERR_OR_ZERO(hwmon_dev); } static void adm1021_init_client(struct i2c_client *client) @@ -462,21 +449,10 @@ static void adm1021_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04); } -static int adm1021_remove(struct i2c_client *client) -{ - struct adm1021_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &adm1021_min_group); - sysfs_remove_group(&client->dev.kobj, &adm1021_group); - - return 0; -} - static struct adm1021_data *adm1021_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; mutex_lock(&data->update_lock); @@ -484,7 +460,7 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) || !data->valid) { int i; - dev_dbg(&client->dev, "Starting adm1021 update\n"); + dev_dbg(dev, "Starting adm1021 update\n"); for (i = 0; i < 2; i++) { data->temp[i] = 1000 * diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index d19c790e410..2804571b269 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -1,7 +1,7 @@ /* * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring * - * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr> + * Copyright (C) 2006 Corentin LABBE <clabbe.montjoie@gmail.com> * * Based on LM83 Driver by Jean Delvare <jdelvare@suse.de> * @@ -232,6 +232,9 @@ static ssize_t set_fan_div(struct device *dev, /* Update the value */ reg = (reg & 0x3F) | (val << 6); + /* Update the cache */ + data->fan_div[attr->index] = reg; + /* Write value */ i2c_smbus_write_byte_data(client, ADM1029_REG_FAN_DIV[attr->index], reg); @@ -449,6 +452,6 @@ static struct adm1029_data *adm1029_update_device(struct device *dev) module_i2c_driver(adm1029_driver); -MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>"); +MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>"); MODULE_DESCRIPTION("adm1029 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index a8a540ca8c3..51c1a5a165a 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -365,6 +365,7 @@ set_auto_temp_min(struct device *dev, struct device_attribute *attr, if (ret) return ret; + val = clamp_val(val, 0, 127000); mutex_lock(&data->update_lock); data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), @@ -394,6 +395,7 @@ set_auto_temp_max(struct device *dev, struct device_attribute *attr, if (ret) return ret; + val = clamp_val(val, 0, 127000); mutex_lock(&data->update_lock); data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); @@ -696,7 +698,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, 127000); mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), @@ -717,7 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, 127000); mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), @@ -738,7 +740,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, if (ret) return ret; - val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); + val = clamp_val(val, -55000, 127000); 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/adt7470.c b/drivers/hwmon/adt7470.c index 0f4dea5ccf1..9ee3913850d 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -515,7 +515,7 @@ static ssize_t set_temp_min(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); 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 = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); mutex_lock(&data->lock); data->temp_max[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 = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); mutex_lock(&data->lock); data->pwm_tmin[attr->index] = temp; diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index eea81729651..9f2be3dd28f 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -704,7 +704,7 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, get_temp_alarm, NULL, IDX_TEMP1_MAX); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, get_temp_alarm, NULL, IDX_TEMP1_CRIT); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR, +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp, NULL, IDX_TEMP2_INPUT); static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp, set_temp, IDX_TEMP2_MIN); diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 8d9f2a0e8ef..71463689d16 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1115,7 +1115,6 @@ asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; i2c_set_clientdata(client, data); - data->valid = 0; mutex_init(&data->update_lock); /* Initialize the asc7621 chip */ diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index ddff02e3e66..2ae8a304b5e 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -45,30 +45,6 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; -static int atxp1_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int atxp1_remove(struct i2c_client *client); -static struct atxp1_data *atxp1_update_device(struct device *dev); -static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info); - -static const struct i2c_device_id atxp1_id[] = { - { "atxp1", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, atxp1_id); - -static struct i2c_driver atxp1_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "atxp1", - }, - .probe = atxp1_probe, - .remove = atxp1_remove, - .id_table = atxp1_id, - .detect = atxp1_detect, - .address_list = normal_i2c, -}; - struct atxp1_data { struct device *hwmon_dev; struct mutex update_lock; @@ -353,8 +329,6 @@ static int atxp1_probe(struct i2c_client *new_client, data->vrm = vid_which_vrm(); i2c_set_clientdata(new_client, data); - data->valid = 0; - mutex_init(&data->update_lock); /* Register sysfs hooks */ @@ -388,4 +362,22 @@ static int atxp1_remove(struct i2c_client *client) return 0; }; +static const struct i2c_device_id atxp1_id[] = { + { "atxp1", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, atxp1_id); + +static struct i2c_driver atxp1_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "atxp1", + }, + .probe = atxp1_probe, + .remove = atxp1_remove, + .id_table = atxp1_id, + .detect = atxp1_detect, + .address_list = normal_i2c, +}; + module_i2c_driver(atxp1_driver); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index bbb0b0d463f..d76f0b70c6e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -94,6 +94,8 @@ struct temp_data { bool valid; struct sensor_device_attribute sd_attrs[TOTAL_ATTRS]; char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH]; + struct attribute *attrs[TOTAL_ATTRS + 1]; + struct attribute_group attr_group; struct mutex update_lock; }; @@ -114,12 +116,6 @@ struct pdev_entry { static LIST_HEAD(pdev_list); static DEFINE_MUTEX(pdev_list_mutex); -static ssize_t show_name(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - return sprintf(buf, "%s\n", DRVNAME); -} - static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -369,12 +365,12 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) if (cpu_has_tjmax(c)) dev_warn(dev, "Unable to read TjMax from CPU %u\n", id); } else { - val = (eax >> 16) & 0x7f; + val = (eax >> 16) & 0xff; /* * If the TjMax is not plausible, an assumption * will be used */ - if (val >= 85) { + if (val) { dev_dbg(dev, "TjMax is %d degrees C\n", val); return val * 1000; } @@ -393,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return adjust_tjmax(c, id, dev); } -static int create_name_attr(struct platform_data *pdata, - struct device *dev) -{ - sysfs_attr_init(&pdata->name_attr.attr); - pdata->name_attr.attr.name = "name"; - pdata->name_attr.attr.mode = S_IRUGO; - pdata->name_attr.show = show_name; - return device_create_file(dev, &pdata->name_attr); -} - static int create_core_attrs(struct temp_data *tdata, struct device *dev, int attr_no) { - int err, i; + int i; static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_temp, show_tjmax, @@ -424,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; tdata->sd_attrs[i].index = attr_no; - err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr); - if (err) - goto exit_free; + tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr; } - return 0; - -exit_free: - while (--i >= 0) - device_remove_file(dev, &tdata->sd_attrs[i].dev_attr); - return err; + tdata->attr_group.attrs = tdata->attrs; + return sysfs_create_group(&dev->kobj, &tdata->attr_group); } @@ -548,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, pdata->core_data[attr_no] = tdata; /* Create sysfs interfaces */ - err = create_core_attrs(tdata, &pdev->dev, attr_no); + err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no); if (err) goto exit_free; @@ -573,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag) } static void coretemp_remove_core(struct platform_data *pdata, - struct device *dev, int indx) + int indx) { - int i; struct temp_data *tdata = pdata->core_data[indx]; /* Remove the sysfs attributes */ - for (i = 0; i < tdata->attr_size; i++) - device_remove_file(dev, &tdata->sd_attrs[i].dev_attr); + sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group); kfree(pdata->core_data[indx]); pdata->core_data[indx] = NULL; @@ -588,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata, static int coretemp_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct platform_data *pdata; - int err; /* Initialize the per-package data structures */ - pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; - err = create_name_attr(pdata, &pdev->dev); - if (err) - goto exit_free; - pdata->phys_proc_id = pdev->id; platform_set_drvdata(pdev, pdata); - pdata->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(pdata->hwmon_dev)) { - err = PTR_ERR(pdata->hwmon_dev); - dev_err(&pdev->dev, "Class registration failed (%d)\n", err); - goto exit_name; - } - return 0; - -exit_name: - device_remove_file(&pdev->dev, &pdata->name_attr); -exit_free: - kfree(pdata); - return err; + pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, + pdata, NULL); + return PTR_ERR_OR_ZERO(pdata->hwmon_dev); } static int coretemp_remove(struct platform_device *pdev) @@ -625,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev) for (i = MAX_CORE_DATA - 1; i >= 0; --i) if (pdata->core_data[i]) - coretemp_remove_core(pdata, &pdev->dev, i); + coretemp_remove_core(pdata, i); - device_remove_file(&pdev->dev, &pdata->name_attr); - hwmon_device_unregister(pdata->hwmon_dev); - kfree(pdata); return 0; } @@ -777,7 +738,7 @@ static void put_core_offline(unsigned int cpu) return; if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu) - coretemp_remove_core(pdata, &pdev->dev, indx); + coretemp_remove_core(pdata, indx); /* * If a HT sibling of a core is taken offline, but another HT sibling @@ -849,20 +810,20 @@ static int __init coretemp_init(void) if (err) goto exit; - get_online_cpus(); + cpu_notifier_register_begin(); for_each_online_cpu(i) get_core_online(i); #ifndef CONFIG_HOTPLUG_CPU if (list_empty(&pdev_list)) { - put_online_cpus(); + cpu_notifier_register_done(); err = -ENODEV; goto exit_driver_unreg; } #endif - register_hotcpu_notifier(&coretemp_cpu_notifier); - put_online_cpus(); + __register_hotcpu_notifier(&coretemp_cpu_notifier); + cpu_notifier_register_done(); return 0; #ifndef CONFIG_HOTPLUG_CPU @@ -877,8 +838,8 @@ static void __exit coretemp_exit(void) { struct pdev_entry *p, *n; - get_online_cpus(); - unregister_hotcpu_notifier(&coretemp_cpu_notifier); + cpu_notifier_register_begin(); + __unregister_hotcpu_notifier(&coretemp_cpu_notifier); mutex_lock(&pdev_list_mutex); list_for_each_entry_safe(p, n, &pdev_list, list) { platform_device_unregister(p->pdev); @@ -886,7 +847,7 @@ static void __exit coretemp_exit(void) kfree(p); } mutex_unlock(&pdev_list_mutex); - put_online_cpus(); + cpu_notifier_register_done(); platform_driver_unregister(&coretemp_driver); } diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index afd31042b45..d14ab3c45da 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -194,7 +194,7 @@ static ssize_t da9052_hwmon_show_name(struct device *dev, struct device_attribute *devattr, char *buf) { - return sprintf(buf, "da9052-hwmon\n"); + return sprintf(buf, "da9052\n"); } static ssize_t show_label(struct device *dev, diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c index 029ecabc438..35eb7738d71 100644 --- a/drivers/hwmon/da9055-hwmon.c +++ b/drivers/hwmon/da9055-hwmon.c @@ -204,7 +204,7 @@ static ssize_t da9055_hwmon_show_name(struct device *dev, struct device_attribute *devattr, char *buf) { - return sprintf(buf, "da9055-hwmon\n"); + return sprintf(buf, "da9055\n"); } static ssize_t show_label(struct device *dev, @@ -278,10 +278,6 @@ static int da9055_hwmon_probe(struct platform_device *pdev) 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, diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 90ec1173b8a..a37b2204a41 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -18,9 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * TODO - * - cache alarm and critical limit registers */ #include <linux/module.h> @@ -32,22 +29,18 @@ #include <linux/err.h> #include <linux/sysfs.h> #include <linux/mutex.h> -#include <linux/jiffies.h> +#include <linux/regmap.h> #define THERMAL_PID_REG 0xfd #define THERMAL_SMSC_ID_REG 0xfe #define THERMAL_REVISION_REG 0xff +enum emc1403_chip { emc1402, emc1403, emc1404 }; + struct thermal_data { - struct i2c_client *client; - const struct attribute_group *groups[3]; + struct regmap *regmap; struct mutex mutex; - /* - * Cache the hyst value so we don't keep re-reading it. In theory - * we could cache it forever as nobody else should be writing it. - */ - u8 cached_hyst; - unsigned long hyst_valid; + const struct attribute_group *groups[4]; }; static ssize_t show_temp(struct device *dev, @@ -55,12 +48,13 @@ static ssize_t show_temp(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; int retval; - retval = i2c_smbus_read_byte_data(data->client, sda->index); + retval = regmap_read(data->regmap, sda->index, &val); if (retval < 0) return retval; - return sprintf(buf, "%d000\n", retval); + return sprintf(buf, "%d000\n", val); } static ssize_t show_bit(struct device *dev, @@ -68,12 +62,13 @@ static ssize_t show_bit(struct device *dev, { struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; int retval; - retval = i2c_smbus_read_byte_data(data->client, sda->nr); + retval = regmap_read(data->regmap, sda->nr, &val); if (retval < 0) return retval; - return sprintf(buf, "%d\n", !!(retval & sda->index)); + return sprintf(buf, "%d\n", !!(val & sda->index)); } static ssize_t store_temp(struct device *dev, @@ -86,8 +81,8 @@ static ssize_t store_temp(struct device *dev, if (kstrtoul(buf, 10, &val)) return -EINVAL; - retval = i2c_smbus_write_byte_data(data->client, sda->index, - DIV_ROUND_CLOSEST(val, 1000)); + retval = regmap_write(data->regmap, sda->index, + DIV_ROUND_CLOSEST(val, 1000)); if (retval < 0) return retval; return count; @@ -98,51 +93,51 @@ static ssize_t store_bit(struct device *dev, { struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int retval; if (kstrtoul(buf, 10, &val)) return -EINVAL; - mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->nr); + retval = regmap_update_bits(data->regmap, sda->nr, sda->index, + val ? sda->index : 0); if (retval < 0) - goto fail; - - retval &= ~sda->index; - if (val) - retval |= sda->index; - - retval = i2c_smbus_write_byte_data(client, sda->index, retval); - if (retval == 0) - retval = count; -fail: - mutex_unlock(&data->mutex); - return retval; + return retval; + return count; } -static ssize_t show_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_hyst_common(struct device *dev, + struct device_attribute *attr, char *buf, + bool is_min) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; + unsigned int limit; + unsigned int hyst; int retval; - int hyst; - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) return retval; - if (time_after(jiffies, data->hyst_valid)) { - hyst = i2c_smbus_read_byte_data(client, 0x21); - if (hyst < 0) - return retval; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } - return sprintf(buf, "%d000\n", retval - data->cached_hyst); + retval = regmap_read(regmap, 0x21, &hyst); + if (retval < 0) + return retval; + + return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst); +} + +static ssize_t show_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, false); +} + +static ssize_t show_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, true); } static ssize_t store_hyst(struct device *dev, @@ -150,7 +145,8 @@ static ssize_t store_hyst(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; + unsigned int limit; int retval; int hyst; unsigned long val; @@ -159,23 +155,15 @@ static ssize_t store_hyst(struct device *dev, return -EINVAL; mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) goto fail; - hyst = val - retval * 1000; - hyst = DIV_ROUND_CLOSEST(hyst, 1000); - if (hyst < 0 || hyst > 255) { - retval = -ERANGE; - goto fail; - } - - retval = i2c_smbus_write_byte_data(client, 0x21, hyst); - if (retval == 0) { + hyst = limit * 1000 - val; + hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255); + retval = regmap_write(regmap, 0x21, hyst); + if (retval == 0) retval = count; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } fail: mutex_unlock(&data->mutex); return retval; @@ -198,6 +186,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x01); static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x01); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x06); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_hyst, store_hyst, 0x20); @@ -208,14 +198,16 @@ static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x19); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x02); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x19); +static SENSOR_DEVICE_ATTR(temp2_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x08); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19); static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x16); @@ -224,14 +216,16 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x1A); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x04); -static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x1A); +static SENSOR_DEVICE_ATTR(temp3_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x16); +static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A); static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x2D); @@ -240,44 +234,66 @@ static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x30); static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A); +static SENSOR_DEVICE_ATTR_2(temp4_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x08); -static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x30); +static SENSOR_DEVICE_ATTR(temp4_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x2D); +static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C); +static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30); static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, show_bit, store_bit, 0x03, 0x40); -static struct attribute *emc1403_attrs[] = { +static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + + &sensor_dev_attr_power_state.dev_attr.attr, + NULL +}; + +static const struct attribute_group emc1402_group = { + .attrs = emc1402_attrs, +}; + +static struct attribute *emc1403_attrs[] = { + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + + &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, - &sensor_dev_attr_power_state.dev_attr.attr, NULL }; @@ -290,9 +306,12 @@ static struct attribute *emc1404_attrs[] = { &sensor_dev_attr_temp4_max.dev_attr.attr, &sensor_dev_attr_temp4_crit.dev_attr.attr, &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, NULL }; @@ -301,6 +320,39 @@ static const struct attribute_group emc1404_group = { .attrs = emc1404_attrs, }; +/* + * EMC14x2 uses a different register and different bits to report alarm and + * fault status. For simplicity, provide a separate attribute group for this + * chip series. + * Since we can not re-use the same attribute names, create a separate attribute + * array. + */ +static struct sensor_device_attribute_2 emc1402_alarms[] = { + SENSOR_ATTR_2(temp1_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x20), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x40), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x01), + + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x02, 0x04), + SENSOR_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x08), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x10), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x02), +}; + +static struct attribute *emc1402_alarm_attrs[] = { + &emc1402_alarms[0].dev_attr.attr, + &emc1402_alarms[1].dev_attr.attr, + &emc1402_alarms[2].dev_attr.attr, + &emc1402_alarms[3].dev_attr.attr, + &emc1402_alarms[4].dev_attr.attr, + &emc1402_alarms[5].dev_attr.attr, + &emc1402_alarms[6].dev_attr.attr, + NULL, +}; + +static const struct attribute_group emc1402_alarm_group = { + .attrs = emc1402_alarm_attrs, +}; + static int emc1403_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -313,9 +365,15 @@ static int emc1403_detect(struct i2c_client *client, id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); switch (id) { + case 0x20: + strlcpy(info->type, "emc1402", I2C_NAME_SIZE); + break; case 0x21: strlcpy(info->type, "emc1403", I2C_NAME_SIZE); break; + case 0x22: + strlcpy(info->type, "emc1422", I2C_NAME_SIZE); + break; case 0x23: strlcpy(info->type, "emc1423", I2C_NAME_SIZE); break; @@ -330,12 +388,41 @@ static int emc1403_detect(struct i2c_client *client, } id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG); - if (id != 0x01) + if (id < 0x01 || id > 0x04) return -ENODEV; return 0; } +static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00: /* internal diode high byte */ + case 0x01: /* external diode 1 high byte */ + case 0x02: /* status */ + case 0x10: /* external diode 1 low byte */ + case 0x1b: /* external diode fault */ + case 0x23: /* external diode 2 high byte */ + case 0x24: /* external diode 2 low byte */ + case 0x29: /* internal diode low byte */ + case 0x2a: /* externl diode 3 high byte */ + case 0x2b: /* external diode 3 low byte */ + case 0x35: /* high limit status */ + case 0x36: /* low limit status */ + case 0x37: /* therm limit status */ + return true; + default: + return false; + } +} + +static struct regmap_config emc1403_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = emc1403_regmap_is_volatile, +}; + static int emc1403_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -347,17 +434,27 @@ static int emc1403_probe(struct i2c_client *client, if (data == NULL) return -ENOMEM; - data->client = client; + data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + mutex_init(&data->mutex); - data->hyst_valid = jiffies - 1; /* Expired */ - data->groups[0] = &emc1403_group; - if (id->driver_data) - data->groups[1] = &emc1404_group; + switch (id->driver_data) { + case emc1404: + data->groups[2] = &emc1404_group; + case emc1403: + data->groups[1] = &emc1403_group; + case emc1402: + data->groups[0] = &emc1402_group; + } + + if (id->driver_data == emc1402) + data->groups[1] = &emc1402_alarm_group; - hwmon_dev = hwmon_device_register_with_groups(&client->dev, - client->name, data, - data->groups); + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); @@ -366,14 +463,20 @@ static int emc1403_probe(struct i2c_client *client, } static const unsigned short emc1403_address_list[] = { - 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END + 0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END }; +/* Last digit of chip name indicates number of channels */ static const struct i2c_device_id emc1403_idtable[] = { - { "emc1403", 0 }, - { "emc1404", 1 }, - { "emc1423", 0 }, - { "emc1424", 1 }, + { "emc1402", emc1402 }, + { "emc1403", emc1403 }, + { "emc1404", emc1404 }, + { "emc1412", emc1402 }, + { "emc1413", emc1403 }, + { "emc1414", emc1404 }, + { "emc1422", emc1402 }, + { "emc1423", emc1403 }, + { "emc1424", emc1404 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 2c137b26acb..78002de46cb 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -250,9 +250,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *da, if (result < 0) return result; - val = DIV_ROUND_CLOSEST(val, 1000); - if ((val < -63) || (val > 127)) - return -EINVAL; + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); mutex_lock(&data->update_lock); data->temp_min[nr] = val; @@ -274,9 +272,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *da, if (result < 0) return result; - val = DIV_ROUND_CLOSEST(val, 1000); - if ((val < -63) || (val > 127)) - return -EINVAL; + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); mutex_lock(&data->update_lock); data->temp_max[nr] = val; @@ -349,7 +345,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_FAN_CONF1, status); mutex_unlock(&data->update_lock); - return -EIO; + return status; } status &= 0x9F; status |= (new_range_bits << 5); @@ -390,15 +386,14 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, { struct emc2103_data *data = emc2103_update_device(dev); struct i2c_client *client = to_i2c_client(dev); - long rpm_target; + unsigned long rpm_target; - int result = kstrtol(buf, 10, &rpm_target); + int result = kstrtoul(buf, 10, &rpm_target); if (result < 0) return result; /* Datasheet states 16384 as maximum RPM target (table 3.2) */ - if ((rpm_target < 0) || (rpm_target > 16384)) - return -EINVAL; + rpm_target = clamp_val(rpm_target, 0, 16384); mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 1a8aa126526..9e57b77ecd3 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1387,10 +1387,8 @@ static int f71805f_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2, @@ -1648,7 +1646,7 @@ static void __exit f71805f_exit(void) platform_driver_unregister(&f71805f_driver); } -MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); +MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver"); diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index b4b8b5bef71..98a8618d8fb 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -586,7 +586,7 @@ static int do_set_fan_startv(struct device *dev, unsigned long val) */ #ifdef CONFIG_OF -static struct of_device_id g762_dt_match[] = { +static const struct of_device_id g762_dt_match[] = { { .compatible = "gmt,g762" }, { .compatible = "gmt,g763" }, { }, diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 73181be5b30..2566c43dd1e 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -482,7 +482,7 @@ static int gpio_fan_get_of_pdata(struct device *dev, return 0; } -static struct of_device_id of_gpio_fan_match[] = { +static const struct of_device_id of_gpio_fan_match[] = { { .compatible = "gpio-fan", }, {}, }; @@ -538,7 +538,7 @@ static int gpio_fan_probe(struct platform_device *pdev) /* Make this driver part of hwmon class. */ fan_data->hwmon_dev = hwmon_device_register_with_groups(&pdev->dev, - "gpio-fan", fan_data, + "gpio_fan", fan_data, gpio_fan_groups); if (IS_ERR(fan_data->hwmon_dev)) return PTR_ERR(fan_data->hwmon_dev); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index e176a43af63..a26c385a435 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -22,6 +22,7 @@ #include <linux/gfp.h> #include <linux/spinlock.h> #include <linux/pci.h> +#include <linux/string.h> #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" @@ -99,6 +100,10 @@ hwmon_device_register_with_groups(struct device *dev, const char *name, struct hwmon_device *hwdev; int err, id; + /* Do not accept invalid characters in hwmon name attribute */ + if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) + return ERR_PTR(-EINVAL); + id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); if (id < 0) return ERR_PTR(id); diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 20ab0fb8539..030e7ff589b 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -463,10 +463,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev) int err; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Insufficient memory for BMC interface.\n"); + if (!data) return; - } data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; data->address.channel = IPMI_BMC_CHANNEL; diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 708081b68c6..14c82daab01 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -31,6 +31,7 @@ struct iio_hwmon_state { int num_channels; struct device *hwmon_dev; struct attribute_group attr_group; + const struct attribute_group *groups[2]; struct attribute **attrs; }; @@ -56,19 +57,6 @@ static ssize_t iio_hwmon_read_val(struct device *dev, return sprintf(buf, "%d\n", result); } -static ssize_t show_name(struct device *dev, struct device_attribute *attr, - char *buf) -{ - const char *name = "iio_hwmon"; - - if (dev->of_node && dev->of_node->name) - name = dev->of_node->name; - - return sprintf(buf, "%s\n", name); -} - -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - static int iio_hwmon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -78,6 +66,10 @@ static int iio_hwmon_probe(struct platform_device *pdev) int in_i = 1, temp_i = 1, curr_i = 1; enum iio_chan_type type; struct iio_channel *channels; + const char *name = "iio_hwmon"; + + if (dev->of_node && dev->of_node->name) + name = dev->of_node->name; channels = iio_channel_get_all(dev); if (IS_ERR(channels)) @@ -96,7 +88,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) st->num_channels++; st->attrs = devm_kzalloc(dev, - sizeof(*st->attrs) * (st->num_channels + 2), + sizeof(*st->attrs) * (st->num_channels + 1), GFP_KERNEL); if (st->attrs == NULL) { ret = -ENOMEM; @@ -144,22 +136,18 @@ static int iio_hwmon_probe(struct platform_device *pdev) a->index = i; st->attrs[i] = &a->dev_attr.attr; } - st->attrs[st->num_channels] = &dev_attr_name.attr; - st->attr_group.attrs = st->attrs; - platform_set_drvdata(pdev, st); - ret = sysfs_create_group(&dev->kobj, &st->attr_group); - if (ret < 0) - goto error_release_channels; - st->hwmon_dev = hwmon_device_register(dev); + st->attr_group.attrs = st->attrs; + st->groups[0] = &st->attr_group; + st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st, + st->groups); if (IS_ERR(st->hwmon_dev)) { ret = PTR_ERR(st->hwmon_dev); - goto error_remove_group; + goto error_release_channels; } + platform_set_drvdata(pdev, st); return 0; -error_remove_group: - sysfs_remove_group(&dev->kobj, &st->attr_group); error_release_channels: iio_channel_release_all(channels); return ret; @@ -170,13 +158,12 @@ static int iio_hwmon_remove(struct platform_device *pdev) struct iio_hwmon_state *st = platform_get_drvdata(pdev); hwmon_device_unregister(st->hwmon_dev); - sysfs_remove_group(&pdev->dev.kobj, &st->attr_group); iio_channel_release_all(st->channels); return 0; } -static struct of_device_id iio_hwmon_of_match[] = { +static const struct of_device_id iio_hwmon_of_match[] = { { .compatible = "iio-hwmon", }, { } }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 93d26e8af3e..bfd3f3eeabc 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -148,7 +148,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) switch (reg) { case INA2XX_SHUNT_VOLTAGE: - val = DIV_ROUND_CLOSEST(data->regs[reg], + /* signed register */ + val = DIV_ROUND_CLOSEST((s16)data->regs[reg], data->config->shunt_div); break; case INA2XX_BUS_VOLTAGE: @@ -160,8 +161,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) val = data->regs[reg] * data->config->power_lsb; break; case INA2XX_CURRENT: - /* LSB=1mA (selected). Is in mA */ - val = data->regs[reg]; + /* signed register, LSB=1mA (selected), in mA */ + val = (s16)data->regs[reg]; break; default: /* programmer goofed */ diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 70749fc15a4..a327fd3402a 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -11,6 +11,7 @@ * similar parts. The other devices are supported by different drivers. * * Supports: IT8603E Super I/O chip w/LPC interface + * IT8623E Super I/O chip w/LPC interface * IT8705F Super I/O chip w/LPC interface * IT8712F Super I/O chip w/LPC interface * IT8716F Super I/O chip w/LPC interface @@ -147,7 +148,8 @@ static inline void superio_exit(void) #define IT8772E_DEVID 0x8772 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 -#define IT8306E_DEVID 0x8603 +#define IT8603E_DEVID 0x8603 +#define IT8623E_DEVID 0x8623 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -1431,7 +1433,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2); -/* special AVCC3 IT8306E in9 */ +/* special AVCC3 IT8603E in9 */ static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0); static ssize_t show_name(struct device *dev, struct device_attribute @@ -1766,7 +1768,8 @@ static int __init it87_find(unsigned short *address, case IT8783E_DEVID: sio_data->type = it8783; break; - case IT8306E_DEVID: + case IT8603E_DEVID: + case IT8623E_DEVID: sio_data->type = it8603; break; case 0xffff: /* No device at all */ diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 6013611e4f2..388f8bcd898 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -65,6 +65,7 @@ static const unsigned short normal_i2c[] = { /* Manufacturer IDs */ #define ADT_MANID 0x11d4 /* Analog Devices */ #define ATMEL_MANID 0x001f /* Atmel */ +#define ATMEL_MANID2 0x1114 /* Atmel */ #define MAX_MANID 0x004d /* Maxim */ #define IDT_MANID 0x00b3 /* IDT */ #define MCP_MANID 0x0054 /* Microchip */ @@ -82,6 +83,9 @@ static const unsigned short normal_i2c[] = { #define AT30TS00_DEVID 0x8201 #define AT30TS00_DEVID_MASK 0xffff +#define AT30TSE004_DEVID 0x2200 +#define AT30TSE004_DEVID_MASK 0xffff + /* IDT */ #define TS3000B3_DEVID 0x2903 /* Also matches TSE2002B3 */ #define TS3000B3_DEVID_MASK 0xffff @@ -130,6 +134,9 @@ static const unsigned short normal_i2c[] = { #define STTS2002_DEVID 0x0300 #define STTS2002_DEVID_MASK 0xffff +#define STTS2004_DEVID 0x2201 +#define STTS2004_DEVID_MASK 0xffff + #define STTS3000_DEVID 0x0200 #define STTS3000_DEVID_MASK 0xffff @@ -144,6 +151,7 @@ struct jc42_chips { static struct jc42_chips jc42_chips[] = { { ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK }, { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK }, + { ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK }, { IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK }, { IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK }, { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK }, @@ -158,9 +166,25 @@ static struct jc42_chips jc42_chips[] = { { STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK }, { STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK }, { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK }, + { STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK }, { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK }, }; +enum temp_index { + t_input = 0, + t_crit, + t_min, + t_max, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = JC42_REG_TEMP, + [t_crit] = JC42_REG_TEMP_CRITICAL, + [t_min] = JC42_REG_TEMP_LOWER, + [t_max] = JC42_REG_TEMP_UPPER, +}; + /* Each client has this additional data */ struct jc42_data { struct i2c_client *client; @@ -170,69 +194,7 @@ struct jc42_data { unsigned long last_updated; /* In jiffies */ u16 orig_config; /* original configuration */ u16 config; /* current configuration */ - u16 temp_input; /* Temperatures */ - u16 temp_crit; - u16 temp_min; - u16 temp_max; -}; - -static int jc42_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info); -static int jc42_remove(struct i2c_client *client); - -static struct jc42_data *jc42_update_device(struct device *dev); - -static const struct i2c_device_id jc42_id[] = { - { "jc42", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, jc42_id); - -#ifdef CONFIG_PM - -static int jc42_suspend(struct device *dev) -{ - struct jc42_data *data = dev_get_drvdata(dev); - - data->config |= JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); - return 0; -} - -static int jc42_resume(struct device *dev) -{ - struct jc42_data *data = dev_get_drvdata(dev); - - data->config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); - return 0; -} - -static const struct dev_pm_ops jc42_dev_pm_ops = { - .suspend = jc42_suspend, - .resume = jc42_resume, -}; - -#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops) -#else -#define JC42_DEV_PM_OPS NULL -#endif /* CONFIG_PM */ - -/* This is the driver that will be inserted */ -static struct i2c_driver jc42_driver = { - .class = I2C_CLASS_SPD, - .driver = { - .name = "jc42", - .pm = JC42_DEV_PM_OPS, - }, - .probe = jc42_probe, - .remove = jc42_remove, - .id_table = jc42_id, - .detect = jc42_detect, - .address_list = normal_i2c, + u16 temp[t_num_temp];/* Temperatures */ }; #define JC42_TEMP_MIN_EXTENDED (-40000) @@ -261,79 +223,81 @@ static int jc42_temp_from_reg(s16 reg) return reg * 125 / 2; } -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct jc42_data *data = jc42_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", jc42_temp_from_reg(data->value)); \ +static struct jc42_data *jc42_update_device(struct device *dev) +{ + struct jc42_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct jc42_data *ret = data; + int i, val; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + for (i = 0; i < t_num_temp; i++) { + val = i2c_smbus_read_word_swapped(client, temp_regs[i]); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i] = val; + } + data->last_updated = jiffies; + data->valid = true; + } +abort: + mutex_unlock(&data->update_lock); + return ret; } -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); +/* sysfs functions */ -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct jc42_data *data = jc42_update_device(dev); - int temp, hyst; - if (IS_ERR(data)) return PTR_ERR(data); - - temp = jc42_temp_from_reg(data->temp_crit); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; - return sprintf(buf, "%d\n", temp - hyst); + return sprintf(buf, "%d\n", + jc42_temp_from_reg(data->temp[attr->index])); } -static ssize_t show_temp_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct jc42_data *data = jc42_update_device(dev); int temp, hyst; if (IS_ERR(data)) return PTR_ERR(data); - temp = jc42_temp_from_reg(data->temp_max); + temp = jc42_temp_from_reg(data->temp[attr->index]); hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) >> JC42_CFG_HYST_SHIFT]; return sprintf(buf, "%d\n", temp - hyst); } -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct jc42_data *data = dev_get_drvdata(dev); \ - int err, ret = count; \ - long val; \ - if (kstrtol(buf, 10, &val) < 0) \ - return -EINVAL; \ - mutex_lock(&data->update_lock); \ - data->value = jc42_temp_to_reg(val, data->extended); \ - err = i2c_smbus_write_word_swapped(data->client, reg, data->value); \ - if (err < 0) \ - ret = err; \ - mutex_unlock(&data->update_lock); \ - return ret; \ -} +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct jc42_data *data = dev_get_drvdata(dev); + int err, ret = count; + int nr = attr->index; + long val; -set(temp_min, JC42_REG_TEMP_LOWER); -set(temp_max, JC42_REG_TEMP_UPPER); -set(temp_crit, JC42_REG_TEMP_CRITICAL); + if (kstrtol(buf, 10, &val) < 0) + return -EINVAL; + mutex_lock(&data->update_lock); + data->temp[nr] = jc42_temp_to_reg(val, data->extended); + err = i2c_smbus_write_word_swapped(data->client, temp_regs[nr], + data->temp[nr]); + if (err < 0) + ret = err; + mutex_unlock(&data->update_lock); + return ret; +} /* * JC42.4 compliant chips only support four hysteresis values. @@ -352,7 +316,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - diff = jc42_temp_from_reg(data->temp_crit) - val; + diff = jc42_temp_from_reg(data->temp[t_crit]) - val; hyst = 0; if (diff > 0) { if (diff < 2250) @@ -384,25 +348,20 @@ static ssize_t show_alarm(struct device *dev, if (IS_ERR(data)) return PTR_ERR(data); - val = data->temp_input; + val = data->temp[t_input]; if (bit != JC42_ALARM_CRIT_BIT && (data->config & JC42_CFG_CRIT_ONLY)) val = 0; return sprintf(buf, "%u\n", (val >> bit) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IRUGO, - show_temp_max, set_temp_max); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, set_temp, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, set_temp, t_min); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, set_temp, t_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_hyst, + set_temp_crit_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, JC42_ALARM_CRIT_BIT); @@ -412,12 +371,12 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, JC42_ALARM_MAX_BIT); static struct attribute *jc42_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, @@ -432,12 +391,12 @@ static umode_t jc42_attribute_mode(struct kobject *kobj, unsigned int config = data->config; bool readonly; - if (attr == &dev_attr_temp1_crit.attr) + if (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr) readonly = config & JC42_CFG_TCRIT_LOCK; - else if (attr == &dev_attr_temp1_min.attr || - attr == &dev_attr_temp1_max.attr) + else if (attr == &sensor_dev_attr_temp1_min.dev_attr.attr || + attr == &sensor_dev_attr_temp1_max.dev_attr.attr) readonly = config & JC42_CFG_EVENT_LOCK; - else if (attr == &dev_attr_temp1_crit_hyst.attr) + else if (attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr) readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK); else readonly = true; @@ -537,52 +496,56 @@ static int jc42_remove(struct i2c_client *client) return 0; } -static struct jc42_data *jc42_update_device(struct device *dev) +#ifdef CONFIG_PM + +static int jc42_suspend(struct device *dev) { struct jc42_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - struct jc42_data *ret = data; - int val; - mutex_lock(&data->update_lock); + data->config |= JC42_CFG_SHUTDOWN; + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); + return 0; +} - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_input = val; +static int jc42_resume(struct device *dev) +{ + struct jc42_data *data = dev_get_drvdata(dev); - val = i2c_smbus_read_word_swapped(client, - JC42_REG_TEMP_CRITICAL); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_crit = val; + data->config &= ~JC42_CFG_SHUTDOWN; + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); + return 0; +} - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_min = val; +static const struct dev_pm_ops jc42_dev_pm_ops = { + .suspend = jc42_suspend, + .resume = jc42_resume, +}; - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_max = val; +#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops) +#else +#define JC42_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ - data->last_updated = jiffies; - data->valid = true; - } -abort: - mutex_unlock(&data->update_lock); - return ret; -} +static const struct i2c_device_id jc42_id[] = { + { "jc42", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, jc42_id); + +static struct i2c_driver jc42_driver = { + .class = I2C_CLASS_SPD, + .driver = { + .name = "jc42", + .pm = JC42_DEV_PM_OPS, + }, + .probe = jc42_probe, + .remove = jc42_remove, + .id_table = jc42_id, + .detect = jc42_detect, + .address_list = normal_i2c, +}; module_i2c_driver(jc42_driver); diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index a183e488db7..7488e36809c 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -28,7 +28,6 @@ #include <linux/hwmon.h> struct jz4740_hwmon { - struct resource *mem; void __iomem *base; int irq; @@ -106,6 +105,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) { int ret; struct jz4740_hwmon *hwmon; + struct resource *mem; hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); if (!hwmon) @@ -120,25 +120,10 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) return hwmon->irq; } - hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!hwmon->mem) { - dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); - return -ENOENT; - } - - hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start, - resource_size(hwmon->mem), pdev->name); - if (!hwmon->mem) { - dev_err(&pdev->dev, "Failed to request mmio memory region\n"); - return -EBUSY; - } - - hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start, - resource_size(hwmon->mem)); - if (!hwmon->base) { - dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); - return -EBUSY; - } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hwmon->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(hwmon->base)) + return PTR_ERR(hwmon->base); init_completion(&hwmon->read_completion); mutex_init(&hwmon->lock); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index baf375b5ab0..f7b46f68ef4 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -212,6 +212,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, {} }; MODULE_DEVICE_TABLE(pci, k10temp_id_table); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index b4ad598feb6..848b9611151 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -155,8 +155,9 @@ enum chips { lm63, lm64, lm96163 }; */ struct lm63_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; + const struct attribute_group *groups[5]; char valid; /* zero until following fields are valid */ char lut_valid; /* zero until lut fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -218,9 +219,9 @@ static inline int lut_temp_to_reg(struct lm63_data *data, long val) * Update the lookup table register cache. * client->update_lock must be held when calling this function. */ -static void lm63_update_lut(struct i2c_client *client) +static void lm63_update_lut(struct lm63_data *data) { - struct lm63_data *data = i2c_get_clientdata(client); + struct i2c_client *client = data->client; int i; if (time_after(jiffies, data->lut_last_updated + 5 * HZ) || @@ -241,8 +242,8 @@ static void lm63_update_lut(struct i2c_client *client) static struct lm63_data *lm63_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long next_update; mutex_lock(&data->update_lock); @@ -310,7 +311,7 @@ static struct lm63_data *lm63_update_device(struct device *dev) data->valid = 1; } - lm63_update_lut(client); + lm63_update_lut(data); mutex_unlock(&data->update_lock); @@ -321,18 +322,17 @@ static struct lm63_data *lm63_update_device(struct device *dev) * Trip points in the lookup table should be in ascending order for both * temperatures and PWM output values. */ -static int lm63_lut_looks_bad(struct i2c_client *client) +static int lm63_lut_looks_bad(struct device *dev, struct lm63_data *data) { - struct lm63_data *data = i2c_get_clientdata(client); int i; mutex_lock(&data->update_lock); - lm63_update_lut(client); + lm63_update_lut(data); for (i = 1; i < data->lut_size; i++) { if (data->pwm1[1 + i - 1] > data->pwm1[1 + i] || data->temp8[3 + i - 1] > data->temp8[3 + i]) { - dev_warn(&client->dev, + dev_warn(dev, "Lookup table doesn't look sane (check entries %d and %d)\n", i, i + 1); break; @@ -358,8 +358,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -399,8 +399,8 @@ static ssize_t set_pwm1(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 lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; unsigned long val; int err; @@ -435,8 +435,8 @@ static ssize_t set_pwm1_enable(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -450,7 +450,7 @@ static ssize_t set_pwm1_enable(struct device *dev, * Only let the user switch to automatic mode if the lookup table * looks sane. */ - if (val == 2 && lm63_lut_looks_bad(client)) + if (val == 2 && lm63_lut_looks_bad(dev, data)) return -EPERM; mutex_lock(&data->update_lock); @@ -461,7 +461,7 @@ static ssize_t set_pwm1_enable(struct device *dev, else data->config_fan &= ~0x20; i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN, - data->config_fan); + data->config_fan); mutex_unlock(&data->update_lock); return count; } @@ -505,8 +505,8 @@ static ssize_t set_temp8(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 lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long val; int err; @@ -579,8 +579,8 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; int nr = attr->index; @@ -635,8 +635,8 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; long hyst; @@ -657,11 +657,11 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, * Set conversion rate. * client->update_lock must be held when calling this function. */ -static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data, - unsigned int interval) +static void lm63_set_convrate(struct lm63_data *data, unsigned int interval) { - int i; + struct i2c_client *client = data->client; unsigned int update_interval; + int i; /* Shift calculations to avoid rounding errors */ interval <<= 6; @@ -689,8 +689,7 @@ static ssize_t set_update_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); unsigned long val; int err; @@ -699,7 +698,7 @@ static ssize_t set_update_interval(struct device *dev, return err; mutex_lock(&data->update_lock); - lm63_set_convrate(client, data, clamp_val(val, 0, 100000)); + lm63_set_convrate(data, clamp_val(val, 0, 100000)); mutex_unlock(&data->update_lock); return count; @@ -708,8 +707,7 @@ static ssize_t set_update_interval(struct device *dev, static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); return sprintf(buf, data->trutherm ? "1\n" : "2\n"); } @@ -717,8 +715,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, static ssize_t set_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int ret; u8 reg; @@ -915,6 +913,15 @@ static struct attribute *lm63_attributes[] = { NULL }; +static struct attribute *lm63_attributes_temp2_type[] = { + &dev_attr_temp2_type.attr, + NULL +}; + +static const struct attribute_group lm63_group_temp2_type = { + .attrs = lm63_attributes_temp2_type, +}; + static struct attribute *lm63_attributes_extra_lut[] = { &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr, @@ -946,8 +953,7 @@ static umode_t lm63_attribute_mode(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); + struct lm63_data *data = dev_get_drvdata(dev); if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr && (data->kind == lm64 || @@ -1026,9 +1032,10 @@ static int lm63_detect(struct i2c_client *client, * Ideally we shouldn't have to initialize anything, since the BIOS * should have taken care of everything */ -static void lm63_init_client(struct i2c_client *client) +static void lm63_init_client(struct lm63_data *data) { - struct lm63_data *data = i2c_get_clientdata(client); + struct i2c_client *client = data->client; + struct device *dev = &client->dev; u8 convrate; data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); @@ -1037,7 +1044,7 @@ static void lm63_init_client(struct i2c_client *client) /* Start converting if needed */ if (data->config & 0x40) { /* standby */ - dev_dbg(&client->dev, "Switching to operational mode\n"); + dev_dbg(dev, "Switching to operational mode\n"); data->config &= 0xA7; i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, data->config); @@ -1090,13 +1097,13 @@ static void lm63_init_client(struct i2c_client *client) /* Show some debug info about the LM63 configuration */ if (data->kind == lm63) - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", + dev_dbg(dev, "Alert/tach pin configured for %s\n", (data->config & 0x04) ? "tachometer input" : "alert output"); - dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", + dev_dbg(dev, "PWM clock %s kHz, output frequency %u Hz\n", (data->config_fan & 0x08) ? "1.4" : "360", ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); - dev_dbg(&client->dev, "PWM output active %s, %s mode\n", + dev_dbg(dev, "PWM output active %s, %s mode\n", (data->config_fan & 0x10) ? "low" : "high", (data->config_fan & 0x20) ? "manual" : "auto"); } @@ -1104,15 +1111,16 @@ static void lm63_init_client(struct i2c_client *client) static int lm63_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm63_data *data; - int err; + int groups = 0; - data = devm_kzalloc(&client->dev, sizeof(struct lm63_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm63_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); - data->valid = 0; + data->client = client; mutex_init(&data->update_lock); /* Set the device type */ @@ -1121,59 +1129,21 @@ static int lm63_probe(struct i2c_client *client, data->temp2_offset = 16000; /* Initialize chip */ - lm63_init_client(client); + lm63_init_client(data); /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &lm63_group); - if (err) - return err; - if (data->config & 0x04) { /* tachometer enabled */ - err = sysfs_create_group(&client->dev.kobj, &lm63_group_fan1); - if (err) - goto exit_remove_files; - } - if (data->kind == lm96163) { - err = device_create_file(&client->dev, &dev_attr_temp2_type); - if (err) - goto exit_remove_files; - - err = sysfs_create_group(&client->dev.kobj, - &lm63_group_extra_lut); - if (err) - goto exit_remove_files; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } + data->groups[groups++] = &lm63_group; + if (data->config & 0x04) /* tachometer enabled */ + data->groups[groups++] = &lm63_group_fan1; - return 0; - -exit_remove_files: - sysfs_remove_group(&client->dev.kobj, &lm63_group); - sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); if (data->kind == lm96163) { - device_remove_file(&client->dev, &dev_attr_temp2_type); - sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut); + data->groups[groups++] = &lm63_group_temp2_type; + data->groups[groups++] = &lm63_group_extra_lut; } - return err; -} - -static int lm63_remove(struct i2c_client *client) -{ - struct lm63_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm63_group); - sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); - if (data->kind == lm96163) { - device_remove_file(&client->dev, &dev_attr_temp2_type); - sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut); - } - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* @@ -1194,7 +1164,6 @@ static struct i2c_driver lm63_driver = { .name = "lm63", }, .probe = lm63_probe, - .remove = lm63_remove, .id_table = lm63_id, .detect = lm63_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 505a59e100b..97204dce162 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -47,7 +47,7 @@ #define LM70_CHIP_LM74 3 /* NS LM74 */ struct lm70 { - struct device *hwmon_dev; + struct spi_device *spi; struct mutex lock; unsigned int chip; }; @@ -56,11 +56,11 @@ struct lm70 { static ssize_t lm70_sense_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); + struct lm70 *p_lm70 = dev_get_drvdata(dev); + struct spi_device *spi = p_lm70->spi; int status, val = 0; u8 rxbuf[2]; s16 raw = 0; - struct lm70 *p_lm70 = spi_get_drvdata(spi); if (mutex_lock_interruptible(&p_lm70->lock)) return -ERESTARTSYS; @@ -121,21 +121,20 @@ out: static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); -static ssize_t lm70_show_name(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); -} +static struct attribute *lm70_attrs[] = { + &dev_attr_temp1_input.attr, + NULL +}; -static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); +ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ static int lm70_probe(struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; + struct device *hwmon_dev; struct lm70 *p_lm70; - int status; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -149,46 +148,14 @@ static int lm70_probe(struct spi_device *spi) mutex_init(&p_lm70->lock); p_lm70->chip = chip; + p_lm70->spi = spi; - spi_set_drvdata(spi, p_lm70); - - status = device_create_file(&spi->dev, &dev_attr_temp1_input); - if (status) - goto out_dev_create_temp_file_failed; - status = device_create_file(&spi->dev, &dev_attr_name); - if (status) - goto out_dev_create_file_failed; - - /* sysfs hook */ - p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); - if (IS_ERR(p_lm70->hwmon_dev)) { - dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(p_lm70->hwmon_dev); - goto out_dev_reg_failed; - } - - return 0; - -out_dev_reg_failed: - device_remove_file(&spi->dev, &dev_attr_name); -out_dev_create_file_failed: - device_remove_file(&spi->dev, &dev_attr_temp1_input); -out_dev_create_temp_file_failed: - return status; + hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev, + spi->modalias, + p_lm70, lm70_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm70_remove(struct spi_device *spi) -{ - struct lm70 *p_lm70 = spi_get_drvdata(spi); - - hwmon_device_unregister(p_lm70->hwmon_dev); - device_remove_file(&spi->dev, &dev_attr_temp1_input); - device_remove_file(&spi->dev, &dev_attr_name); - - return 0; -} - - static const struct spi_device_id lm70_ids[] = { { "lm70", LM70_CHIP_LM70 }, { "tmp121", LM70_CHIP_TMP121 }, @@ -205,7 +172,6 @@ static struct spi_driver lm70_driver = { }, .id_table = lm70_ids, .probe = lm70_probe, - .remove = lm70_remove, }; module_spi_driver(lm70_driver); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 84a55eacd90..479ffbeed3f 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -72,6 +72,7 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { + struct i2c_client *client; struct device *hwmon_dev; struct thermal_zone_device *tz; struct mutex update_lock; @@ -130,8 +131,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long temp; int error; @@ -165,17 +166,14 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static struct attribute *lm75_attributes[] = { +static struct attribute *lm75_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; - -static const struct attribute_group lm75_group = { - .attrs = lm75_attributes, -}; +ATTRIBUTE_GROUPS(lm75); /*-----------------------------------------------------------------------*/ @@ -184,6 +182,7 @@ static const struct attribute_group lm75_group = { static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm75_data *data; int status; u8 set_mask, clr_mask; @@ -194,10 +193,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -EIO; - data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); if (!data) return -ENOMEM; + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -269,7 +269,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) /* configure as specified */ status = lm75_read_value(client, LM75_REG_CONF); if (status < 0) { - dev_dbg(&client->dev, "Can't read config? %d\n", status); + dev_dbg(dev, "Can't read config? %d\n", status); return status; } data->orig_conf = status; @@ -277,43 +277,32 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) new |= set_mask; if (status != new) lm75_write_value(client, LM75_REG_CONF, new); - dev_dbg(&client->dev, "Config %02x\n", new); + dev_dbg(dev, "Config %02x\n", new); - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &lm75_group); - if (status) - return status; + data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + data, lm75_groups); + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->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; - } - - data->tz = thermal_zone_of_sensor_register(&client->dev, + data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0, - &client->dev, + data->hwmon_dev, lm75_read_temp, NULL); if (IS_ERR(data->tz)) data->tz = NULL; - dev_info(&client->dev, "%s: sensor '%s'\n", + dev_info(dev, "%s: sensor '%s'\n", dev_name(data->hwmon_dev), client->name); return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &lm75_group); - return status; } static int lm75_remove(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, data->tz); + thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm75_group); lm75_write_value(client, LM75_REG_CONF, data->orig_conf); return 0; } @@ -507,8 +496,8 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) static struct lm75_data *lm75_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct lm75_data *ret = data; mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index f17beb5e6dd..5ceb443b938 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -19,10 +19,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -47,50 +43,33 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, #define LM77_REG_TEMP_MIN 0x04 #define LM77_REG_TEMP_MAX 0x05 +enum temp_index { + t_input = 0, + t_crit, + t_min, + t_max, + t_hyst, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM77_REG_TEMP, + [t_min] = LM77_REG_TEMP_MIN, + [t_max] = LM77_REG_TEMP_MAX, + [t_crit] = LM77_REG_TEMP_CRIT, + [t_hyst] = LM77_REG_TEMP_HYST, +}; + /* Each client has this additional data */ struct lm77_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ - int temp_input; /* Temperatures */ - int temp_crit; - int temp_min; - int temp_max; - int temp_hyst; + int temp[t_num_temp]; /* index using temp_index */ u8 alarms; }; -static int lm77_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm77_init_client(struct i2c_client *client); -static int lm77_remove(struct i2c_client *client); -static u16 lm77_read_value(struct i2c_client *client, u8 reg); -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); - -static struct lm77_data *lm77_update_device(struct device *dev); - - -static const struct i2c_device_id lm77_id[] = { - { "lm77", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm77_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver lm77_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm77", - }, - .probe = lm77_probe, - .remove = lm77_remove, - .id_table = lm77_id, - .detect = lm77_detect, - .address_list = normal_i2c, -}; - /* straight from the datasheet */ #define LM77_TEMP_MIN (-55000) #define LM77_TEMP_MAX 125000 @@ -110,97 +89,109 @@ static inline int LM77_TEMP_FROM_REG(s16 reg) return (reg / 8) * 500; } -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm77_data *data = lm77_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ +/* + * All registers are word-sized, except for the configuration register. + * The LM77 uses the high-byte first convention. + */ +static u16 lm77_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return i2c_smbus_read_word_swapped(client, reg); } -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_swapped(client, reg, value); +} -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static struct lm77_data *lm77_update_device(struct device *dev) { - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm77 update\n"); + for (i = 0; i < t_num_temp; i++) { + data->temp[i] = + LM77_TEMP_FROM_REG(lm77_read_value(client, + temp_regs[i])); + } + data->alarms = + lm77_read_value(client, LM77_REG_TEMP) & 0x0007; + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; } -static ssize_t show_temp_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +/* sysfs stuff */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); + + return sprintf(buf, "%d\n", data->temp[attr->index]); } -static ssize_t show_temp_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); -} + int nr = attr->index; + int temp; -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ - \ - mutex_lock(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} + temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] : + data->temp[nr] - data->temp[t_hyst]; -set(temp_min, LM77_REG_TEMP_MIN); -set(temp_max, LM77_REG_TEMP_MAX); + return sprintf(buf, "%d\n", temp); +} -/* - * hysteresis is stored as a relative value on the chip, so it has to be - * converted first - */ -static ssize_t set_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; int err; - err = kstrtoul(buf, 10, &val); + err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); - data->temp_hyst = data->temp_crit - val; - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); + data->temp[nr] = val; + lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val)); mutex_unlock(&data->update_lock); return count; } -/* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, +/* + * hysteresis is stored as a relative value on the chip, so it has to be + * converted first. + */ +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - int oldcrithyst; + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -209,13 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - oldcrithyst = data->temp_crit - data->temp_hyst; - data->temp_crit = val; - data->temp_hyst = data->temp_crit - oldcrithyst; - lm77_write_value(client, LM77_REG_TEMP_CRIT, - LM77_TEMP_TO_REG(data->temp_crit)); + data->temp[t_hyst] = data->temp[t_crit] - val; lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); + LM77_TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -228,43 +215,37 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_max, set_temp_max); - -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, - show_temp_min_hyst, NULL); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); + +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); -static struct attribute *lm77_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max_hyst.attr, +static struct attribute *lm77_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm77_group = { - .attrs = lm77_attributes, -}; +ATTRIBUTE_GROUPS(lm77); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -337,112 +318,52 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } +static void lm77_init_client(struct i2c_client *client) +{ + /* Initialize the LM77 chip - turn off shutdown mode */ + int conf = lm77_read_value(client, LM77_REG_CONF); + if (conf & 1) + lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); +} + static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm77_data *data; - int err; data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); - data->valid = 0; + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM77 chip */ lm77_init_client(client); - /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &lm77_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&dev->kobj, &lm77_group); - return err; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm77_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm77_remove(struct i2c_client *client) -{ - struct lm77_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm77_group); - return 0; -} - -/* - * All registers are word-sized, except for the configuration register. - * The LM77 uses the high-byte first convention. - */ -static u16 lm77_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return i2c_smbus_read_word_swapped(client, reg); -} - -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_swapped(client, reg, value); -} - -static void lm77_init_client(struct i2c_client *client) -{ - /* Initialize the LM77 chip - turn off shutdown mode */ - int conf = lm77_read_value(client, LM77_REG_CONF); - if (conf & 1) - lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); -} - -static struct lm77_data *lm77_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); - data->alarms = - lm77_read_value(client, LM77_REG_TEMP) & 0x0007; - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm77_id[] = { + { "lm77", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm77_id); - return data; -} +/* This is the driver that will be inserted */ +static struct i2c_driver lm77_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm77", + }, + .probe = lm77_probe, + .id_table = lm77_id, + .detect = lm77_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm77_driver); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index eba89aac3ec..4bcd9b88294 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -86,140 +86,234 @@ static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ (val) == 255 ? 0 : 1350000/((div) * (val))) -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; +#define TEMP_FROM_REG(reg) ((reg) * 125 / 32) +#define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \ + -128000, 127000), 1000) << 8) - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; +#define DIV_FROM_REG(val) (1 << (val)) - return res / 10; -} +enum temp_index { + t_input = 0, + t_hot_max, + t_hot_hyst, + t_os_max, + t_os_hyst, + t_num_temp +}; -#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ - (val) - 0x100 : (val)) * 1000) +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM80_REG_TEMP, + [t_hot_max] = LM80_REG_TEMP_HOT_MAX, + [t_hot_hyst] = LM80_REG_TEMP_HOT_HYST, + [t_os_max] = LM80_REG_TEMP_OS_MAX, + [t_os_hyst] = LM80_REG_TEMP_OS_HYST, +}; -#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \ - ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255) +enum in_index { + i_input = 0, + i_max, + i_min, + i_num_in +}; -#define DIV_FROM_REG(val) (1 << (val)) +enum fan_index { + f_input, + f_min, + f_num_fan +}; /* * Client data (each client gets its own) */ struct lm80_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char error; /* !=0 if error occurred during last update */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ + u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */ + u8 fan[f_num_fan][2]; /* Register value, 1st index enum fan_index */ u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ + s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */ u16 alarms; /* Register encoding, combined */ }; -/* - * Functions declaration - */ +static int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} -static int lm80_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm80_init_client(struct i2c_client *client); -static int lm80_remove(struct i2c_client *client); -static struct lm80_data *lm80_update_device(struct device *dev); -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} -/* - * Driver data (common to all clients) - */ +/* Called when we have found a new LM80 and after read errors */ +static void lm80_init_client(struct i2c_client *client) +{ + /* + * Reset all except Watchdog values and last conversion values + * This sets fan-divs to 2, among others. This makes most other + * initializations unnecessary + */ + lm80_write_value(client, LM80_REG_CONFIG, 0x80); + /* Set 11-bit temperature resolution */ + lm80_write_value(client, LM80_REG_RES, 0x08); -static const struct i2c_device_id lm80_id[] = { - { "lm80", 0 }, - { "lm96080", 1 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm80_id); + /* Start monitoring */ + lm80_write_value(client, LM80_REG_CONFIG, 0x01); +} -static struct i2c_driver lm80_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm80", - }, - .probe = lm80_probe, - .remove = lm80_remove, - .id_table = lm80_id, - .detect = lm80_detect, - .address_list = normal_i2c, -}; +static struct lm80_data *lm80_update_device(struct device *dev) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + int rv; + int prev_rv; + struct lm80_data *ret = data; + + mutex_lock(&data->update_lock); + + if (data->error) + lm80_init_client(client); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(dev, "Starting lm80 update\n"); + for (i = 0; i <= 6; i++) { + rv = lm80_read_value(client, LM80_REG_IN(i)); + if (rv < 0) + goto abort; + data->in[i_input][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); + if (rv < 0) + goto abort; + data->in[i_min][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); + if (rv < 0) + goto abort; + data->in[i_max][i] = rv; + } + + rv = lm80_read_value(client, LM80_REG_FAN1); + if (rv < 0) + goto abort; + data->fan[f_input][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + if (rv < 0) + goto abort; + data->fan[f_min][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN2); + if (rv < 0) + goto abort; + data->fan[f_input][1] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); + if (rv < 0) + goto abort; + data->fan[f_min][1] = rv; + + prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_RES); + if (rv < 0) + goto abort; + data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0); + + for (i = t_input + 1; i < t_num_temp; i++) { + rv = lm80_read_value(client, temp_regs[i]); + if (rv < 0) + goto abort; + data->temp[i] = rv << 8; + } + + rv = lm80_read_value(client, LM80_REG_FANDIV); + if (rv < 0) + goto abort; + data->fan_div[0] = (rv >> 2) & 0x03; + data->fan_div[1] = (rv >> 4) & 0x03; + + prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_ALARM2); + if (rv < 0) + goto abort; + data->alarms = prev_rv + (rv << 8); + + data->last_updated = jiffies; + data->valid = 1; + data->error = 0; + } + goto done; + +abort: + ret = ERR_PTR(rv); + data->valid = 0; + data->error = 1; + +done: + mutex_unlock(&data->update_lock); + + return ret; +} /* * Sysfs stuff */ -#define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index])); } -show_in(min, in_min) -show_in(max, in_max) -show_in(input, in) - -#define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock);\ - data->value[nr] = IN_TO_REG(val); \ - lm80_write_value(client, reg(nr), data->value[nr]); \ - mutex_unlock(&data->update_lock);\ - return count; \ + +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + long val; + u8 reg; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index); + + mutex_lock(&data->update_lock); + data->in[nr][index] = IN_TO_REG(val); + lm80_write_value(client, reg, data->in[nr][index]); + mutex_unlock(&data->update_lock); + return count; } -set_in(min, in_min, LM80_REG_IN_MIN) -set_in(max, in_max, LM80_REG_IN_MAX) - -#define show_fan(suffix, value) \ -static ssize_t show_fan_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ - DIV_FROM_REG(data->fan_div[nr]))); \ + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index], + DIV_FROM_REG(data->fan_div[index]))); } -show_fan(min, fan_min) -show_fan(input, fan) static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) @@ -234,17 +328,20 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int nr = to_sensor_dev_attr(attr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err = kstrtoul(buf, 10, &val); if (err < 0) return err; mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[nr][index] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[index])); + lm80_write_value(client, LM80_REG_FAN_MIN(index + 1), + data->fan[nr][index]); mutex_unlock(&data->update_lock); return count; } @@ -259,8 +356,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long min, val; u8 reg; int err = kstrtoul(buf, 10, &val); @@ -269,7 +366,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, /* Save fan_min */ mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], + min = FAN_FROM_REG(data->fan[f_min][nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { @@ -286,69 +383,54 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, data->fan_div[nr] = 3; break; default: - dev_err(&client->dev, + dev_err(dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; } - reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) - | (data->fan_div[nr] << (2 * (nr + 1))); + reg = (lm80_read_value(client, LM80_REG_FANDIV) & + ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1))); lm80_write_value(client, LM80_REG_FANDIV, reg); /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), + data->fan[f_min][nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_input1(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm80_data *data = lm80_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ -} -show_temp(hot_max, temp_hot_max); -show_temp(hot_hyst, temp_hot_hyst); -show_temp(os_max, temp_os_max); -show_temp(os_hyst, temp_os_hyst); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_LIMIT_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8); + mutex_unlock(&data->update_lock); + return count; } -set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); -set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); -set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); -set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -369,60 +451,60 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 0); -static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 1); -static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 2); -static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 3); -static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 4); -static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 5); -static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 6); -static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 0); -static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 1); -static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 2); -static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 3); -static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 4); -static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 5); -static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 6); -static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0); -static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1); -static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2); -static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3); -static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4); -static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5); -static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6); -static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 0); -static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 1); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); -static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 1); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 2); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 3); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 4); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 5); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 6); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 0); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 2); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 3); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 4); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 5); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 6); +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, i_input, 0); +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, i_input, 1); +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, i_input, 2); +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3); +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4); +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5); +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 0); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 1); +static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, f_input, 0); +static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, f_input, 1); static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 1); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, - set_temp_hot_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, - set_temp_hot_hyst); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, - set_temp_os_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, - set_temp_os_hyst); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_hyst); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_max); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_hyst); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); @@ -440,7 +522,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13); * Real code */ -static struct attribute *lm80_attributes[] = { +static struct attribute *lm80_attrs[] = { &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, @@ -468,11 +550,11 @@ static struct attribute *lm80_attributes[] = { &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, @@ -487,10 +569,7 @@ static struct attribute *lm80_attributes[] = { &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm80_group = { - .attrs = lm80_attributes, -}; +ATTRIBUTE_GROUPS(lm80); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -541,188 +620,51 @@ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) static int lm80_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm80_data *data; - int err; - data = devm_kzalloc(&client->dev, sizeof(struct lm80_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM80 chip */ lm80_init_client(client); /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &lm80_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error_remove; - } + data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - return 0; - -error_remove: - sysfs_remove_group(&client->dev.kobj, &lm80_group); - return err; -} - -static int lm80_remove(struct i2c_client *client) -{ - struct lm80_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm80_group); - - return 0; -} - -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* - * Reset all except Watchdog values and last conversion values - * This sets fan-divs to 2, among others. This makes most other - * initializations unnecessary - */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm80_groups); - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static struct lm80_data *lm80_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - int i; - int rv; - int prev_rv; - struct lm80_data *ret = data; - - mutex_lock(&data->update_lock); - - if (data->error) - lm80_init_client(client); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - dev_dbg(&client->dev, "Starting lm80 update\n"); - for (i = 0; i <= 6; i++) { - rv = lm80_read_value(client, LM80_REG_IN(i)); - if (rv < 0) - goto abort; - data->in[i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); - if (rv < 0) - goto abort; - data->in_min[i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); - if (rv < 0) - goto abort; - data->in_max[i] = rv; - } - - rv = lm80_read_value(client, LM80_REG_FAN1); - if (rv < 0) - goto abort; - data->fan[0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - if (rv < 0) - goto abort; - data->fan_min[0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN2); - if (rv < 0) - goto abort; - data->fan[1] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - if (rv < 0) - goto abort; - data->fan_min[1] = rv; - - prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_RES); - if (rv < 0) - goto abort; - data->temp = (prev_rv << 8) | (rv & 0xf0); - - rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - if (rv < 0) - goto abort; - data->temp_os_max = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - if (rv < 0) - goto abort; - data->temp_os_hyst = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - if (rv < 0) - goto abort; - data->temp_hot_max = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - if (rv < 0) - goto abort; - data->temp_hot_hyst = rv; - - rv = lm80_read_value(client, LM80_REG_FANDIV); - if (rv < 0) - goto abort; - data->fan_div[0] = (rv >> 2) & 0x03; - data->fan_div[1] = (rv >> 4) & 0x03; - - prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_ALARM2); - if (rv < 0) - goto abort; - data->alarms = prev_rv + (rv << 8); - - data->last_updated = jiffies; - data->valid = 1; - data->error = 0; - } - goto done; - -abort: - ret = ERR_PTR(rv); - data->valid = 0; - data->error = 1; +/* + * Driver data (common to all clients) + */ -done: - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm80_id[] = { + { "lm80", 0 }, + { "lm96080", 1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm80_id); - return ret; -} +static struct i2c_driver lm80_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm80", + }, + .probe = lm80_probe, + .id_table = lm80_id, + .detect = lm80_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm80_driver); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index abd270243ba..9e4d0e1d3c4 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -25,10 +25,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -111,45 +107,12 @@ static const u8 LM83_REG_W_HIGH[] = { }; /* - * Functions declaration - */ - -static int lm83_detect(struct i2c_client *new_client, - struct i2c_board_info *info); -static int lm83_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm83_remove(struct i2c_client *client); -static struct lm83_data *lm83_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id lm83_id[] = { - { "lm83", lm83 }, - { "lm82", lm82 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm83_id); - -static struct i2c_driver lm83_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm83", - }, - .probe = lm83_probe, - .remove = lm83_remove, - .id_table = lm83_id, - .detect = lm83_detect, - .address_list = normal_i2c, -}; - -/* * Client data (each client gets its own) */ struct lm83_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -161,6 +124,36 @@ struct lm83_data { u16 alarms; /* bitvector, combined */ }; +static struct lm83_data *lm83_update_device(struct device *dev) +{ + struct lm83_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int nr; + + dev_dbg(&client->dev, "Updating lm83 data.\n"); + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = + i2c_smbus_read_byte_data(client, + LM83_REG_R_TEMP[nr]); + } + data->alarms = + i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) + << 8); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* * Sysfs stuff */ @@ -177,8 +170,8 @@ static ssize_t set_temp(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 lm83_data *data = i2c_get_clientdata(client); + struct lm83_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int nr = attr->index; int err; @@ -340,16 +333,15 @@ static int lm83_detect(struct i2c_client *new_client, static int lm83_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { + struct device *hwmon_dev; struct lm83_data *data; - int err; data = devm_kzalloc(&new_client->dev, sizeof(struct lm83_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); - data->valid = 0; + data->client = new_client; mutex_init(&data->update_lock); /* @@ -358,72 +350,37 @@ static int lm83_probe(struct i2c_client *new_client, * at the same register as the LM83 temp3 entry - so we * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ - - err = sysfs_create_group(&new_client->dev.kobj, &lm83_group); - if (err) - return err; - - if (id->driver_data == lm83) { - err = sysfs_create_group(&new_client->dev.kobj, - &lm83_group_opt); - if (err) - goto exit_remove_files; - } - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &lm83_group); - sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt); - return err; -} - -static int lm83_remove(struct i2c_client *client) -{ - struct lm83_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm83_group); - sysfs_remove_group(&client->dev.kobj, &lm83_group_opt); - - return 0; + data->groups[0] = &lm83_group; + if (id->driver_data == lm83) + data->groups[1] = &lm83_group_opt; + + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static struct lm83_data *lm83_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int nr; - - dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 9; nr++) { - data->temp[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_TEMP[nr]); - } - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) - + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) - << 8); - - data->last_updated = jiffies; - data->valid = 1; - } +/* + * Driver data (common to all clients) + */ - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm83_id[] = { + { "lm83", lm83 }, + { "lm82", lm82 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm83_id); - return data; -} +static struct i2c_driver lm83_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm83", + }, + .probe = lm83_probe, + .id_table = lm83_id, + .detect = lm83_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm83_driver); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index bed4af35830..b0129a54e1a 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -5,7 +5,7 @@ * Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> * Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> * Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com> - * Copyright (C) 2007--2009 Jean Delvare <jdelvare@suse.de> + * Copyright (C) 2007--2014 Jean Delvare <jdelvare@suse.de> * * Chip details at <http://www.national.com/ds/LM/LM85.pdf> * @@ -39,7 +39,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; enum chips { - any_chip, lm85b, lm85c, + lm85, adm1027, adt7463, adt7468, emc6d100, emc6d102, emc6d103, emc6d103s }; @@ -75,9 +75,6 @@ enum chips { #define LM85_COMPANY_NATIONAL 0x01 #define LM85_COMPANY_ANALOG_DEV 0x41 #define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_GENERIC2 0x70 #define LM85_VERSTEP_LM85C 0x60 #define LM85_VERSTEP_LM85B 0x62 #define LM85_VERSTEP_LM96000_1 0x68 @@ -351,9 +348,9 @@ static const struct i2c_device_id lm85_id[] = { { "adm1027", adm1027 }, { "adt7463", adt7463 }, { "adt7468", adt7468 }, - { "lm85", any_chip }, - { "lm85b", lm85b }, - { "lm85c", lm85c }, + { "lm85", lm85 }, + { "lm85b", lm85 }, + { "lm85c", lm85 }, { "emc6d100", emc6d100 }, { "emc6d101", emc6d100 }, { "emc6d102", emc6d102 }, @@ -1281,7 +1278,7 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; int address = client->addr; - const char *type_name; + const char *type_name = NULL; int company, verstep; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -1297,16 +1294,6 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) "Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n", address, company, verstep); - /* All supported chips have the version in common */ - if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC && - (verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC2) { - dev_dbg(&adapter->dev, - "Autodetection failed: unsupported version\n"); - return -ENODEV; - } - type_name = "lm85"; - - /* Now, refine the detection */ if (company == LM85_COMPANY_NATIONAL) { switch (verstep) { case LM85_VERSTEP_LM85C: @@ -1323,6 +1310,7 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) "Found Winbond WPCD377I, ignoring\n"); return -ENODEV; } + type_name = "lm85"; break; } } else if (company == LM85_COMPANY_ANALOG_DEV) { @@ -1357,12 +1345,11 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) type_name = "emc6d103s"; break; } - } else { - dev_dbg(&adapter->dev, - "Autodetection failed: unknown vendor\n"); - return -ENODEV; } + if (!type_name) + return -ENODEV; + strlcpy(info->type, type_name, I2C_NAME_SIZE); return 0; diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 4c5f20231c1..ba1d83d4805 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -903,7 +903,6 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; i2c_set_clientdata(client, data); - data->valid = 0; mutex_init(&data->update_lock); /* Initialize the LM87 chip */ diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 701e952ae52..c9ff08dbe10 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -365,7 +365,9 @@ enum lm90_temp11_reg_index { */ struct lm90_data { + struct i2c_client *client; struct device *hwmon_dev; + const struct attribute_group *groups[6]; struct mutex update_lock; struct regulator *regulator; char valid; /* zero until following fields are valid */ @@ -513,8 +515,8 @@ static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, static struct lm90_data *lm90_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long next_update; mutex_lock(&data->update_lock); @@ -793,8 +795,8 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long val; int err; @@ -860,8 +862,8 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, }; struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->nr; int index = attr->index; long val; @@ -922,8 +924,8 @@ static ssize_t show_temphyst(struct device *dev, static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; int temp; @@ -976,8 +978,8 @@ static ssize_t set_update_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -1057,6 +1059,15 @@ static const struct attribute_group lm90_group = { .attrs = lm90_attributes, }; +static struct attribute *lm90_temp2_offset_attributes[] = { + &sensor_dev_attr_temp2_offset.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm90_temp2_offset_group = { + .attrs = lm90_temp2_offset_attributes, +}; + /* * Additional attributes for devices with emergency sensors */ @@ -1393,22 +1404,6 @@ static int lm90_detect(struct i2c_client *client, return 0; } -static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data) -{ - struct device *dev = &client->dev; - - if (data->flags & LM90_HAVE_TEMP3) - sysfs_remove_group(&dev->kobj, &lm90_temp3_group); - if (data->flags & LM90_HAVE_EMERGENCY_ALARM) - sysfs_remove_group(&dev->kobj, &lm90_emergency_alarm_group); - if (data->flags & LM90_HAVE_EMERGENCY) - sysfs_remove_group(&dev->kobj, &lm90_emergency_group); - if (data->flags & LM90_HAVE_OFFSET) - device_remove_file(dev, &sensor_dev_attr_temp2_offset.dev_attr); - device_remove_file(dev, &dev_attr_pec); - sysfs_remove_group(&dev->kobj, &lm90_group); -} - static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data) { /* Restore initial configuration */ @@ -1418,10 +1413,9 @@ static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data) data->config_orig); } -static void lm90_init_client(struct i2c_client *client) +static void lm90_init_client(struct i2c_client *client, struct lm90_data *data) { u8 config, convrate; - struct lm90_data *data = i2c_get_clientdata(client); if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) { dev_warn(&client->dev, "Failed to read convrate register!\n"); @@ -1519,6 +1513,7 @@ static int lm90_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); struct lm90_data *data; struct regulator *regulator; + int groups = 0; int err; regulator = devm_regulator_get(dev, "vcc"); @@ -1527,15 +1522,15 @@ static int lm90_probe(struct i2c_client *client, err = regulator_enable(regulator); if (err < 0) { - dev_err(&client->dev, - "Failed to enable regulator: %d\n", err); + dev_err(dev, "Failed to enable regulator: %d\n", err); return err; } - data = devm_kzalloc(&client->dev, sizeof(struct lm90_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL); if (!data) return -ENOMEM; + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -1562,44 +1557,34 @@ static int lm90_probe(struct i2c_client *client, data->max_convrate = lm90_params[data->kind].max_convrate; /* Initialize the LM90 chip */ - lm90_init_client(client); + lm90_init_client(client, data); /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &lm90_group); - if (err) - goto exit_restore; + data->groups[groups++] = &lm90_group; + + if (data->flags & LM90_HAVE_OFFSET) + data->groups[groups++] = &lm90_temp2_offset_group; + + if (data->flags & LM90_HAVE_EMERGENCY) + data->groups[groups++] = &lm90_emergency_group; + + if (data->flags & LM90_HAVE_EMERGENCY_ALARM) + data->groups[groups++] = &lm90_emergency_alarm_group; + + if (data->flags & LM90_HAVE_TEMP3) + data->groups[groups++] = &lm90_temp3_group; + if (client->flags & I2C_CLIENT_PEC) { err = device_create_file(dev, &dev_attr_pec); if (err) - goto exit_remove_files; - } - if (data->flags & LM90_HAVE_OFFSET) { - err = device_create_file(dev, - &sensor_dev_attr_temp2_offset.dev_attr); - if (err) - goto exit_remove_files; - } - if (data->flags & LM90_HAVE_EMERGENCY) { - err = sysfs_create_group(&dev->kobj, &lm90_emergency_group); - if (err) - goto exit_remove_files; - } - if (data->flags & LM90_HAVE_EMERGENCY_ALARM) { - err = sysfs_create_group(&dev->kobj, - &lm90_emergency_alarm_group); - if (err) - goto exit_remove_files; - } - if (data->flags & LM90_HAVE_TEMP3) { - err = sysfs_create_group(&dev->kobj, &lm90_temp3_group); - if (err) - goto exit_remove_files; + goto exit_restore; } - data->hwmon_dev = hwmon_device_register(dev); + data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + data, data->groups); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; + goto exit_remove_pec; } if (client->irq) { @@ -1618,8 +1603,8 @@ static int lm90_probe(struct i2c_client *client, exit_unregister: hwmon_device_unregister(data->hwmon_dev); -exit_remove_files: - lm90_remove_files(client, data); +exit_remove_pec: + device_remove_file(dev, &dev_attr_pec); exit_restore: lm90_restore_conf(client, data); regulator_disable(data->regulator); @@ -1632,7 +1617,7 @@ static int lm90_remove(struct i2c_client *client) struct lm90_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); - lm90_remove_files(client, data); + device_remove_file(&client->dev, &dev_attr_pec); lm90_restore_conf(client, data); regulator_disable(data->regulator); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 9d0e87a4f0c..d2060e245ff 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -34,10 +34,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -93,46 +89,53 @@ static inline u8 ALARMS_FROM_REG(s16 reg) return reg & 0x0007; } -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; +enum temp_index { + t_input, + t_crit, + t_min, + t_max, + t_hyst, + t_num_regs +}; + +static const u8 regs[t_num_regs] = { + [t_input] = LM92_REG_TEMP, + [t_crit] = LM92_REG_TEMP_CRIT, + [t_min] = LM92_REG_TEMP_LOW, + [t_max] = LM92_REG_TEMP_HIGH, + [t_hyst] = LM92_REG_TEMP_HYST, +}; /* Client data (each client gets its own) */ struct lm92_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ /* registers values */ - s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; + s16 temp[t_num_regs]; /* index with enum temp_index */ }; - /* * Sysfs attributes and callback functions */ static struct lm92_data *lm92_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP); - data->temp1_hyst = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HYST); - data->temp1_crit = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_CRIT); - data->temp1_min = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_LOW); - data->temp1_max = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HIGH); - + for (i = 0; i < t_num_regs; i++) { + data->temp[i] = + i2c_smbus_read_word_swapped(client, regs[i]); + } data->last_updated = jiffies; data->valid = 1; } @@ -142,68 +145,60 @@ static struct lm92_data *lm92_update_device(struct device *dev) return data; } -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm92_data *data = lm92_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm92_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_swapped(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = lm92_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - - TEMP_FROM_REG(data->temp1_hyst)); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); + mutex_unlock(&data->update_lock); + return count; } -static ssize_t show_temp1_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - - TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) + - TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t show_temp1_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) - + TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) + + TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t set_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; @@ -212,9 +207,9 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, return err; mutex_lock(&data->update_lock); - data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; + data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val; i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, - TEMP_TO_REG(data->temp1_hyst)); + TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -223,7 +218,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); } static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, @@ -231,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1); + return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, - set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, - set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, - set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, - set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); - /* * Detection and registration */ @@ -322,24 +316,21 @@ static int max6635_check(struct i2c_client *client) return 1; } -static struct attribute *lm92_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min.attr, +static struct attribute *lm92_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm92_group = { - .attrs = lm92_attributes, -}; +ATTRIBUTE_GROUPS(lm92); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm92_detect(struct i2c_client *new_client, @@ -371,47 +362,24 @@ static int lm92_detect(struct i2c_client *new_client, static int lm92_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { + struct device *hwmon_dev; struct lm92_data *data; - int err; data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); - data->valid = 0; + data->client = new_client; mutex_init(&data->update_lock); /* Initialize the chipset */ lm92_init_client(new_client); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm92_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm92_group); - return err; -} - -static int lm92_remove(struct i2c_client *client) -{ - struct lm92_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm92_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, lm92_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } @@ -432,7 +400,6 @@ static struct i2c_driver lm92_driver = { .name = "lm92", }, .probe = lm92_probe, - .remove = lm92_remove, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 6f1c6c0dbaf..6c2df576f25 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2747,14 +2747,11 @@ static int lm93_probe(struct i2c_client *client, } data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL); - if (!data) { - dev_dbg(&client->dev, "out of memory!\n"); + if (!data) return -ENOMEM; - } i2c_set_clientdata(client, data); /* housekeeping */ - data->valid = 0; data->update = update; mutex_init(&data->update_lock); diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 4b68fb2a31d..cdf19adaec7 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -89,7 +89,7 @@ static const u8 lm95241_reg_address[] = { /* Client data (each client gets its own) */ struct lm95241_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; unsigned long last_updated, interval; /* in jiffies */ char valid; /* zero until following fields are valid */ @@ -113,8 +113,8 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l) static struct lm95241_data *lm95241_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; mutex_lock(&data->update_lock); @@ -122,7 +122,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev) !data->valid) { int i; - dev_dbg(&client->dev, "Updating lm95241 data.\n"); + dev_dbg(dev, "Updating lm95241 data.\n"); for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++) data->temp[i] = i2c_smbus_read_byte_data(client, @@ -153,8 +153,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr, static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE - 1, data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n"); @@ -163,8 +162,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, static ssize_t set_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int shift; u8 mask = to_sensor_dev_attr(attr)->index; @@ -201,8 +200,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr, static ssize_t show_min(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE - 1, data->config & to_sensor_dev_attr(attr)->index ? @@ -212,8 +210,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr, static ssize_t set_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); long val; if (kstrtol(buf, 10, &val) < 0) @@ -229,7 +226,8 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr, data->config &= ~to_sensor_dev_attr(attr)->index; data->valid = 0; - i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); + i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG, + data->config); mutex_unlock(&data->update_lock); @@ -239,8 +237,7 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr, static ssize_t show_max(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE - 1, data->config & to_sensor_dev_attr(attr)->index ? @@ -250,8 +247,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr, static ssize_t set_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); long val; if (kstrtol(buf, 10, &val) < 0) @@ -267,7 +263,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *attr, data->config &= ~to_sensor_dev_attr(attr)->index; data->valid = 0; - i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); + i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG, + data->config); mutex_unlock(&data->update_lock); @@ -286,8 +283,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr, static ssize_t set_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); + struct lm95241_data *data = dev_get_drvdata(dev); unsigned long val; if (kstrtoul(buf, 10, &val) < 0) @@ -316,7 +312,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, set_interval); -static struct attribute *lm95241_attributes[] = { +static struct attribute *lm95241_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, @@ -329,10 +325,7 @@ static struct attribute *lm95241_attributes[] = { &dev_attr_update_interval.attr, NULL }; - -static const struct attribute_group lm95241_group = { - .attrs = lm95241_attributes, -}; +ATTRIBUTE_GROUPS(lm95241); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm95241_detect(struct i2c_client *new_client, @@ -366,14 +359,11 @@ static int lm95241_detect(struct i2c_client *new_client, return 0; } -static void lm95241_init_client(struct i2c_client *client) +static void lm95241_init_client(struct i2c_client *client, + struct lm95241_data *data) { - struct lm95241_data *data = i2c_get_clientdata(client); - data->interval = HZ; /* 1 sec default */ - data->valid = 0; data->config = CFG_CR0076; - data->model = 0; data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); @@ -385,49 +375,27 @@ static void lm95241_init_client(struct i2c_client *client) data->model); } -static int lm95241_probe(struct i2c_client *new_client, +static int lm95241_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm95241_data *data; - int err; + struct device *hwmon_dev; - data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM95241 chip */ - lm95241_init_client(new_client); + lm95241_init_client(client, data); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &lm95241_group); - return err; -} - -static int lm95241_remove(struct i2c_client *client) -{ - struct lm95241_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm95241_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + lm95241_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* Driver data (common to all clients) */ @@ -444,7 +412,6 @@ static struct i2c_driver lm95241_driver = { .name = DEVNAME, }, .probe = lm95241_probe, - .remove = lm95241_remove, .id_table = lm95241_id, .detect = lm95241_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index a6c85f0ff8f..0ae0dfdafdf 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -115,7 +115,7 @@ static const u8 lm95245_reg_address[] = { /* Client data (each client gets its own) */ struct lm95245_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; unsigned long last_updated; /* in jiffies */ unsigned long interval; /* in msecs */ @@ -140,8 +140,8 @@ static int temp_from_reg_signed(u8 val_h, u8 val_l) static struct lm95245_data *lm95245_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; mutex_lock(&data->update_lock); @@ -149,7 +149,6 @@ static struct lm95245_data *lm95245_update_device(struct device *dev) + msecs_to_jiffies(data->interval)) || !data->valid) { int i; - dev_dbg(&client->dev, "Updating lm95245 data.\n"); for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++) data->regs[i] = i2c_smbus_read_byte_data(client, @@ -249,9 +248,9 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr, static ssize_t set_limit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = data->client; unsigned long val; if (kstrtoul(buf, 10, &val) < 0) @@ -272,27 +271,38 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm95245_data *data = lm95245_update_device(dev); + int index = to_sensor_dev_attr(attr)->index; + int hyst = data->regs[index] - data->regs[8]; + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000); +} + static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = data->client; unsigned long val; + int hyst, limit; if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - val /= 1000; - - val = clamp_val(val, 0, 31); - mutex_lock(&data->update_lock); - data->valid = 0; + limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]); + hyst = limit - val / 1000; + hyst = clamp_val(hyst, 0, 31); + data->regs[8] = hyst; /* shared crit hysteresis */ i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS, - val); + hyst); mutex_unlock(&data->update_lock); @@ -302,8 +312,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr, static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE - 1, data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n"); @@ -312,8 +321,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, static ssize_t set_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; if (kstrtoul(buf, 10, &val) < 0) @@ -359,8 +368,8 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr, static ssize_t set_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95245_data *data = i2c_get_clientdata(client); + struct lm95245_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; if (kstrtoul(buf, 10, &val) < 0) @@ -378,16 +387,15 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit, set_limit, 6); -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit, - set_crit_hyst, 8); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst, + set_crit_hyst, 6); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, STATUS1_LOC); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2); static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit, set_limit, 7); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit, - set_crit_hyst, 8); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, STATUS1_RTCRIT); static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, @@ -398,7 +406,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, set_interval); -static struct attribute *lm95245_attributes[] = { +static struct attribute *lm95245_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, @@ -412,10 +420,7 @@ static struct attribute *lm95245_attributes[] = { &dev_attr_update_interval.attr, NULL }; - -static const struct attribute_group lm95245_group = { - .attrs = lm95245_attributes, -}; +ATTRIBUTE_GROUPS(lm95245); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm95245_detect(struct i2c_client *new_client, @@ -436,11 +441,9 @@ static int lm95245_detect(struct i2c_client *new_client, return 0; } -static void lm95245_init_client(struct i2c_client *client) +static void lm95245_init_client(struct i2c_client *client, + struct lm95245_data *data) { - struct lm95245_data *data = i2c_get_clientdata(client); - - data->valid = 0; data->interval = lm95245_read_conversion_rate(client); data->config1 = i2c_smbus_read_byte_data(client, @@ -456,49 +459,27 @@ static void lm95245_init_client(struct i2c_client *client) } } -static int lm95245_probe(struct i2c_client *new_client, +static int lm95245_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm95245_data *data; - int err; + struct device *hwmon_dev; - data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM95245 chip */ - lm95245_init_client(new_client); - - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &lm95245_group); - return err; -} + lm95245_init_client(client, data); -static int lm95245_remove(struct i2c_client *client) -{ - struct lm95245_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm95245_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + lm95245_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* Driver data (common to all clients) */ @@ -514,7 +495,6 @@ static struct i2c_driver lm95245_driver = { .name = DEVNAME, }, .probe = lm95245_probe, - .remove = lm95245_remove, .id_table = lm95245_id, .detect = lm95245_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c new file mode 100644 index 00000000000..3701b329b6a --- /dev/null +++ b/drivers/hwmon/ltc2945.c @@ -0,0 +1,519 @@ +/* + * Driver for Linear Technology LTC2945 I2C Power Monitor + * + * Copyright (c) 2014 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 + * 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/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/regmap.h> + +/* chip registers */ +#define LTC2945_CONTROL 0x00 +#define LTC2945_ALERT 0x01 +#define LTC2945_STATUS 0x02 +#define LTC2945_FAULT 0x03 +#define LTC2945_POWER_H 0x05 +#define LTC2945_MAX_POWER_H 0x08 +#define LTC2945_MIN_POWER_H 0x0b +#define LTC2945_MAX_POWER_THRES_H 0x0e +#define LTC2945_MIN_POWER_THRES_H 0x11 +#define LTC2945_SENSE_H 0x14 +#define LTC2945_MAX_SENSE_H 0x16 +#define LTC2945_MIN_SENSE_H 0x18 +#define LTC2945_MAX_SENSE_THRES_H 0x1a +#define LTC2945_MIN_SENSE_THRES_H 0x1c +#define LTC2945_VIN_H 0x1e +#define LTC2945_MAX_VIN_H 0x20 +#define LTC2945_MIN_VIN_H 0x22 +#define LTC2945_MAX_VIN_THRES_H 0x24 +#define LTC2945_MIN_VIN_THRES_H 0x26 +#define LTC2945_ADIN_H 0x28 +#define LTC2945_MAX_ADIN_H 0x2a +#define LTC2945_MIN_ADIN_H 0x2c +#define LTC2945_MAX_ADIN_THRES_H 0x2e +#define LTC2945_MIN_ADIN_THRES_H 0x30 +#define LTC2945_MIN_ADIN_THRES_L 0x31 + +/* Fault register bits */ + +#define FAULT_ADIN_UV (1 << 0) +#define FAULT_ADIN_OV (1 << 1) +#define FAULT_VIN_UV (1 << 2) +#define FAULT_VIN_OV (1 << 3) +#define FAULT_SENSE_UV (1 << 4) +#define FAULT_SENSE_OV (1 << 5) +#define FAULT_POWER_UV (1 << 6) +#define FAULT_POWER_OV (1 << 7) + +/* Control register bits */ + +#define CONTROL_MULT_SELECT (1 << 0) +#define CONTROL_TEST_MODE (1 << 4) + +static inline bool is_power_reg(u8 reg) +{ + return reg < LTC2945_SENSE_H; +} + +/* Return the value from the given register in uW, mV, or mA */ +static long long ltc2945_reg_to_val(struct device *dev, u8 reg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int control; + u8 buf[3]; + long long val; + int ret; + + ret = regmap_bulk_read(regmap, reg, buf, + is_power_reg(reg) ? 3 : 2); + if (ret < 0) + return ret; + + if (is_power_reg(reg)) { + /* power */ + val = (buf[0] << 16) + (buf[1] << 8) + buf[2]; + } else { + /* current, voltage */ + val = (buf[0] << 4) + (buf[1] >> 4); + } + + switch (reg) { + case LTC2945_POWER_H: + case LTC2945_MAX_POWER_H: + case LTC2945_MIN_POWER_H: + case LTC2945_MAX_POWER_THRES_H: + case LTC2945_MIN_POWER_THRES_H: + /* + * Convert to uW by assuming current is measured with + * an 1mOhm sense resistor, similar to current + * measurements. + * Control register bit 0 selects if voltage at SENSE+/VDD + * or voltage at ADIN is used to measure power. + */ + ret = regmap_read(regmap, LTC2945_CONTROL, &control); + if (ret < 0) + return ret; + if (control & CONTROL_MULT_SELECT) { + /* 25 mV * 25 uV = 0.625 uV resolution. */ + val *= 625LL; + } else { + /* 0.5 mV * 25 uV = 0.0125 uV resolution. */ + val = (val * 25LL) >> 1; + } + break; + case LTC2945_VIN_H: + case LTC2945_MAX_VIN_H: + case LTC2945_MIN_VIN_H: + case LTC2945_MAX_VIN_THRES_H: + case LTC2945_MIN_VIN_THRES_H: + /* 25 mV resolution. Convert to mV. */ + val *= 25; + break; + case LTC2945_ADIN_H: + case LTC2945_MAX_ADIN_H: + case LTC2945_MIN_ADIN_THRES_H: + case LTC2945_MAX_ADIN_THRES_H: + case LTC2945_MIN_ADIN_H: + /* 0.5mV resolution. Convert to mV. */ + val = val >> 1; + break; + case LTC2945_SENSE_H: + case LTC2945_MAX_SENSE_H: + case LTC2945_MIN_SENSE_H: + case LTC2945_MAX_SENSE_THRES_H: + case LTC2945_MIN_SENSE_THRES_H: + /* + * 25 uV resolution. Convert to current as measured with + * an 1 mOhm sense resistor, in mA. If a different sense + * resistor is installed, calculate the actual current by + * dividing the reported current by the sense resistor value + * in mOhm. + */ + val *= 25; + break; + default: + return -EINVAL; + } + return val; +} + +static int ltc2945_val_to_reg(struct device *dev, u8 reg, + unsigned long val) +{ + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int control; + int ret; + + switch (reg) { + case LTC2945_POWER_H: + case LTC2945_MAX_POWER_H: + case LTC2945_MIN_POWER_H: + case LTC2945_MAX_POWER_THRES_H: + case LTC2945_MIN_POWER_THRES_H: + /* + * Convert to register value by assuming current is measured + * with an 1mOhm sense resistor, similar to current + * measurements. + * Control register bit 0 selects if voltage at SENSE+/VDD + * or voltage at ADIN is used to measure power, which in turn + * determines register calculations. + */ + ret = regmap_read(regmap, LTC2945_CONTROL, &control); + if (ret < 0) + return ret; + if (control & CONTROL_MULT_SELECT) { + /* 25 mV * 25 uV = 0.625 uV resolution. */ + val = DIV_ROUND_CLOSEST(val, 625); + } else { + /* + * 0.5 mV * 25 uV = 0.0125 uV resolution. + * Divide first to avoid overflow; + * accept loss of accuracy. + */ + val = DIV_ROUND_CLOSEST(val, 25) * 2; + } + break; + case LTC2945_VIN_H: + case LTC2945_MAX_VIN_H: + case LTC2945_MIN_VIN_H: + case LTC2945_MAX_VIN_THRES_H: + case LTC2945_MIN_VIN_THRES_H: + /* 25 mV resolution. */ + val /= 25; + break; + case LTC2945_ADIN_H: + case LTC2945_MAX_ADIN_H: + case LTC2945_MIN_ADIN_THRES_H: + case LTC2945_MAX_ADIN_THRES_H: + case LTC2945_MIN_ADIN_H: + /* 0.5mV resolution. */ + val *= 2; + break; + case LTC2945_SENSE_H: + case LTC2945_MAX_SENSE_H: + case LTC2945_MIN_SENSE_H: + case LTC2945_MAX_SENSE_THRES_H: + case LTC2945_MIN_SENSE_THRES_H: + /* + * 25 uV resolution. Convert to current as measured with + * an 1 mOhm sense resistor, in mA. If a different sense + * resistor is installed, calculate the actual current by + * dividing the reported current by the sense resistor value + * in mOhm. + */ + val = DIV_ROUND_CLOSEST(val, 25); + break; + default: + return -EINVAL; + } + return val; +} + +static ssize_t ltc2945_show_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + long long value; + + value = ltc2945_reg_to_val(dev, attr->index); + if (value < 0) + return value; + return snprintf(buf, PAGE_SIZE, "%lld\n", value); +} + +static ssize_t ltc2945_set_value(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct regmap *regmap = dev_get_drvdata(dev); + u8 reg = attr->index; + unsigned long val; + u8 regbuf[3]; + int num_regs; + int regval; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + /* convert to register value, then clamp and write result */ + regval = ltc2945_val_to_reg(dev, reg, val); + if (is_power_reg(reg)) { + regval = clamp_val(regval, 0, 0xffffff); + regbuf[0] = regval >> 16; + regbuf[1] = (regval >> 8) & 0xff; + regbuf[2] = regval; + num_regs = 3; + } else { + regval = clamp_val(regval, 0, 0xfff) << 4; + regbuf[0] = regval >> 8; + regbuf[1] = regval & 0xff; + num_regs = 2; + } + ret = regmap_bulk_write(regmap, reg, regbuf, num_regs); + return ret < 0 ? ret : count; +} + +static ssize_t ltc2945_reset_history(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct regmap *regmap = dev_get_drvdata(dev); + u8 reg = attr->index; + int num_regs = is_power_reg(reg) ? 3 : 2; + u8 buf_min[3] = { 0xff, 0xff, 0xff }; + u8 buf_max[3] = { 0, 0, 0 }; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val != 1) + return -EINVAL; + + ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, + CONTROL_TEST_MODE); + + /* Reset minimum */ + ret = regmap_bulk_write(regmap, reg, buf_min, num_regs); + if (ret) + return ret; + + switch (reg) { + case LTC2945_MIN_POWER_H: + reg = LTC2945_MAX_POWER_H; + break; + case LTC2945_MIN_SENSE_H: + reg = LTC2945_MAX_SENSE_H; + break; + case LTC2945_MIN_VIN_H: + reg = LTC2945_MAX_VIN_H; + break; + case LTC2945_MIN_ADIN_H: + reg = LTC2945_MAX_ADIN_H; + break; + default: + WARN_ONCE(1, "Bad register: 0x%x\n", reg); + return -EINVAL; + } + /* Reset maximum */ + ret = regmap_bulk_write(regmap, reg, buf_max, num_regs); + + /* Try resetting test mode even if there was an error */ + regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0); + + return ret ? : count; +} + +static ssize_t ltc2945_show_bool(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int fault; + int ret; + + ret = regmap_read(regmap, LTC2945_FAULT, &fault); + if (ret < 0) + return ret; + + fault &= attr->index; + if (fault) /* Clear reported faults in chip register */ + regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0); + + return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); +} + +/* Input voltages */ + +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_VIN_H); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MIN_VIN_THRES_H); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MAX_VIN_THRES_H); +static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MIN_VIN_H); +static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MAX_VIN_H); +static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL, + ltc2945_reset_history, LTC2945_MIN_VIN_H); + +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_ADIN_H); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H); +static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MIN_ADIN_H); +static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MAX_ADIN_H); +static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL, + ltc2945_reset_history, LTC2945_MIN_ADIN_H); + +/* Voltage alarms */ + +static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_VIN_UV); +static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_VIN_OV); +static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_ADIN_UV); +static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_ADIN_OV); + +/* Currents (via sense resistor) */ + +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_SENSE_H); +static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H); +static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H); +static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MIN_SENSE_H); +static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_MAX_SENSE_H); +static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL, + ltc2945_reset_history, LTC2945_MIN_SENSE_H); + +/* Current alarms */ + +static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_SENSE_UV); +static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_SENSE_OV); + +/* Power */ + +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL, + LTC2945_POWER_H); +static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MIN_POWER_THRES_H); +static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value, + ltc2945_set_value, LTC2945_MAX_POWER_THRES_H); +static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value, + NULL, LTC2945_MIN_POWER_H); +static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value, + NULL, LTC2945_MAX_POWER_H); +static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL, + ltc2945_reset_history, LTC2945_MIN_POWER_H); + +/* Power alarms */ + +static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_POWER_UV); +static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL, + FAULT_POWER_OV); + +static struct attribute *ltc2945_attrs[] = { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_lowest.dev_attr.attr, + &sensor_dev_attr_in1_highest.dev_attr.attr, + &sensor_dev_attr_in1_reset_history.dev_attr.attr, + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, + + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_lowest.dev_attr.attr, + &sensor_dev_attr_in2_highest.dev_attr.attr, + &sensor_dev_attr_in2_reset_history.dev_attr.attr, + &sensor_dev_attr_in2_min_alarm.dev_attr.attr, + &sensor_dev_attr_in2_max_alarm.dev_attr.attr, + + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_curr1_min.dev_attr.attr, + &sensor_dev_attr_curr1_max.dev_attr.attr, + &sensor_dev_attr_curr1_lowest.dev_attr.attr, + &sensor_dev_attr_curr1_highest.dev_attr.attr, + &sensor_dev_attr_curr1_reset_history.dev_attr.attr, + &sensor_dev_attr_curr1_min_alarm.dev_attr.attr, + &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, + + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_power1_min.dev_attr.attr, + &sensor_dev_attr_power1_max.dev_attr.attr, + &sensor_dev_attr_power1_input_lowest.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_min_alarm.dev_attr.attr, + &sensor_dev_attr_power1_max_alarm.dev_attr.attr, + + NULL, +}; +ATTRIBUTE_GROUPS(ltc2945); + +static struct regmap_config ltc2945_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LTC2945_MIN_ADIN_THRES_L, +}; + +static int ltc2945_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, <c2945_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to allocate register map\n"); + return PTR_ERR(regmap); + } + + /* Clear faults */ + regmap_write(regmap, LTC2945_FAULT, 0x00); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + regmap, + ltc2945_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id ltc2945_id[] = { + {"ltc2945", 0}, + { } +}; + +MODULE_DEVICE_TABLE(i2c, ltc2945_id); + +static struct i2c_driver ltc2945_driver = { + .driver = { + .name = "ltc2945", + }, + .probe = ltc2945_probe, + .id_table = ltc2945_id, +}; + +module_i2c_driver(ltc2945_driver); + +MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("LTC2945 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index af81be1237c..c86a1840249 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -47,7 +47,7 @@ #define LTC4151_ADIN_L 0x05 struct ltc4151_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; @@ -59,8 +59,8 @@ struct ltc4151_data { static struct ltc4151_data *ltc4151_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4151_data *data = i2c_get_clientdata(client); + struct ltc4151_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct ltc4151_data *ret = data; mutex_lock(&data->update_lock); @@ -159,7 +159,7 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL, * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ -static struct attribute *ltc4151_attributes[] = { +static struct attribute *ltc4151_attrs[] = { &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, @@ -167,54 +167,30 @@ static struct attribute *ltc4151_attributes[] = { NULL, }; - -static const struct attribute_group ltc4151_group = { - .attrs = ltc4151_attributes, -}; +ATTRIBUTE_GROUPS(ltc4151); static int ltc4151_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; struct ltc4151_data *data; - int ret; + struct device *hwmon_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); - /* Register sysfs hooks */ - ret = sysfs_create_group(&client->dev.kobj, <c4151_group); - if (ret) - return ret; - - 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, <c4151_group); - return ret; -} - -static int ltc4151_remove(struct i2c_client *client) -{ - struct ltc4151_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, <c4151_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + ltc4151_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ltc4151_id[] = { @@ -229,7 +205,6 @@ static struct i2c_driver ltc4151_driver = { .name = "ltc4151", }, .probe = ltc4151_probe, - .remove = ltc4151_remove, .id_table = ltc4151_id, }; diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index 8a142960d69..c8a9bd9b050 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -33,7 +33,7 @@ enum ltc4215_cmd { }; struct ltc4215_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; @@ -45,8 +45,8 @@ struct ltc4215_data { static struct ltc4215_data *ltc4215_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4215_data *data = i2c_get_clientdata(client); + struct ltc4215_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; s32 val; int i; @@ -214,7 +214,7 @@ static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL, * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ -static struct attribute *ltc4215_attributes[] = { +static struct attribute *ltc4215_attrs[] = { &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, @@ -229,57 +229,33 @@ static struct attribute *ltc4215_attributes[] = { NULL, }; - -static const struct attribute_group ltc4215_group = { - .attrs = ltc4215_attributes, -}; +ATTRIBUTE_GROUPS(ltc4215); static int ltc4215_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; struct ltc4215_data *data; - int ret; + struct device *hwmon_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LTC4215 chip */ i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00); - /* Register sysfs hooks */ - ret = sysfs_create_group(&client->dev.kobj, <c4215_group); - if (ret) - return ret; - - 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, <c4215_group); - return ret; -} - -static int ltc4215_remove(struct i2c_client *client) -{ - struct ltc4215_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, <c4215_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + ltc4215_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ltc4215_id[] = { @@ -294,7 +270,6 @@ static struct i2c_driver ltc4215_driver = { .name = "ltc4215", }, .probe = ltc4215_probe, - .remove = ltc4215_remove, .id_table = ltc4215_id, }; diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c new file mode 100644 index 00000000000..07c25653659 --- /dev/null +++ b/drivers/hwmon/ltc4222.c @@ -0,0 +1,237 @@ +/* + * Driver for Linear Technology LTC4222 Dual Hot Swap controller + * + * Copyright (c) 2014 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 + * 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/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/bitops.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/regmap.h> + +/* chip registers */ + +#define LTC4222_CONTROL1 0xd0 +#define LTC4222_ALERT1 0xd1 +#define LTC4222_STATUS1 0xd2 +#define LTC4222_FAULT1 0xd3 +#define LTC4222_CONTROL2 0xd4 +#define LTC4222_ALERT2 0xd5 +#define LTC4222_STATUS2 0xd6 +#define LTC4222_FAULT2 0xd7 +#define LTC4222_SOURCE1 0xd8 +#define LTC4222_SOURCE2 0xda +#define LTC4222_ADIN1 0xdc +#define LTC4222_ADIN2 0xde +#define LTC4222_SENSE1 0xe0 +#define LTC4222_SENSE2 0xe2 +#define LTC4222_ADC_CONTROL 0xe4 + +/* + * Fault register bits + */ +#define FAULT_OV BIT(0) +#define FAULT_UV BIT(1) +#define FAULT_OC BIT(2) +#define FAULT_POWER_BAD BIT(3) +#define FAULT_FET_BAD BIT(5) + +/* Return the voltage from the given register in mV or mA */ +static int ltc4222_get_value(struct device *dev, u8 reg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int val; + u8 buf[2]; + int ret; + + ret = regmap_bulk_read(regmap, reg, buf, 2); + if (ret < 0) + return ret; + + val = ((buf[0] << 8) + buf[1]) >> 6; + + switch (reg) { + case LTC4222_ADIN1: + case LTC4222_ADIN2: + /* 1.25 mV resolution. Convert to mV. */ + val = DIV_ROUND_CLOSEST(val * 5, 4); + break; + case LTC4222_SOURCE1: + case LTC4222_SOURCE2: + /* 31.25 mV resolution. Convert to mV. */ + val = DIV_ROUND_CLOSEST(val * 125, 4); + break; + case LTC4222_SENSE1: + case LTC4222_SENSE2: + /* + * 62.5 uV resolution. Convert to current as measured with + * an 1 mOhm sense resistor, in mA. If a different sense + * resistor is installed, calculate the actual current by + * dividing the reported current by the sense resistor value + * in mOhm. + */ + val = DIV_ROUND_CLOSEST(val * 125, 2); + break; + default: + return -EINVAL; + } + return val; +} + +static ssize_t ltc4222_show_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value; + + value = ltc4222_get_value(dev, attr->index); + if (value < 0) + return value; + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t ltc4222_show_bool(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da); + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int fault; + int ret; + + ret = regmap_read(regmap, attr->nr, &fault); + if (ret < 0) + return ret; + fault &= attr->index; + if (fault) /* Clear reported faults in chip register */ + regmap_update_bits(regmap, attr->nr, attr->index, 0); + + return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); +} + +/* Voltages */ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_SOURCE1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_ADIN1); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_SOURCE2); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_ADIN2); + +/* + * Voltage alarms + * UV/OV faults are associated with the input voltage, and power bad and fet + * faults are associated with the output voltage. + */ +static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT1, FAULT_UV); +static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT1, FAULT_OV); +static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD); + +static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT2, FAULT_UV); +static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT2, FAULT_OV); +static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD); + +/* Current (via sense resistor) */ +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_SENSE1); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL, + LTC4222_SENSE2); + +/* Overcurrent alarm */ +static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT1, FAULT_OC); +static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL, + LTC4222_FAULT2, FAULT_OC); + +static struct attribute *ltc4222_attrs[] = { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min_alarm.dev_attr.attr, + &sensor_dev_attr_in3_max_alarm.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_curr2_max_alarm.dev_attr.attr, + + NULL, +}; +ATTRIBUTE_GROUPS(ltc4222); + +static struct regmap_config ltc4222_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LTC4222_ADC_CONTROL, +}; + +static int ltc4222_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, <c4222_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to allocate register map\n"); + return PTR_ERR(regmap); + } + + /* Clear faults */ + regmap_write(regmap, LTC4222_FAULT1, 0x00); + regmap_write(regmap, LTC4222_FAULT2, 0x00); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + regmap, + ltc4222_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id ltc4222_id[] = { + {"ltc4222", 0}, + { } +}; + +MODULE_DEVICE_TABLE(i2c, ltc4222_id); + +static struct i2c_driver ltc4222_driver = { + .driver = { + .name = "ltc4222", + }, + .probe = ltc4222_probe, + .id_table = ltc4222_id, +}; + +module_i2c_driver(ltc4222_driver); + +MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("LTC4222 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index d4172933ce4..681b5b7b3c3 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -95,7 +95,6 @@ static void ltc4245_update_gpios(struct device *dev) * readings as stale by setting them to -EAGAIN */ if (time_after(jiffies, data->last_updated + 5 * HZ)) { - dev_dbg(&client->dev, "Marking GPIOs invalid\n"); for (i = 0; i < ARRAY_SIZE(data->gpios); i++) data->gpios[i] = -EAGAIN; } @@ -141,8 +140,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - dev_dbg(&client->dev, "Starting ltc4245 update\n"); - /* Read control registers -- 0x00 to 0x07 */ for (i = 0; i < ARRAY_SIZE(data->cregs); i++) { val = i2c_smbus_read_byte_data(client, i); @@ -470,19 +467,15 @@ static void ltc4245_sysfs_add_groups(struct ltc4245_data *data) static bool ltc4245_use_extra_gpios(struct i2c_client *client) { struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev); -#ifdef CONFIG_OF struct device_node *np = client->dev.of_node; -#endif /* prefer platform data */ if (pdata) return pdata->use_extra_gpios; -#ifdef CONFIG_OF /* fallback on OF */ if (of_find_property(np, "ltc4245,use-extra-gpios", NULL)) return true; -#endif return false; } @@ -512,24 +505,10 @@ static int ltc4245_probe(struct i2c_client *client, /* Add sysfs hooks */ ltc4245_sysfs_add_groups(data); - hwmon_dev = hwmon_device_register_with_groups(&client->dev, - client->name, data, - data->groups); - if (IS_ERR(hwmon_dev)) - return PTR_ERR(hwmon_dev); - - i2c_set_clientdata(client, hwmon_dev); - - return 0; -} - -static int ltc4245_remove(struct i2c_client *client) -{ - struct device *hwmon_dev = i2c_get_clientdata(client); - - hwmon_device_unregister(hwmon_dev); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ltc4245_id[] = { @@ -544,7 +523,6 @@ static struct i2c_driver ltc4245_driver = { .name = "ltc4245", }, .probe = ltc4245_probe, - .remove = ltc4245_remove, .id_table = ltc4245_id, }; diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c new file mode 100644 index 00000000000..453a250d9df --- /dev/null +++ b/drivers/hwmon/ltc4260.c @@ -0,0 +1,200 @@ +/* + * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller + * + * Copyright (c) 2014 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 + * 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/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/regmap.h> + +/* chip registers */ +#define LTC4260_CONTROL 0x00 +#define LTC4260_ALERT 0x01 +#define LTC4260_STATUS 0x02 +#define LTC4260_FAULT 0x03 +#define LTC4260_SENSE 0x04 +#define LTC4260_SOURCE 0x05 +#define LTC4260_ADIN 0x06 + +/* + * Fault register bits + */ +#define FAULT_OV (1 << 0) +#define FAULT_UV (1 << 1) +#define FAULT_OC (1 << 2) +#define FAULT_POWER_BAD (1 << 3) +#define FAULT_FET_SHORT (1 << 5) + +/* Return the voltage from the given register in mV or mA */ +static int ltc4260_get_value(struct device *dev, u8 reg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = regmap_read(regmap, reg, &val); + if (ret < 0) + return ret; + + switch (reg) { + case LTC4260_ADIN: + /* 10 mV resolution. Convert to mV. */ + val = val * 10; + break; + case LTC4260_SOURCE: + /* 400 mV resolution. Convert to mV. */ + val = val * 400; + break; + case LTC4260_SENSE: + /* + * 300 uV resolution. Convert to current as measured with + * an 1 mOhm sense resistor, in mA. If a different sense + * resistor is installed, calculate the actual current by + * dividing the reported current by the sense resistor value + * in mOhm. + */ + val = val * 300; + break; + default: + return -EINVAL; + } + + return val; +} + +static ssize_t ltc4260_show_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value; + + value = ltc4260_get_value(dev, attr->index); + if (value < 0) + return value; + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t ltc4260_show_bool(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct regmap *regmap = dev_get_drvdata(dev); + unsigned int fault; + int ret; + + ret = regmap_read(regmap, LTC4260_FAULT, &fault); + if (ret < 0) + return ret; + + fault &= attr->index; + if (fault) /* Clear reported faults in chip register */ + regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0); + + return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); +} + +/* Voltages */ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL, + LTC4260_SOURCE); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL, + LTC4260_ADIN); + +/* + * Voltage alarms + * UV/OV faults are associated with the input voltage, and the POWER BAD and + * FET SHORT faults are associated with the output voltage. + */ +static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL, + FAULT_UV); +static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL, + FAULT_OV); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL, + FAULT_POWER_BAD | FAULT_FET_SHORT); + +/* Current (via sense resistor) */ +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL, + LTC4260_SENSE); + +/* Overcurrent alarm */ +static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL, + FAULT_OC); + +static struct attribute *ltc4260_attrs[] = { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, + + NULL, +}; +ATTRIBUTE_GROUPS(ltc4260); + +static struct regmap_config ltc4260_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LTC4260_ADIN, +}; + +static int ltc4260_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, <c4260_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to allocate register map\n"); + return PTR_ERR(regmap); + } + + /* Clear faults */ + regmap_write(regmap, LTC4260_FAULT, 0x00); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + regmap, + ltc4260_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id ltc4260_id[] = { + {"ltc4260", 0}, + { } +}; + +MODULE_DEVICE_TABLE(i2c, ltc4260_id); + +static struct i2c_driver ltc4260_driver = { + .driver = { + .name = "ltc4260", + }, + .probe = ltc4260_probe, + .id_table = ltc4260_id, +}; + +module_i2c_driver(ltc4260_driver); + +MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("LTC4260 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index eda077de8a9..f67d71ee838 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -192,10 +192,8 @@ static int max1111_probe(struct spi_device *spi) return err; data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL); - if (data == NULL) { - dev_err(&spi->dev, "failed to allocate memory\n"); + if (data == NULL) return -ENOMEM; - } switch (chip) { case max1110: diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 6638e997f83..eda9cf59968 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -19,13 +19,8 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -76,38 +71,14 @@ static int temp_to_reg(int val) return (val < 0 ? val+0x100*1000 : val) / 1000; } -/* - * Functions declaration - */ - -static int max1619_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int max1619_detect(struct i2c_client *client, - struct i2c_board_info *info); -static void max1619_init_client(struct i2c_client *client); -static int max1619_remove(struct i2c_client *client); -static struct max1619_data *max1619_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id max1619_id[] = { - { "max1619", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max1619_id); - -static struct i2c_driver max1619_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "max1619", - }, - .probe = max1619_probe, - .remove = max1619_remove, - .id_table = max1619_id, - .detect = max1619_detect, - .address_list = normal_i2c, +enum temp_index { + t_input1 = 0, + t_input2, + t_low2, + t_high2, + t_crit2, + t_hyst2, + t_num_regs }; /* @@ -115,60 +86,92 @@ static struct i2c_driver max1619_driver = { */ struct max1619_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 temp_input1; /* local */ - u8 temp_input2, temp_low2, temp_high2; /* remote */ - u8 temp_crit2; - u8 temp_hyst2; + u8 temp[t_num_regs]; /* index with enum temp_index */ u8 alarms; }; +static const u8 regs_read[t_num_regs] = { + [t_input1] = MAX1619_REG_R_LOCAL_TEMP, + [t_input2] = MAX1619_REG_R_REMOTE_TEMP, + [t_low2] = MAX1619_REG_R_REMOTE_LOW, + [t_high2] = MAX1619_REG_R_REMOTE_HIGH, + [t_crit2] = MAX1619_REG_R_REMOTE_CRIT, + [t_hyst2] = MAX1619_REG_R_TCRIT_HYST, +}; + +static const u8 regs_write[t_num_regs] = { + [t_low2] = MAX1619_REG_W_REMOTE_LOW, + [t_high2] = MAX1619_REG_W_REMOTE_HIGH, + [t_crit2] = MAX1619_REG_W_REMOTE_CRIT, + [t_hyst2] = MAX1619_REG_W_TCRIT_HYST, +}; + +static struct max1619_data *max1619_update_device(struct device *dev) +{ + struct max1619_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int config, i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Updating max1619 data.\n"); + for (i = 0; i < t_num_regs; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + regs_read[i]); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + /* If OVERT polarity is low, reverse alarm bit */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (!(config & 0x20)) + data->alarms ^= 0x02; + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* * Sysfs stuff */ -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct max1619_data *data = max1619_update_device(dev); \ - return sprintf(buf, "%d\n", temp_from_reg(data->value)); \ -} -show_temp(temp_input1); -show_temp(temp_input2); -show_temp(temp_low2); -show_temp(temp_high2); -show_temp(temp_crit2); -show_temp(temp_hyst2); - -#define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct max1619_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = temp_to_reg(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max1619_data *data = max1619_update_device(dev); + + return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index])); } -set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); -set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); -set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); -set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max1619_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + int err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp[attr->index] = temp_to_reg(val); + i2c_smbus_write_byte_data(client, regs_write[attr->index], + data->temp[attr->index]); + mutex_unlock(&data->update_lock); + return count; +} static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -185,29 +188,30 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, - set_temp_hyst2); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, t_input2); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_low2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_high2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit2); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hyst2); + static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); -static struct attribute *max1619_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_crit.attr, - &dev_attr_temp2_crit_hyst.attr, +static struct attribute *max1619_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, @@ -216,14 +220,7 @@ static struct attribute *max1619_attributes[] = { &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group max1619_group = { - .attrs = max1619_attributes, -}; - -/* - * Real code - */ +ATTRIBUTE_GROUPS(max1619); /* Return 0 if detection is successful, -ENODEV otherwise */ static int max1619_detect(struct i2c_client *client, @@ -261,42 +258,6 @@ static int max1619_detect(struct i2c_client *client, return 0; } -static int max1619_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) -{ - struct max1619_data *data; - int err; - - data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - i2c_set_clientdata(new_client, data); - data->valid = 0; - mutex_init(&data->update_lock); - - /* Initialize the MAX1619 chip */ - max1619_init_client(new_client); - - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &max1619_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &max1619_group); - return err; -} - static void max1619_init_client(struct i2c_client *client) { u8 config; @@ -312,48 +273,46 @@ static void max1619_init_client(struct i2c_client *client) config & 0xBF); /* run */ } -static int max1619_remove(struct i2c_client *client) +static int max1619_probe(struct i2c_client *new_client, + const struct i2c_device_id *id) { - struct max1619_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &max1619_group); - - return 0; -} + struct max1619_data *data; + struct device *hwmon_dev; -static struct max1619_data *max1619_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); + data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; - mutex_lock(&data->update_lock); + data->client = new_client; + mutex_init(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Updating max1619 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->temp_input2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->temp_high2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_HIGH); - data->temp_low2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_LOW); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_CRIT); - data->temp_hyst2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_TCRIT_HYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); + /* Initialize the MAX1619 chip */ + max1619_init_client(new_client); - data->last_updated = jiffies; - data->valid = 1; - } + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, + max1619_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} - mutex_unlock(&data->update_lock); +static const struct i2c_device_id max1619_id[] = { + { "max1619", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max1619_id); - return data; -} +static struct i2c_driver max1619_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "max1619", + }, + .probe = max1619_probe, + .id_table = max1619_id, + .detect = max1619_detect, + .address_list = normal_i2c, +}; module_i2c_driver(max1619_driver); diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index a7626358c95..e3ed0a5b6d9 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -66,7 +66,8 @@ MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); enum chips { max1668, max1805, max1989 }; struct max1668_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; enum chips type; struct mutex update_lock; @@ -82,8 +83,8 @@ struct max1668_data { static struct max1668_data *max1668_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max1668_data *data = i2c_get_clientdata(client); + struct max1668_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct max1668_data *ret = data; s32 val; int i; @@ -205,8 +206,8 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, size_t count) { int index = to_sensor_dev_attr(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct max1668_data *data = i2c_get_clientdata(client); + struct max1668_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long temp; int ret; @@ -216,10 +217,11 @@ static ssize_t set_temp_max(struct device *dev, mutex_lock(&data->update_lock); data->temp_max[index] = clamp_val(temp/1000, -128, 127); - if (i2c_smbus_write_byte_data(client, + ret = i2c_smbus_write_byte_data(client, MAX1668_REG_LIMH_WR(index), - data->temp_max[index])) - count = -EIO; + data->temp_max[index]); + if (ret < 0) + count = ret; mutex_unlock(&data->update_lock); return count; @@ -230,8 +232,8 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, size_t count) { int index = to_sensor_dev_attr(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct max1668_data *data = i2c_get_clientdata(client); + struct max1668_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long temp; int ret; @@ -241,10 +243,11 @@ static ssize_t set_temp_min(struct device *dev, mutex_lock(&data->update_lock); data->temp_min[index] = clamp_val(temp/1000, -128, 127); - if (i2c_smbus_write_byte_data(client, + ret = i2c_smbus_write_byte_data(client, MAX1668_REG_LIML_WR(index), - data->temp_max[index])) - count = -EIO; + data->temp_min[index]); + if (ret < 0) + count = ret; mutex_unlock(&data->update_lock); return count; @@ -405,60 +408,29 @@ static int max1668_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; + struct device *hwmon_dev; struct max1668_data *data; - int err; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(struct max1668_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; data->type = id->driver_data; mutex_init(&data->update_lock); - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &max1668_group_common); - if (err) - return err; - - if (data->type == max1668 || data->type == max1989) { - err = sysfs_create_group(&client->dev.kobj, - &max1668_group_unique); - if (err) - goto error_sysrem0; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error_sysrem1; - } - - return 0; - -error_sysrem1: + /* sysfs hooks */ + data->groups[0] = &max1668_group_common; if (data->type == max1668 || data->type == max1989) - sysfs_remove_group(&client->dev.kobj, &max1668_group_unique); -error_sysrem0: - sysfs_remove_group(&client->dev.kobj, &max1668_group_common); - return err; -} - -static int max1668_remove(struct i2c_client *client) -{ - struct max1668_data *data = i2c_get_clientdata(client); + data->groups[1] = &max1668_group_unique; - hwmon_device_unregister(data->hwmon_dev); - if (data->type == max1668 || data->type == max1989) - sysfs_remove_group(&client->dev.kobj, &max1668_group_unique); - - sysfs_remove_group(&client->dev.kobj, &max1668_group_common); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id max1668_id[] = { @@ -476,7 +448,6 @@ static struct i2c_driver max1668_driver = { .name = "max1668", }, .probe = max1668_probe, - .remove = max1668_remove, .id_table = max1668_id, .detect = max1668_detect, .address_list = max1668_addr_list, diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 96dccaf919d..82128ad79a9 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -275,10 +275,8 @@ static int max197_probe(struct platform_device *pdev) } data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "devm_kzalloc failed\n"); + if (!data) return -ENOMEM; - } data->pdata = pdata; mutex_init(&data->lock); diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 066e587a18a..70650de2cbd 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -80,7 +80,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 }; * Client data (each client gets its own) */ struct max6639_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -104,8 +104,8 @@ struct max6639_data { static struct max6639_data *max6639_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); + struct max6639_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct max6639_data *ret = data; int i; int status_reg; @@ -191,9 +191,8 @@ static ssize_t show_temp_fault(struct device *dev, static ssize_t show_temp_max(struct device *dev, struct device_attribute *dev_attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000)); } @@ -202,9 +201,9 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int res; @@ -224,9 +223,8 @@ static ssize_t set_temp_max(struct device *dev, static ssize_t show_temp_crit(struct device *dev, struct device_attribute *dev_attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000)); } @@ -235,9 +233,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int res; @@ -258,9 +256,8 @@ static ssize_t show_temp_emergency(struct device *dev, struct device_attribute *dev_attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000)); } @@ -269,9 +266,9 @@ static ssize_t set_temp_emergency(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int res; @@ -291,9 +288,8 @@ static ssize_t set_temp_emergency(struct device *dev, static ssize_t show_pwm(struct device *dev, struct device_attribute *dev_attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120); } @@ -302,9 +298,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6639_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6639_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int res; @@ -378,7 +374,7 @@ static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4); -static struct attribute *max6639_attributes[] = { +static struct attribute *max6639_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp1_fault.dev_attr.attr, @@ -403,10 +399,7 @@ static struct attribute *max6639_attributes[] = { &sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group max6639_group = { - .attrs = max6639_attributes, -}; +ATTRIBUTE_GROUPS(max6639); /* * returns respective index in rpm_ranges table @@ -424,9 +417,9 @@ static int rpm_range_to_reg(int range) return 1; /* default: 4000 RPM */ } -static int max6639_init_client(struct i2c_client *client) +static int max6639_init_client(struct i2c_client *client, + struct max6639_data *data) { - struct max6639_data *data = i2c_get_clientdata(client); struct max6639_platform_data *max6639_info = dev_get_platdata(&client->dev); int i; @@ -545,50 +538,27 @@ static int max6639_detect(struct i2c_client *client, static int max6639_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct max6639_data *data; + struct device *hwmon_dev; int err; - data = devm_kzalloc(&client->dev, sizeof(struct max6639_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the max6639 chip */ - err = max6639_init_client(client); + err = max6639_init_client(client, data); if (err < 0) return err; - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &max6639_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error_remove; - } - - dev_info(&client->dev, "temperature sensor and fan control found\n"); - - return 0; - -error_remove: - sysfs_remove_group(&client->dev.kobj, &max6639_group); - return err; -} - -static int max6639_remove(struct i2c_client *client) -{ - struct max6639_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &max6639_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + max6639_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } #ifdef CONFIG_PM_SLEEP @@ -622,9 +592,7 @@ static const struct i2c_device_id max6639_id[] = { MODULE_DEVICE_TABLE(i2c, max6639_id); -static const struct dev_pm_ops max6639_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume) -}; +static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); static struct i2c_driver max6639_driver = { .class = I2C_CLASS_HWMON, @@ -633,7 +601,6 @@ static struct i2c_driver max6639_driver = { .pm = &max6639_pm_ops, }, .probe = max6639_probe, - .remove = max6639_remove, .id_table = max6639_id, .detect = max6639_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 0cafc390db4..162a520f4bd 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -105,38 +105,13 @@ module_param(clock, int, S_IRUGO); #define DIV_FROM_REG(reg) (1 << (reg & 7)) -static int max6650_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int max6650_init_client(struct i2c_client *client); -static int max6650_remove(struct i2c_client *client); -static struct max6650_data *max6650_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id max6650_id[] = { - { "max6650", 1 }, - { "max6651", 4 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max6650_id); - -static struct i2c_driver max6650_driver = { - .driver = { - .name = "max6650", - }, - .probe = max6650_probe, - .remove = max6650_remove, - .id_table = max6650_id, -}; - /* * Client data (each client gets its own) */ struct max6650_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex update_lock; int nr_fans; char valid; /* zero until following fields are valid */ @@ -151,6 +126,51 @@ struct max6650_data { u8 alarm; }; +static const u8 tach_reg[] = { + MAX6650_REG_TACH0, + MAX6650_REG_TACH1, + MAX6650_REG_TACH2, + MAX6650_REG_TACH3, +}; + +static struct max6650_data *max6650_update_device(struct device *dev) +{ + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->speed = i2c_smbus_read_byte_data(client, + MAX6650_REG_SPEED); + data->config = i2c_smbus_read_byte_data(client, + MAX6650_REG_CONFIG); + for (i = 0; i < data->nr_fans; i++) { + data->tach[i] = i2c_smbus_read_byte_data(client, + tach_reg[i]); + } + data->count = i2c_smbus_read_byte_data(client, + MAX6650_REG_COUNT); + data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + + /* + * Alarms are cleared on read in case the condition that + * caused the alarm is removed. Keep the value latched here + * for providing the register through different alarm files. + */ + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -235,8 +255,8 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr, static ssize_t set_target(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6650_data *data = i2c_get_clientdata(client); + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int kscale, ktach; unsigned long rpm; int err; @@ -304,8 +324,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6650_data *data = i2c_get_clientdata(client); + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long pwm; int err; @@ -350,8 +370,8 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr, static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6650_data *data = i2c_get_clientdata(client); + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int max6650_modes[3] = {0, 3, 2}; unsigned long mode; int err; @@ -400,8 +420,8 @@ static ssize_t get_div(struct device *dev, struct device_attribute *devattr, static ssize_t set_div(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct max6650_data *data = i2c_get_clientdata(client); + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long div; int err; @@ -446,7 +466,7 @@ static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct max6650_data *data = max6650_update_device(dev); - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = data->client; int alarm = 0; if (data->alarm & attr->index) { @@ -484,7 +504,8 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); struct device_attribute *devattr; @@ -519,7 +540,7 @@ static struct attribute *max6650_attrs[] = { NULL }; -static struct attribute_group max6650_attr_grp = { +static const struct attribute_group max6650_group = { .attrs = max6650_attrs, .is_visible = max6650_attrs_visible, }; @@ -531,7 +552,7 @@ static struct attribute *max6651_attrs[] = { NULL }; -static const struct attribute_group max6651_attr_grp = { +static const struct attribute_group max6651_group = { .attrs = max6651_attrs, }; @@ -539,74 +560,17 @@ static const struct attribute_group max6651_attr_grp = { * Real code */ -static int max6650_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct max6650_data *data; - int err; - - data = devm_kzalloc(&client->dev, sizeof(struct max6650_data), - GFP_KERNEL); - if (!data) { - dev_err(&client->dev, "out of memory.\n"); - return -ENOMEM; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->nr_fans = id->driver_data; - - /* - * Initialize the max6650 chip - */ - err = max6650_init_client(client); - if (err) - return err; - - err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp); - if (err) - return err; - /* 3 additional fan inputs for the MAX6651 */ - if (data->nr_fans == 4) { - err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp); - if (err) - goto err_remove; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (!IS_ERR(data->hwmon_dev)) - return 0; - - err = PTR_ERR(data->hwmon_dev); - dev_err(&client->dev, "error registering hwmon device.\n"); - if (data->nr_fans == 4) - sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp); -err_remove: - sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); - return err; -} - -static int max6650_remove(struct i2c_client *client) +static int max6650_init_client(struct max6650_data *data, + struct i2c_client *client) { - struct max6650_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - if (data->nr_fans == 4) - sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp); - sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); - return 0; -} - -static int max6650_init_client(struct i2c_client *client) -{ - struct max6650_data *data = i2c_get_clientdata(client); + struct device *dev = &client->dev; int config; int err = -EIO; config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG); if (config < 0) { - dev_err(&client->dev, "Error reading config, aborting.\n"); + dev_err(dev, "Error reading config, aborting.\n"); return err; } @@ -620,11 +584,11 @@ static int max6650_init_client(struct i2c_client *client) config |= MAX6650_CFG_V12; break; default: - dev_err(&client->dev, "illegal value for fan_voltage (%d)\n", + dev_err(dev, "illegal value for fan_voltage (%d)\n", fan_voltage); } - dev_info(&client->dev, "Fan voltage is set to %dV.\n", + dev_info(dev, "Fan voltage is set to %dV.\n", (config & MAX6650_CFG_V12) ? 12 : 5); switch (prescaler) { @@ -650,11 +614,10 @@ static int max6650_init_client(struct i2c_client *client) | MAX6650_CFG_PRESCALER_16; break; default: - dev_err(&client->dev, "illegal value for prescaler (%d)\n", - prescaler); + dev_err(dev, "illegal value for prescaler (%d)\n", prescaler); } - dev_info(&client->dev, "Prescaler is set to %d.\n", + dev_info(dev, "Prescaler is set to %d.\n", 1 << (config & MAX6650_CFG_PRESCALER_MASK)); /* @@ -664,17 +627,17 @@ static int max6650_init_client(struct i2c_client *client) */ if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) { - dev_dbg(&client->dev, "Change mode to open loop, full off.\n"); + dev_dbg(dev, "Change mode to open loop, full off.\n"); config = (config & ~MAX6650_CFG_MODE_MASK) | MAX6650_CFG_MODE_OPEN_LOOP; if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) { - dev_err(&client->dev, "DAC write error, aborting.\n"); + dev_err(dev, "DAC write error, aborting.\n"); return err; } } if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) { - dev_err(&client->dev, "Config write error, aborting.\n"); + dev_err(dev, "Config write error, aborting.\n"); return err; } @@ -684,51 +647,55 @@ static int max6650_init_client(struct i2c_client *client) return 0; } -static const u8 tach_reg[] = { - MAX6650_REG_TACH0, - MAX6650_REG_TACH1, - MAX6650_REG_TACH2, - MAX6650_REG_TACH3, -}; - -static struct max6650_data *max6650_update_device(struct device *dev) +static int max6650_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int i; - struct i2c_client *client = to_i2c_client(dev); - struct max6650_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); + struct device *dev = &client->dev; + struct max6650_data *data; + struct device *hwmon_dev; + int err; - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - data->speed = i2c_smbus_read_byte_data(client, - MAX6650_REG_SPEED); - data->config = i2c_smbus_read_byte_data(client, - MAX6650_REG_CONFIG); - for (i = 0; i < data->nr_fans; i++) { - data->tach[i] = i2c_smbus_read_byte_data(client, - tach_reg[i]); - } - data->count = i2c_smbus_read_byte_data(client, - MAX6650_REG_COUNT); - data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL); + if (!data) + return -ENOMEM; - /* - * Alarms are cleared on read in case the condition that - * caused the alarm is removed. Keep the value latched here - * for providing the register through different alarm files. - */ - data->alarm |= i2c_smbus_read_byte_data(client, - MAX6650_REG_ALARM); + data->client = client; + mutex_init(&data->update_lock); + data->nr_fans = id->driver_data; - data->last_updated = jiffies; - data->valid = 1; - } + /* + * Initialize the max6650 chip + */ + err = max6650_init_client(data, client); + if (err) + return err; - mutex_unlock(&data->update_lock); + data->groups[0] = &max6650_group; + /* 3 additional fan inputs for the MAX6651 */ + if (data->nr_fans == 4) + data->groups[1] = &max6651_group; - return data; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, data, + data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } +static const struct i2c_device_id max6650_id[] = { + { "max6650", 1 }, + { "max6651", 4 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max6650_id); + +static struct i2c_driver max6650_driver = { + .driver = { + .name = "max6650", + }, + .probe = max6650_probe, + .id_table = max6650_id, +}; + module_i2c_driver(max6650_driver); MODULE_AUTHOR("Hans J. Koch"); diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c new file mode 100644 index 00000000000..7710f4694ba --- /dev/null +++ b/drivers/hwmon/nct6683.c @@ -0,0 +1,1457 @@ +/* + * nct6683 - Driver for the hardware monitoring functionality of + * Nuvoton NCT6683D eSIO + * + * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net> + * + * Derived from nct6775 driver + * Copyright (C) 2012, 2013 Guenter Roeck <linux@roeck-us.net> + * + * 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. + * + * Supports the following chips: + * + * Chip #vin #fan #pwm #temp chip ID + * nct6683d 21(1) 16 8 32(1) 0xc730 + * + * Notes: + * (1) Total number of vin and temp inputs is 32. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +enum kinds { nct6683 }; + +static bool force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards"); + +static const char * const nct6683_device_names[] = { + "nct6683", +}; + +static const char * const nct6683_chip_names[] = { + "NCT6683D", +}; + +#define DRVNAME "nct6683" + +/* + * Super-I/O constants and functions + */ + +#define NCT6683_LD_ACPI 0x0a +#define NCT6683_LD_HWM 0x0b +#define NCT6683_LD_VID 0x0d + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_NCT6681_ID 0xb270 /* for later */ +#define SIO_NCT6683_ID 0xc730 +#define SIO_ID_MASK 0xFFF0 + +static inline void +superio_outb(int ioreg, int reg, int val) +{ + outb(reg, ioreg); + outb(val, ioreg + 1); +} + +static inline int +superio_inb(int ioreg, int reg) +{ + outb(reg, ioreg); + return inb(ioreg + 1); +} + +static inline void +superio_select(int ioreg, int ld) +{ + outb(SIO_REG_LDSEL, ioreg); + outb(ld, ioreg + 1); +} + +static inline int +superio_enter(int ioreg) +{ + /* + * Try to reserve <ioreg> and <ioreg + 1> for exclusive access. + */ + if (!request_muxed_region(ioreg, 2, DRVNAME)) + return -EBUSY; + + outb(0x87, ioreg); + outb(0x87, ioreg); + + return 0; +} + +static inline void +superio_exit(int ioreg) +{ + outb(0xaa, ioreg); + outb(0x02, ioreg); + outb(0x02, ioreg + 1); + release_region(ioreg, 2); +} + +/* + * ISA constants + */ + +#define IOREGION_ALIGNMENT (~7) +#define IOREGION_OFFSET 4 /* Use EC port 1 */ +#define IOREGION_LENGTH 4 + +#define EC_PAGE_REG 0 +#define EC_INDEX_REG 1 +#define EC_DATA_REG 2 +#define EC_EVENT_REG 3 + +/* Common and NCT6683 specific data */ + +#define NCT6683_NUM_REG_MON 32 +#define NCT6683_NUM_REG_FAN 16 +#define NCT6683_NUM_REG_PWM 8 + +#define NCT6683_REG_MON(x) (0x100 + (x) * 2) +#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2) +#define NCT6683_REG_PWM(x) (0x160 + (x)) + +#define NCT6683_REG_MON_STS(x) (0x174 + (x)) +#define NCT6683_REG_IDLE(x) (0x178 + (x)) + +#define NCT6683_REG_FAN_STS(x) (0x17c + (x)) +#define NCT6683_REG_FAN_ERRSTS 0x17e +#define NCT6683_REG_FAN_INITSTS 0x17f + +#define NCT6683_HWM_CFG 0x180 + +#define NCT6683_REG_MON_CFG(x) (0x1a0 + (x)) +#define NCT6683_REG_FANIN_CFG(x) (0x1c0 + (x)) +#define NCT6683_REG_FANOUT_CFG(x) (0x1d0 + (x)) + +#define NCT6683_REG_INTEL_TEMP_MAX(x) (0x901 + (x) * 16) +#define NCT6683_REG_INTEL_TEMP_CRIT(x) (0x90d + (x) * 16) + +#define NCT6683_REG_TEMP_HYST(x) (0x330 + (x)) /* 8 bit */ +#define NCT6683_REG_TEMP_MAX(x) (0x350 + (x)) /* 8 bit */ +#define NCT6683_REG_MON_HIGH(x) (0x370 + (x) * 2) /* 8 bit */ +#define NCT6683_REG_MON_LOW(x) (0x371 + (x) * 2) /* 8 bit */ + +#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */ + +#define NCT6683_REG_CUSTOMER_ID 0x602 +#define NCT6683_CUSTOMER_ID_INTEL 0x805 + +#define NCT6683_REG_BUILD_YEAR 0x604 +#define NCT6683_REG_BUILD_MONTH 0x605 +#define NCT6683_REG_BUILD_DAY 0x606 +#define NCT6683_REG_SERIAL 0x607 +#define NCT6683_REG_VERSION_HI 0x608 +#define NCT6683_REG_VERSION_LO 0x609 + +#define NCT6683_REG_CR_CASEOPEN 0xe8 +#define NCT6683_CR_CASEOPEN_MASK (1 << 7) + +#define NCT6683_REG_CR_BEEP 0xe0 +#define NCT6683_CR_BEEP_MASK (1 << 6) + +static const char *const nct6683_mon_label[] = { + NULL, /* disabled */ + "Local", + "Diode 0 (curr)", + "Diode 1 (curr)", + "Diode 2 (curr)", + "Diode 0 (volt)", + "Diode 1 (volt)", + "Diode 2 (volt)", + "Thermistor 14", + "Thermistor 15", + "Thermistor 16", + "Thermistor 0", + "Thermistor 1", + "Thermistor 2", + "Thermistor 3", + "Thermistor 4", + "Thermistor 5", /* 0x10 */ + "Thermistor 6", + "Thermistor 7", + "Thermistor 8", + "Thermistor 9", + "Thermistor 10", + "Thermistor 11", + "Thermistor 12", + "Thermistor 13", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "PECI 0.0", /* 0x20 */ + "PECI 1.0", + "PECI 2.0", + "PECI 3.0", + "PECI 0.1", + "PECI 1.1", + "PECI 2.1", + "PECI 3.1", + "PECI DIMM 0", + "PECI DIMM 1", + "PECI DIMM 2", + "PECI DIMM 3", + NULL, NULL, NULL, NULL, + "PCH CPU", /* 0x30 */ + "PCH CHIP", + "PCH CHIP CPU MAX", + "PCH MCH", + "PCH DIMM 0", + "PCH DIMM 1", + "PCH DIMM 2", + "PCH DIMM 3", + "SMBus 0", + "SMBus 1", + "SMBus 2", + "SMBus 3", + "SMBus 4", + "SMBus 5", + "DIMM 0", + "DIMM 1", + "DIMM 2", /* 0x40 */ + "DIMM 3", + "AMD TSI Addr 90h", + "AMD TSI Addr 92h", + "AMD TSI Addr 94h", + "AMD TSI Addr 96h", + "AMD TSI Addr 98h", + "AMD TSI Addr 9ah", + "AMD TSI Addr 9ch", + "AMD TSI Addr 9dh", + NULL, NULL, NULL, NULL, NULL, NULL, + "Virtual 0", /* 0x50 */ + "Virtual 1", + "Virtual 2", + "Virtual 3", + "Virtual 4", + "Virtual 5", + "Virtual 6", + "Virtual 7", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "VCC", /* 0x60 voltage sensors */ + "VSB", + "AVSB", + "VTT", + "VBAT", + "VREF", + "VIN0", + "VIN1", + "VIN2", + "VIN3", + "VIN4", + "VIN5", + "VIN6", + "VIN7", + "VIN8", + "VIN9", + "VIN10", + "VIN11", + "VIN12", + "VIN13", + "VIN14", + "VIN15", + "VIN16", +}; + +#define NUM_MON_LABELS ARRAY_SIZE(nct6683_mon_label) +#define MON_VOLTAGE_START 0x60 + +/* ------------------------------------------------------- */ + +struct nct6683_data { + int addr; /* IO base of EC space */ + int sioreg; /* SIO register */ + enum kinds kind; + u16 customer_id; + + struct device *hwmon_dev; + const struct attribute_group *groups[6]; + + int temp_num; /* number of temperature attributes */ + u8 temp_index[NCT6683_NUM_REG_MON]; + u8 temp_src[NCT6683_NUM_REG_MON]; + + u8 in_num; /* number of voltage attributes */ + u8 in_index[NCT6683_NUM_REG_MON]; + u8 in_src[NCT6683_NUM_REG_MON]; + + struct mutex update_lock; /* used to protect sensor updates */ + bool valid; /* true if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Voltage attribute values */ + u8 in[3][NCT6683_NUM_REG_MON]; /* [0]=in, [1]=in_max, [2]=in_min */ + + /* Temperature attribute values */ + s16 temp_in[NCT6683_NUM_REG_MON]; + s8 temp[4][NCT6683_NUM_REG_MON];/* [0]=min, [1]=max, [2]=hyst, + * [3]=crit + */ + + /* Fan attribute values */ + unsigned int rpm[NCT6683_NUM_REG_FAN]; + u16 fan_min[NCT6683_NUM_REG_FAN]; + u8 fanin_cfg[NCT6683_NUM_REG_FAN]; + u8 fanout_cfg[NCT6683_NUM_REG_FAN]; + u16 have_fan; /* some fan inputs can be disabled */ + + u8 have_pwm; + u8 pwm[NCT6683_NUM_REG_PWM]; + +#ifdef CONFIG_PM + /* Remember extra register values over suspend/resume */ + u8 hwm_cfg; +#endif +}; + +struct nct6683_sio_data { + int sioreg; + enum kinds kind; +}; + +struct sensor_device_template { + struct device_attribute dev_attr; + union { + struct { + u8 nr; + u8 index; + } s; + int index; + } u; + bool s2; /* true if both index and nr are used */ +}; + +struct sensor_device_attr_u { + union { + struct sensor_device_attribute a1; + struct sensor_device_attribute_2 a2; + } u; + char name[32]; +}; + +#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \ + .attr = {.name = _template, .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \ + { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ + .u.index = _index, \ + .s2 = false } + +#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ + _nr, _index) \ + { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ + .u.s.index = _index, \ + .u.s.nr = _nr, \ + .s2 = true } + +#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \ +static struct sensor_device_template sensor_dev_template_##_name \ + = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \ + _index) + +#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \ + _nr, _index) \ +static struct sensor_device_template sensor_dev_template_##_name \ + = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ + _nr, _index) + +struct sensor_template_group { + struct sensor_device_template **templates; + umode_t (*is_visible)(struct kobject *, struct attribute *, int); + int base; +}; + +static struct attribute_group * +nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg, + int repeat) +{ + struct sensor_device_attribute_2 *a2; + struct sensor_device_attribute *a; + struct sensor_device_template **t; + struct sensor_device_attr_u *su; + struct attribute_group *group; + struct attribute **attrs; + int i, j, count; + + if (repeat <= 0) + return ERR_PTR(-EINVAL); + + t = tg->templates; + for (count = 0; *t; t++, count++) + ; + + if (count == 0) + return ERR_PTR(-EINVAL); + + group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL); + if (group == NULL) + return ERR_PTR(-ENOMEM); + + attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1), + GFP_KERNEL); + if (attrs == NULL) + return ERR_PTR(-ENOMEM); + + su = devm_kzalloc(dev, sizeof(*su) * repeat * count, + GFP_KERNEL); + if (su == NULL) + return ERR_PTR(-ENOMEM); + + group->attrs = attrs; + group->is_visible = tg->is_visible; + + for (i = 0; i < repeat; i++) { + t = tg->templates; + for (j = 0; *t != NULL; j++) { + snprintf(su->name, sizeof(su->name), + (*t)->dev_attr.attr.name, tg->base + i); + if ((*t)->s2) { + a2 = &su->u.a2; + a2->dev_attr.attr.name = su->name; + a2->nr = (*t)->u.s.nr + i; + a2->index = (*t)->u.s.index; + a2->dev_attr.attr.mode = + (*t)->dev_attr.attr.mode; + a2->dev_attr.show = (*t)->dev_attr.show; + a2->dev_attr.store = (*t)->dev_attr.store; + *attrs = &a2->dev_attr.attr; + } else { + a = &su->u.a1; + a->dev_attr.attr.name = su->name; + a->index = (*t)->u.index + i; + a->dev_attr.attr.mode = + (*t)->dev_attr.attr.mode; + a->dev_attr.show = (*t)->dev_attr.show; + a->dev_attr.store = (*t)->dev_attr.store; + *attrs = &a->dev_attr.attr; + } + attrs++; + su++; + t++; + } + } + + return group; +} + +/* LSB is 16 mV, except for the following sources, where it is 32 mV */ +#define MON_SRC_VCC 0x60 +#define MON_SRC_VSB 0x61 +#define MON_SRC_AVSB 0x62 +#define MON_SRC_VBAT 0x64 + +static inline long in_from_reg(u16 reg, u8 src) +{ + int scale = 16; + + if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB || + src == MON_SRC_VBAT) + scale <<= 1; + return reg * scale; +} + +static inline u16 in_to_reg(u32 val, u8 src) +{ + int scale = 16; + + if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB || + src == MON_SRC_VBAT) + scale <<= 1; + + return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127); +} + +static u16 nct6683_read(struct nct6683_data *data, u16 reg) +{ + int res; + + outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */ + outb_p(reg >> 8, data->addr + EC_PAGE_REG); + outb_p(reg & 0xff, data->addr + EC_INDEX_REG); + res = inb_p(data->addr + EC_DATA_REG); + return res; +} + +static u16 nct6683_read16(struct nct6683_data *data, u16 reg) +{ + return (nct6683_read(data, reg) << 8) | nct6683_read(data, reg + 1); +} + +static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value) +{ + outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */ + outb_p(reg >> 8, data->addr + EC_PAGE_REG); + outb_p(reg & 0xff, data->addr + EC_INDEX_REG); + outb_p(value & 0xff, data->addr + EC_DATA_REG); +} + +static int get_in_reg(struct nct6683_data *data, int nr, int index) +{ + int ch = data->in_index[index]; + int reg = -EINVAL; + + switch (nr) { + case 0: + reg = NCT6683_REG_MON(ch); + break; + case 1: + if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL) + reg = NCT6683_REG_MON_LOW(ch); + break; + case 2: + if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL) + reg = NCT6683_REG_MON_HIGH(ch); + break; + default: + break; + } + return reg; +} + +static int get_temp_reg(struct nct6683_data *data, int nr, int index) +{ + int ch = data->temp_index[index]; + int reg = -EINVAL; + + switch (data->customer_id) { + case NCT6683_CUSTOMER_ID_INTEL: + switch (nr) { + default: + case 1: /* max */ + reg = NCT6683_REG_INTEL_TEMP_MAX(ch); + break; + case 3: /* crit */ + reg = NCT6683_REG_INTEL_TEMP_CRIT(ch); + break; + } + break; + default: + switch (nr) { + default: + case 0: /* min */ + reg = NCT6683_REG_MON_LOW(ch); + break; + case 1: /* max */ + reg = NCT6683_REG_TEMP_MAX(ch); + break; + case 2: /* hyst */ + reg = NCT6683_REG_TEMP_HYST(ch); + break; + case 3: /* crit */ + reg = NCT6683_REG_MON_HIGH(ch); + break; + } + break; + } + return reg; +} + +static void nct6683_update_pwm(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int i; + + for (i = 0; i < NCT6683_NUM_REG_PWM; i++) { + if (!(data->have_pwm & (1 << i))) + continue; + data->pwm[i] = nct6683_read(data, NCT6683_REG_PWM(i)); + } +} + +static struct nct6683_data *nct6683_update_device(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int i, j; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + /* Measured voltages and limits */ + for (i = 0; i < data->in_num; i++) { + for (j = 0; j < 3; j++) { + int reg = get_in_reg(data, j, i); + + if (reg >= 0) + data->in[j][i] = + nct6683_read(data, reg); + } + } + + /* Measured temperatures and limits */ + for (i = 0; i < data->temp_num; i++) { + u8 ch = data->temp_index[i]; + + data->temp_in[i] = nct6683_read16(data, + NCT6683_REG_MON(ch)); + for (j = 0; j < 4; j++) { + int reg = get_temp_reg(data, j, i); + + if (reg >= 0) + data->temp[j][i] = + nct6683_read(data, reg); + } + } + + /* Measured fan speeds and limits */ + for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { + if (!(data->have_fan & (1 << i))) + continue; + + data->rpm[i] = nct6683_read16(data, + NCT6683_REG_FAN_RPM(i)); + data->fan_min[i] = nct6683_read16(data, + NCT6683_REG_FAN_MIN(i)); + } + + nct6683_update_pwm(dev); + + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ +static ssize_t +show_in_label(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + + return sprintf(buf, "%s\n", nct6683_mon_label[data->in_src[nr]]); +} + +static ssize_t +show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + int nr = sattr->nr; + + return sprintf(buf, "%ld\n", + in_from_reg(data->in[index][nr], data->in_index[index])); +} + +static umode_t nct6683_in_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int nr = index % 4; /* attribute */ + + /* + * Voltage limits exist for Intel boards, + * but register location and encoding is unknown + */ + if ((nr == 2 || nr == 3) && + data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + return attr->mode; +} + +SENSOR_TEMPLATE(in_label, "in%d_label", S_IRUGO, show_in_label, NULL, 0); +SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0); +SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IRUGO, show_in_reg, NULL, 0, 1); +SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IRUGO, show_in_reg, NULL, 0, 2); + +static struct sensor_device_template *nct6683_attributes_in_template[] = { + &sensor_dev_template_in_label, + &sensor_dev_template_in_input, + &sensor_dev_template_in_min, + &sensor_dev_template_in_max, + NULL +}; + +static struct sensor_template_group nct6683_in_template_group = { + .templates = nct6683_attributes_in_template, + .is_visible = nct6683_in_is_visible, +}; + +static ssize_t +show_fan(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + + return sprintf(buf, "%d\n", data->rpm[sattr->index]); +} + +static ssize_t +show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + int nr = sattr->index; + + return sprintf(buf, "%d\n", data->fan_min[nr]); +} + +static ssize_t +show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + + return sprintf(buf, "%d\n", + ((data->fanin_cfg[sattr->index] >> 5) & 0x03) + 1); +} + +static umode_t nct6683_fan_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int fan = index / 3; /* fan index */ + int nr = index % 3; /* attribute index */ + + if (!(data->have_fan & (1 << fan))) + return 0; + + /* + * Intel may have minimum fan speed limits, + * but register location and encoding are unknown. + */ + if (nr == 2 && data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + return attr->mode; +} + +SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0); +SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IRUGO, show_fan_pulses, NULL, 0); +SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IRUGO, show_fan_min, NULL, 0); + +/* + * nct6683_fan_is_visible uses the index into the following array + * to determine if attributes should be created or not. + * Any change in order or content must be matched. + */ +static struct sensor_device_template *nct6683_attributes_fan_template[] = { + &sensor_dev_template_fan_input, + &sensor_dev_template_fan_pulses, + &sensor_dev_template_fan_min, + NULL +}; + +static struct sensor_template_group nct6683_fan_template_group = { + .templates = nct6683_attributes_fan_template, + .is_visible = nct6683_fan_is_visible, + .base = 1, +}; + +static ssize_t +show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + + return sprintf(buf, "%s\n", nct6683_mon_label[data->temp_src[nr]]); +} + +static ssize_t +show_temp8(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + int nr = sattr->nr; + + return sprintf(buf, "%d\n", data->temp[index][nr] * 1000); +} + +static ssize_t +show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + int temp = data->temp[1][nr] - data->temp[2][nr]; + + return sprintf(buf, "%d\n", temp * 1000); +} + +static ssize_t +show_temp16(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + + return sprintf(buf, "%d\n", (data->temp_in[index] / 128) * 500); +} + +/* + * Temperature sensor type is determined by temperature source + * and can not be modified. + * 0x02..0x07: Thermal diode + * 0x08..0x18: Thermistor + * 0x20..0x2b: Intel PECI + * 0x42..0x49: AMD TSI + * Others are unspecified (not visible) + */ + +static int get_temp_type(u8 src) +{ + if (src >= 0x02 && src <= 0x07) + return 3; /* thermal diode */ + else if (src >= 0x08 && src <= 0x18) + return 4; /* thermistor */ + else if (src >= 0x20 && src <= 0x2b) + return 6; /* PECI */ + else if (src >= 0x42 && src <= 0x49) + return 5; + + return 0; +} + +static ssize_t +show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + int nr = sattr->index; + return sprintf(buf, "%d\n", get_temp_type(data->temp_src[nr])); +} + +static umode_t nct6683_temp_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int temp = index / 7; /* temp index */ + int nr = index % 7; /* attribute index */ + + /* + * Intel does not have low temperature limits or temperature hysteresis + * registers, or at least register location and encoding is unknown. + */ + if ((nr == 2 || nr == 4) && + data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + if (nr == 6 && get_temp_type(data->temp_src[temp]) == 0) + return 0; /* type */ + + return attr->mode; +} + +SENSOR_TEMPLATE(temp_input, "temp%d_input", S_IRUGO, show_temp16, NULL, 0); +SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0); +SENSOR_TEMPLATE_2(temp_min, "temp%d_min", S_IRUGO, show_temp8, NULL, 0, 0); +SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO, show_temp8, NULL, 0, 1); +SENSOR_TEMPLATE(temp_max_hyst, "temp%d_max_hyst", S_IRUGO, show_temp_hyst, NULL, + 0); +SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO, show_temp8, NULL, 0, 3); +SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO, show_temp_type, NULL, 0); + +/* + * nct6683_temp_is_visible uses the index into the following array + * to determine if attributes should be created or not. + * Any change in order or content must be matched. + */ +static struct sensor_device_template *nct6683_attributes_temp_template[] = { + &sensor_dev_template_temp_input, + &sensor_dev_template_temp_label, + &sensor_dev_template_temp_min, /* 2 */ + &sensor_dev_template_temp_max, /* 3 */ + &sensor_dev_template_temp_max_hyst, /* 4 */ + &sensor_dev_template_temp_crit, /* 5 */ + &sensor_dev_template_temp_type, /* 6 */ + NULL +}; + +static struct sensor_template_group nct6683_temp_template_group = { + .templates = nct6683_attributes_temp_template, + .is_visible = nct6683_temp_is_visible, + .base = 1, +}; + +static ssize_t +show_pwm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int index = sattr->index; + + return sprintf(buf, "%d\n", data->pwm[index]); +} + +SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0); + +static umode_t nct6683_pwm_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int pwm = index; /* pwm index */ + + if (!(data->have_pwm & (1 << pwm))) + return 0; + + return attr->mode; +} + +static struct sensor_device_template *nct6683_attributes_pwm_template[] = { + &sensor_dev_template_pwm, + NULL +}; + +static struct sensor_template_group nct6683_pwm_template_group = { + .templates = nct6683_attributes_pwm_template, + .is_visible = nct6683_pwm_is_visible, + .base = 1, +}; + +static ssize_t +show_global_beep(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int ret; + u8 reg; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) + goto error; + superio_select(data->sioreg, NCT6683_LD_HWM); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP); + superio_exit(data->sioreg); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%u\n", !!(reg & NCT6683_CR_BEEP_MASK)); + +error: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t +store_global_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + unsigned long val; + u8 reg; + int ret; + + if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1)) + return -EINVAL; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) { + count = ret; + goto error; + } + + superio_select(data->sioreg, NCT6683_LD_HWM); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP); + if (val) + reg |= NCT6683_CR_BEEP_MASK; + else + reg &= ~NCT6683_CR_BEEP_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg); + superio_exit(data->sioreg); +error: + mutex_unlock(&data->update_lock); + return count; +} + +/* Case open detection */ + +static ssize_t +show_caseopen(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int ret; + u8 reg; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) + goto error; + superio_select(data->sioreg, NCT6683_LD_ACPI); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN); + superio_exit(data->sioreg); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%u\n", !(reg & NCT6683_CR_CASEOPEN_MASK)); + +error: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t +clear_caseopen(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + unsigned long val; + u8 reg; + int ret; + + if (kstrtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + + /* + * Use CR registers to clear caseopen status. + * Caseopen is activ low, clear by writing 1 into the register. + */ + + ret = superio_enter(data->sioreg); + if (ret) { + count = ret; + goto error; + } + + superio_select(data->sioreg, NCT6683_LD_ACPI); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN); + reg |= NCT6683_CR_CASEOPEN_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); + reg &= ~NCT6683_CR_CASEOPEN_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); + superio_exit(data->sioreg); + + data->valid = false; /* Force cache refresh */ +error: + mutex_unlock(&data->update_lock); + return count; +} + +static DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen, + clear_caseopen); +static DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_global_beep, + store_global_beep); + +static struct attribute *nct6683_attributes_other[] = { + &dev_attr_intrusion0_alarm.attr, + &dev_attr_beep_enable.attr, + NULL +}; + +static const struct attribute_group nct6683_group_other = { + .attrs = nct6683_attributes_other, +}; + +/* Get the monitoring functions started */ +static inline void nct6683_init_device(struct nct6683_data *data) +{ + u8 tmp; + + /* Start hardware monitoring if needed */ + tmp = nct6683_read(data, NCT6683_HWM_CFG); + if (!(tmp & 0x80)) + nct6683_write(data, NCT6683_HWM_CFG, tmp | 0x80); +} + +/* + * There are a total of 24 fan inputs. Each can be configured as input + * or as output. A maximum of 16 inputs and 8 outputs is configurable. + */ +static void +nct6683_setup_fans(struct nct6683_data *data) +{ + int i; + u8 reg; + + for (i = 0; i < NCT6683_NUM_REG_FAN; i++) { + reg = nct6683_read(data, NCT6683_REG_FANIN_CFG(i)); + if (reg & 0x80) + data->have_fan |= 1 << i; + data->fanin_cfg[i] = reg; + } + for (i = 0; i < NCT6683_NUM_REG_PWM; i++) { + reg = nct6683_read(data, NCT6683_REG_FANOUT_CFG(i)); + if (reg & 0x80) + data->have_pwm |= 1 << i; + data->fanout_cfg[i] = reg; + } +} + +/* + * Translation from monitoring register to temperature and voltage attributes + * ========================================================================== + * + * There are a total of 32 monitoring registers. Each can be assigned to either + * a temperature or voltage monitoring source. + * NCT6683_REG_MON_CFG(x) defines assignment for each monitoring source. + * + * Temperature and voltage attribute mapping is determined by walking through + * the NCT6683_REG_MON_CFG registers. If the assigned source is + * a temperature, temp_index[n] is set to the monitor register index, and + * temp_src[n] is set to the temperature source. If the assigned source is + * a voltage, the respective values are stored in in_index[] and in_src[], + * respectively. + */ + +static void nct6683_setup_sensors(struct nct6683_data *data) +{ + u8 reg; + int i; + + data->temp_num = 0; + data->in_num = 0; + for (i = 0; i < NCT6683_NUM_REG_MON; i++) { + reg = nct6683_read(data, NCT6683_REG_MON_CFG(i)) & 0x7f; + /* Ignore invalid assignments */ + if (reg >= NUM_MON_LABELS) + continue; + /* Skip if disabled or reserved */ + if (nct6683_mon_label[reg] == NULL) + continue; + if (reg < MON_VOLTAGE_START) { + data->temp_index[data->temp_num] = i; + data->temp_src[data->temp_num] = reg; + data->temp_num++; + } else { + data->in_index[data->in_num] = i; + data->in_src[data->in_num] = reg; + data->in_num++; + } + } +} + +static int nct6683_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct nct6683_sio_data *sio_data = dev->platform_data; + struct attribute_group *group; + struct nct6683_data *data; + struct device *hwmon_dev; + struct resource *res; + int groups = 0; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) + return -EBUSY; + + data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->kind = sio_data->kind; + data->sioreg = sio_data->sioreg; + data->addr = res->start; + mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); + + data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID); + + nct6683_init_device(data); + nct6683_setup_fans(data); + nct6683_setup_sensors(data); + + /* Register sysfs hooks */ + + if (data->have_pwm) { + group = nct6683_create_attr_group(dev, + &nct6683_pwm_template_group, + fls(data->have_pwm)); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->in_num) { + group = nct6683_create_attr_group(dev, + &nct6683_in_template_group, + data->in_num); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->have_fan) { + group = nct6683_create_attr_group(dev, + &nct6683_fan_template_group, + fls(data->have_fan)); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->temp_num) { + group = nct6683_create_attr_group(dev, + &nct6683_temp_template_group, + data->temp_num); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + data->groups[groups++] = &nct6683_group_other; + + dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n", + nct6683_chip_names[data->kind], + nct6683_read(data, NCT6683_REG_VERSION_HI), + nct6683_read(data, NCT6683_REG_VERSION_LO), + nct6683_read(data, NCT6683_REG_BUILD_MONTH), + nct6683_read(data, NCT6683_REG_BUILD_DAY), + nct6683_read(data, NCT6683_REG_BUILD_YEAR)); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + nct6683_device_names[data->kind], data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +#ifdef CONFIG_PM +static int nct6683_suspend(struct device *dev) +{ + struct nct6683_data *data = nct6683_update_device(dev); + + mutex_lock(&data->update_lock); + data->hwm_cfg = nct6683_read(data, NCT6683_HWM_CFG); + mutex_unlock(&data->update_lock); + + return 0; +} + +static int nct6683_resume(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->update_lock); + + nct6683_write(data, NCT6683_HWM_CFG, data->hwm_cfg); + + /* Force re-reading all values */ + data->valid = false; + mutex_unlock(&data->update_lock); + + return 0; +} + +static const struct dev_pm_ops nct6683_dev_pm_ops = { + .suspend = nct6683_suspend, + .resume = nct6683_resume, + .freeze = nct6683_suspend, + .restore = nct6683_resume, +}; + +#define NCT6683_DEV_PM_OPS (&nct6683_dev_pm_ops) +#else +#define NCT6683_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static struct platform_driver nct6683_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + .pm = NCT6683_DEV_PM_OPS, + }, + .probe = nct6683_probe, +}; + +static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data) +{ + const char *board_vendor; + int addr; + u16 val; + int err; + + /* + * Only run on Intel boards unless the 'force' module parameter is set + */ + if (!force) { + board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + if (!board_vendor || strcmp(board_vendor, "Intel Corporation")) + return -ENODEV; + } + + err = superio_enter(sioaddr); + if (err) + return err; + + val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) + | superio_inb(sioaddr, SIO_REG_DEVID + 1); + + switch (val & SIO_ID_MASK) { + case SIO_NCT6683_ID: + sio_data->kind = nct6683; + break; + default: + if (val != 0xffff) + pr_debug("unsupported chip ID: 0x%04x\n", val); + goto fail; + } + + /* We have a known chip, find the HWM I/O address */ + superio_select(sioaddr, NCT6683_LD_HWM); + val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) + | superio_inb(sioaddr, SIO_REG_ADDR + 1); + addr = val & IOREGION_ALIGNMENT; + if (addr == 0) { + pr_err("EC base I/O port unconfigured\n"); + goto fail; + } + + /* Activate logical device if needed */ + val = superio_inb(sioaddr, SIO_REG_ENABLE); + if (!(val & 0x01)) { + pr_err("EC is disabled\n"); + goto fail; + } + + superio_exit(sioaddr); + pr_info("Found %s or compatible chip at %#x:%#x\n", + nct6683_chip_names[sio_data->kind], sioaddr, addr); + sio_data->sioreg = sioaddr; + + return addr; + +fail: + superio_exit(sioaddr); + return -ENODEV; +} + +/* + * when Super-I/O functions move to a separate file, the Super-I/O + * bus will manage the lifetime of the device and this module will only keep + * track of the nct6683 driver. But since we use platform_device_alloc(), we + * must keep track of the device + */ +static struct platform_device *pdev[2]; + +static int __init sensors_nct6683_init(void) +{ + struct nct6683_sio_data sio_data; + int sioaddr[2] = { 0x2e, 0x4e }; + struct resource res; + bool found = false; + int address; + int i, err; + + err = platform_driver_register(&nct6683_driver); + if (err) + return err; + + /* + * initialize sio_data->kind and sio_data->sioreg. + * + * when Super-I/O functions move to a separate file, the Super-I/O + * driver will probe 0x2e and 0x4e and auto-detect the presence of a + * nct6683 hardware monitor, and call probe() + */ + for (i = 0; i < ARRAY_SIZE(pdev); i++) { + address = nct6683_find(sioaddr[i], &sio_data); + if (address <= 0) + continue; + + found = true; + + pdev[i] = platform_device_alloc(DRVNAME, address); + if (!pdev[i]) { + err = -ENOMEM; + goto exit_device_unregister; + } + + err = platform_device_add_data(pdev[i], &sio_data, + sizeof(struct nct6683_sio_data)); + if (err) + goto exit_device_put; + + memset(&res, 0, sizeof(res)); + res.name = DRVNAME; + res.start = address + IOREGION_OFFSET; + res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; + res.flags = IORESOURCE_IO; + + err = acpi_check_resource_conflict(&res); + if (err) { + platform_device_put(pdev[i]); + pdev[i] = NULL; + continue; + } + + err = platform_device_add_resources(pdev[i], &res, 1); + if (err) + goto exit_device_put; + + /* platform_device_add calls probe() */ + err = platform_device_add(pdev[i]); + if (err) + goto exit_device_put; + } + if (!found) { + err = -ENODEV; + goto exit_unregister; + } + + return 0; + +exit_device_put: + platform_device_put(pdev[i]); +exit_device_unregister: + while (--i >= 0) { + if (pdev[i]) + platform_device_unregister(pdev[i]); + } +exit_unregister: + platform_driver_unregister(&nct6683_driver); + return err; +} + +static void __exit sensors_nct6683_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pdev); i++) { + if (pdev[i]) + platform_device_unregister(pdev[i]); + } + platform_driver_unregister(&nct6683_driver); +} + +MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); +MODULE_DESCRIPTION("NCT6683D driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_nct6683_init); +module_exit(sensors_nct6683_exit); diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 38d5a633405..59d9a3fc96b 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -4160,7 +4160,7 @@ static int __init sensors_nct6775_init(void) pdev[i] = platform_device_alloc(DRVNAME, address); if (!pdev[i]) { err = -ENOMEM; - goto exit_device_put; + goto exit_device_unregister; } err = platform_device_add_data(pdev[i], &sio_data, @@ -4198,9 +4198,11 @@ static int __init sensors_nct6775_init(void) return 0; exit_device_put: - for (i = 0; i < ARRAY_SIZE(pdev); i++) { + platform_device_put(pdev[i]); +exit_device_unregister: + while (--i >= 0) { if (pdev[i]) - platform_device_put(pdev[i]); + platform_device_unregister(pdev[i]); } exit_unregister: platform_driver_unregister(&nct6775_driver); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 8c23203915a..ae66f42c4d6 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -44,6 +44,7 @@ struct ntc_compensation { unsigned int ohm; }; +/* Order matters, ntc_match references the entries by index */ static const struct platform_device_id ntc_thermistor_id[] = { { "ncp15wb473", TYPE_NCPXXWB473 }, { "ncp18wb473", TYPE_NCPXXWB473 }, @@ -141,11 +142,11 @@ struct ntc_data { char name[PLATFORM_NAME_SIZE]; }; -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO) static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) { struct iio_channel *channel = pdata->chan; - unsigned int result; + s64 result; int val, ret; ret = iio_read_channel_raw(channel, &val); @@ -155,23 +156,35 @@ static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) } /* unit: mV */ - result = pdata->pullup_uv * val; + result = pdata->pullup_uv * (s64) val; result >>= 12; - return result; + return (int)result; } static const struct of_device_id ntc_match[] = { + { .compatible = "murata,ncp15wb473", + .data = &ntc_thermistor_id[0] }, + { .compatible = "murata,ncp18wb473", + .data = &ntc_thermistor_id[1] }, + { .compatible = "murata,ncp21wb473", + .data = &ntc_thermistor_id[2] }, + { .compatible = "murata,ncp03wb473", + .data = &ntc_thermistor_id[3] }, + { .compatible = "murata,ncp15wl333", + .data = &ntc_thermistor_id[4] }, + + /* Usage of vendor name "ntc" is deprecated */ { .compatible = "ntc,ncp15wb473", - .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + .data = &ntc_thermistor_id[0] }, { .compatible = "ntc,ncp18wb473", - .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + .data = &ntc_thermistor_id[1] }, { .compatible = "ntc,ncp21wb473", - .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + .data = &ntc_thermistor_id[2] }, { .compatible = "ntc,ncp03wb473", - .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + .data = &ntc_thermistor_id[3] }, { .compatible = "ntc,ncp15wl333", - .data = &ntc_thermistor_id[TYPE_NCPXXWL333] }, + .data = &ntc_thermistor_id[4] }, { }, }; MODULE_DEVICE_TABLE(of, ntc_match); @@ -223,6 +236,8 @@ ntc_thermistor_parse_dt(struct platform_device *pdev) return NULL; } +#define ntc_match NULL + static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata) { } #endif @@ -497,7 +512,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n", - pdev->name); + pdev_id->name); return 0; err_after_sysfs: @@ -531,7 +546,7 @@ static struct platform_driver ntc_thermistor_driver = { module_platform_driver(ntc_thermistor_driver); -MODULE_DESCRIPTION("NTC Thermistor Driver"); +MODULE_DESCRIPTION("NTC Thermistor Driver from Murata"); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ntc-thermistor"); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 330fe117e21..988181e4cfc 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -1225,7 +1225,7 @@ static int pc87360_probe(struct platform_device *pdev) int i; struct pc87360_data *data; int err = 0; - const char *name = "pc87360"; + const char *name; int use_thermistors = 0; struct device *dev = &pdev->dev; @@ -1233,13 +1233,14 @@ static int pc87360_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - data->fannr = 2; - data->innr = 0; - data->tempnr = 0; - switch (devid) { + default: + name = "pc87360"; + data->fannr = 2; + break; case 0xe8: name = "pc87363"; + data->fannr = 2; break; case 0xe4: name = "pc87364"; @@ -1260,7 +1261,6 @@ static int pc87360_probe(struct platform_device *pdev) } data->name = name; - data->valid = 0; mutex_init(&data->lock); mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index d847e0a084e..9e4684e747e 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1081,10 +1081,8 @@ static int pc87427_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } data->address[0] = sio_data->address[0]; data->address[1] = sio_data->address[1]; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index de3c152a1d9..e24ed521051 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,9 +1,9 @@ /* * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, - * and LTC3883 + * LTC3883, and LTM4676 * * Copyright (c) 2011 Ericsson AB. - * Copyright (c) 2013 Guenter Roeck + * Copyright (c) 2013, 2014 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 @@ -14,10 +14,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -28,7 +24,7 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -45,7 +41,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 }; #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880 and LTC3883 */ +/* LTC3880, LTC3883, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -53,7 +49,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 }; /* LTC3883 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 -#define LTC2974_ID 0x0212 +#define LTC2974_ID_REV1 0x0212 +#define LTC2974_ID_REV2 0x0213 #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0121 #define LTC2978_ID_REV2 0x0122 @@ -62,6 +59,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 }; #define LTC3880_ID_MASK 0xff00 #define LTC3883_ID 0x4300 #define LTC3883_ID_MASK 0xff00 +#define LTM4676_ID 0x4480 /* datasheet claims 0x440X */ +#define LTM4676_ID_MASK 0xfff0 #define LTC2974_NUM_PAGES 4 #define LTC2978_NUM_PAGES 8 @@ -370,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, {"ltc3883", ltc3883}, + {"ltm4676", ltm4676}, {} }; MODULE_DEVICE_TABLE(i2c, ltc2978_id); @@ -394,7 +394,7 @@ static int ltc2978_probe(struct i2c_client *client, if (chip_id < 0) return chip_id; - if (chip_id == LTC2974_ID) { + if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) { data->id = ltc2974; } else if (chip_id == LTC2977_ID) { data->id = ltc2977; @@ -405,6 +405,8 @@ static int ltc2978_probe(struct i2c_client *client, data->id = ltc3880; } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) { data->id = ltc3883; + } else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) { + data->id = ltm4676; } else { dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); return -ENODEV; @@ -458,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client, } break; case ltc3880: + case ltm4676: info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN @@ -500,5 +503,5 @@ static struct i2c_driver ltc2978_driver = { module_i2c_driver(ltc2978_driver); MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883"); +MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 3cbf66e9d86..291d11fe93e 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -90,7 +90,8 @@ struct pmbus_data { u32 flags; /* from platform data */ - int exponent; /* linear mode: exponent for output voltages */ + int exponent[PMBUS_PAGES]; + /* linear mode: exponent for output voltages */ const struct pmbus_driver_info *info; @@ -410,7 +411,7 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, long val; if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ - exponent = data->exponent; + exponent = data->exponent[sensor->page]; mantissa = (u16) sensor->data; } else { /* LINEAR11 */ exponent = ((s16)sensor->data) >> 11; @@ -516,7 +517,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) #define MIN_MANTISSA (511 * 1000) static u16 pmbus_data2reg_linear(struct pmbus_data *data, - enum pmbus_sensor_classes class, long val) + struct pmbus_sensor *sensor, long val) { s16 exponent = 0, mantissa; bool negative = false; @@ -525,7 +526,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, if (val == 0) return 0; - if (class == PSC_VOLTAGE_OUT) { + if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 does not support negative voltages */ if (val < 0) return 0; @@ -534,10 +535,10 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, * For a static exponents, we don't have a choice * but to adjust the value to it. */ - if (data->exponent < 0) - val <<= -data->exponent; + if (data->exponent[sensor->page] < 0) + val <<= -data->exponent[sensor->page]; else - val >>= data->exponent; + val >>= data->exponent[sensor->page]; val = DIV_ROUND_CLOSEST(val, 1000); return val & 0xffff; } @@ -548,14 +549,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, } /* Power is in uW. Convert to mW before converting. */ - if (class == PSC_POWER) + if (sensor->class == PSC_POWER) val = DIV_ROUND_CLOSEST(val, 1000L); /* * For simplicity, convert fan data to milli-units * before calculating the exponent. */ - if (class == PSC_FAN) + if (sensor->class == PSC_FAN) val = val * 1000; /* Reduce large mantissa until it fits into 10 bit */ @@ -585,22 +586,22 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, } static u16 pmbus_data2reg_direct(struct pmbus_data *data, - enum pmbus_sensor_classes class, long val) + struct pmbus_sensor *sensor, long val) { long m, b, R; - m = data->info->m[class]; - b = data->info->b[class]; - R = data->info->R[class]; + m = data->info->m[sensor->class]; + b = data->info->b[sensor->class]; + R = data->info->R[sensor->class]; /* Power is in uW. Adjust R and b. */ - if (class == PSC_POWER) { + if (sensor->class == PSC_POWER) { R -= 3; b *= 1000; } /* Calculate Y = (m * X + b) * 10^R */ - if (class != PSC_FAN) { + if (sensor->class != PSC_FAN) { R -= 3; /* Adjust R and b for data in milli-units */ b *= 1000; } @@ -619,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) + struct pmbus_sensor *sensor, long val) { val = clamp_val(val, 500, 1600); @@ -627,20 +628,20 @@ static u16 pmbus_data2reg_vid(struct pmbus_data *data, } static u16 pmbus_data2reg(struct pmbus_data *data, - enum pmbus_sensor_classes class, long val) + struct pmbus_sensor *sensor, long val) { u16 regval; - switch (data->info->format[class]) { + switch (data->info->format[sensor->class]) { case direct: - regval = pmbus_data2reg_direct(data, class, val); + regval = pmbus_data2reg_direct(data, sensor, val); break; case vid: - regval = pmbus_data2reg_vid(data, class, val); + regval = pmbus_data2reg_vid(data, sensor, val); break; case linear: default: - regval = pmbus_data2reg_linear(data, class, val); + regval = pmbus_data2reg_linear(data, sensor, val); break; } return regval; @@ -746,7 +747,7 @@ static ssize_t pmbus_set_sensor(struct device *dev, return -EINVAL; mutex_lock(&data->update_lock); - regval = pmbus_data2reg(data, sensor->class, val); + regval = pmbus_data2reg(data, sensor, val); ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); if (ret < 0) rv = ret; @@ -1643,12 +1644,13 @@ static int pmbus_find_attributes(struct i2c_client *client, * This function is called for all chips. */ static int pmbus_identify_common(struct i2c_client *client, - struct pmbus_data *data) + struct pmbus_data *data, int page) { int vout_mode = -1; - if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) - vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) + vout_mode = _pmbus_read_byte_data(client, page, + PMBUS_VOUT_MODE); if (vout_mode >= 0 && vout_mode != 0xff) { /* * Not all chips support the VOUT_MODE command, @@ -1659,7 +1661,7 @@ static int pmbus_identify_common(struct i2c_client *client, if (data->info->format[PSC_VOLTAGE_OUT] != linear) return -ENODEV; - data->exponent = ((s8)(vout_mode << 3)) >> 3; + data->exponent[page] = ((s8)(vout_mode << 3)) >> 3; break; case 1: /* VID mode */ if (data->info->format[PSC_VOLTAGE_OUT] != vid) @@ -1674,7 +1676,7 @@ static int pmbus_identify_common(struct i2c_client *client, } } - pmbus_clear_fault_page(client, 0); + pmbus_clear_fault_page(client, page); return 0; } @@ -1682,7 +1684,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, struct pmbus_driver_info *info) { struct device *dev = &client->dev; - int ret; + int page, ret; /* * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try @@ -1715,10 +1717,12 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, return -ENODEV; } - ret = pmbus_identify_common(client, data); - if (ret < 0) { - dev_err(dev, "Failed to identify chip capabilities\n"); - return ret; + for (page = 0; page < info->pages; page++) { + ret = pmbus_identify_common(client, data, page); + if (ret < 0) { + dev_err(dev, "Failed to identify chip capabilities\n"); + return ret; + } } return 0; } diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index 73bd64e8c30..0674c13bbd4 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -285,10 +285,8 @@ static int s3c_hwmon_probe(struct platform_device *dev) } hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL); - if (hwmon == NULL) { - dev_err(&dev->dev, "no memory\n"); + if (hwmon == NULL) return -ENOMEM; - } platform_set_drvdata(dev, hwmon); diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c new file mode 100644 index 00000000000..decd7df995a --- /dev/null +++ b/drivers/hwmon/shtc1.c @@ -0,0 +1,251 @@ +/* Sensirion SHTC1 humidity and temperature sensor driver + * + * Copyright (C) 2014 Sensirion AG, Switzerland + * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.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. + * + * 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/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_data/shtc1.h> + +/* commands (high precision mode) */ +static const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 }; +static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 }; + +/* commands (low precision mode) */ +static const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 }; +static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c }; + +/* command for reading the ID register */ +static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; + +/* constants for reading the ID register */ +#define SHTC1_ID 0x07 +#define SHTC1_ID_REG_MASK 0x1f + +/* delays for non-blocking i2c commands, both in us */ +#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 +#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000 + +#define SHTC1_CMD_LENGTH 2 +#define SHTC1_RESPONSE_LENGTH 6 + +struct shtc1_data { + struct i2c_client *client; + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + const unsigned char *command; + unsigned int nonblocking_wait_time; /* in us */ + + struct shtc1_platform_data setup; + + int temperature; /* 1000 * temperature in dgr C */ + int humidity; /* 1000 * relative humidity in %RH */ +}; + +static int shtc1_update_values(struct i2c_client *client, + struct shtc1_data *data, + char *buf, int bufsize) +{ + int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH); + if (ret != SHTC1_CMD_LENGTH) { + dev_err(&client->dev, "failed to send command: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + /* + * In blocking mode (clock stretching mode) the I2C bus + * is blocked for other traffic, thus the call to i2c_master_recv() + * will wait until the data is ready. For non blocking mode, we + * have to wait ourselves. + */ + if (!data->setup.blocking_io) + usleep_range(data->nonblocking_wait_time, + data->nonblocking_wait_time + 1000); + + ret = i2c_master_recv(client, buf, bufsize); + if (ret != bufsize) { + dev_err(&client->dev, "failed to read values: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +/* sysfs attributes */ +static struct shtc1_data *shtc1_update_client(struct device *dev) +{ + struct shtc1_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + unsigned char buf[SHTC1_RESPONSE_LENGTH]; + int val; + int ret = 0; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) { + ret = shtc1_update_values(client, data, buf, sizeof(buf)); + if (ret) + goto out; + + /* + * From datasheet: + * T = -45 + 175 * ST / 2^16 + * RH = 100 * SRH / 2^16 + * + * Adapted for integer fixed point (3 digit) arithmetic. + */ + val = be16_to_cpup((__be16 *)buf); + data->temperature = ((21875 * val) >> 13) - 45000; + val = be16_to_cpup((__be16 *)(buf + 3)); + data->humidity = ((12500 * val) >> 13); + + data->last_updated = jiffies; + data->valid = true; + } + +out: + mutex_unlock(&data->update_lock); + + return ret == 0 ? data : ERR_PTR(ret); +} + +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct shtc1_data *data = shtc1_update_client(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->temperature); +} + +static ssize_t humidity1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct shtc1_data *data = shtc1_update_client(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->humidity); +} + +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RO(humidity1_input); + +static struct attribute *shtc1_attrs[] = { + &dev_attr_temp1_input.attr, + &dev_attr_humidity1_input.attr, + NULL +}; + +ATTRIBUTE_GROUPS(shtc1); + +static void shtc1_select_command(struct shtc1_data *data) +{ + if (data->setup.high_precision) { + data->command = data->setup.blocking_io ? + shtc1_cmd_measure_blocking_hpm : + shtc1_cmd_measure_nonblocking_hpm; + data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM; + + } else { + data->command = data->setup.blocking_io ? + shtc1_cmd_measure_blocking_lpm : + shtc1_cmd_measure_nonblocking_lpm; + data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM; + } +} + +static int shtc1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + char id_reg[2]; + struct shtc1_data *data; + struct device *hwmon_dev; + struct i2c_adapter *adap = client->adapter; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) { + dev_err(dev, "plain i2c transactions not supported\n"); + return -ENODEV; + } + + ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH); + if (ret != SHTC1_CMD_LENGTH) { + dev_err(dev, "could not send read_id_reg command: %d\n", ret); + return ret < 0 ? ret : -ENODEV; + } + ret = i2c_master_recv(client, id_reg, sizeof(id_reg)); + if (ret != sizeof(id_reg)) { + dev_err(dev, "could not read ID register: %d\n", ret); + return -ENODEV; + } + if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) { + dev_err(dev, "ID register doesn't match\n"); + return -ENODEV; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->setup.blocking_io = false; + data->setup.high_precision = true; + data->client = client; + + if (client->dev.platform_data) + data->setup = *(struct shtc1_platform_data *)dev->platform_data; + shtc1_select_command(data); + mutex_init(&data->update_lock); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, + data, + shtc1_groups); + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +/* device ID table */ +static const struct i2c_device_id shtc1_id[] = { + { "shtc1", 0 }, + { "shtw1", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, shtc1_id); + +static struct i2c_driver shtc1_i2c_driver = { + .driver.name = "shtc1", + .probe = shtc1_probe, + .id_table = shtc1_id, +}; + +module_i2c_driver(shtc1_i2c_driver); + +MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>"); +MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index d9e1b7de78d..4ef5802df6d 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -222,7 +222,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc) rv = i2c_smbus_read_word_swapped(client, 0); if (rv < 0) { dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv); - return -1; + return rv; } /* * Validate/verify readback adc channel (in bit 11..14). diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index efee4c59239..34b9a601ad0 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -86,7 +86,7 @@ static inline u8 IN_TO_REG(unsigned long val, int n) */ static inline s8 TEMP_TO_REG(int val) { - return clamp_val(SCALE(val, 1, 1000), -128000, 127000); + return SCALE(clamp_val(val, -128000, 127000), 1, 1000); } static inline int TEMP_FROM_REG(s8 val) @@ -384,6 +384,8 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; + if (val > 255) + return -EINVAL; data->vrm = val; return count; diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 6748b4583e7..51719956cc0 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -51,6 +51,7 @@ #define TMP102_THIGH_REG 0x03 struct tmp102 { + struct i2c_client *client; struct device *hwmon_dev; struct thermal_zone_device *tz; struct mutex lock; @@ -77,9 +78,10 @@ static const u8 tmp102_reg[] = { TMP102_THIGH_REG, }; -static struct tmp102 *tmp102_update_device(struct i2c_client *client) +static struct tmp102 *tmp102_update_device(struct device *dev) { - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; mutex_lock(&tmp102->lock); if (time_after(jiffies, tmp102->last_update + HZ / 3)) { @@ -98,7 +100,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client) static int tmp102_read_temp(void *dev, long *temp) { - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); *temp = tmp102->temp[0]; @@ -110,7 +112,7 @@ static ssize_t tmp102_show_temp(struct device *dev, char *buf) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); return sprintf(buf, "%d\n", tmp102->temp[sda->index]); } @@ -120,8 +122,8 @@ static ssize_t tmp102_set_temp(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct i2c_client *client = to_i2c_client(dev); - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; long val; int status; @@ -145,16 +147,13 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, tmp102_set_temp, 2); -static struct attribute *tmp102_attributes[] = { +static struct attribute *tmp102_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, NULL }; - -static const struct attribute_group tmp102_attr_group = { - .attrs = tmp102_attributes, -}; +ATTRIBUTE_GROUPS(tmp102); #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) @@ -162,72 +161,68 @@ static const struct attribute_group tmp102_attr_group = { static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp102 *tmp102; int status; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(&client->dev, + dev_err(dev, "adapter doesn't support SMBus word transactions\n"); return -ENODEV; } - tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL); + tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL); if (!tmp102) return -ENOMEM; i2c_set_clientdata(client, tmp102); + tmp102->client = client; status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); return status; } tmp102->config_orig = status; status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, TMP102_CONFIG); if (status < 0) { - dev_err(&client->dev, "error writing config register\n"); + dev_err(dev, "error writing config register\n"); goto fail_restore_config; } status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); goto fail_restore_config; } status &= ~TMP102_CONFIG_RD_ONLY; if (status != TMP102_CONFIG) { - dev_err(&client->dev, "config settings did not stick\n"); + dev_err(dev, "config settings did not stick\n"); status = -ENODEV; goto fail_restore_config; } tmp102->last_update = jiffies - HZ; mutex_init(&tmp102->lock); - status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group); - if (status) { - dev_dbg(&client->dev, "could not create sysfs files\n"); + hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + tmp102, tmp102_groups); + if (IS_ERR(hwmon_dev)) { + dev_dbg(dev, "unable to register hwmon device\n"); + status = PTR_ERR(hwmon_dev); goto fail_restore_config; } - tmp102->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(tmp102->hwmon_dev)) { - dev_dbg(&client->dev, "unable to register hwmon device\n"); - status = PTR_ERR(tmp102->hwmon_dev); - goto fail_remove_sysfs; - } - - tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0, - &client->dev, + tmp102->hwmon_dev = hwmon_dev; + tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, tmp102_read_temp, NULL); if (IS_ERR(tmp102->tz)) tmp102->tz = NULL; - dev_info(&client->dev, "initialized\n"); + dev_info(dev, "initialized\n"); return 0; -fail_remove_sysfs: - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); fail_restore_config: i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, tmp102->config_orig); @@ -238,9 +233,8 @@ static int tmp102_remove(struct i2c_client *client) { struct tmp102 *tmp102 = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz); + thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz); hwmon_device_unregister(tmp102->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); /* Stop monitoring if device was stopped originally */ if (tmp102->config_orig & TMP102_CONF_SD) { diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index ae26b06fa81..7bab7a9bedc 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -69,7 +69,7 @@ static const struct i2c_device_id tmp421_id[] = { MODULE_DEVICE_TABLE(i2c, tmp421_id); struct tmp421_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; @@ -99,8 +99,8 @@ static int temp_from_u16(u16 reg) static struct tmp421_data *tmp421_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp421_data *data = i2c_get_clientdata(client); + struct tmp421_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); @@ -198,6 +198,11 @@ static const struct attribute_group tmp421_group = { .is_visible = tmp421_is_visible, }; +static const struct attribute_group *tmp421_groups[] = { + &tmp421_group, + NULL +}; + static int tmp421_init_client(struct i2c_client *client) { int config, config_orig; @@ -264,47 +269,26 @@ static int tmp421_detect(struct i2c_client *client, static int tmp421_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp421_data *data; int err; - data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->channels = id->driver_data; + data->client = client; err = tmp421_init_client(client); if (err) return err; - err = sysfs_create_group(&client->dev.kobj, &tmp421_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - data->hwmon_dev = NULL; - goto exit_remove; - } - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - return err; -} - -static int tmp421_remove(struct i2c_client *client) -{ - struct tmp421_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, tmp421_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct i2c_driver tmp421_driver = { @@ -313,7 +297,6 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", }, .probe = tmp421_probe, - .remove = tmp421_remove, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index fb3e69341c1..7d465863606 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -252,7 +252,7 @@ static const struct attribute_group env_group = { static int env_probe(struct platform_device *op) { - struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); + struct env *p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL); int err = -ENOMEM; if (!p) @@ -262,7 +262,7 @@ static int env_probe(struct platform_device *op) p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747"); if (!p->regs) - goto out_free; + goto out; err = sysfs_create_group(&op->dev.kobj, &env_group); if (err) @@ -286,8 +286,6 @@ out_sysfs_remove_group: out_iounmap: of_iounmap(&op->resource[0], p->regs, REG_SIZE); -out_free: - kfree(p); goto out; } @@ -299,7 +297,6 @@ static int env_remove(struct platform_device *op) sysfs_remove_group(&op->dev.kobj, &env_group); hwmon_device_unregister(p->hwmon_dev); of_iounmap(&op->resource[0], p->regs, REG_SIZE); - kfree(p); } return 0; diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c index d867e6bb2be..c53619086f3 100644 --- a/drivers/hwmon/vexpress.c +++ b/drivers/hwmon/vexpress.c @@ -26,26 +26,14 @@ struct vexpress_hwmon_data { struct device *hwmon_dev; - struct vexpress_config_func *func; + struct regmap *reg; }; -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); } @@ -56,7 +44,7 @@ static ssize_t vexpress_hwmon_u32_show(struct device *dev, int err; u32 value; - err = vexpress_config_read(data->func, 0, &value); + err = regmap_read(data->reg, 0, &value); if (err) return err; @@ -71,11 +59,11 @@ static ssize_t vexpress_hwmon_u64_show(struct device *dev, int err; u32 value_hi, value_lo; - err = vexpress_config_read(data->func, 0, &value_lo); + err = regmap_read(data->reg, 0, &value_lo); if (err) return err; - err = vexpress_config_read(data->func, 1, &value_hi); + err = regmap_read(data->reg, 1, &value_hi); if (err) return err; @@ -84,77 +72,146 @@ static ssize_t vexpress_hwmon_u64_show(struct device *dev, to_sensor_dev_attr(dev_attr)->index)); } -static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); +static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = kobj_to_dev(kobj); + struct device_attribute *dev_attr = container_of(attr, + struct device_attribute, attr); + + if (dev_attr->show == vexpress_hwmon_label_show && + !of_get_property(dev->of_node, "label", NULL)) + return 0; -#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 \ + return attr->mode; } +struct vexpress_hwmon_type { + const char *name; + const struct attribute_group **attr_groups; +}; + #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 *vexpress_hwmon_attrs_volt[] = { + &dev_attr_in1_label.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_volt = { + .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_volt, }; +static struct vexpress_hwmon_type vexpress_hwmon_volt = { + .name = "vexpress_volt", + .attr_groups = (const struct attribute_group *[]) { + &vexpress_hwmon_group_volt, + NULL, + }, +}; #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 *vexpress_hwmon_attrs_amp[] = { + &dev_attr_curr1_label.attr, + &sensor_dev_attr_curr1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_amp = { + .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_amp, }; +static struct vexpress_hwmon_type vexpress_hwmon_amp = { + .name = "vexpress_amp", + .attr_groups = (const struct attribute_group *[]) { + &vexpress_hwmon_group_amp, + NULL + }, +}; 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 *vexpress_hwmon_attrs_temp[] = { + &dev_attr_temp1_label.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_temp = { + .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_temp, }; +static struct vexpress_hwmon_type vexpress_hwmon_temp = { + .name = "vexpress_temp", + .attr_groups = (const struct attribute_group *[]) { + &vexpress_hwmon_group_temp, + NULL + }, +}; 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 *vexpress_hwmon_attrs_power[] = { + &dev_attr_power1_label.attr, + &sensor_dev_attr_power1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_power = { + .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_power, }; +static struct vexpress_hwmon_type vexpress_hwmon_power = { + .name = "vexpress_power", + .attr_groups = (const struct attribute_group *[]) { + &vexpress_hwmon_group_power, + NULL + }, +}; 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 *vexpress_hwmon_attrs_energy[] = { + &dev_attr_energy1_label.attr, + &sensor_dev_attr_energy1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_energy = { + .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_energy, }; +static struct vexpress_hwmon_type vexpress_hwmon_energy = { + .name = "vexpress_energy", + .attr_groups = (const struct attribute_group *[]) { + &vexpress_hwmon_group_energy, + NULL + }, +}; static struct of_device_id vexpress_hwmon_of_match[] = { #if !defined(CONFIG_REGULATOR_VEXPRESS) { .compatible = "arm,vexpress-volt", - .data = &vexpress_hwmon_group_volt, + .data = &vexpress_hwmon_volt, }, #endif { .compatible = "arm,vexpress-amp", - .data = &vexpress_hwmon_group_amp, + .data = &vexpress_hwmon_amp, }, { .compatible = "arm,vexpress-temp", - .data = &vexpress_hwmon_group_temp, + .data = &vexpress_hwmon_temp, }, { .compatible = "arm,vexpress-power", - .data = &vexpress_hwmon_group_power, + .data = &vexpress_hwmon_power, }, { .compatible = "arm,vexpress-energy", - .data = &vexpress_hwmon_group_energy, + .data = &vexpress_hwmon_energy, }, {} }; @@ -162,9 +219,9 @@ 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; + const struct vexpress_hwmon_type *type; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -174,47 +231,20 @@ static int vexpress_hwmon_probe(struct platform_device *pdev) match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); if (!match) return -ENODEV; + type = match->data; - 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); + data->reg = devm_regmap_init_vexpress_config(&pdev->dev); + if (IS_ERR(data->reg)) + return PTR_ERR(data->reg); - vexpress_config_func_put(data->func); + data->hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, + type->name, data, type->attr_groups); - return 0; + return PTR_ERR_OR_ZERO(data->hwmon_dev); } static struct platform_driver vexpress_hwmon_driver = { .probe = vexpress_hwmon_probe, - .remove = vexpress_hwmon_remove, .driver = { .name = DRVNAME, .owner = THIS_MODULE, diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 38944e94f65..8df43c51de2 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -319,7 +319,7 @@ static int __init via_cputemp_init(void) if (err) goto exit; - get_online_cpus(); + cpu_notifier_register_begin(); for_each_online_cpu(i) { struct cpuinfo_x86 *c = &cpu_data(i); @@ -339,14 +339,14 @@ static int __init via_cputemp_init(void) #ifndef CONFIG_HOTPLUG_CPU if (list_empty(&pdev_list)) { - put_online_cpus(); + cpu_notifier_register_done(); err = -ENODEV; goto exit_driver_unreg; } #endif - register_hotcpu_notifier(&via_cputemp_cpu_notifier); - put_online_cpus(); + __register_hotcpu_notifier(&via_cputemp_cpu_notifier); + cpu_notifier_register_done(); return 0; #ifndef CONFIG_HOTPLUG_CPU @@ -361,8 +361,8 @@ static void __exit via_cputemp_exit(void) { struct pdev_entry *p, *n; - get_online_cpus(); - unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); + cpu_notifier_register_begin(); + __unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); mutex_lock(&pdev_list_mutex); list_for_each_entry_safe(p, n, &pdev_list, list) { platform_device_unregister(p->pdev); @@ -370,7 +370,7 @@ static void __exit via_cputemp_exit(void) kfree(p); } mutex_unlock(&pdev_list_mutex); - put_online_cpus(); + cpu_notifier_register_done(); platform_driver_unregister(&via_cputemp_driver); } diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 6b2f1a42b3f..344b22ec255 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1152,10 +1152,8 @@ static int vt1211_probe(struct platform_device *pdev) int i, err; data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(dev, res->start, resource_size(res), diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index df585808adb..4068db4d958 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1376,7 +1376,6 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; i2c_set_clientdata(client, data); - data->valid = 0; mutex_init(&data->update_lock); err = w83792d_detect_subclients(client); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 6384b268f59..ac304312201 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -188,12 +188,8 @@ static int w83l785ts_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); - data->valid = 0; mutex_init(&data->update_lock); - /* Default values in case the first read fails (unlikely). */ - data->temp[1] = data->temp[0] = 0; - /* * Initialize the W83L785TS chip * Nothing yet, assume it is already started. diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 6ed76ceb927..32487c19cbf 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -249,7 +249,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ int nr = to_sensor_dev_attr(attr)->index; \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ return sprintf(buf, "%d\n", \ - FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); |
