----------------------------
-What: Legacy, non-standard chassis intrusion detection interface.
-When: June 2011
-Why: The adm9240, w83792d and w83793 hardware monitoring drivers have
- legacy interfaces for chassis intrusion detection. A standard
- interface has been added to each driver, so the legacy interface
- can be removed.
-Who: Jean Delvare <khali@linux-fr.org>
-
-----------------------------
-
What: i2c_driver.attach_adapter
i2c_driver.detach_adapter
When: September 2011
--- /dev/null
+Kernel driver adt7410
+=====================
+
+Supported chips:
+ * Analog Devices ADT7410
+ Prefix: 'adt7410'
+ Addresses scanned: I2C 0x48 - 0x4B
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/static/imported-files/data_sheets/ADT7410.pdf
+
+Author: Hartmut Knaack <knaack.h@gmx.de>
+
+Description
+-----------
+
+The ADT7410 is a temperature sensor with rated temperature range of -55°C to
++150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
+of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
+indicate that a minimum or maximum temperature set point has been exceeded, as
+well as a critical temperature (CT) pin to indicate that the critical
+temperature set point has been exceeded. Both pins can be set up with a common
+hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
+pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410
+supports continous temperature sampling, as well as sampling one temperature
+value per second or even justget one sample on demand for power saving.
+Besides, it can completely power down its ADC, if power management is
+required.
+
+Configuration Notes
+-------------------
+
+Since the device uses one hysteresis value, which is an offset to minimum,
+maximum and critical temperature, it can only be set for temp#_max_hyst.
+However, temp#_min_hyst and temp#_crit_hyst show their corresponding
+hysteresis.
+The device is set to 16 bit resolution and comparator mode.
+
+sysfs-Interface
+---------------
+
+temp#_input - temperature input
+temp#_min - temperature minimum setpoint
+temp#_max - temperature maximum setpoint
+temp#_crit - critical temperature setpoint
+temp#_min_hyst - hysteresis for temperature minimum (read-only)
+temp#_max_hyst - hysteresis for temperature maximum (read/write)
+temp#_crit_hyst - hysteresis for critical temperature (read-only)
+temp#_min_alarm - temperature minimum alarm flag
+temp#_max_alarm - temperature maximum alarm flag
+temp#_crit_alarm - critical temperature alarm flag
Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/
+ * Texas Instruments INA220
+ Prefix: 'ina220'
+ Addresses: I2C 0x40 - 0x4f
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/
+
* Texas Instruments INA226
Prefix: 'ina226'
Addresses: I2C 0x40 - 0x4f
Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/
+ * Texas Instruments INA230
+ Prefix: 'ina230'
+ Addresses: I2C 0x40 - 0x4f
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/
+
Author: Lothar Felten <l-felten@ti.com>
Description
interface. The INA219 monitors both shunt drop and supply voltage, with
programmable conversion times and filtering.
+The INA220 is a high or low side current shunt and power monitor with an I2C
+interface. The INA220 monitors both shunt drop and supply voltage.
+
The INA226 is a current shunt and power monitor with an I2C interface.
The INA226 monitors both a shunt voltage drop and bus supply voltage.
+The INA230 is a high or low side current shunt and power monitor with an I2C
+interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
+
The shunt value in micro-ohms can be set via platform data.
Datasheet: http://www.national.com/pf/LM/LM70.html
* Texas Instruments TMP121/TMP123
Information: http://focus.ti.com/docs/prod/folders/print/tmp121.html
+ * National Semiconductor LM71
+ Datasheet: http://www.ti.com/product/LM71
+ * National Semiconductor LM74
+ Datasheet: http://www.ti.com/product/LM74
Author:
Kaiwan N Billimoria <kaiwan@designergraphix.com>
with a "SPI master controller driver", see drivers/spi/spi_lm70llp.c
and its associated documentation.
-The TMP121/TMP123 are very similar; main differences are 4 wire SPI inter-
-face (read only) and 13-bit temperature data (0.0625 degrees celsius reso-
-lution).
+The LM74 and TMP121/TMP123 are very similar; main difference is 13-bit
+temperature data (0.0625 degrees celsius resolution).
+
+The LM71 is also very similar; main difference is 14-bit temperature
+data (0.03125 degrees celsius resolution).
Thanks to
---------
--- /dev/null
+Maxim MAX197 driver
+===================
+
+Author:
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+
+Supported chips:
+ * Maxim MAX197
+ Prefix: 'max197'
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX197.pdf
+
+ * Maxim MAX199
+ Prefix: 'max199'
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX199.pdf
+
+Description
+-----------
+
+The A/D converters MAX197, and MAX199 are both 8-Channel, Multi-Range, 5V,
+12-Bit DAS with 8+4 Bus Interface and Fault Protection.
+
+The available ranges for the MAX197 are {0,-5V} to 5V, and {0,-10V} to 10V,
+while they are {0,-2V} to 2V, and {0,-4V} to 4V on the MAX199.
+
+Platform data
+-------------
+
+The MAX197 platform data (defined in linux/platform_data/max197.h) should be
+filled with a pointer to a conversion function, defined like:
+
+ int convert(u8 ctrl);
+
+ctrl is the control byte to write to start a new conversion.
+On success, the function must return the 12-bit raw value read from the chip,
+or a negative error code otherwise.
+
+Control byte format:
+
+Bit Name Description
+7,6 PD1,PD0 Clock and Power-Down modes
+5 ACQMOD Internal or External Controlled Acquisition
+4 RNG Full-scale voltage magnitude at the input
+3 BIP Unipolar or Bipolar conversion mode
+2,1,0 A2,A1,A0 Channel
+
+Sysfs interface
+---------------
+
+* in[0-7]_input: The conversion value for the corresponding channel.
+ RO
+
+* in[0-7]_min: The lower limit (in mV) for the corresponding channel.
+ For the MAX197, it will be adjusted to -10000, -5000, or 0.
+ For the MAX199, it will be adjusted to -4000, -2000, or 0.
+ RW
+
+* in[0-7]_max: The higher limit (in mV) for the corresponding channel.
+ For the MAX197, it will be adjusted to 0, 5000, or 10000.
+ For the MAX199, it will be adjusted to 0, 2000, or 4000.
+ RW
* Microchip Technology MCP3021
Prefix: 'mcp3021'
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
+ * Microchip Technology MCP3221
+ Prefix: 'mcp3221'
+ Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21732c.pdf
-Author: Mingkai Hu
+Authors:
+ Mingkai Hu
+ Sven Schuchmann <schuchmann@schleissheimer.de>
Description
-----------
-This driver implements support for the Microchip Technology MCP3021 chip.
+This driver implements support for the Microchip Technology MCP3021 and
+MCP3221 chip.
The Microchip Technology Inc. MCP3021 is a successive approximation A/D
-converter (ADC) with 10-bit resolution.
-This device provides one single-ended input with very low power consumption.
-Communication to the MCP3021 is performed using a 2-wire I2C compatible
-interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
-The default I2C device address is 0x4d (contact the Microchip factory for
-additional address options).
+converter (ADC) with 10-bit resolution. The MCP3221 has 12-bit resolution.
+
+These devices provide one single-ended input with very low power consumption.
+Communication to the MCP3021/MCP3221 is performed using a 2-wire I2C
+compatible interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are
+available. The default I2C device address is 0x4d (contact the Microchip
+factory for additional address options).
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mfd/da903x.h>
-#include <linux/sht15.h>
+#include <linux/platform_data/sht15.h>
#include "devices.h"
#include "generic.h"
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
- depends on X86 && DMI && EXPERIMENTAL
+ depends on X86 && DMI
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
- depends on X86 && DMI && EXPERIMENTAL
+ depends on X86 && DMI
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
config SENSORS_AD7314
tristate "Analog Devices AD7314 and compatibles"
- depends on SPI && EXPERIMENTAL
+ depends on SPI
help
If you say yes here you get support for the Analog Devices
AD7314, ADT7301 and ADT7302 temperature sensors.
config SENSORS_AD7414
tristate "Analog Devices AD7414"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Analog Devices
AD7414 temperature monitoring chip.
config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Analog Devices
AD7416, AD7417 and AD7418 temperature monitoring chips.
config SENSORS_ADCXX
tristate "National Semiconductor ADCxxxSxxx"
- depends on SPI_MASTER && EXPERIMENTAL
+ 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
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_ADT7410
+ tristate "Analog Devices ADT7410"
+ depends on I2C
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7410 temperature monitoring chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7410.
+
config SENSORS_ADT7411
tristate "Analog Devices ADT7411"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Analog Devices
ADT7411 voltage and temperature monitoring chip.
config SENSORS_ADT7462
tristate "Analog Devices ADT7462"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Analog Devices
ADT7462 temperature monitoring chips.
config SENSORS_ADT7470
tristate "Analog Devices ADT7470"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Analog Devices
ADT7470 temperature monitoring chips.
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
- depends on X86 && PCI && EXPERIMENTAL
+ depends on X86 && PCI
help
If you say yes here you get support for the temperature
sensor(s) inside your CPU. Supported is whole AMD K8
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
- depends on X86 && I2C && EXPERIMENTAL
+ depends on X86 && I2C
select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Attansic ATXP1 VID
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
If you say yes here you get support for FB-DIMM AMB temperature
monitoring chips on systems with the Intel 5000 series chipset.
config SENSORS_HIH6130
tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for Honeywell Humidicon
HIH-6130 and HIH-6131 Humidicon humidity sensors.
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
- depends on X86 && PCI && EXPERIMENTAL
+ depends on X86 && PCI
help
If you say yes here you get support for the temperature
sensor inside your CPU. Most of the family 6 CPUs
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
- IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E
- sensor chips, and the SiS960 clone.
+ IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
+ IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
This driver can also be built as a module. If so, the module
will be called it87.
config SENSORS_LINEAGE
tristate "Lineage Compact Power Line Power Entry Module"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Lineage Compact Power Line
series of DC/DC and AC/DC converters such as CP1800, CP2000AC,
will be called lm63.
config SENSORS_LM70
- tristate "National Semiconductor LM70 / Texas Instruments TMP121"
+ tristate "National Semiconductor LM70 and compatibles"
depends on SPI_MASTER
help
If you say yes here you get support for the National Semiconductor
- LM70 and Texas Instruments TMP121/TMP123 digital temperature
- sensor chips.
+ LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
+ ture sensor chips.
This driver can also be built as a module. If so, the module
will be called lm70.
config SENSORS_LTC4215
tristate "Linear Technology LTC4215"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
default n
help
If you say yes here you get support for Linear Technology LTC4215
config SENSORS_LTC4245
tristate "Linear Technology LTC4245"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
default n
help
If you say yes here you get support for Linear Technology LTC4245
config SENSORS_LTC4261
tristate "Linear Technology LTC4261"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
default n
help
If you say yes here you get support for Linear Technology LTC4261
config SENSORS_LM95245
tristate "National Semiconductor LM95245 sensor chip"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for LM95245 sensor chip.
will be called lm95245.
config SENSORS_MAX1111
- tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
+ tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
depends on SPI_MASTER
help
- Say y here to support Maxim's MAX1111 ADC chips.
+ 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_MAX1668
tristate "Maxim MAX1668 and compatibles"
- depends on I2C && EXPERIMENTAL
+ 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 && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the MAX6639
sensor chips.
config SENSORS_MAX6642
tristate "Maxim MAX6642 sensor chip"
- depends on I2C && EXPERIMENTAL
+ 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
config SENSORS_MAX6650
tristate "Maxim MAX6650 sensor chip"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the MAX6650 / MAX6651
sensor chips.
will be called max6650.
config SENSORS_MCP3021
- tristate "Microchip MCP3021"
- depends on I2C && EXPERIMENTAL
+ tristate "Microchip MCP3021 and compatibles"
+ depends on I2C
help
- If you say yes here you get support for the MCP3021 chip
- that is a A/D converter (ADC) with 10-bit resolution.
+ 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_NTC_THERMISTOR
tristate "NTC thermistor support"
- depends on EXPERIMENTAL
help
This driver supports NTC thermistors sensor reading and its
interpretation. The driver can also monitor the temperature and
config SENSORS_SMM665
tristate "Summit Microelectronics SMM665"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
default n
help
If you say yes here you get support for the hardware monitoring
config SENSORS_DME1737
tristate "SMSC DME1737, SCH311x and compatibles"
- depends on I2C && EXPERIMENTAL && !PPC
+ depends on I2C && !PPC
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
- depends on EXPERIMENTAL && !PPC
+ depends on !PPC
help
If you say yes here you get support for the SMSC LPC47B397-NC
sensor chip.
config SENSORS_AMC6821
tristate "Texas Instruments AMC6821"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Texas Instruments
AMC6821 hardware monitoring chips.
will be called amc6821.
config SENSORS_INA2XX
- tristate "Texas Instruments INA219, INA226"
- depends on I2C && EXPERIMENTAL
+ tristate "Texas Instruments INA219 and compatibles"
+ depends on I2C
help
- If you say yes here you get support for INA219 and INA226 power
- monitor chips.
+ If you say yes here you get support for INA219, INA220, INA226, and
+ INA230 power monitor chips.
The INA2xx driver is configured for the default configuration of
the part as described in the datasheet.
config SENSORS_TMP102
tristate "Texas Instruments TMP102"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for Texas Instruments TMP102
sensor chips.
config SENSORS_TMP401
tristate "Texas Instruments TMP401 and compatibles"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for Texas Instruments TMP401 and
TMP411 temperature sensor chips.
config SENSORS_TMP421
tristate "Texas Instruments TMP421 and compatible"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for Texas Instruments TMP421,
TMP422 and TMP423 temperature sensor chips.
config SENSORS_W83793
tristate "Winbond W83793"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Winbond W83793
config SENSORS_W83795
tristate "Winbond/Nuvoton W83795G/ADG"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Winbond W83795G and
W83795ADG hardware monitoring chip, including manual fan speed
config SENSORS_W83795_FANCTRL
boolean "Include automatic fan control support (DANGEROUS)"
- depends on SENSORS_W83795 && EXPERIMENTAL
+ depends on SENSORS_W83795
default n
help
If you say yes here, support for automatic fan speed control
config SENSORS_W83L785TS
tristate "Winbond W83L785TS-S"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Winbond W83L785TS-S
sensor chip, which is used on the Asus A7N8X, among other
config SENSORS_W83L786NG
tristate "Winbond W83L786NG, W83L786NR"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Winbond W83L786NG
and W83L786NR sensor chips.
config SENSORS_ATK0110
tristate "ASUS ATK0110"
- depends on X86 && EXPERIMENTAL
+ depends on X86
help
If you say yes here you get support for the ACPI hardware
monitoring interface found in many ASUS motherboards. This
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
+obj-$(CONFIG_SENSORS_ADT7410) += adt7410.o
obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
+obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
- data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return res;
}
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
u8 buf[2];
u16 id;
- data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru3_sysfs_attr[i].dev_attr);
- kfree(data);
return res;
}
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru3_sysfs_attr[i].dev_attr);
- kfree(data);
-
return 0;
}
int ret;
struct ad7314_data *chip;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
dev_set_drvdata(&spi_dev->dev, chip);
ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
if (ret < 0)
- goto error_free_chip;
+ return ret;
+
chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
if (IS_ERR(chip->hwmon_dev)) {
ret = PTR_ERR(chip->hwmon_dev);
return 0;
error_remove_group:
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-error_free_chip:
- kfree(chip);
-error_ret:
return ret;
}
hwmon_device_unregister(chip->hwmon_dev);
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
- kfree(chip);
return 0;
}
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_READ_WORD_DATA)) {
- err = -EOPNOTSUPP;
- goto exit;
- }
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -EOPNOTSUPP;
- data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct ad7414_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-exit_free:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
- kfree(data);
return 0;
}
int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_WORD_DATA)) {
- err = -EOPNOTSUPP;
- goto exit;
- }
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
- data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct ad7418_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
- kfree(data);
-exit:
return err;
}
struct ad7418_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- kfree(data);
return 0;
}
static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
- struct spi_device *spi = to_spi_device(dev);
- struct adcxx *adc = spi_get_drvdata(spi);
-
- return sprintf(buf, "adcxx%ds\n", adc->channels);
+ return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
static struct sensor_device_attribute ad_input[] = {
int status;
int i;
- adc = kzalloc(sizeof *adc, GFP_KERNEL);
+ adc = devm_kzalloc(&spi->dev, sizeof(*adc), GFP_KERNEL);
if (!adc)
return -ENOMEM;
spi_set_drvdata(spi, NULL);
mutex_unlock(&adc->lock);
- kfree(adc);
return status;
}
spi_set_drvdata(spi, NULL);
mutex_unlock(&adc->lock);
- kfree(adc);
return 0;
}
struct adm1029_data *data;
int err;
- data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct adm1029_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
* Initialize the ADM1029 chip
* Check config register
*/
- if (adm1029_init_client(client) == 0) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (adm1029_init_client(client) == 0)
+ return -ENODEV;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- exit_free:
- kfree(data);
- exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- kfree(data);
return 0;
}
}
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
-/* chassis_clear */
-static ssize_t chassis_clear_legacy(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- long val;
- int err;
-
- err = kstrtol(buf, 10, &val);
- if (err)
- return err;
-
- dev_warn(dev, "Attribute chassis_clear is deprecated, "
- "use intrusion0_alarm instead\n");
-
- if (val == 1) {
- i2c_smbus_write_byte_data(client,
- ADM9240_REG_CHASSIS_CLEAR, 0x80);
- dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
- }
- return count;
-}
-static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear_legacy);
-
static ssize_t chassis_clear(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
- &dev_attr_chassis_clear.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
NULL
hwmon_device_unregister(data->hwmon_dev);
for (k = 0; k < ADS1015_CHANNELS; ++k)
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
- kfree(data);
return 0;
}
int err;
unsigned int k;
- data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
exit_remove:
for (k = 0; k < ADS1015_CHANNELS; ++k)
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
- kfree(data);
-exit:
return err;
}
struct ads7828_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
- kfree(i2c_get_clientdata(client));
return 0;
}
struct ads7828_data *data;
int err;
- data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct ads7828_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-exit_free:
- kfree(data);
-exit:
return err;
}
* because there is no other error checking on an SPI bus
* we need to make sure we really have a chip
*/
- if (val != ret) {
- err = -ENODEV;
- goto exit;
- }
+ if (val != ret)
+ return -ENODEV;
- pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
- if (!pdata) {
- err = -ENOMEM;
- goto exit;
- }
+ pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
err = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
if (err < 0)
- goto error_free;
+ return err;
spi_set_drvdata(spi, pdata);
error_remove:
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-error_free:
- kfree(pdata);
-exit:
return err;
}
hwmon_device_unregister(pdata->hwmon_dev);
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
- kfree(pdata);
return 0;
}
--- /dev/null
+/*
+ * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.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.
+ *
+ * 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>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE 0
+#define ADT7410_STATUS 2
+#define ADT7410_CONFIG 3
+#define ADT7410_T_ALARM_HIGH 4
+#define ADT7410_T_ALARM_LOW 6
+#define ADT7410_T_CRIT 8
+#define ADT7410_T_HYST 0xA
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW (1 << 4)
+#define ADT7410_STAT_T_HIGH (1 << 5)
+#define ADT7410_STAT_T_CRIT (1 << 6)
+#define ADT7410_STAT_NOT_RDY (1 << 7)
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
+#define ADT7410_CT_POLARITY (1 << 2)
+#define ADT7410_INT_POLARITY (1 << 3)
+#define ADT7410_EVENT_MODE (1 << 4)
+#define ADT7410_MODE_MASK (1 << 5 | 1 << 6)
+#define ADT7410_FULL (0 << 5 | 0 << 6)
+#define ADT7410_PD (1 << 5 | 1 << 6)
+#define ADT7410_RESOLUTION (1 << 7)
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T13_VALUE_MASK 0xFFF8
+#define ADT7410_T_HYST_MASK 0xF
+
+/* straight from the datasheet */
+#define ADT7410_TEMP_MIN (-55000)
+#define ADT7410_TEMP_MAX 150000
+
+enum adt7410_type { /* keep sorted in alphabetical order */
+ adt7410,
+};
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ I2C_CLIENT_END };
+
+static const u8 ADT7410_REG_TEMP[4] = {
+ ADT7410_TEMPERATURE, /* input */
+ ADT7410_T_ALARM_HIGH, /* high */
+ ADT7410_T_ALARM_LOW, /* low */
+ ADT7410_T_CRIT, /* critical */
+};
+
+/* Each client has this additional data */
+struct adt7410_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ u8 config;
+ u8 oldconfig;
+ bool valid; /* true if registers valid */
+ unsigned long last_updated; /* In jiffies */
+ s16 temp[4]; /* Register values,
+ 0 = input
+ 1 = high
+ 2 = low
+ 3 = critical */
+ u8 hyst; /* hysteresis offset */
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+static int adt7410_temp_ready(struct i2c_client *client)
+{
+ int i, status;
+
+ for (i = 0; i < 6; i++) {
+ status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+ if (status < 0)
+ return status;
+ if (!(status & ADT7410_STAT_NOT_RDY))
+ return 0;
+ msleep(60);
+ }
+ return -ETIMEDOUT;
+}
+
+static struct adt7410_data *adt7410_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7410_data *data = i2c_get_clientdata(client);
+ struct adt7410_data *ret = data;
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ int i, status;
+
+ dev_dbg(&client->dev, "Starting update\n");
+
+ status = adt7410_temp_ready(client); /* check for new value */
+ if (unlikely(status)) {
+ ret = ERR_PTR(status);
+ goto abort;
+ }
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ status = i2c_smbus_read_word_swapped(client,
+ ADT7410_REG_TEMP[i]);
+ if (unlikely(status < 0)) {
+ dev_dbg(dev,
+ "Failed to read value: reg %d, error %d\n",
+ ADT7410_REG_TEMP[i], status);
+ ret = ERR_PTR(status);
+ goto abort;
+ }
+ data->temp[i] = status;
+ }
+ status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+ if (unlikely(status < 0)) {
+ dev_dbg(dev,
+ "Failed to read value: reg %d, error %d\n",
+ ADT7410_T_HYST, status);
+ ret = ERR_PTR(status);
+ goto abort;
+ }
+ data->hyst = status;
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static s16 ADT7410_TEMP_TO_REG(long temp)
+{
+ return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
+ ADT7410_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+{
+ /* in 13 bit mode, bits 0-2 are status flags - mask them out */
+ if (!(data->config & ADT7410_RESOLUTION))
+ reg &= ADT7410_T13_VALUE_MASK;
+ /*
+ * temperature is stored in twos complement format, in steps of
+ * 1/128°C
+ */
+ return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7410_show_temp(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct adt7410_data *data = adt7410_update_device(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
+ data->temp[attr->index]));
+}
+
+static ssize_t adt7410_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 adt7410_data *data = i2c_get_clientdata(client);
+ int nr = attr->index;
+ long temp;
+ int ret;
+
+ ret = kstrtol(buf, 10, &temp);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
+ ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
+ data->temp[nr]);
+ if (ret)
+ count = ret;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct adt7410_data *data;
+ int nr = attr->index;
+ int hyst;
+
+ data = adt7410_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
+
+ /*
+ * hysteresis is stored as a 4 bit offset in the device, convert it
+ * to an absolute value
+ */
+ if (nr == 2) /* min has positive offset, others have negative */
+ hyst = -hyst;
+ return sprintf(buf, "%d\n",
+ ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7410_set_t_hyst(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7410_data *data = i2c_get_clientdata(client);
+ int limit, ret;
+ long hyst;
+
+ ret = kstrtol(buf, 10, &hyst);
+ if (ret)
+ return ret;
+ /* convert absolute hysteresis value to a 4 bit delta value */
+ limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
+ hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+ data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+ 0, ADT7410_T_HYST_MASK);
+ ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t adt7410_show_alarm(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ adt7410_show_temp, adt7410_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+ adt7410_show_temp, adt7410_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+ adt7410_show_temp, adt7410_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+ adt7410_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+ adt7410_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
+ NULL, ADT7410_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
+ NULL, ADT7410_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
+ NULL, ADT7410_STAT_T_CRIT);
+
+static struct attribute *adt7410_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.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,
+ NULL
+};
+
+static const struct attribute_group adt7410_group = {
+ .attrs = adt7410_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int adt7410_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7410_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* configure as specified */
+ ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "Can't read config? %d\n", ret);
+ return ret;
+ }
+ data->oldconfig = ret;
+ /*
+ * Set to 16 bit resolution, continous conversion and comparator mode.
+ */
+ data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
+ ADT7410_EVENT_MODE;
+ if (data->config != data->oldconfig) {
+ ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+ data->config);
+ if (ret)
+ return ret;
+ }
+ dev_dbg(&client->dev, "Config %02x\n", data->config);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
+ if (ret)
+ goto exit_restore;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&client->dev, "sensor '%s'\n", client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+exit_restore:
+ i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
+ return ret;
+}
+
+static int adt7410_remove(struct i2c_client *client)
+{
+ struct adt7410_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+ if (data->oldconfig != data->config)
+ i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+ data->oldconfig);
+ return 0;
+}
+
+static const struct i2c_device_id adt7410_ids[] = {
+ { "adt7410", adt7410, },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
+#ifdef CONFIG_PM
+static int adt7410_suspend(struct device *dev)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7410_data *data = i2c_get_clientdata(client);
+
+ ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+ data->config | ADT7410_PD);
+ return ret;
+}
+
+static int adt7410_resume(struct device *dev)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7410_data *data = i2c_get_clientdata(client);
+
+ ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
+ return ret;
+}
+
+static const struct dev_pm_ops adt7410_dev_pm_ops = {
+ .suspend = adt7410_suspend,
+ .resume = adt7410_resume,
+};
+#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
+#else
+#define ADT7410_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver adt7410_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "adt7410",
+ .pm = ADT7410_DEV_PM_OPS,
+ },
+ .probe = adt7410_probe,
+ .remove = adt7410_remove,
+ .id_table = adt7410_ids,
+ .address_list = normal_i2c,
+};
+
+module_i2c_driver(adt7410_driver);
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_LICENSE("GPL");
struct adt7411_data *data;
int ret;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
ADT7411_CFG1_START_MONITOR, 1);
if (ret < 0)
- goto exit_free;
+ return ret;
/* force update on first occasion */
data->next_update = jiffies;
ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
if (ret)
- goto exit_free;
+ return ret;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- exit_free:
- kfree(data);
return ret;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- kfree(data);
return 0;
}
struct adt7462_data *data;
int err;
- data = kzalloc(sizeof(struct adt7462_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct adt7462_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
data->attrs.attrs = adt7462_attr;
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- kfree(data);
return 0;
}
struct adt7470_data *data;
int err;
- data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct adt7470_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->num_temp_sensors = -1;
data->auto_update_interval = AUTO_UPDATE_INTERVAL;
data->attrs.attrs = adt7470_attr;
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
hwmon_device_unregister(data->hwmon_dev);
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
- kfree(data);
-exit:
return err;
}
wait_for_completion(&data->auto_update_stop);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- kfree(data);
return 0;
}
struct amc6821_data *data;
int err;
- data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "out of memory.\n");
+ data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
+ GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- }
-
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
*/
err = amc6821_init_client(client);
if (err)
- goto err_free;
+ return err;
err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
if (err)
- goto err_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (!IS_ERR(data->hwmon_dev))
err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
-err_free:
- kfree(data);
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
- kfree(data);
-
return 0;
}
int err;
struct asb100_data *data;
- data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
- if (!data) {
- pr_debug("probe failed, kzalloc failed!\n");
- err = -ENOMEM;
- goto ERROR0;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
/* Attach secondary lm75 clients */
err = asb100_detect_subclients(client);
if (err)
- goto ERROR1;
+ return err;
/* Initialize the chip */
asb100_init_client(client);
ERROR3:
i2c_unregister_device(data->lm75[1]);
i2c_unregister_device(data->lm75[0]);
-ERROR1:
- kfree(data);
-ERROR0:
return err;
}
i2c_unregister_device(data->lm75[1]);
i2c_unregister_device(data->lm75[0]);
- kfree(data);
-
return 0;
}
return 1;
out:
- kfree(sensor->acpi_name);
kfree(sensor);
return err;
}
struct device *dev = &client->dev;
int err;
- data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
data->type = id->driver_data;
err = dme1737_init_device(dev);
if (err) {
dev_err(dev, "Failed to initialize device.\n");
- goto exit_kfree;
+ return err;
}
/* Create sysfs files */
err = dme1737_create_files(dev);
if (err) {
dev_err(dev, "Failed to create sysfs files.\n");
- goto exit_kfree;
+ return err;
}
/* Register device */
exit_remove:
dme1737_remove_files(dev);
-exit_kfree:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
dme1737_remove_files(&client->dev);
- kfree(data);
return 0;
}
int err;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+ if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
(unsigned short)res->start,
(unsigned short)res->start + DME1737_EXTENT - 1);
- err = -EBUSY;
- goto exit;
+ return -EBUSY;
}
- data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit_release_region;
- }
+ data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->addr = res->start;
platform_set_drvdata(pdev, data);
(device == SCH5127_DEVICE)) {
data->type = sch5127;
} else {
- err = -ENODEV;
- goto exit_kfree;
+ return -ENODEV;
}
}
err = dme1737_init_device(dev);
if (err) {
dev_err(dev, "Failed to initialize device.\n");
- goto exit_kfree;
+ return err;
}
/* Create sysfs files */
err = dme1737_create_files(dev);
if (err) {
dev_err(dev, "Failed to create sysfs files.\n");
- goto exit_kfree;
+ return err;
}
/* Register device */
exit_remove_files:
dme1737_remove_files(dev);
-exit_kfree:
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-exit_release_region:
- release_region(res->start, DME1737_EXTENT);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
dme1737_remove_files(&pdev->dev);
- release_region(data->addr, DME1737_EXTENT);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
struct ds620_data *data;
int err;
- data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct ds620_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ds620_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &ds620_group);
-exit_free:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ds620_group);
- kfree(data);
-
return 0;
}
int res;
struct thermal_data *data;
- data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
- if (data == NULL) {
- dev_warn(&client->dev, "out of memory");
+ data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
+ GFP_KERNEL);
+ if (data == NULL)
return -ENOMEM;
- }
i2c_set_clientdata(client, data);
mutex_init(&data->mutex);
res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
if (res) {
dev_warn(&client->dev, "create group failed\n");
- goto thermal_error1;
+ return res;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
res = PTR_ERR(data->hwmon_dev);
dev_warn(&client->dev, "register hwmon dev failed\n");
- goto thermal_error2;
+ goto thermal_error;
}
dev_info(&client->dev, "EMC1403 Thermal chip found\n");
- return res;
+ return 0;
-thermal_error2:
+thermal_error:
sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-thermal_error1:
- kfree(data);
return res;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
- kfree(data);
return 0;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- data = kzalloc(sizeof(struct emc2103_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
if (status < 0) {
dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
status);
- goto exit_free;
+ return status;
}
/* detect current state of hardware */
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &emc2103_group);
if (status)
- goto exit_free;
+ return status;
if (data->temp_count >= 3) {
status = sysfs_create_group(&client->dev.kobj,
sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
exit_remove:
sysfs_remove_group(&client->dev.kobj, &emc2103_group);
-exit_free:
- kfree(data);
return status;
}
sysfs_remove_group(&client->dev.kobj, &emc2103_group);
- kfree(data);
return 0;
}
int err, i;
u8 start_reg, reg;
- data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
start_reg = f71882fg_read8(data, F71882FG_REG_START);
if (start_reg & 0x04) {
dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
- err = -ENODEV;
- goto exit_free;
+ return -ENODEV;
}
if (!(start_reg & 0x03)) {
dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
- err = -ENODEV;
- goto exit_free;
+ return -ENODEV;
}
/* Register sysfs interface files */
exit_unregister_sysfs:
f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
return err; /* f71882fg_remove() also frees our data */
-exit_free:
- kfree(data);
return err;
}
ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
}
}
-
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
-static int __init f71882fg_find(int sioaddr, unsigned short *address,
- struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
{
u16 devid;
+ unsigned short address;
int err = superio_enter(sioaddr);
if (err)
return err;
goto exit;
}
- *address = superio_inw(sioaddr, SIO_REG_ADDR);
- if (*address == 0) {
+ address = superio_inw(sioaddr, SIO_REG_ADDR);
+ if (address == 0) {
pr_warn("Base address not set\n");
err = -ENODEV;
goto exit;
}
- *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
+ address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
- err = 0;
+ err = address;
pr_info("Found %s chip at %#x, revision %d\n",
- f71882fg_names[sio_data->type], (unsigned int)*address,
+ f71882fg_names[sio_data->type], (unsigned int)address,
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
superio_exit(sioaddr);
return err;
}
-static int __init f71882fg_device_add(unsigned short address,
- const struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_device_add(int address,
+ const struct f71882fg_sio_data *sio_data)
{
struct resource res = {
.start = address,
static int __init f71882fg_init(void)
{
- int err = -ENODEV;
- unsigned short address;
+ int err;
+ int address;
struct f71882fg_sio_data sio_data;
memset(&sio_data, 0, sizeof(sio_data));
- if (f71882fg_find(0x2e, &address, &sio_data) &&
- f71882fg_find(0x4e, &address, &sio_data))
- goto exit;
+ address = f71882fg_find(0x2e, &sio_data);
+ if (address < 0)
+ address = f71882fg_find(0x4e, &sio_data);
+ if (address < 0)
+ return address;
err = platform_driver_register(&f71882fg_driver);
if (err)
- goto exit;
+ return err;
err = f71882fg_device_add(address, &sio_data);
if (err)
exit_driver:
platform_driver_unregister(&f71882fg_driver);
-exit:
return err;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
err = sysfs_create_group(&client->dev.kobj, &f75375_group);
if (err)
- goto exit_free;
+ return err;
if (data->kind != f75373) {
err = sysfs_chmod_file(&client->dev.kobj,
exit_remove:
sysfs_remove_group(&client->dev.kobj, &f75375_group);
-exit_free:
- kfree(data);
return err;
}
struct f75375_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &f75375_group);
- kfree(data);
return 0;
}
const struct pci_device_id *id)
{
struct fam15h_power_data *data;
- struct device *dev;
+ struct device *dev = &pdev->dev;
int err;
/*
*/
tweak_runavg_range(pdev);
- if (!fam15h_power_is_internal_node0(pdev)) {
- err = -ENODEV;
- goto exit;
- }
+ if (!fam15h_power_is_internal_node0(pdev))
+ return -ENODEV;
+
+ data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
fam15h_power_init_data(pdev, data);
- dev = &pdev->dev;
dev_set_drvdata(dev, data);
err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
if (err)
- goto exit_free_data;
+ return err;
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove_group:
sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-exit_free_data:
- kfree(data);
-exit:
return err;
}
data = dev_get_drvdata(dev);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
- dev_set_drvdata(dev, NULL);
- kfree(data);
}
static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- data = kzalloc(sizeof(struct g760a_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct g760a_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &g760a_group);
if (err)
- goto error_sysfs_create_group;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
error_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, &g760a_group);
-error_sysfs_create_group:
- kfree(data);
-
return err;
}
struct g760a_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &g760a_group);
- kfree(data);
-
return 0;
}
* Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
* Datasheet: http://www.ti.com/product/ina219
*
+ * INA220:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina220
+ *
* INA226:
* Bi-Directional Current/Power Monitor with I2C Interface
* Datasheet: http://www.ti.com/product/ina226
*
+ * INA230:
+ * Bi-directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina230
+ *
* Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
* Thanks to Jan Volkering
*
enum ina2xx_ids { ina219, ina226 };
+struct ina2xx_config {
+ u16 config_default;
+ int calibration_factor;
+ int registers;
+ int shunt_div;
+ int bus_voltage_shift;
+ int bus_voltage_lsb; /* uV */
+ int power_lsb; /* uW */
+};
+
struct ina2xx_data {
struct device *hwmon_dev;
+ const struct ina2xx_config *config;
struct mutex update_lock;
bool valid;
unsigned long last_updated;
int kind;
- int registers;
u16 regs[INA2XX_MAX_REGISTERS];
};
+static const struct ina2xx_config ina2xx_config[] = {
+ [ina219] = {
+ .config_default = INA219_CONFIG_DEFAULT,
+ .calibration_factor = 40960000,
+ .registers = INA219_REGISTERS,
+ .shunt_div = 100,
+ .bus_voltage_shift = 3,
+ .bus_voltage_lsb = 4000,
+ .power_lsb = 20000,
+ },
+ [ina226] = {
+ .config_default = INA226_CONFIG_DEFAULT,
+ .calibration_factor = 5120000,
+ .registers = INA226_REGISTERS,
+ .shunt_div = 400,
+ .bus_voltage_shift = 0,
+ .bus_voltage_lsb = 1250,
+ .power_lsb = 25000,
+ },
+};
+
static struct ina2xx_data *ina2xx_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(&client->dev, "Starting ina2xx update\n");
/* Read all registers */
- for (i = 0; i < data->registers; i++) {
+ for (i = 0; i < data->config->registers; i++) {
int rv = i2c_smbus_read_word_swapped(client, i);
if (rv < 0) {
ret = ERR_PTR(rv);
return ret;
}
-static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
{
- /*
- * calculate exact value for the given register
- * we assume default power-on reset settings:
- * bus voltage range 32V
- * gain = /8
- * adc 1 & 2 -> conversion time 532uS
- * mode is continuous shunt and bus
- * calibration value is INA219_CALIBRATION_VALUE
- */
- int val = data->regs[reg];
+ int val;
switch (reg) {
case INA2XX_SHUNT_VOLTAGE:
- /* LSB=10uV. Convert to mV. */
- val = DIV_ROUND_CLOSEST(val, 100);
+ val = DIV_ROUND_CLOSEST(data->regs[reg],
+ data->config->shunt_div);
break;
case INA2XX_BUS_VOLTAGE:
- /* LSB=4mV. Register is not right aligned, convert to mV. */
- val = (val >> 3) * 4;
+ val = (data->regs[reg] >> data->config->bus_voltage_shift)
+ * data->config->bus_voltage_lsb;
+ val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_POWER:
- /* LSB=20mW. Convert to uW */
- val = val * 20 * 1000;
- break;
- case INA2XX_CURRENT:
- /* LSB=1mA (selected). Is in mA */
- break;
- default:
- /* programmer goofed */
- WARN_ON_ONCE(1);
- val = 0;
- break;
- }
-
- return val;
-}
-
-static int ina226_get_value(struct ina2xx_data *data, u8 reg)
-{
- /*
- * calculate exact value for the given register
- * we assume default power-on reset settings:
- * bus voltage range 32V
- * gain = /8
- * adc 1 & 2 -> conversion time 532uS
- * mode is continuous shunt and bus
- * calibration value is INA226_CALIBRATION_VALUE
- */
- int val = data->regs[reg];
-
- switch (reg) {
- case INA2XX_SHUNT_VOLTAGE:
- /* LSB=2.5uV. Convert to mV. */
- val = DIV_ROUND_CLOSEST(val, 400);
- break;
- case INA2XX_BUS_VOLTAGE:
- /* LSB=1.25mV. Convert to mV. */
- val = val + DIV_ROUND_CLOSEST(val, 4);
- break;
- case INA2XX_POWER:
- /* LSB=25mW. Convert to uW */
- val = val * 25 * 1000;
+ val = data->regs[reg] * data->config->power_lsb;
break;
case INA2XX_CURRENT:
/* LSB=1mA (selected). Is in mA */
+ val = data->regs[reg];
break;
default:
/* programmer goofed */
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ina2xx_data *data = ina2xx_update_device(dev);
- int value = 0;
if (IS_ERR(data))
return PTR_ERR(data);
- switch (data->kind) {
- case ina219:
- value = ina219_get_value(data, attr->index);
- break;
- case ina226:
- value = ina226_get_value(data, attr->index);
- break;
- default:
- WARN_ON_ONCE(1);
- break;
- }
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ina2xx_get_value(data, attr->index));
}
/* shunt voltage */
struct i2c_adapter *adapter = client->adapter;
struct ina2xx_data *data;
struct ina2xx_platform_data *pdata;
- int ret = 0;
+ int ret;
long shunt = 10000; /* default shunt value 10mOhms */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
/* set the device type */
data->kind = id->driver_data;
+ data->config = &ina2xx_config[data->kind];
- switch (data->kind) {
- case ina219:
- /* device configuration */
- i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- INA219_CONFIG_DEFAULT);
-
- /* set current LSB to 1mA, shunt is in uOhms */
- /* (equation 13 in datasheet) */
- i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- 40960000 / shunt);
- dev_info(&client->dev,
- "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
- data->registers = INA219_REGISTERS;
- break;
- case ina226:
- /* device configuration */
- i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- INA226_CONFIG_DEFAULT);
-
- /* set current LSB to 1mA, shunt is in uOhms */
- /* (equation 1 in datasheet)*/
- i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- 5120000 / shunt);
- dev_info(&client->dev,
- "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
- data->registers = INA226_REGISTERS;
- break;
- default:
- /* unknown device id */
- return -ENODEV;
- }
+ /* device configuration */
+ i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+ data->config->config_default);
+ /* set current LSB to 1mA, shunt is in uOhms */
+ /* (equation 13 in datasheet) */
+ i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / shunt);
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
goto out_err_hwmon;
}
+ dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n",
+ id->name, shunt);
+
return 0;
out_err_hwmon:
static const struct i2c_device_id ina2xx_id[] = {
{ "ina219", ina219 },
+ { "ina220", ina219 },
{ "ina226", ina226 },
+ { "ina230", ina226 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/completion.h>
#include <linux/mfd/core.h>
int ret;
struct jz4740_hwmon *hwmon;
- hwmon = kmalloc(sizeof(*hwmon), GFP_KERNEL);
- if (!hwmon) {
- dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+ if (!hwmon)
return -ENOMEM;
- }
hwmon->cell = mfd_get_cell(pdev);
hwmon->irq = platform_get_irq(pdev, 0);
if (hwmon->irq < 0) {
- ret = hwmon->irq;
- dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
- goto err_free;
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+ hwmon->irq);
+ return hwmon->irq;
}
hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!hwmon->mem) {
- ret = -ENOENT;
dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
- goto err_free;
+ return -ENOENT;
}
- hwmon->mem = request_mem_region(hwmon->mem->start,
+ hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
resource_size(hwmon->mem), pdev->name);
if (!hwmon->mem) {
- ret = -EBUSY;
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
- goto err_free;
+ return -EBUSY;
}
- hwmon->base = ioremap_nocache(hwmon->mem->start,
- resource_size(hwmon->mem));
+ hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
+ resource_size(hwmon->mem));
if (!hwmon->base) {
- ret = -EBUSY;
dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
- goto err_release_mem_region;
+ return -EBUSY;
}
init_completion(&hwmon->read_completion);
platform_set_drvdata(pdev, hwmon);
- ret = request_irq(hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon);
+ ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
+ pdev->name, hwmon);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
- goto err_iounmap;
+ return ret;
}
disable_irq(hwmon->irq);
ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
if (ret) {
dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
- goto err_free_irq;
+ return ret;
}
hwmon->hwmon = hwmon_device_register(&pdev->dev);
err_remove_file:
sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
-err_free_irq:
- free_irq(hwmon->irq, hwmon);
-err_iounmap:
- platform_set_drvdata(pdev, NULL);
- iounmap(hwmon->base);
-err_release_mem_region:
- release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-err_free:
- kfree(hwmon);
-
return ret;
}
hwmon_device_unregister(hwmon->hwmon);
sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
- free_irq(hwmon->irq, hwmon);
-
- iounmap(hwmon->base);
- release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-
- platform_set_drvdata(pdev, NULL);
- kfree(hwmon);
-
return 0;
}
#define LM70_CHIP_LM70 0 /* original NS LM70 */
#define LM70_CHIP_TMP121 1 /* TI TMP121/TMP123 */
+#define LM70_CHIP_LM71 2 /* NS LM71 */
+#define LM70_CHIP_LM74 3 /* NS LM74 */
struct lm70 {
struct device *hwmon_dev;
* Celsius.
* So it's equivalent to multiplying by 0.25 * 1000 = 250.
*
- * TMP121/TMP123:
+ * LM74 and TMP121/TMP123:
* 13 bits of 2's complement data, discard LSB 3 bits,
* resolution 0.0625 degrees celsius.
+ *
+ * LM71:
+ * 14 bits of 2's complement data, discard LSB 2 bits,
+ * resolution 0.0312 degrees celsius.
*/
switch (p_lm70->chip) {
case LM70_CHIP_LM70:
break;
case LM70_CHIP_TMP121:
+ case LM70_CHIP_LM74:
val = ((int)raw / 8) * 625 / 10;
break;
+
+ case LM70_CHIP_LM71:
+ val = ((int)raw / 4) * 3125 / 100;
+ break;
}
status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
static ssize_t lm70_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
- struct lm70 *p_lm70 = dev_get_drvdata(dev);
- int ret;
-
- switch (p_lm70->chip) {
- case LM70_CHIP_LM70:
- ret = sprintf(buf, "lm70\n");
- break;
- case LM70_CHIP_TMP121:
- ret = sprintf(buf, "tmp121\n");
- break;
- default:
- ret = -EINVAL;
- }
- return ret;
+ return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
struct lm70 *p_lm70;
int status;
- /* signaling is SPI_MODE_0 for both LM70 and TMP121 */
+ /* signaling is SPI_MODE_0 */
if (spi->mode & (SPI_CPOL | SPI_CPHA))
return -EINVAL;
- /* 3-wire link (shared SI/SO) for LM70 */
- if (chip == LM70_CHIP_LM70 && !(spi->mode & SPI_3WIRE))
- return -EINVAL;
-
/* NOTE: we assume 8-bit words, and convert to 16 bits manually */
- p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
+ p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL);
if (!p_lm70)
return -ENOMEM;
device_remove_file(&spi->dev, &dev_attr_temp1_input);
out_dev_create_temp_file_failed:
spi_set_drvdata(spi, NULL);
- kfree(p_lm70);
return status;
}
device_remove_file(&spi->dev, &dev_attr_temp1_input);
device_remove_file(&spi->dev, &dev_attr_name);
spi_set_drvdata(spi, NULL);
- kfree(p_lm70);
return 0;
}
static const struct spi_device_id lm70_ids[] = {
{ "lm70", LM70_CHIP_LM70 },
{ "tmp121", LM70_CHIP_TMP121 },
+ { "lm71", LM70_CHIP_LM71 },
+ { "lm74", LM70_CHIP_LM74 },
{ },
};
MODULE_DEVICE_TABLE(spi, lm70_ids);
module_spi_driver(lm70_driver);
MODULE_AUTHOR("Kaiwan N Billimoria");
-MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
+MODULE_DESCRIPTION("NS LM70 and compatibles Linux driver");
MODULE_LICENSE("GPL");
mutex_lock(&data->update_lock);
/* sanity test, ignore the write otherwise */
- if (0 <= val && val <= 2) {
+ if (val <= 2) {
/* can't enable if pwm freq is 22.5KHz */
if (val) {
u8 ctl4 = lm93_read_byte(client,
struct lm95241_data *data;
int err;
- data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(new_client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
-exit_free:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm95241_group);
- kfree(data);
return 0;
}
struct lm95245_data *data;
int err;
- data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(new_client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
-exit_free:
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm95245_group);
- kfree(data);
return 0;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto out_kzalloc;
- }
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
ret = sysfs_create_group(&client->dev.kobj, <c4151_group);
if (ret)
- goto out_sysfs_create_group;
+ return ret;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
out_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, <c4151_group);
-out_sysfs_create_group:
- kfree(data);
-out_kzalloc:
return ret;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, <c4151_group);
- kfree(data);
-
return 0;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto out_kzalloc;
- }
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
ret = sysfs_create_group(&client->dev.kobj, <c4215_group);
if (ret)
- goto out_sysfs_create_group;
+ return ret;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
out_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, <c4215_group);
-out_sysfs_create_group:
- kfree(data);
-out_kzalloc:
return ret;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, <c4215_group);
- kfree(data);
-
return 0;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto out_kzalloc;
- }
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Register sysfs hooks */
ret = ltc4245_sysfs_create_groups(client);
if (ret)
- goto out_sysfs_create_groups;
+ return ret;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
out_hwmon_device_register:
ltc4245_sysfs_remove_groups(client);
-out_sysfs_create_groups:
- kfree(data);
-out_kzalloc:
return ret;
}
hwmon_device_unregister(data->hwmon_dev);
ltc4245_sysfs_remove_groups(client);
- kfree(data);
return 0;
}
#include <linux/spi/spi.h>
#include <linux/slab.h>
+enum chips { max1110, max1111, max1112, max1113 };
+
#define MAX1111_TX_BUF_SIZE 1
#define MAX1111_RX_BUF_SIZE 2
#define MAX1111_CTRL_PD1 (1u << 1)
#define MAX1111_CTRL_SGL (1u << 2)
#define MAX1111_CTRL_UNI (1u << 3)
+#define MAX1110_CTRL_SEL_SH (4)
#define MAX1111_CTRL_SEL_SH (5) /* NOTE: bit 4 is ignored */
#define MAX1111_CTRL_STR (1u << 7)
uint8_t rx_buf[MAX1111_RX_BUF_SIZE];
struct mutex drvdata_lock;
/* protect msg, xfer and buffers from multiple access */
+ int sel_sh;
+ int lsb;
};
static int max1111_read(struct device *dev, int channel)
/* writing to drvdata struct is not thread safe, wait on mutex */
mutex_lock(&data->drvdata_lock);
- data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) |
+ data->tx_buf[0] = (channel << data->sel_sh) |
MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 |
MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR;
static ssize_t show_name(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "max1111\n");
+ return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
static ssize_t show_adc(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct max1111_data *data = dev_get_drvdata(dev);
int channel = to_sensor_dev_attr(attr)->index;
int ret;
return ret;
/*
- * assume the reference voltage to be 2.048V, with an 8-bit sample,
- * the LSB weight is 8mV
+ * Assume the reference voltage to be 2.048V or 4.096V, with an 8-bit
+ * sample. The LSB weight is 8mV or 16mV depending on the chip type.
*/
- return sprintf(buf, "%d\n", ret * 8);
+ return sprintf(buf, "%d\n", ret * data->lsb);
}
#define MAX1111_ADC_ATTR(_id) \
static MAX1111_ADC_ATTR(1);
static MAX1111_ADC_ATTR(2);
static MAX1111_ADC_ATTR(3);
+static MAX1111_ADC_ATTR(4);
+static MAX1111_ADC_ATTR(5);
+static MAX1111_ADC_ATTR(6);
+static MAX1111_ADC_ATTR(7);
static struct attribute *max1111_attributes[] = {
&dev_attr_name.attr,
.attrs = max1111_attributes,
};
+static struct attribute *max1110_attributes[] = {
+ &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_in7_input.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group max1110_attr_group = {
+ .attrs = max1110_attributes,
+};
+
static int __devinit setup_transfer(struct max1111_data *data)
{
struct spi_message *m;
static int __devinit max1111_probe(struct spi_device *spi)
{
+ enum chips chip = spi_get_device_id(spi)->driver_data;
struct max1111_data *data;
int err;
return -ENOMEM;
}
+ switch (chip) {
+ case max1110:
+ data->lsb = 8;
+ data->sel_sh = MAX1110_CTRL_SEL_SH;
+ break;
+ case max1111:
+ data->lsb = 8;
+ data->sel_sh = MAX1111_CTRL_SEL_SH;
+ break;
+ case max1112:
+ data->lsb = 16;
+ data->sel_sh = MAX1110_CTRL_SEL_SH;
+ break;
+ case max1113:
+ data->lsb = 16;
+ data->sel_sh = MAX1111_CTRL_SEL_SH;
+ break;
+ }
err = setup_transfer(data);
if (err)
return err;
dev_err(&spi->dev, "failed to create attribute group\n");
return err;
}
+ if (chip == max1110 || chip == max1112) {
+ err = sysfs_create_group(&spi->dev.kobj, &max1110_attr_group);
+ if (err) {
+ dev_err(&spi->dev,
+ "failed to create extended attribute group\n");
+ goto err_remove;
+ }
+ }
data->hwmon_dev = hwmon_device_register(&spi->dev);
if (IS_ERR(data->hwmon_dev)) {
return 0;
err_remove:
+ sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
return err;
}
struct max1111_data *data = spi_get_drvdata(spi);
hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
mutex_destroy(&data->drvdata_lock);
return 0;
}
+static const struct spi_device_id max1111_ids[] = {
+ { "max1110", max1110 },
+ { "max1111", max1111 },
+ { "max1112", max1112 },
+ { "max1113", max1113 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, max1111_ids);
+
static struct spi_driver max1111_driver = {
.driver = {
.name = "max1111",
.owner = THIS_MODULE,
},
+ .id_table = max1111_ids,
.probe = max1111_probe,
.remove = __devexit_p(max1111_remove),
};
module_spi_driver(max1111_driver);
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
-MODULE_DESCRIPTION("MAX1111 ADC Driver");
+MODULE_DESCRIPTION("MAX1110/MAX1111/MAX1112/MAX1113 ADC Driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:max1111");
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
if (err)
- goto error_free;
+ return err;
if (data->type == max1668 || data->type == max1989) {
err = sysfs_create_group(&client->dev.kobj,
sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
error_sysrem0:
sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-error_free:
- kfree(data);
return err;
}
sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
- kfree(data);
return 0;
}
--- /dev/null
+/*
+ * Maxim MAX197 A/D Converter driver
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/max197 file.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/max197.h>
+
+#define MAX199_LIMIT 4000 /* 4V */
+#define MAX197_LIMIT 10000 /* 10V */
+
+#define MAX197_NUM_CH 8 /* 8 Analog Input Channels */
+
+/* Control byte format */
+#define MAX197_BIP (1 << 3) /* Bipolarity */
+#define MAX197_RNG (1 << 4) /* Full range */
+
+#define MAX197_SCALE 12207 /* Scale coefficient for raw data */
+
+/* List of supported chips */
+enum max197_chips { max197, max199 };
+
+/**
+ * struct max197_data - device instance specific data
+ * @pdata: Platform data.
+ * @hwmon_dev: The hwmon device.
+ * @lock: Read/Write mutex.
+ * @limit: Max range value (10V for MAX197, 4V for MAX199).
+ * @scale: Need to scale.
+ * @ctrl_bytes: Channels control byte.
+ */
+struct max197_data {
+ struct max197_platform_data *pdata;
+ struct device *hwmon_dev;
+ struct mutex lock;
+ int limit;
+ bool scale;
+ u8 ctrl_bytes[MAX197_NUM_CH];
+};
+
+static inline void max197_set_unipolarity(struct max197_data *data, int channel)
+{
+ data->ctrl_bytes[channel] &= ~MAX197_BIP;
+}
+
+static inline void max197_set_bipolarity(struct max197_data *data, int channel)
+{
+ data->ctrl_bytes[channel] |= MAX197_BIP;
+}
+
+static inline void max197_set_half_range(struct max197_data *data, int channel)
+{
+ data->ctrl_bytes[channel] &= ~MAX197_RNG;
+}
+
+static inline void max197_set_full_range(struct max197_data *data, int channel)
+{
+ data->ctrl_bytes[channel] |= MAX197_RNG;
+}
+
+static inline bool max197_is_bipolar(struct max197_data *data, int channel)
+{
+ return data->ctrl_bytes[channel] & MAX197_BIP;
+}
+
+static inline bool max197_is_full_range(struct max197_data *data, int channel)
+{
+ return data->ctrl_bytes[channel] & MAX197_RNG;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_show_range(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct max197_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int channel = attr->index;
+ bool is_min = attr->nr;
+ int range;
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -ERESTARTSYS;
+
+ range = max197_is_full_range(data, channel) ?
+ data->limit : data->limit / 2;
+ if (is_min) {
+ if (max197_is_bipolar(data, channel))
+ range = -range;
+ else
+ range = 0;
+ }
+
+ mutex_unlock(&data->lock);
+
+ return sprintf(buf, "%d\n", range);
+}
+
+/* Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_store_range(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct max197_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int channel = attr->index;
+ bool is_min = attr->nr;
+ long value;
+ int half = data->limit / 2;
+ int full = data->limit;
+
+ if (kstrtol(buf, 10, &value))
+ return -EINVAL;
+
+ if (is_min) {
+ if (value <= -full)
+ value = -full;
+ else if (value < 0)
+ value = -half;
+ else
+ value = 0;
+ } else {
+ if (value >= full)
+ value = full;
+ else
+ value = half;
+ }
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -ERESTARTSYS;
+
+ if (value == 0) {
+ /* We can deduce only the polarity */
+ max197_set_unipolarity(data, channel);
+ } else if (value == -half) {
+ max197_set_bipolarity(data, channel);
+ max197_set_half_range(data, channel);
+ } else if (value == -full) {
+ max197_set_bipolarity(data, channel);
+ max197_set_full_range(data, channel);
+ } else if (value == half) {
+ /* We can deduce only the range */
+ max197_set_half_range(data, channel);
+ } else if (value == full) {
+ /* We can deduce only the range */
+ max197_set_full_range(data, channel);
+ }
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_input */
+static ssize_t max197_show_input(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct max197_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int channel = attr->index;
+ s32 value;
+ int ret;
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -ERESTARTSYS;
+
+ ret = data->pdata->convert(data->ctrl_bytes[channel]);
+ if (ret < 0) {
+ dev_err(dev, "conversion failed\n");
+ goto unlock;
+ }
+ value = ret;
+
+ /*
+ * Coefficient to apply on raw value.
+ * See Table 1. Full Scale and Zero Scale in the MAX197 datasheet.
+ */
+ if (data->scale) {
+ value *= MAX197_SCALE;
+ if (max197_is_full_range(data, channel))
+ value *= 2;
+ value /= 10000;
+ }
+
+ ret = sprintf(buf, "%d\n", value);
+
+unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static ssize_t max197_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ return sprintf(buf, "%s\n", pdev->name);
+}
+
+#define MAX197_SENSOR_DEVICE_ATTR_CH(chan) \
+ static SENSOR_DEVICE_ATTR(in##chan##_input, S_IRUGO, \
+ max197_show_input, NULL, chan); \
+ static SENSOR_DEVICE_ATTR_2(in##chan##_min, S_IRUGO | S_IWUSR, \
+ max197_show_range, \
+ max197_store_range, \
+ true, chan); \
+ static SENSOR_DEVICE_ATTR_2(in##chan##_max, S_IRUGO | S_IWUSR, \
+ max197_show_range, \
+ max197_store_range, \
+ false, chan)
+
+#define MAX197_SENSOR_DEV_ATTR_IN(chan) \
+ &sensor_dev_attr_in##chan##_input.dev_attr.attr, \
+ &sensor_dev_attr_in##chan##_max.dev_attr.attr, \
+ &sensor_dev_attr_in##chan##_min.dev_attr.attr
+
+static DEVICE_ATTR(name, S_IRUGO, max197_show_name, NULL);
+
+MAX197_SENSOR_DEVICE_ATTR_CH(0);
+MAX197_SENSOR_DEVICE_ATTR_CH(1);
+MAX197_SENSOR_DEVICE_ATTR_CH(2);
+MAX197_SENSOR_DEVICE_ATTR_CH(3);
+MAX197_SENSOR_DEVICE_ATTR_CH(4);
+MAX197_SENSOR_DEVICE_ATTR_CH(5);
+MAX197_SENSOR_DEVICE_ATTR_CH(6);
+MAX197_SENSOR_DEVICE_ATTR_CH(7);
+
+static const struct attribute_group max197_sysfs_group = {
+ .attrs = (struct attribute *[]) {
+ &dev_attr_name.attr,
+ MAX197_SENSOR_DEV_ATTR_IN(0),
+ MAX197_SENSOR_DEV_ATTR_IN(1),
+ MAX197_SENSOR_DEV_ATTR_IN(2),
+ MAX197_SENSOR_DEV_ATTR_IN(3),
+ MAX197_SENSOR_DEV_ATTR_IN(4),
+ MAX197_SENSOR_DEV_ATTR_IN(5),
+ MAX197_SENSOR_DEV_ATTR_IN(6),
+ MAX197_SENSOR_DEV_ATTR_IN(7),
+ NULL
+ },
+};
+
+static int __devinit max197_probe(struct platform_device *pdev)
+{
+ int ch, ret;
+ struct max197_data *data;
+ struct max197_platform_data *pdata = pdev->dev.platform_data;
+ enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "no platform data supplied\n");
+ return -EINVAL;
+ }
+
+ if (pdata->convert == NULL) {
+ dev_err(&pdev->dev, "no convert function supplied\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "devm_kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ data->pdata = pdata;
+ mutex_init(&data->lock);
+
+ if (chip == max197) {
+ data->limit = MAX197_LIMIT;
+ data->scale = true;
+ } else {
+ data->limit = MAX199_LIMIT;
+ data->scale = false;
+ }
+
+ for (ch = 0; ch < MAX197_NUM_CH; ch++)
+ data->ctrl_bytes[ch] = (u8) ch;
+
+ platform_set_drvdata(pdev, data);
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &max197_sysfs_group);
+ if (ret) {
+ dev_err(&pdev->dev, "sysfs create group failed\n");
+ return ret;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "hwmon device register failed\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+ return ret;
+}
+
+static int __devexit max197_remove(struct platform_device *pdev)
+{
+ struct max197_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+
+ return 0;
+}
+
+static struct platform_device_id max197_device_ids[] = {
+ { "max197", max197 },
+ { "max199", max199 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max197_device_ids);
+
+static struct platform_driver max197_driver = {
+ .driver = {
+ .name = "max197",
+ .owner = THIS_MODULE,
+ },
+ .probe = max197_probe,
+ .remove = __devexit_p(max197_remove),
+ .id_table = max197_device_ids,
+};
+module_platform_driver(max197_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");
/*
- * mcp3021.c - driver for the Microchip MCP3021 chip
+ * mcp3021.c - driver for Microchip MCP3021 and MCP3221
*
* Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
* Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
*
* This driver export the value of analog input voltage to sysfs, the
* voltage unit is mV. Through the sysfs interface, lm-sensors tool
#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */
#define MCP3021_OUTPUT_SCALE 4
+#define MCP3221_SAR_SHIFT 0
+#define MCP3221_SAR_MASK 0xfff
+#define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */
+#define MCP3221_OUTPUT_SCALE 1
+
+enum chips {
+ mcp3021,
+ mcp3221
+};
+
/*
* Client data (each client gets its own)
*/
struct mcp3021_data {
struct device *hwmon_dev;
u32 vdd; /* device power supply */
+ u16 sar_shift;
+ u16 sar_mask;
+ u8 output_res;
+ u8 output_scale;
};
static int mcp3021_read16(struct i2c_client *client)
{
+ struct mcp3021_data *data = i2c_get_clientdata(client);
int ret;
u16 reg;
__be16 buf;
* The ten-bit output code is composed of the lower 4-bit of the
* first byte and the upper 6-bit of the second byte.
*/
- reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
+ reg = (reg >> data->sar_shift) & data->sar_mask;
return reg;
}
-static inline u16 volts_from_reg(u16 vdd, u16 val)
+static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
{
if (val == 0)
return 0;
- val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
+ val = val * data->output_scale - data->output_scale / 2;
- return val * DIV_ROUND_CLOSEST(vdd,
- (1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
+ return val * DIV_ROUND_CLOSEST(data->vdd,
+ (1 << data->output_res) * data->output_scale);
}
static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
if (reg < 0)
return reg;
- in_input = volts_from_reg(data->vdd, reg);
+ in_input = volts_from_reg(data, reg);
+
return sprintf(buf, "%d\n", in_input);
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
+ switch (id->driver_data) {
+ case mcp3021:
+ data->sar_shift = MCP3021_SAR_SHIFT;
+ data->sar_mask = MCP3021_SAR_MASK;
+ data->output_res = MCP3021_OUTPUT_RES;
+ data->output_scale = MCP3021_OUTPUT_SCALE;
+ break;
+
+ case mcp3221:
+ data->sar_shift = MCP3221_SAR_SHIFT;
+ data->sar_mask = MCP3221_SAR_MASK;
+ data->output_res = MCP3221_OUTPUT_RES;
+ data->output_scale = MCP3221_OUTPUT_SCALE;
+ break;
+ }
+
if (client->dev.platform_data) {
data->vdd = *(u32 *)client->dev.platform_data;
- if (data->vdd > MCP3021_VDD_MAX ||
- data->vdd < MCP3021_VDD_MIN) {
- err = -EINVAL;
- goto exit_free;
- }
+ if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
+ return -EINVAL;
} else
data->vdd = MCP3021_VDD_REF;
err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
if (err)
- goto exit_free;
+ return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
exit_remove:
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-exit_free:
- kfree(data);
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
- kfree(data);
return 0;
}
static const struct i2c_device_id mcp3021_id[] = {
- { "mcp3021", 0 },
+ { "mcp3021", mcp3021 },
+ { "mcp3221", mcp3221 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3021_id);
module_i2c_driver(mcp3021_driver);
MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
-MODULE_DESCRIPTION("Microchip MCP3021 driver");
+MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver");
MODULE_LICENSE("GPL");
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
struct sch5627_data *data;
int err, build_code, build_id, hwmon_rev, val;
- data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
device_remove_file(&pdev->dev,
&sch5636_fan_attr[i].dev_attr);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
int i, err, val, revision[2];
char id[4];
- data = kzalloc(sizeof(struct sch5636_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct sch5636_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
* platform dev find, add and remove functions
*/
-static int __init sch56xx_find(int sioaddr, unsigned short *address,
- const char **name)
+static int __init sch56xx_find(int sioaddr, const char **name)
{
u8 devid;
+ unsigned short address;
int err;
err = superio_enter(sioaddr);
* Warning the order of the low / high byte is the other way around
* as on most other superio devices!!
*/
- *address = superio_inb(sioaddr, SIO_REG_ADDR) |
+ address = superio_inb(sioaddr, SIO_REG_ADDR) |
superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
- if (*address == 0) {
+ if (address == 0) {
pr_warn("Base address not set\n");
err = -ENODEV;
goto exit;
}
+ err = address;
exit:
superio_exit(sioaddr);
return err;
}
-static int __init sch56xx_device_add(unsigned short address, const char *name)
+static int __init sch56xx_device_add(int address, const char *name)
{
struct resource res = {
.start = address,
static int __init sch56xx_init(void)
{
- int err;
- unsigned short address;
- const char *name;
-
- err = sch56xx_find(0x4e, &address, &name);
- if (err)
- err = sch56xx_find(0x2e, &address, &name);
- if (err)
- return err;
+ int address;
+ const char *name = NULL;
+
+ address = sch56xx_find(0x4e, &name);
+ if (address < 0)
+ address = sch56xx_find(0x2e, &name);
+ if (address < 0)
+ return address;
return sch56xx_device_add(address, name);
}
/*
* sht15.c - support for the SHT15 Temperature and Humidity Sensor
*
- * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ * Portions Copyright (c) 2010-2012 Savoir-faire Linux Inc.
* Jerome Oufella <jerome.oufella@savoirfairelinux.com>
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/mutex.h>
+#include <linux/platform_data/sht15.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/err.h>
-#include <linux/sht15.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#define SHT15_STATUS_HEATER 0x04
#define SHT15_STATUS_LOW_BATTERY 0x40
+/* List of supported chips */
+enum sht15_chips { sht10, sht11, sht15, sht71, sht75 };
+
/* Actions the driver may be doing */
enum sht15_state {
SHT15_READING_NOTHING,
static int __devinit sht15_probe(struct platform_device *pdev)
{
int ret;
- struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ struct sht15_data *data;
u8 status = 0;
- if (!data) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "kzalloc failed\n");
- goto error_ret;
- }
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
INIT_WORK(&data->read_work, sht15_bh_read_data);
INIT_WORK(&data->update_supply_work, sht15_update_voltage);
init_waitqueue_head(&data->wait_queue);
if (pdev->dev.platform_data == NULL) {
- ret = -EINVAL;
dev_err(&pdev->dev, "no platform data supplied\n");
- goto err_free_data;
+ return -EINVAL;
}
data->pdata = pdev->dev.platform_data;
data->supply_uV = data->pdata->supply_mv * 1000;
* If a regulator is available,
* query what the supply voltage actually is!
*/
- data->reg = regulator_get(data->dev, "vcc");
+ data->reg = devm_regulator_get(data->dev, "vcc");
if (!IS_ERR(data->reg)) {
int voltage;
dev_err(&pdev->dev,
"regulator notifier request failed\n");
regulator_disable(data->reg);
- regulator_put(data->reg);
- goto err_free_data;
+ return ret;
}
}
/* Try requesting the GPIOs */
- ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
+ ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
if (ret) {
dev_err(&pdev->dev, "gpio request failed\n");
goto err_release_reg;
}
gpio_direction_output(data->pdata->gpio_sck, 0);
- ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
+ ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
+ "SHT15 data");
if (ret) {
dev_err(&pdev->dev, "gpio request failed\n");
- goto err_release_gpio_sck;
+ goto err_release_reg;
}
- ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
- sht15_interrupt_fired,
- IRQF_TRIGGER_FALLING,
- "sht15 data",
- data);
+ ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+ sht15_interrupt_fired,
+ IRQF_TRIGGER_FALLING,
+ "sht15 data",
+ data);
if (ret) {
dev_err(&pdev->dev, "failed to get irq for data line\n");
- goto err_release_gpio_data;
+ goto err_release_reg;
}
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
sht15_connection_reset(data);
ret = sht15_soft_reset(data);
if (ret)
- goto err_release_irq;
+ goto err_release_reg;
/* write status with platform data options */
if (status) {
ret = sht15_send_status(data, status);
if (ret)
- goto err_release_irq;
+ goto err_release_reg;
}
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");
- goto err_release_irq;
+ goto err_release_reg;
}
data->hwmon_dev = hwmon_device_register(data->dev);
err_release_sysfs_group:
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
-err_release_irq:
- free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-err_release_gpio_data:
- gpio_free(data->pdata->gpio_data);
-err_release_gpio_sck:
- gpio_free(data->pdata->gpio_sck);
err_release_reg:
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
regulator_disable(data->reg);
- regulator_put(data->reg);
}
-err_free_data:
- kfree(data);
-error_ret:
return ret;
}
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
regulator_disable(data->reg);
- regulator_put(data->reg);
}
- free_irq(gpio_to_irq(data->pdata->gpio_data), data);
- gpio_free(data->pdata->gpio_data);
- gpio_free(data->pdata->gpio_sck);
mutex_unlock(&data->read_lock);
- kfree(data);
return 0;
}
-/*
- * sht_drivers simultaneously refers to __devinit and __devexit function
- * which causes spurious section mismatch warning. So use __refdata to
- * get rid from this.
- */
-static struct platform_driver __refdata sht_drivers[] = {
- {
- .driver = {
- .name = "sht10",
- .owner = THIS_MODULE,
- },
- .probe = sht15_probe,
- .remove = __devexit_p(sht15_remove),
- }, {
- .driver = {
- .name = "sht11",
- .owner = THIS_MODULE,
- },
- .probe = sht15_probe,
- .remove = __devexit_p(sht15_remove),
- }, {
- .driver = {
- .name = "sht15",
- .owner = THIS_MODULE,
- },
- .probe = sht15_probe,
- .remove = __devexit_p(sht15_remove),
- }, {
- .driver = {
- .name = "sht71",
- .owner = THIS_MODULE,
- },
- .probe = sht15_probe,
- .remove = __devexit_p(sht15_remove),
- }, {
- .driver = {
- .name = "sht75",
- .owner = THIS_MODULE,
- },
- .probe = sht15_probe,
- .remove = __devexit_p(sht15_remove),
- },
+static struct platform_device_id sht15_device_ids[] = {
+ { "sht10", sht10 },
+ { "sht11", sht11 },
+ { "sht15", sht15 },
+ { "sht71", sht71 },
+ { "sht75", sht75 },
+ { }
};
+MODULE_DEVICE_TABLE(platform, sht15_device_ids);
-static int __init sht15_init(void)
-{
- int ret;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(sht_drivers); i++) {
- ret = platform_driver_register(&sht_drivers[i]);
- if (ret)
- goto error_unreg;
- }
-
- return 0;
-
-error_unreg:
- while (--i >= 0)
- platform_driver_unregister(&sht_drivers[i]);
-
- return ret;
-}
-module_init(sht15_init);
-
-static void __exit sht15_exit(void)
-{
- int i;
- for (i = ARRAY_SIZE(sht_drivers) - 1; i >= 0; i--)
- platform_driver_unregister(&sht_drivers[i]);
-}
-module_exit(sht15_exit);
+static struct platform_driver sht15_driver = {
+ .driver = {
+ .name = "sht15",
+ .owner = THIS_MODULE,
+ },
+ .probe = sht15_probe,
+ .remove = __devexit_p(sht15_remove),
+ .id_table = sht15_device_ids,
+};
+module_platform_driver(sht15_driver);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver");
return -ENODEV;
}
- sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
- if (!sht21) {
- dev_dbg(&client->dev, "kzalloc failed\n");
+ sht21 = devm_kzalloc(&client->dev, sizeof(*sht21), GFP_KERNEL);
+ if (!sht21)
return -ENOMEM;
- }
+
i2c_set_clientdata(client, sht21);
mutex_init(&sht21->lock);
err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
if (err) {
dev_dbg(&client->dev, "could not create sysfs files\n");
- goto fail_free;
+ return err;
}
sht21->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(sht21->hwmon_dev)) {
fail_remove_sysfs:
sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-fail_free:
- kfree(sht21);
-
return err;
}
hwmon_device_unregister(sht21->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
- kfree(sht21);
return 0;
}
int err;
u32 eax, edx;
- data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- dev_err(&pdev->dev, "Out of memory\n");
- goto exit;
- }
+ data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->id = pdev->id;
data->name = "via_cputemp";
data->msr_temp = 0x1423;
break;
default:
- err = -ENODEV;
- goto exit_free;
+ return -ENODEV;
}
/* test if we can access the TEMPERATURE MSR */
if (err) {
dev_err(&pdev->dev,
"Unable to access TEMPERATURE MSR, giving up\n");
- goto exit_free;
+ return err;
}
platform_set_drvdata(pdev, data);
err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
if (err)
- goto exit_free;
+ return err;
if (data->msr_vid)
data->vrm = vid_which_vrm();
if (data->vrm)
device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-exit_free:
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-exit:
return err;
}
if (data->vrm)
device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
/* Reserve the ISA region */
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, VT8231_EXTENT,
- vt8231_driver.driver.name)) {
+ if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT,
+ vt8231_driver.driver.name)) {
dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
(unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
- data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit_release;
- }
+ data = devm_kzalloc(&pdev->dev, sizeof(struct vt8231_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
platform_set_drvdata(pdev, data);
data->addr = res->start;
/* Register sysfs hooks */
err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group);
if (err)
- goto exit_free;
+ return err;
/* Must update device information to find out the config field */
data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
-
-exit_free:
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-
-exit_release:
- release_region(res->start, VT8231_EXTENT);
return err;
}
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
- release_region(data->addr, VT8231_EXTENT);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
((val) + 500) / 1000)
/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
-#define TOL_TEMP_TO_REG(val) ((val) < 0 ? 0 : \
- (val) >= 15000 ? 15 : \
+#define TOL_TEMP_TO_REG(val) ((val) >= 15000 ? 15 : \
((val) + 500) / 1000)
#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
struct i2c_client *client = to_i2c_client(dev);
struct w83791d_data *data = i2c_get_clientdata(client);
int nr = sensor_attr->index;
- unsigned long val;
+ long val;
u8 target_mask;
- if (kstrtoul(buf, 10, &val))
+ if (kstrtol(buf, 10, &val))
return -EINVAL;
mutex_lock(&data->update_lock);
u8 pwmenable[3];
u32 alarms; /* realtime status register encoding,combined */
u8 chassis; /* Chassis status */
- u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */
u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */
u8 tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */
u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */
}
static ssize_t
-show_chassis(struct device *dev, struct device_attribute *attr,
+show_chassis_clear(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct w83792d_data *data = w83792d_update_device(dev);
}
static ssize_t
-show_regs_chassis(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- dev_warn(dev,
- "Attribute %s is deprecated, use intrusion0_alarm instead\n",
- "chassis");
- return show_chassis(dev, attr, buf);
-}
-
-static ssize_t
-show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct w83792d_data *data = w83792d_update_device(dev);
- return sprintf(buf, "%d\n", data->chassis_clear);
-}
-
-static ssize_t
-store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83792d_data *data = i2c_get_clientdata(client);
- unsigned long val;
- int err;
- u8 temp1 = 0, temp2 = 0;
-
- dev_warn(dev,
- "Attribute %s is deprecated, use intrusion0_alarm instead\n",
- "chassis_clear");
-
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
- data->chassis_clear = SENSORS_LIMIT(val, 0, 1);
- temp1 = ((data->chassis_clear) << 7) & 0x80;
- temp2 = w83792d_read_value(client,
- W83792D_REG_CHASSIS_CLR) & 0x7f;
- w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
- mutex_unlock(&data->update_lock);
-
- return count;
-}
-
-static ssize_t
store_chassis_clear(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
-static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
-static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
- show_chassis_clear, store_chassis_clear_legacy);
static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
- show_chassis, store_chassis_clear);
+ show_chassis_clear, store_chassis_clear);
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
&sensor_dev_attr_pwm3_mode.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&dev_attr_alarms.attr,
- &dev_attr_chassis.attr,
- &dev_attr_chassis_clear.attr,
&dev_attr_intrusion0_alarm.attr,
&sensor_dev_attr_tolerance1.dev_attr.attr,
&sensor_dev_attr_thermal_cruise1.dev_attr.attr,
/* Update CaseOpen status and it's CLR_CHS. */
data->chassis = (w83792d_read_value(client,
W83792D_REG_CHASSIS) >> 5) & 0x01;
- data->chassis_clear = (w83792d_read_value(client,
- W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
/* Update Thermal Cruise/Smart Fan I target value */
for (i = 0; i < 3; i++) {
return count;
}
-/* Write any value to clear chassis alarm */
-static ssize_t
-store_chassis_clear_legacy(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83793_data *data = i2c_get_clientdata(client);
- u8 val;
-
- dev_warn(dev, "Attribute chassis is deprecated, "
- "use intrusion0_alarm instead\n");
-
- mutex_lock(&data->update_lock);
- val = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
- val |= 0x80;
- w83793_write_value(client, W83793_REG_CLR_CHASSIS, val);
- mutex_unlock(&data->update_lock);
- return count;
-}
-
/* Write 0 to clear chassis alarm */
static ssize_t
store_chassis_clear(struct device *dev,
static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
static struct sensor_device_attribute_2 sda_single_files[] = {
- SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
- store_chassis_clear_legacy, ALARM_STATUS, 30),
SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 30),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
int i, err = 0;
u8 reg_tmp;
- data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
+ data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
exit_remove:
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
- kfree(data);
-exit:
return err;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
- kfree(data);
-
return 0;
}
--- /dev/null
+/*
+ * Maxim MAX197 A/D Converter Driver
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/max197 file.
+ */
+
+/**
+ * struct max197_platform_data - MAX197 connectivity info
+ * @convert: Function used to start a conversion with control byte ctrl.
+ * It must return the raw data, or a negative error code.
+ */
+struct max197_platform_data {
+ int (*convert)(u8 ctrl);
+};
bool no_otp_reload;
bool low_resolution;
};
-