aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwmon/emc140359
-rw-r--r--Documentation/hwmon/hwmon-kernel-api.txt107
-rw-r--r--Documentation/hwmon/jc4216
-rw-r--r--Documentation/hwmon/lm7720
-rw-r--r--Documentation/hwmon/nct668357
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/adm1029.c4
-rw-r--r--drivers/hwmon/emc1403.c267
-rw-r--r--drivers/hwmon/f71805f.c4
-rw-r--r--drivers/hwmon/g762.c2
-rw-r--r--drivers/hwmon/gpio-fan.c2
-rw-r--r--drivers/hwmon/ibmpex.c4
-rw-r--r--drivers/hwmon/iio_hwmon.c2
-rw-r--r--drivers/hwmon/jc42.c315
-rw-r--r--drivers/hwmon/lm70.c62
-rw-r--r--drivers/hwmon/lm75.c51
-rw-r--r--drivers/hwmon/lm77.c374
-rw-r--r--drivers/hwmon/lm80.c640
-rw-r--r--drivers/hwmon/lm83.c168
-rw-r--r--drivers/hwmon/lm92.c224
-rw-r--r--drivers/hwmon/lm93.c4
-rw-r--r--drivers/hwmon/ltc2945.c2
-rw-r--r--drivers/hwmon/max1111.c4
-rw-r--r--drivers/hwmon/max1619.c304
-rw-r--r--drivers/hwmon/max197.c4
-rw-r--r--drivers/hwmon/nct6683.c1457
-rw-r--r--drivers/hwmon/nct6775.c8
-rw-r--r--drivers/hwmon/pc87427.c4
-rw-r--r--drivers/hwmon/s3c-hwmon.c4
-rw-r--r--drivers/hwmon/tmp102.c62
-rw-r--r--drivers/hwmon/tmp421.c47
-rw-r--r--drivers/hwmon/ultra45_env.c7
-rw-r--r--drivers/hwmon/vt1211.c4
35 files changed, 2885 insertions, 1417 deletions
diff --git a/Documentation/hwmon/emc1403 b/Documentation/hwmon/emc1403
new file mode 100644
index 000000000000..a869b0ef6a9d
--- /dev/null
+++ b/Documentation/hwmon/emc1403
@@ -0,0 +1,59 @@
+Kernel driver emc1403
+=====================
+
+Supported chips:
+ * SMSC / Microchip EMC1402, EMC1412
+ Addresses scanned: I2C 0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c
+ Prefix: 'emc1402'
+ Datasheets:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1412.pdf
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1402.pdf
+ * SMSC / Microchip EMC1403, EMC1404, EMC1413, EMC1414
+ Addresses scanned: I2C 0x18, 0x29, 0x4c, 0x4d
+ Prefix: 'emc1403', 'emc1404'
+ Datasheets:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1403_1404.pdf
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1413_1414.pdf
+ * SMSC / Microchip EMC1422
+ Addresses scanned: I2C 0x4c
+ Prefix: 'emc1422'
+ Datasheet:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1422.pdf
+ * SMSC / Microchip EMC1423, EMC1424
+ Addresses scanned: I2C 0x4c
+ Prefix: 'emc1423', 'emc1424'
+ Datasheet:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/1423_1424.pdf
+
+Author:
+ Kalhan Trisal <kalhan.trisal@intel.com
+
+
+Description
+-----------
+
+The Standard Microsystems Corporation (SMSC) / Microchip EMC14xx chips
+contain up to four temperature sensors. EMC14x2 support two sensors
+(one internal, one external). EMC14x3 support three sensors (one internal,
+two external), and EMC14x4 support four sensors (one internal, three
+external).
+
+The chips implement three limits for each sensor: low (tempX_min), high
+(tempX_max) and critical (tempX_crit.) The chips also implement an
+hysteresis mechanism which applies to all limits. The relative difference
+is stored in a single register on the chip, which means that the relative
+difference between the limit and its hysteresis is always the same for
+all three limits.
+
+This implementation detail implies the following:
+* When setting a limit, its hysteresis will automatically follow, the
+ difference staying unchanged. For example, if the old critical limit
+ was 80 degrees C, and the hysteresis was 75 degrees C, and you change
+ the critical limit to 90 degrees C, then the hysteresis will
+ automatically change to 85 degrees C.
+* The hysteresis values can't be set independently. We decided to make
+ only temp1_crit_hyst writable, while all other hysteresis attributes
+ are read-only. Setting temp1_crit_hyst writes the difference between
+ temp1_crit_hyst and temp1_crit into the chip, and the same relative
+ hysteresis applies automatically to all other limits.
+* The limits should be set before the hysteresis.
diff --git a/Documentation/hwmon/hwmon-kernel-api.txt b/Documentation/hwmon/hwmon-kernel-api.txt
new file mode 100644
index 000000000000..2ecdbfc85ecf
--- /dev/null
+++ b/Documentation/hwmon/hwmon-kernel-api.txt
@@ -0,0 +1,107 @@
+The Linux Hardware Monitoring kernel API.
+=========================================
+
+Guenter Roeck
+
+Introduction
+------------
+
+This document describes the API that can be used by hardware monitoring
+drivers that want to use the hardware monitoring framework.
+
+This document does not describe what a hardware monitoring (hwmon) Driver or
+Device is. It also does not describe the API which can be used by user space
+to communicate with a hardware monitoring device. If you want to know this
+then please read the following file: Documentation/hwmon/sysfs-interface.
+
+For additional guidelines on how to write and improve hwmon drivers, please
+also read Documentation/hwmon/submitting-patches.
+
+The API
+-------
+Each hardware monitoring driver must #include <linux/hwmon.h> and, in most
+cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following
+register/unregister functions:
+
+struct device *hwmon_device_register(struct device *dev);
+struct device *
+hwmon_device_register_with_groups(struct device *dev, const char *name,
+ void *drvdata,
+ const struct attribute_group **groups);
+
+struct device *
+devm_hwmon_device_register_with_groups(struct device *dev,
+ const char *name, void *drvdata,
+ const struct attribute_group **groups);
+
+void hwmon_device_unregister(struct device *dev);
+void devm_hwmon_device_unregister(struct device *dev);
+
+hwmon_device_register registers a hardware monitoring device. The parameter
+of this function is a pointer to the parent device.
+This function returns a pointer to the newly created hardware monitoring device
+or PTR_ERR for failure. If this registration function is used, hardware
+monitoring sysfs attributes are expected to have been created and attached to
+the parent device prior to calling hwmon_device_register. A name attribute must
+have been created by the caller.
+
+hwmon_device_register_with_groups is similar to hwmon_device_register. However,
+it has additional parameters. The name parameter is a pointer to the hwmon
+device name. The registration function wil create a name sysfs attribute
+pointing to this name. The drvdata parameter is the pointer to the local
+driver data. hwmon_device_register_with_groups will attach this pointer
+to the newly allocated hwmon device. The pointer can be retrieved by the driver
+using dev_get_drvdata() on the hwmon device pointer. The groups parameter is
+a pointer to a list of sysfs attribute groups. The list must be NULL terminated.
+hwmon_device_register_with_groups creates the hwmon device with name attribute
+as well as all sysfs attributes attached to the hwmon device.
+
+devm_hwmon_device_register_with_groups is similar to
+hwmon_device_register_with_groups. However, it is device managed, meaning the
+hwmon device does not have to be removed explicitly by the removal function.
+
+hwmon_device_unregister deregisters a registered hardware monitoring device.
+The parameter of this function is the pointer to the registered hardware
+monitoring device structure. This function must be called from the driver
+remove function if the hardware monitoring device was registered with
+hwmon_device_register or with hwmon_device_register_with_groups.
+
+devm_hwmon_device_unregister does not normally have to be called. It is only
+needed for error handling, and only needed if the driver probe fails after
+the call to devm_hwmon_device_register_with_groups.
+
+The header file linux/hwmon-sysfs.h provides a number of useful macros to
+declare and use hardware monitoring sysfs attributes.
+
+In many cases, you can use the exsting define DEVICE_ATTR to declare such
+attributes. This is feasible if an attribute has no additional context. However,
+in many cases there will be additional information such as a sensor index which
+will need to be passed to the sysfs attribute handling function.
+
+SENSOR_DEVICE_ATTR and SENSOR_DEVICE_ATTR_2 can be used to define attributes
+which need such additional context information. SENSOR_DEVICE_ATTR requires
+one additional argument, SENSOR_DEVICE_ATTR_2 requires two.
+
+SENSOR_DEVICE_ATTR defines a struct sensor_device_attribute variable.
+This structure has the following fields.
+
+struct sensor_device_attribute {
+ struct device_attribute dev_attr;
+ int index;
+};
+
+You can use to_sensor_dev_attr to get the pointer to this structure from the
+attribute read or write function. Its parameter is the device to which the
+attribute is attached.
+
+SENSOR_DEVICE_ATTR_2 defines a struct sensor_device_attribute_2 variable,
+which is defined as follows.
+
+struct sensor_device_attribute_2 {
+ struct device_attribute dev_attr;
+ u8 index;
+ u8 nr;
+};
+
+Use to_sensor_dev_attr_2 to get the pointer to this structure. Its parameter
+is the device to which the attribute is attached.
diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42
index 868d74d6b773..f3893f7440de 100644
--- a/Documentation/hwmon/jc42
+++ b/Documentation/hwmon/jc42
@@ -5,9 +5,12 @@ Supported chips:
* Analog Devices ADT7408
Datasheets:
http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf
- * Atmel AT30TS00
+ * Atmel AT30TS00, AT30TS002A/B, AT30TSE004A
Datasheets:
http://www.atmel.com/Images/doc8585.pdf
+ http://www.atmel.com/Images/doc8711.pdf
+ http://www.atmel.com/Images/Atmel-8852-SEEPROM-AT30TSE002A-Datasheet.pdf
+ http://www.atmel.com/Images/Atmel-8868-DTS-AT30TSE004A-Datasheet.pdf
* IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2
Datasheets:
http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
@@ -34,12 +37,13 @@ Supported chips:
Datasheet:
http://www.onsemi.com/pub_link/Collateral/CAT34TS02-D.PDF
http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF
- * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS3000
+ * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS2004, STTS3000
Datasheets:
- http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157556.pdf
- http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157558.pdf
- http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf
- http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf
+ http://www.st.com/web/en/resource/technical/document/datasheet/CD00157556.pdf
+ http://www.st.com/web/en/resource/technical/document/datasheet/CD00157558.pdf
+ http://www.st.com/web/en/resource/technical/document/datasheet/CD00266638.pdf
+ http://www.st.com/web/en/resource/technical/document/datasheet/CD00225278.pdf
+ http://www.st.com/web/en/resource/technical/document/datasheet/DM00076709.pdf
* JEDEC JC 42.4 compliant temperature sensor chips
Datasheet:
http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf
diff --git a/Documentation/hwmon/lm77 b/Documentation/hwmon/lm77
index 57c3a46d6370..bfc915fe3639 100644
--- a/Documentation/hwmon/lm77
+++ b/Documentation/hwmon/lm77
@@ -18,5 +18,21 @@ sensor incorporates a band-gap type temperature sensor,
10-bit ADC, and a digital comparator with user-programmable upper
and lower limit values.
-Limits can be set through the Overtemperature Shutdown register and
-Hysteresis register.
+The LM77 implements 3 limits: low (temp1_min), high (temp1_max) and
+critical (temp1_crit.) It also implements an hysteresis mechanism which
+applies to all 3 limits. The relative difference is stored in a single
+register on the chip, which means that the relative difference between
+the limit and its hysteresis is always the same for all 3 limits.
+
+This implementation detail implies the following:
+* When setting a limit, its hysteresis will automatically follow, the
+ difference staying unchanged. For example, if the old critical limit
+ was 80 degrees C, and the hysteresis was 75 degrees C, and you change
+ the critical limit to 90 degrees C, then the hysteresis will
+ automatically change to 85 degrees C.
+* All 3 hysteresis can't be set independently. We decided to make
+ temp1_crit_hyst writable, while temp1_min_hyst and temp1_max_hyst are
+ read-only. Setting temp1_crit_hyst writes the difference between
+ temp1_crit_hyst and temp1_crit into the chip, and the same relative
+ hysteresis applies automatically to the low and high limits.
+* The limits should be set before the hysteresis.
diff --git a/Documentation/hwmon/nct6683 b/Documentation/hwmon/nct6683
new file mode 100644
index 000000000000..c1301d4300cd
--- /dev/null
+++ b/Documentation/hwmon/nct6683
@@ -0,0 +1,57 @@
+Kernel driver nct6683
+=====================
+
+Supported chips:
+ * Nuvoton NCT6683D
+ Prefix: 'nct6683'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+
+Authors:
+ Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for the Nuvoton NCT6683D eSIO chip.
+
+The chips implement up to shared 32 temperature and voltage sensors.
+It supports up to 16 fan rotation sensors and up to 8 fan control engines.
+
+Temperatures are measured in degrees Celsius. Measurement resolution is
+0.5 degrees C.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+
+Fan rotation speeds are reported in RPM (rotations per minute).
+
+Usage Note
+----------
+
+Limit register locations on Intel boards with EC firmware version 1.0
+build date 04/03/13 do not match the register locations in the Nuvoton
+datasheet. Nuvoton confirms that Intel uses a special firmware version
+with different register addresses. The specification describing the Intel
+firmware is held under NDA by Nuvoton and Intel and not available
+to the public.
+
+Some of the register locations can be reverse engineered; others are too
+well hidden. Given this, writing any values from the operating system is
+considered too risky with this firmware and has been disabled. All limits
+must all be written from the BIOS.
+
+The driver has only been tested with the Intel firmware, and by default
+only instantiates on Intel boards. To enable it on non-Intel boards,
+set the 'force' module parameter to 1.
+
+Tested Boards and Firmware Versions
+-----------------------------------
+
+The driver has been reported to work with the following boards and
+firmware versions.
+
+Board Firmware version
+---------------------------------------------------------------
+Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13
+Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13
+Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13
diff --git a/MAINTAINERS b/MAINTAINERS
index 8227716f9306..53feaaf1cf15 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -355,7 +355,7 @@ F: Documentation/hwmon/adm1025
F: drivers/hwmon/adm1025.c
ADM1029 HARDWARE MONITOR DRIVER
-M: Corentin Labbe <corentin.labbe@geomatys.fr>
+M: Corentin Labbe <clabbe.montjoie@gmail.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/adm1029.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 4af0da96c2e2..00343166feb1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1065,6 +1065,16 @@ config SENSORS_NTC_THERMISTOR
This driver can also be built as a module. If so, the module
will be called ntc-thermistor.
+config SENSORS_NCT6683
+ tristate "Nuvoton NCT6683D"
+ depends on !PPC
+ help
+ If you say yes here you get support for the hardware monitoring
+ functionality of the Nuvoton NCT6683D eSIO chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called nct6683.
+
config SENSORS_NCT6775
tristate "Nuvoton NCT6775F and compatibles"
depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index c48f9873ac73..11798ad7e801 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -114,6 +114,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
+obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o
obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index d19c790e410a..78339e880bd6 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -1,7 +1,7 @@
/*
* adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
*
- * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
+ * Copyright (C) 2006 Corentin LABBE <clabbe.montjoie@gmail.com>
*
* Based on LM83 Driver by Jean Delvare <jdelvare@suse.de>
*
@@ -449,6 +449,6 @@ static struct adm1029_data *adm1029_update_device(struct device *dev)
module_i2c_driver(adm1029_driver);
-MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
+MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
MODULE_DESCRIPTION("adm1029 driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 01723f04fe45..a37b2204a418 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -18,9 +18,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * TODO
- * - cache alarm and critical limit registers
*/
#include <linux/module.h>
@@ -32,22 +29,18 @@
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
-#include <linux/jiffies.h>
+#include <linux/regmap.h>
#define THERMAL_PID_REG 0xfd
#define THERMAL_SMSC_ID_REG 0xfe
#define THERMAL_REVISION_REG 0xff
+enum emc1403_chip { emc1402, emc1403, emc1404 };
+
struct thermal_data {
- struct i2c_client *client;
- const struct attribute_group *groups[3];
+ struct regmap *regmap;
struct mutex mutex;
- /*
- * Cache the hyst value so we don't keep re-reading it. In theory
- * we could cache it forever as nobody else should be writing it.
- */
- u8 cached_hyst;
- unsigned long hyst_valid;
+ const struct attribute_group *groups[4];
};
static ssize_t show_temp(struct device *dev,
@@ -55,12 +48,13 @@ static ssize_t show_temp(struct device *dev,
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
+ unsigned int val;
int retval;
- retval = i2c_smbus_read_byte_data(data->client, sda->index);
+ retval = regmap_read(data->regmap, sda->index, &val);
if (retval < 0)
return retval;
- return sprintf(buf, "%d000\n", retval);
+ return sprintf(buf, "%d000\n", val);
}
static ssize_t show_bit(struct device *dev,
@@ -68,12 +62,13 @@ static ssize_t show_bit(struct device *dev,
{
struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
struct thermal_data *data = dev_get_drvdata(dev);
+ unsigned int val;
int retval;
- retval = i2c_smbus_read_byte_data(data->client, sda->nr);
+ retval = regmap_read(data->regmap, sda->nr, &val);
if (retval < 0)
return retval;
- return sprintf(buf, "%d\n", !!(retval & sda->index));
+ return sprintf(buf, "%d\n", !!(val & sda->index));
}
static ssize_t store_temp(struct device *dev,
@@ -86,8 +81,8 @@ static ssize_t store_temp(struct device *dev,
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- retval = i2c_smbus_write_byte_data(data->client, sda->index,
- DIV_ROUND_CLOSEST(val, 1000));
+ retval = regmap_write(data->regmap, sda->index,
+ DIV_ROUND_CLOSEST(val, 1000));
if (retval < 0)
return retval;
return count;
@@ -98,51 +93,51 @@ static ssize_t store_bit(struct device *dev,
{
struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
struct thermal_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
unsigned long val;
int retval;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- mutex_lock(&data->mutex);
- retval = i2c_smbus_read_byte_data(client, sda->nr);
+ retval = regmap_update_bits(data->regmap, sda->nr, sda->index,
+ val ? sda->index : 0);
if (retval < 0)
- goto fail;
-
- retval &= ~sda->index;
- if (val)
- retval |= sda->index;
-
- retval = i2c_smbus_write_byte_data(client, sda->index, retval);
- if (retval == 0)
- retval = count;
-fail:
- mutex_unlock(&data->mutex);
- return retval;
+ return retval;
+ return count;
}
-static ssize_t show_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_hyst_common(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ bool is_min)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
+ struct regmap *regmap = data->regmap;
+ unsigned int limit;
+ unsigned int hyst;
int retval;
- int hyst;
- retval = i2c_smbus_read_byte_data(client, sda->index);
+ retval = regmap_read(regmap, sda->index, &limit);
if (retval < 0)
return retval;
- if (time_after(jiffies, data->hyst_valid)) {
- hyst = i2c_smbus_read_byte_data(client, 0x21);
- if (hyst < 0)
- return retval;
- data->cached_hyst = hyst;
- data->hyst_valid = jiffies + HZ;
- }
- return sprintf(buf, "%d000\n", retval - data->cached_hyst);
+ retval = regmap_read(regmap, 0x21, &hyst);
+ if (retval < 0)
+ return retval;
+
+ return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst);
+}
+
+static ssize_t show_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return show_hyst_common(dev, attr, buf, false);
+}
+
+static ssize_t show_min_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return show_hyst_common(dev, attr, buf, true);
}
static ssize_t store_hyst(struct device *dev,
@@ -150,7 +145,8 @@ static ssize_t store_hyst(struct device *dev,
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
+ struct regmap *regmap = data->regmap;
+ unsigned int limit;
int retval;
int hyst;
unsigned long val;
@@ -159,23 +155,15 @@ static ssize_t store_hyst(struct device *dev,
return -EINVAL;
mutex_lock(&data->mutex);
- retval = i2c_smbus_read_byte_data(client, sda->index);
+ retval = regmap_read(regmap, sda->index, &limit);
if (retval < 0)
goto fail;
- hyst = retval * 1000 - val;
- hyst = DIV_ROUND_CLOSEST(hyst, 1000);
- if (hyst < 0 || hyst > 255) {
- retval = -ERANGE;
- goto fail;
- }
-
- retval = i2c_smbus_write_byte_data(client, 0x21, hyst);
- if (retval == 0) {
+ hyst = limit * 1000 - val;
+ hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
+ retval = regmap_write(regmap, 0x21, hyst);
+ if (retval == 0)
retval = count;
- data->cached_hyst = hyst;
- data->hyst_valid = jiffies + HZ;
- }
fail:
mutex_unlock(&data->mutex);
return retval;
@@ -198,6 +186,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO,
show_bit, NULL, 0x35, 0x01);
static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO,
show_bit, NULL, 0x37, 0x01);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x06);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05);
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
show_hyst, store_hyst, 0x20);
@@ -208,14 +198,16 @@ static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x19);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x02);
static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO,
show_bit, NULL, 0x36, 0x02);
static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO,
show_bit, NULL, 0x35, 0x02);
static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO,
show_bit, NULL, 0x37, 0x02);
-static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR,
- show_hyst, store_hyst, 0x19);
+static SENSOR_DEVICE_ATTR(temp2_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x08);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19);
static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x16);
@@ -224,14 +216,16 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x1A);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x04);
static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO,
show_bit, NULL, 0x36, 0x04);
static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO,
show_bit, NULL, 0x35, 0x04);
static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO,
show_bit, NULL, 0x37, 0x04);
-static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR,
- show_hyst, store_hyst, 0x1A);
+static SENSOR_DEVICE_ATTR(temp3_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x16);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A);
static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x2D);
@@ -240,44 +234,66 @@ static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x30);
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A);
+static SENSOR_DEVICE_ATTR_2(temp4_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x08);
static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO,
show_bit, NULL, 0x36, 0x08);
static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO,
show_bit, NULL, 0x35, 0x08);
static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO,
show_bit, NULL, 0x37, 0x08);
-static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO | S_IWUSR,
- show_hyst, store_hyst, 0x30);
+static SENSOR_DEVICE_ATTR(temp4_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x2D);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C);
+static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30);
static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR,
show_bit, store_bit, 0x03, 0x40);
-static struct attribute *emc1403_attrs[] = {
+static struct attribute *emc1402_attrs[] = {
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_power_state.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group emc1402_group = {
+ .attrs = emc1402_attrs,
+};
+
+static struct attribute *emc1403_attrs[] = {
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
- &sensor_dev_attr_power_state.dev_attr.attr,
NULL
};
@@ -290,9 +306,12 @@ static struct attribute *emc1404_attrs[] = {
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp4_crit.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_crit_hyst.dev_attr.attr,
NULL
};
@@ -301,6 +320,39 @@ static const struct attribute_group emc1404_group = {
.attrs = emc1404_attrs,
};
+/*
+ * EMC14x2 uses a different register and different bits to report alarm and
+ * fault status. For simplicity, provide a separate attribute group for this
+ * chip series.
+ * Since we can not re-use the same attribute names, create a separate attribute
+ * array.
+ */
+static struct sensor_device_attribute_2 emc1402_alarms[] = {
+ SENSOR_ATTR_2(temp1_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x20),
+ SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x40),
+ SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x01),
+
+ SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x02, 0x04),
+ SENSOR_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x08),
+ SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x10),
+ SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x02),
+};
+
+static struct attribute *emc1402_alarm_attrs[] = {
+ &emc1402_alarms[0].dev_attr.attr,
+ &emc1402_alarms[1].dev_attr.attr,
+ &emc1402_alarms[2].dev_attr.attr,
+ &emc1402_alarms[3].dev_attr.attr,
+ &emc1402_alarms[4].dev_attr.attr,
+ &emc1402_alarms[5].dev_attr.attr,
+ &emc1402_alarms[6].dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group emc1402_alarm_group = {
+ .attrs = emc1402_alarm_attrs,
+};
+
static int emc1403_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
@@ -313,9 +365,15 @@ static int emc1403_detect(struct i2c_client *client,
id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
switch (id) {
+ case 0x20:
+ strlcpy(info->type, "emc1402", I2C_NAME_SIZE);
+ break;
case 0x21:
strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
break;
+ case 0x22:
+ strlcpy(info->type, "emc1422", I2C_NAME_SIZE);
+ break;
case 0x23:
strlcpy(info->type, "emc1423", I2C_NAME_SIZE);
break;
@@ -336,6 +394,35 @@ static int emc1403_detect(struct i2c_client *client,
return 0;
}
+static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00: /* internal diode high byte */
+ case 0x01: /* external diode 1 high byte */
+ case 0x02: /* status */
+ case 0x10: /* external diode 1 low byte */
+ case 0x1b: /* external diode fault */
+ case 0x23: /* external diode 2 high byte */
+ case 0x24: /* external diode 2 low byte */
+ case 0x29: /* internal diode low byte */
+ case 0x2a: /* externl diode 3 high byte */
+ case 0x2b: /* external diode 3 low byte */
+ case 0x35: /* high limit status */
+ case 0x36: /* low limit status */
+ case 0x37: /* therm limit status */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct regmap_config emc1403_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = emc1403_regmap_is_volatile,
+};
+
static int emc1403_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -347,13 +434,23 @@ static int emc1403_probe(struct i2c_client *client,
if (data == NULL)
return -ENOMEM;
- data->client = client;
+ data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
mutex_init(&data->mutex);
- data->hyst_valid = jiffies - 1; /* Expired */
- data->groups[0] = &emc1403_group;
- if (id->driver_data)
- data->groups[1] = &emc1404_group;
+ switch (id->driver_data) {
+ case emc1404:
+ data->groups[2] = &emc1404_group;
+ case emc1403:
+ data->groups[1] = &emc1403_group;
+ case emc1402:
+ data->groups[0] = &emc1402_group;
+ }
+
+ if (id->driver_data == emc1402)
+ data->groups[1] = &emc1402_alarm_group;
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
client->name, data,
@@ -366,14 +463,20 @@ static int emc1403_probe(struct i2c_client *client,
}
static const unsigned short emc1403_address_list[] = {
- 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END
+ 0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END
};
+/* Last digit of chip name indicates number of channels */
static const struct i2c_device_id emc1403_idtable[] = {
- { "emc1403", 0 },
- { "emc1404", 1 },
- { "emc1423", 0 },
- { "emc1424", 1 },
+ { "emc1402", emc1402 },
+ { "emc1403", emc1403 },
+ { "emc1404", emc1404 },
+ { "emc1412", emc1402 },
+ { "emc1413", emc1403 },
+ { "emc1414", emc1404 },
+ { "emc1422", emc1402 },
+ { "emc1423", emc1403 },
+ { "emc1424", emc1404 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 32f5132c4652..9e57b77ecd34 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1387,10 +1387,8 @@ static int f71805f_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data),
GFP_KERNEL);
- if (!data) {
- pr_err("Out of memory\n");
+ if (!data)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2,
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
index b4b8b5bef718..98a8618d8fbf 100644
--- a/drivers/hwmon/g762.c
+++ b/drivers/hwmon/g762.c
@@ -586,7 +586,7 @@ static int do_set_fan_startv(struct device *dev, unsigned long val)
*/
#ifdef CONFIG_OF
-static struct of_device_id g762_dt_match[] = {
+static const struct of_device_id g762_dt_match[] = {
{ .compatible = "gmt,g762" },
{ .compatible = "gmt,g763" },
{ },
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 73181be5b30b..ba35e4d530b5 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -482,7 +482,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
return 0;
}
-static struct of_device_id of_gpio_fan_match[] = {
+static const struct of_device_id of_gpio_fan_match[] = {
{ .compatible = "gpio-fan", },
{},
};
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index 20ab0fb85395..030e7ff589be 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -463,10 +463,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(dev, "Insufficient memory for BMC interface.\n");
+ if (!data)
return;
- }
data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
data->address.channel = IPMI_BMC_CHANNEL;
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 9fbb1b1fdff3..14c82daab019 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -163,7 +163,7 @@ static int iio_hwmon_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id iio_hwmon_of_match[] = {
+static const struct of_device_id iio_hwmon_of_match[] = {
{ .compatible = "iio-hwmon", },
{ }
};
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index 6013611e4f21..388f8bcd898e 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -65,6 +65,7 @@ static const unsigned short normal_i2c[] = {
/* Manufacturer IDs */
#define ADT_MANID 0x11d4 /* Analog Devices */
#define ATMEL_MANID 0x001f /* Atmel */
+#define ATMEL_MANID2 0x1114 /* Atmel */
#define MAX_MANID 0x004d /* Maxim */
#define IDT_MANID 0x00b3 /* IDT */
#define MCP_MANID 0x0054 /* Microchip */
@@ -82,6 +83,9 @@ static const unsigned short normal_i2c[] = {
#define AT30TS00_DEVID 0x8201
#define AT30TS00_DEVID_MASK 0xffff
+#define AT30TSE004_DEVID 0x2200
+#define AT30TSE004_DEVID_MASK 0xffff
+
/* IDT */
#define TS3000B3_DEVID 0x2903 /* Also matches TSE2002B3 */
#define TS3000B3_DEVID_MASK 0xffff
@@ -130,6 +134,9 @@ static const unsigned short normal_i2c[] = {
#define STTS2002_DEVID 0x0300
#define STTS2002_DEVID_MASK 0xffff
+#define STTS2004_DEVID 0x2201
+#define STTS2004_DEVID_MASK 0xffff
+
#define STTS3000_DEVID 0x0200
#define STTS3000_DEVID_MASK 0xffff
@@ -144,6 +151,7 @@ struct jc42_chips {
static struct jc42_chips jc42_chips[] = {
{ ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
{ ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
+ { ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK },
{ IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK },
{ IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK },
{ MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
@@ -158,9 +166,25 @@ static struct jc42_chips jc42_chips[] = {
{ STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
{ STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
{ STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
+ { STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK },
{ STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
};
+enum temp_index {
+ t_input = 0,
+ t_crit,
+ t_min,
+ t_max,
+ t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+ [t_input] = JC42_REG_TEMP,
+ [t_crit] = JC42_REG_TEMP_CRITICAL,
+ [t_min] = JC42_REG_TEMP_LOWER,
+ [t_max] = JC42_REG_TEMP_UPPER,
+};
+
/* Each client has this additional data */
struct jc42_data {
struct i2c_client *client;
@@ -170,69 +194,7 @@ struct jc42_data {
unsigned long last_updated; /* In jiffies */
u16 orig_config; /* original configuration */
u16 config; /* current configuration */
- u16 temp_input; /* Temperatures */
- u16 temp_crit;
- u16 temp_min;
- u16 temp_max;
-};
-
-static int jc42_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info);
-static int jc42_remove(struct i2c_client *client);
-
-static struct jc42_data *jc42_update_device(struct device *dev);
-
-static const struct i2c_device_id jc42_id[] = {
- { "jc42", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, jc42_id);
-
-#ifdef CONFIG_PM
-
-static int jc42_suspend(struct device *dev)
-{
- struct jc42_data *data = dev_get_drvdata(dev);
-
- data->config |= JC42_CFG_SHUTDOWN;
- i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
- data->config);
- return 0;
-}
-
-static int jc42_resume(struct device *dev)
-{
- struct jc42_data *data = dev_get_drvdata(dev);
-
- data->config &= ~JC42_CFG_SHUTDOWN;
- i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
- data->config);
- return 0;
-}
-
-static const struct dev_pm_ops jc42_dev_pm_ops = {
- .suspend = jc42_suspend,
- .resume = jc42_resume,
-};
-
-#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
-#else
-#define JC42_DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
-
-/* This is the driver that will be inserted */
-static struct i2c_driver jc42_driver = {
- .class = I2C_CLASS_SPD,
- .driver = {
- .name = "jc42",
- .pm = JC42_DEV_PM_OPS,
- },
- .probe = jc42_probe,
- .remove = jc42_remove,
- .id_table = jc42_id,
- .detect = jc42_detect,
- .address_list = normal_i2c,
+ u16 temp[t_num_temp];/* Temperatures */
};
#define JC42_TEMP_MIN_EXTENDED (-40000)
@@ -261,79 +223,81 @@ static int jc42_temp_from_reg(s16 reg)
return reg * 125 / 2;
}
-/* sysfs stuff */
-
-/* read routines for temperature limits */
-#define show(value) \
-static ssize_t show_##value(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct jc42_data *data = jc42_update_device(dev); \
- if (IS_ERR(data)) \
- return PTR_ERR(data); \
- return sprintf(buf, "%d\n", jc42_temp_from_reg(data->value)); \
+static struct jc42_data *jc42_update_device(struct device *dev)
+{
+ struct jc42_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ struct jc42_data *ret = data;
+ int i, val;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ for (i = 0; i < t_num_temp; i++) {
+ val = i2c_smbus_read_word_swapped(client, temp_regs[i]);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp[i] = val;
+ }
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
-show(temp_input);
-show(temp_crit);
-show(temp_min);
-show(temp_max);
+/* sysfs functions */
-/* read routines for hysteresis values */
-static ssize_t show_temp_crit_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct jc42_data *data = jc42_update_device(dev);
- int temp, hyst;
-
if (IS_ERR(data))
return PTR_ERR(data);
-
- temp = jc42_temp_from_reg(data->temp_crit);
- hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
- >> JC42_CFG_HYST_SHIFT];
- return sprintf(buf, "%d\n", temp - hyst);
+ return sprintf(buf, "%d\n",
+ jc42_temp_from_reg(data->temp[attr->index]));
}
-static ssize_t show_temp_max_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct jc42_data *data = jc42_update_device(dev);
int temp, hyst;
if (IS_ERR(data))
return PTR_ERR(data);
- temp = jc42_temp_from_reg(data->temp_max);
+ temp = jc42_temp_from_reg(data->temp[attr->index]);
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
>> JC42_CFG_HYST_SHIFT];
return sprintf(buf, "%d\n", temp - hyst);
}
-/* write routines */
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct jc42_data *data = dev_get_drvdata(dev); \
- int err, ret = count; \
- long val; \
- if (kstrtol(buf, 10, &val) < 0) \
- return -EINVAL; \
- mutex_lock(&data->update_lock); \
- data->value = jc42_temp_to_reg(val, data->extended); \
- err = i2c_smbus_write_word_swapped(data->client, reg, data->value); \
- if (err < 0) \
- ret = err; \
- mutex_unlock(&data->update_lock); \
- return ret; \
-}
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct jc42_data *data = dev_get_drvdata(dev);
+ int err, ret = count;
+ int nr = attr->index;
+ long val;
-set(temp_min, JC42_REG_TEMP_LOWER);
-set(temp_max, JC42_REG_TEMP_UPPER);
-set(temp_crit, JC42_REG_TEMP_CRITICAL);
+ if (kstrtol(buf, 10, &val) < 0)
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = jc42_temp_to_reg(val, data->extended);
+ err = i2c_smbus_write_word_swapped(data->client, temp_regs[nr],
+ data->temp[nr]);
+ if (err < 0)
+ ret = err;
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
/*
* JC42.4 compliant chips only support four hysteresis values.
@@ -352,7 +316,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
- diff = jc42_temp_from_reg(data->temp_crit) - val;
+ diff = jc42_temp_from_reg(data->temp[t_crit]) - val;
hyst = 0;
if (diff > 0) {
if (diff < 2250)
@@ -384,25 +348,20 @@ static ssize_t show_alarm(struct device *dev,
if (IS_ERR(data))
return PTR_ERR(data);
- val = data->temp_input;
+ val = data->temp[t_input];
if (bit != JC42_ALARM_CRIT_BIT && (data->config & JC42_CFG_CRIT_ONLY))
val = 0;
return sprintf(buf, "%u\n", (val >> bit) & 1);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO,
- show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IRUGO,
- show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IRUGO,
- show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IRUGO,
- show_temp_max, set_temp_max);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, set_temp, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, set_temp, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, set_temp, t_max);
-static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
- show_temp_crit_hyst, set_temp_crit_hyst);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
- show_temp_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_hyst,
+ set_temp_crit_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
JC42_ALARM_CRIT_BIT);
@@ -412,12 +371,12 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
JC42_ALARM_MAX_BIT);
static struct attribute *jc42_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_crit_hyst.attr,
- &dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
@@ -432,12 +391,12 @@ static umode_t jc42_attribute_mode(struct kobject *kobj,
unsigned int config = data->config;
bool readonly;
- if (attr == &dev_attr_temp1_crit.attr)
+ if (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr)
readonly = config & JC42_CFG_TCRIT_LOCK;
- else if (attr == &dev_attr_temp1_min.attr ||
- attr == &dev_attr_temp1_max.attr)
+ else if (attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
+ attr == &sensor_dev_attr_temp1_max.dev_attr.attr)
readonly = config & JC42_CFG_EVENT_LOCK;
- else if (attr == &dev_attr_temp1_crit_hyst.attr)
+ else if (attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)
readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
else
readonly = true;
@@ -537,52 +496,56 @@ static int jc42_remove(struct i2c_client *client)
return 0;
}
-static struct jc42_data *jc42_update_device(struct device *dev)
+#ifdef CONFIG_PM
+
+static int jc42_suspend(struct device *dev)
{
struct jc42_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- struct jc42_data *ret = data;
- int val;
- mutex_lock(&data->update_lock);
+ data->config |= JC42_CFG_SHUTDOWN;
+ i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
+ data->config);
+ return 0;
+}
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP);
- if (val < 0) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->temp_input = val;
+static int jc42_resume(struct device *dev)
+{
+ struct jc42_data *data = dev_get_drvdata(dev);
- val = i2c_smbus_read_word_swapped(client,
- JC42_REG_TEMP_CRITICAL);
- if (val < 0) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->temp_crit = val;
+ data->config &= ~JC42_CFG_SHUTDOWN;
+ i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
+ data->config);
+ return 0;
+}
- val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER);
- if (val < 0) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->temp_min = val;
+static const struct dev_pm_ops jc42_dev_pm_ops = {
+ .suspend = jc42_suspend,
+ .resume = jc42_resume,
+};
- val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER);
- if (val < 0) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->temp_max = val;
+#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
+#else
+#define JC42_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
- data->last_updated = jiffies;
- data->valid = true;
- }
-abort:
- mutex_unlock(&data->update_lock);
- return ret;
-}
+static const struct i2c_device_id jc42_id[] = {
+ { "jc42", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, jc42_id);
+
+static struct i2c_driver jc42_driver = {
+ .class = I2C_CLASS_SPD,
+ .driver = {
+ .name = "jc42",
+ .pm = JC42_DEV_PM_OPS,
+ },
+ .probe = jc42_probe,
+ .remove = jc42_remove,
+ .id_table = jc42_id,
+ .detect = jc42_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(jc42_driver);
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 505a59e100b0..97204dce162d 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -47,7 +47,7 @@
#define LM70_CHIP_LM74 3 /* NS LM74 */
struct lm70 {
- struct device *hwmon_dev;
+ struct spi_device *spi;
struct mutex lock;
unsigned int chip;
};
@@ -56,11 +56,11 @@ struct lm70 {
static ssize_t lm70_sense_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct spi_device *spi = to_spi_device(dev);
+ struct lm70 *p_lm70 = dev_get_drvdata(dev);
+ struct spi_device *spi = p_lm70->spi;
int status, val = 0;
u8 rxbuf[2];
s16 raw = 0;
- struct lm70 *p_lm70 = spi_get_drvdata(spi);
if (mutex_lock_interruptible(&p_lm70->lock))
return -ERESTARTSYS;
@@ -121,21 +121,20 @@ out:
static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
-static ssize_t lm70_show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
-{
- return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
-}
+static struct attribute *lm70_attrs[] = {
+ &dev_attr_temp1_input.attr,
+ NULL
+};
-static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
+ATTRIBUTE_GROUPS(lm70);
/*----------------------------------------------------------------------*/
static int lm70_probe(struct spi_device *spi)
{
int chip = spi_get_device_id(spi)->driver_data;
+ struct device *hwmon_dev;
struct lm70 *p_lm70;
- int status;
/* signaling is SPI_MODE_0 */
if (spi->mode & (SPI_CPOL | SPI_CPHA))
@@ -149,46 +148,14 @@ static int lm70_probe(struct spi_device *spi)
mutex_init(&p_lm70->lock);
p_lm70->chip = chip;
+ p_lm70->spi = spi;
- spi_set_drvdata(spi, p_lm70);
-
- status = device_create_file(&spi->dev, &dev_attr_temp1_input);
- if (status)
- goto out_dev_create_temp_file_failed;
- status = device_create_file(&spi->dev, &dev_attr_name);
- if (status)
- goto out_dev_create_file_failed;
-
- /* sysfs hook */
- p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
- if (IS_ERR(p_lm70->hwmon_dev)) {
- dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
- status = PTR_ERR(p_lm70->hwmon_dev);
- goto out_dev_reg_failed;
- }
-
- return 0;
-
-out_dev_reg_failed:
- device_remove_file(&spi->dev, &dev_attr_name);
-out_dev_create_file_failed:
- device_remove_file(&spi->dev, &dev_attr_temp1_input);
-out_dev_create_temp_file_failed:
- return status;
+ hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev,
+ spi->modalias,
+ p_lm70, lm70_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static int lm70_remove(struct spi_device *spi)
-{
- struct lm70 *p_lm70 = spi_get_drvdata(spi);
-
- hwmon_device_unregister(p_lm70->hwmon_dev);
- device_remove_file(&spi->dev, &dev_attr_temp1_input);
- device_remove_file(&spi->dev, &dev_attr_name);
-
- return 0;
-}
-
-
static const struct spi_device_id lm70_ids[] = {
{ "lm70", LM70_CHIP_LM70 },
{ "tmp121", LM70_CHIP_TMP121 },
@@ -205,7 +172,6 @@ static struct spi_driver lm70_driver = {
},
.id_table = lm70_ids,
.probe = lm70_probe,
- .remove = lm70_remove,
};
module_spi_driver(lm70_driver);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 84a55eacd903..479ffbeed3f8 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -72,6 +72,7 @@ static const u8 LM75_REG_TEMP[3] = {
/* Each client has this additional data */
struct lm75_data {
+ struct i2c_client *client;
struct device *hwmon_dev;
struct thermal_zone_device *tz;
struct mutex update_lock;
@@ -130,8 +131,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct i2c_client *client = to_i2c_client(dev);
- struct lm75_data *data = i2c_get_clientdata(client);
+ struct lm75_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int nr = attr->index;
long temp;
int error;
@@ -165,17 +166,14 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
show_temp, set_temp, 2);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
-static struct attribute *lm75_attributes[] = {
+static struct attribute *lm75_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
NULL
};
-
-static const struct attribute_group lm75_group = {
- .attrs = lm75_attributes,
-};
+ATTRIBUTE_GROUPS(lm75);
/*-----------------------------------------------------------------------*/
@@ -184,6 +182,7 @@ static const struct attribute_group lm75_group = {
static int
lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct lm75_data *data;
int status;
u8 set_mask, clr_mask;
@@ -194,10 +193,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -EIO;
- data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ data->client = client;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
@@ -269,7 +269,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* configure as specified */
status = lm75_read_value(client, LM75_REG_CONF);
if (status < 0) {
- dev_dbg(&client->dev, "Can't read config? %d\n", status);
+ dev_dbg(dev, "Can't read config? %d\n", status);
return status;
}
data->orig_conf = status;
@@ -277,43 +277,32 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
new |= set_mask;
if (status != new)
lm75_write_value(client, LM75_REG_CONF, new);
- dev_dbg(&client->dev, "Config %02x\n", new);
+ dev_dbg(dev, "Config %02x\n", new);
- /* Register sysfs hooks */
- status = sysfs_create_group(&client->dev.kobj, &lm75_group);
- if (status)
- return status;
+ data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+ data, lm75_groups);
+ if (IS_ERR(data->hwmon_dev))
+ return PTR_ERR(data->hwmon_dev);
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- status = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- data->tz = thermal_zone_of_sensor_register(&client->dev,
+ data->tz = thermal_zone_of_sensor_register(data->hwmon_dev,
0,
- &client->dev,
+ data->hwmon_dev,
lm75_read_temp, NULL);
if (IS_ERR(data->tz))
data->tz = NULL;
- dev_info(&client->dev, "%s: sensor '%s'\n",
+ dev_info(dev, "%s: sensor '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
-
-exit_remove:
- sysfs_remove_group(&client->dev.kobj, &lm75_group);
- return status;
}
static int lm75_remove(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
- thermal_zone_of_sensor_unregister(&client->dev, data->tz);
+ thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz);
hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm75_group);
lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
return 0;
}
@@ -507,8 +496,8 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
static struct lm75_data *lm75_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm75_data *data = i2c_get_clientdata(client);
+ struct lm75_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
struct lm75_data *ret = data;
mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 502771c06fd9..5ceb443b938d 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -19,10 +19,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -47,50 +43,33 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
#define LM77_REG_TEMP_MIN 0x04
#define LM77_REG_TEMP_MAX 0x05
+enum temp_index {
+ t_input = 0,
+ t_crit,
+ t_min,
+ t_max,
+ t_hyst,
+ t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+ [t_input] = LM77_REG_TEMP,
+ [t_min] = LM77_REG_TEMP_MIN,
+ [t_max] = LM77_REG_TEMP_MAX,
+ [t_crit] = LM77_REG_TEMP_CRIT,
+ [t_hyst] = LM77_REG_TEMP_HYST,
+};
+
/* Each client has this additional data */
struct lm77_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
- int temp_input; /* Temperatures */
- int temp_crit;
- int temp_min;
- int temp_max;
- int temp_hyst;
+ int temp[t_num_temp]; /* index using temp_index */
u8 alarms;
};
-static int lm77_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm77_init_client(struct i2c_client *client);
-static int lm77_remove(struct i2c_client *client);
-static u16 lm77_read_value(struct i2c_client *client, u8 reg);
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
-
-static struct lm77_data *lm77_update_device(struct device *dev);
-
-
-static const struct i2c_device_id lm77_id[] = {
- { "lm77", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, lm77_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver lm77_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "lm77",
- },
- .probe = lm77_probe,
- .remove = lm77_remove,
- .id_table = lm77_id,
- .detect = lm77_detect,
- .address_list = normal_i2c,
-};
-
/* straight from the datasheet */
#define LM77_TEMP_MIN (-55000)
#define LM77_TEMP_MAX 125000
@@ -110,97 +89,109 @@ static inline int LM77_TEMP_FROM_REG(s16 reg)
return (reg / 8) * 500;
}
-/* sysfs stuff */
-
-/* read routines for temperature limits */
-#define show(value) \
-static ssize_t show_##value(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct lm77_data *data = lm77_update_device(dev); \
- return sprintf(buf, "%d\n", data->value); \
+/*
+ * All registers are word-sized, except for the configuration register.
+ * The LM77 uses the high-byte first convention.
+ */
+static u16 lm77_read_value(struct i2c_client *client, u8 reg)
+{
+ if (reg == LM77_REG_CONF)
+ return i2c_smbus_read_byte_data(client, reg);
+ else
+ return i2c_smbus_read_word_swapped(client, reg);
}
-show(temp_input);
-show(temp_crit);
-show(temp_min);
-show(temp_max);
+static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+ if (reg == LM77_REG_CONF)
+ return i2c_smbus_write_byte_data(client, reg, value);
+ else
+ return i2c_smbus_write_word_swapped(client, reg, value);
+}
-/* read routines for hysteresis values */
-static ssize_t show_temp_crit_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static struct lm77_data *lm77_update_device(struct device *dev)
{
- struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst);
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ dev_dbg(&client->dev, "Starting lm77 update\n");
+ for (i = 0; i < t_num_temp; i++) {
+ data->temp[i] =
+ LM77_TEMP_FROM_REG(lm77_read_value(client,
+ temp_regs[i]));
+ }
+ data->alarms =
+ lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
}
-static ssize_t show_temp_min_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+/* sysfs stuff */
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst);
+
+ return sprintf(buf, "%d\n", data->temp[attr->index]);
}
-static ssize_t show_temp_max_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst);
-}
+ int nr = attr->index;
+ int temp;
-/* write routines */
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm77_data *data = i2c_get_clientdata(client); \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err) \
- return err; \
- \
- mutex_lock(&data->update_lock); \
- data->value = val; \
- lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \
- mutex_unlock(&data->update_lock); \
- return count; \
-}
+ temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
+ data->temp[nr] - data->temp[t_hyst];
-set(temp_min, LM77_REG_TEMP_MIN);
-set(temp_max, LM77_REG_TEMP_MAX);
+ return sprintf(buf, "%d\n", temp);
+}
-/*
- * hysteresis is stored as a relative value on the chip, so it has to be
- * converted first
- */
-static ssize_t set_temp_crit_hyst(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
- unsigned long val;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int nr = attr->index;
+ long val;
int err;
- err = kstrtoul(buf, 10, &val);
+ err = kstrtol(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock);
- data->temp_hyst = data->temp_crit - val;
- lm77_write_value(client, LM77_REG_TEMP_HYST,
- LM77_TEMP_TO_REG(data->temp_hyst));
+ data->temp[nr] = val;
+ lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
mutex_unlock(&data->update_lock);
return count;
}
-/* preserve hysteresis when setting T_crit */
-static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+/*
+ * hysteresis is stored as a relative value on the chip, so it has to be
+ * converted first.
+ */
+static ssize_t set_temp_hyst(struct device *dev,
+ struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
- int oldcrithyst;
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int err;
@@ -209,13 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- oldcrithyst = data->temp_crit - data->temp_hyst;
- data->temp_crit = val;
- data->temp_hyst = data->temp_crit - oldcrithyst;
- lm77_write_value(client, LM77_REG_TEMP_CRIT,
- LM77_TEMP_TO_REG(data->temp_crit));
+ data->temp[t_hyst] = data->temp[t_crit] - val;
lm77_write_value(client, LM77_REG_TEMP_HYST,
- LM77_TEMP_TO_REG(data->temp_hyst));
+ LM77_TEMP_TO_REG(data->temp[t_hyst]));
mutex_unlock(&data->update_lock);
return count;
}
@@ -228,43 +215,37 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO,
- show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
- show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
- show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
- show_temp_max, set_temp_max);
-
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
- show_temp_crit_hyst, set_temp_crit_hyst);
-static DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
- show_temp_min_hyst, NULL);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
- show_temp_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+ set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
-static struct attribute *lm77_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_crit_hyst.attr,
- &dev_attr_temp1_min_hyst.attr,
- &dev_attr_temp1_max_hyst.attr,
+static struct attribute *lm77_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group lm77_group = {
- .attrs = lm77_attributes,
-};
+ATTRIBUTE_GROUPS(lm77);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
@@ -337,111 +318,52 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
return 0;
}
+static void lm77_init_client(struct i2c_client *client)
+{
+ /* Initialize the LM77 chip - turn off shutdown mode */
+ int conf = lm77_read_value(client, LM77_REG_CONF);
+ if (conf & 1)
+ lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
+}
+
static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct lm77_data *data;
- int err;
data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM77 chip */
lm77_init_client(client);
- /* Register sysfs hooks */
- err = sysfs_create_group(&dev->kobj, &lm77_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- return 0;
-
-exit_remove:
- sysfs_remove_group(&dev->kobj, &lm77_group);
- return err;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, lm77_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static int lm77_remove(struct i2c_client *client)
-{
- struct lm77_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm77_group);
- return 0;
-}
-
-/*
- * All registers are word-sized, except for the configuration register.
- * The LM77 uses the high-byte first convention.
- */
-static u16 lm77_read_value(struct i2c_client *client, u8 reg)
-{
- if (reg == LM77_REG_CONF)
- return i2c_smbus_read_byte_data(client, reg);
- else
- return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
- if (reg == LM77_REG_CONF)
- return i2c_smbus_write_byte_data(client, reg, value);
- else
- return i2c_smbus_write_word_swapped(client, reg, value);
-}
-
-static void lm77_init_client(struct i2c_client *client)
-{
- /* Initialize the LM77 chip - turn off shutdown mode */
- int conf = lm77_read_value(client, LM77_REG_CONF);
- if (conf & 1)
- lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
-}
-
-static struct lm77_data *lm77_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
- dev_dbg(&client->dev, "Starting lm77 update\n");
- data->temp_input =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP));
- data->temp_hyst =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_HYST));
- data->temp_crit =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_CRIT));
- data->temp_min =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_MIN));
- data->temp_max =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_MAX));
- data->alarms =
- lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
- data->last_updated = jiffies;
- data->valid = 1;
- }
-
- mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm77_id[] = {
+ { "lm77", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm77_id);
- return data;
-}
+/* This is the driver that will be inserted */
+static struct i2c_driver lm77_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "lm77",
+ },
+ .probe = lm77_probe,
+ .id_table = lm77_id,
+ .detect = lm77_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(lm77_driver);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index bd0a1ebbf867..4bcd9b882948 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -86,26 +86,41 @@ static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
(val) == 255 ? 0 : 1350000/((div) * (val)))
-static inline long TEMP_FROM_REG(u16 temp)
-{
- long res;
+#define TEMP_FROM_REG(reg) ((reg) * 125 / 32)
+#define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \
+ -128000, 127000), 1000) << 8)
- temp >>= 4;
- if (temp < 0x0800)
- res = 625 * (long) temp;
- else
- res = ((long) temp - 0x01000) * 625;
+#define DIV_FROM_REG(val) (1 << (val))
- return res / 10;
-}
+enum temp_index {
+ t_input = 0,
+ t_hot_max,
+ t_hot_hyst,
+ t_os_max,
+ t_os_hyst,
+ t_num_temp
+};
-#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \
- (val) - 0x100 : (val)) * 1000)
+static const u8 temp_regs[t_num_temp] = {
+ [t_input] = LM80_REG_TEMP,
+ [t_hot_max] = LM80_REG_TEMP_HOT_MAX,
+ [t_hot_hyst] = LM80_REG_TEMP_HOT_HYST,
+ [t_os_max] = LM80_REG_TEMP_OS_MAX,
+ [t_os_hyst] = LM80_REG_TEMP_OS_HYST,
+};
-#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \
- ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
+enum in_index {
+ i_input = 0,
+ i_max,
+ i_min,
+ i_num_in
+};
-#define DIV_FROM_REG(val) (1 << (val))
+enum fan_index {
+ f_input,
+ f_min,
+ f_num_fan
+};
/*
* Client data (each client gets its own)
@@ -118,106 +133,187 @@ struct lm80_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u8 in[7]; /* Register value */
- u8 in_max[7]; /* Register value */
- u8 in_min[7]; /* Register value */
- u8 fan[2]; /* Register value */
- u8 fan_min[2]; /* Register value */
+ u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */
+ u8 fan[f_num_fan][2]; /* Register value, 1st index enum fan_index */
u8 fan_div[2]; /* Register encoding, shifted right */
- u16 temp; /* Register values, shifted right */
- u8 temp_hot_max; /* Register value */
- u8 temp_hot_hyst; /* Register value */
- u8 temp_os_max; /* Register value */
- u8 temp_os_hyst; /* Register value */
+ s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */
u16 alarms; /* Register encoding, combined */
};
-/*
- * Functions declaration
- */
+static int lm80_read_value(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
-static int lm80_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm80_init_client(struct i2c_client *client);
-static struct lm80_data *lm80_update_device(struct device *dev);
-static int lm80_read_value(struct i2c_client *client, u8 reg);
-static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
-/*
- * Driver data (common to all clients)
- */
+/* Called when we have found a new LM80 and after read errors */
+static void lm80_init_client(struct i2c_client *client)
+{
+ /*
+ * Reset all except Watchdog values and last conversion values
+ * This sets fan-divs to 2, among others. This makes most other
+ * initializations unnecessary
+ */
+ lm80_write_value(client, LM80_REG_CONFIG, 0x80);
+ /* Set 11-bit temperature resolution */
+ lm80_write_value(client, LM80_REG_RES, 0x08);
-static const struct i2c_device_id lm80_id[] = {
- { "lm80", 0 },
- { "lm96080", 1 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, lm80_id);
+ /* Start monitoring */
+ lm80_write_value(client, LM80_REG_CONFIG, 0x01);
+}
-static struct i2c_driver lm80_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "lm80",
- },
- .probe = lm80_probe,
- .id_table = lm80_id,
- .detect = lm80_detect,
- .address_list = normal_i2c,
-};
+static struct lm80_data *lm80_update_device(struct device *dev)
+{
+ struct lm80_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
+ int rv;
+ int prev_rv;
+ struct lm80_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (data->error)
+ lm80_init_client(client);
+
+ if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+ dev_dbg(dev, "Starting lm80 update\n");
+ for (i = 0; i <= 6; i++) {
+ rv = lm80_read_value(client, LM80_REG_IN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[i_input][i] = rv;
+
+ rv = lm80_read_value(client, LM80_REG_IN_MIN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[i_min][i] = rv;
+
+ rv = lm80_read_value(client, LM80_REG_IN_MAX(i));
+ if (rv < 0)
+ goto abort;
+ data->in[i_max][i] = rv;
+ }
+
+ rv = lm80_read_value(client, LM80_REG_FAN1);
+ if (rv < 0)
+ goto abort;
+ data->fan[f_input][0] = rv;
+
+ rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+ if (rv < 0)
+ goto abort;
+ data->fan[f_min][0] = rv;
+
+ rv = lm80_read_value(client, LM80_REG_FAN2);
+ if (rv < 0)
+ goto abort;
+ data->fan[f_input][1] = rv;
+
+ rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+ if (rv < 0)
+ goto abort;
+ data->fan[f_min][1] = rv;
+
+ prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP);
+ if (rv < 0)
+ goto abort;
+ rv = lm80_read_value(client, LM80_REG_RES);
+ if (rv < 0)
+ goto abort;
+ data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0);
+
+ for (i = t_input + 1; i < t_num_temp; i++) {
+ rv = lm80_read_value(client, temp_regs[i]);
+ if (rv < 0)
+ goto abort;
+ data->temp[i] = rv << 8;
+ }
+
+ rv = lm80_read_value(client, LM80_REG_FANDIV);
+ if (rv < 0)
+ goto abort;
+ data->fan_div[0] = (rv >> 2) & 0x03;
+ data->fan_div[1] = (rv >> 4) & 0x03;
+
+ prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1);
+ if (rv < 0)
+ goto abort;
+ rv = lm80_read_value(client, LM80_REG_ALARM2);
+ if (rv < 0)
+ goto abort;
+ data->alarms = prev_rv + (rv << 8);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ data->error = 0;
+ }
+ goto done;
+
+abort:
+ ret = ERR_PTR(rv);
+ data->valid = 0;
+ data->error = 1;
+
+done:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
/*
* Sysfs stuff
*/
-#define show_in(suffix, value) \
-static ssize_t show_in_##suffix(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- int nr = to_sensor_dev_attr(attr)->index; \
- struct lm80_data *data = lm80_update_device(dev); \
- if (IS_ERR(data)) \
- return PTR_ERR(data); \
- return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm80_data *data = lm80_update_device(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index]));
}
-show_in(min, in_min)
-show_in(max, in_max)
-show_in(input, in)
-
-#define set_in(suffix, value, reg) \
-static ssize_t set_in_##suffix(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- int nr = to_sensor_dev_attr(attr)->index; \
- struct lm80_data *data = dev_get_drvdata(dev); \
- struct i2c_client *client = data->client; \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err < 0) \
- return err; \
-\
- mutex_lock(&data->update_lock);\
- data->value[nr] = IN_TO_REG(val); \
- lm80_write_value(client, reg(nr), data->value[nr]); \
- mutex_unlock(&data->update_lock);\
- return count; \
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lm80_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ long val;
+ u8 reg;
+ int err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index);
+
+ mutex_lock(&data->update_lock);
+ data->in[nr][index] = IN_TO_REG(val);
+ lm80_write_value(client, reg, data->in[nr][index]);
+ mutex_unlock(&data->update_lock);
+ return count;
}
-set_in(min, in_min, LM80_REG_IN_MIN)
-set_in(max, in_max, LM80_REG_IN_MAX)
-
-#define show_fan(suffix, value) \
-static ssize_t show_fan_##suffix(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- int nr = to_sensor_dev_attr(attr)->index; \
- struct lm80_data *data = lm80_update_device(dev); \
- if (IS_ERR(data)) \
- return PTR_ERR(data); \
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \
- DIV_FROM_REG(data->fan_div[nr]))); \
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ struct lm80_data *data = lm80_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index],
+ DIV_FROM_REG(data->fan_div[index])));
}
-show_fan(min, fan_min)
-show_fan(input, fan)
static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -232,7 +328,8 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int nr = to_sensor_dev_attr(attr)->index;
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
struct lm80_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val;
@@ -241,8 +338,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
+ data->fan[nr][index] = FAN_TO_REG(val,
+ DIV_FROM_REG(data->fan_div[index]));
+ lm80_write_value(client, LM80_REG_FAN_MIN(index + 1),
+ data->fan[nr][index]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -267,7 +366,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Save fan_min */
mutex_lock(&data->update_lock);
- min = FAN_FROM_REG(data->fan_min[nr],
+ min = FAN_FROM_REG(data->fan[f_min][nr],
DIV_FROM_REG(data->fan_div[nr]));
switch (val) {
@@ -291,62 +390,47 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
- reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1))))
- | (data->fan_div[nr] << (2 * (nr + 1)));
+ reg = (lm80_read_value(client, LM80_REG_FANDIV) &
+ ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1)));
lm80_write_value(client, LM80_REG_FANDIV, reg);
/* Restore fan_min */
- data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
+ data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1),
+ data->fan[f_min][nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_input1(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm80_data *data = lm80_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
- return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
}
-#define show_temp(suffix, value) \
-static ssize_t show_temp_##suffix(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct lm80_data *data = lm80_update_device(dev); \
- if (IS_ERR(data)) \
- return PTR_ERR(data); \
- return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \
-}
-show_temp(hot_max, temp_hot_max);
-show_temp(hot_hyst, temp_hot_hyst);
-show_temp(os_max, temp_os_max);
-show_temp(os_hyst, temp_os_hyst);
-
-#define set_temp(suffix, value, reg) \
-static ssize_t set_temp_##suffix(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct lm80_data *data = dev_get_drvdata(dev); \
- struct i2c_client *client = data->client; \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err < 0) \
- return err; \
-\
- mutex_lock(&data->update_lock); \
- data->value = TEMP_LIMIT_TO_REG(val); \
- lm80_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm80_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int nr = attr->index;
+ long val;
+ int err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = TEMP_TO_REG(val);
+ lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8);
+ mutex_unlock(&data->update_lock);
+ return count;
}
-set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
-set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);
-set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);
-set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -367,60 +451,60 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
-static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 0);
-static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 1);
-static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 2);
-static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 3);
-static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 4);
-static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 5);
-static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
- show_in_min, set_in_min, 6);
-static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 0);
-static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 1);
-static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 2);
-static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 3);
-static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 4);
-static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 5);
-static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
- show_in_max, set_in_max, 6);
-static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0);
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1);
-static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2);
-static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3);
-static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4);
-static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5);
-static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6);
-static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
- show_fan_min, set_fan_min, 0);
-static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
- show_fan_min, set_fan_min, 1);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
-static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 2);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 3);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 4);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 5);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_min, 6);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 0);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 3);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 4);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 5);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+ show_in, set_in, i_max, 6);
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, i_input, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, i_input, 1);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, i_input, 2);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5);
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan, set_fan_min, f_min, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan, set_fan_min, f_min, 1);
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, f_input, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, f_input, 1);
static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
show_fan_div, set_fan_div, 0);
static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
show_fan_div, set_fan_div, 1);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max,
- set_temp_hot_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst,
- set_temp_hot_hyst);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max,
- set_temp_os_max);
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst,
- set_temp_os_hyst);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, t_hot_max);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, t_hot_hyst);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, t_os_max);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, t_os_hyst);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
@@ -466,11 +550,11 @@ static struct attribute *lm80_attrs[] = {
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp1_crit_hyst.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
&dev_attr_alarms.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
@@ -551,8 +635,8 @@ static int lm80_probe(struct i2c_client *client,
lm80_init_client(client);
/* A few vars need to be filled upon startup */
- data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
- data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+ data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+ data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, lm80_groups);
@@ -560,143 +644,27 @@ static int lm80_probe(struct i2c_client *client,
return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static int lm80_read_value(struct i2c_client *client, u8 reg)
-{
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-/* Called when we have found a new LM80. */
-static void lm80_init_client(struct i2c_client *client)
-{
- /*
- * Reset all except Watchdog values and last conversion values
- * This sets fan-divs to 2, among others. This makes most other
- * initializations unnecessary
- */
- lm80_write_value(client, LM80_REG_CONFIG, 0x80);
- /* Set 11-bit temperature resolution */
- lm80_write_value(client, LM80_REG_RES, 0x08);
-
- /* Start monitoring */
- lm80_write_value(client, LM80_REG_CONFIG, 0x01);
-}
-
-static struct lm80_data *lm80_update_device(struct device *dev)
-{
- struct lm80_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- int i;
- int rv;
- int prev_rv;
- struct lm80_data *ret = data;
-
- mutex_lock(&data->update_lock);
-
- if (data->error)
- lm80_init_client(client);
-
- if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
- dev_dbg(dev, "Starting lm80 update\n");
- for (i = 0; i <= 6; i++) {
- rv = lm80_read_value(client, LM80_REG_IN(i));
- if (rv < 0)
- goto abort;
- data->in[i] = rv;
-
- rv = lm80_read_value(client, LM80_REG_IN_MIN(i));
- if (rv < 0)
- goto abort;
- data->in_min[i] = rv;
-
- rv = lm80_read_value(client, LM80_REG_IN_MAX(i));
- if (rv < 0)
- goto abort;
- data->in_max[i] = rv;
- }
-
- rv = lm80_read_value(client, LM80_REG_FAN1);
- if (rv < 0)
- goto abort;
- data->fan[0] = rv;
-
- rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
- if (rv < 0)
- goto abort;
- data->fan_min[0] = rv;
-
- rv = lm80_read_value(client, LM80_REG_FAN2);
- if (rv < 0)
- goto abort;
- data->fan[1] = rv;
-
- rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
- if (rv < 0)
- goto abort;
- data->fan_min[1] = rv;
-
- prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP);
- if (rv < 0)
- goto abort;
- rv = lm80_read_value(client, LM80_REG_RES);
- if (rv < 0)
- goto abort;
- data->temp = (prev_rv << 8) | (rv & 0xf0);
-
- rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
- if (rv < 0)
- goto abort;
- data->temp_os_max = rv;
-
- rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
- if (rv < 0)
- goto abort;
- data->temp_os_hyst = rv;
-
- rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
- if (rv < 0)
- goto abort;
- data->temp_hot_max = rv;
-
- rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
- if (rv < 0)
- goto abort;
- data->temp_hot_hyst = rv;
-
- rv = lm80_read_value(client, LM80_REG_FANDIV);
- if (rv < 0)
- goto abort;
- data->fan_div[0] = (rv >> 2) & 0x03;
- data->fan_div[1] = (rv >> 4) & 0x03;
-
- prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1);
- if (rv < 0)
- goto abort;
- rv = lm80_read_value(client, LM80_REG_ALARM2);
- if (rv < 0)
- goto abort;
- data->alarms = prev_rv + (rv << 8);
-
- data->last_updated = jiffies;
- data->valid = 1;
- data->error = 0;
- }
- goto done;
-
-abort:
- ret = ERR_PTR(rv);
- data->valid = 0;
- data->error = 1;
+/*
+ * Driver data (common to all clients)
+ */
-done:
- mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm80_id[] = {
+ { "lm80", 0 },
+ { "lm96080", 1 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm80_id);
- return ret;
-}
+static struct i2c_driver lm80_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "lm80",
+ },
+ .probe = lm80_probe,
+ .id_table = lm80_id,
+ .detect = lm80_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(lm80_driver);
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index be02155788c3..9e4d0e1d3c4b 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -25,10 +25,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -111,45 +107,12 @@ static const u8 LM83_REG_W_HIGH[] = {
};
/*
- * Functions declaration
- */
-
-static int lm83_detect(struct i2c_client *new_client,
- struct i2c_board_info *info);
-static int lm83_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int lm83_remove(struct i2c_client *client);
-static struct lm83_data *lm83_update_device(struct device *dev);
-
-/*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id lm83_id[] = {
- { "lm83", lm83 },
- { "lm82", lm82 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, lm83_id);
-
-static struct i2c_driver lm83_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "lm83",
- },
- .probe = lm83_probe,
- .remove = lm83_remove,
- .id_table = lm83_id,
- .detect = lm83_detect,
- .address_list = normal_i2c,
-};
-
-/*
* Client data (each client gets its own)
*/
struct lm83_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
+ const struct attribute_group *groups[3];
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -161,6 +124,36 @@ struct lm83_data {
u16 alarms; /* bitvector, combined */
};
+static struct lm83_data *lm83_update_device(struct device *dev)
+{
+ struct lm83_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+ int nr;
+
+ dev_dbg(&client->dev, "Updating lm83 data.\n");
+ for (nr = 0; nr < 9; nr++) {
+ data->temp[nr] =
+ i2c_smbus_read_byte_data(client,
+ LM83_REG_R_TEMP[nr]);
+ }
+ data->alarms =
+ i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
+ + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
+ << 8);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
/*
* Sysfs stuff
*/
@@ -177,8 +170,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct lm83_data *data = i2c_get_clientdata(client);
+ struct lm83_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long val;
int nr = attr->index;
int err;
@@ -340,15 +333,15 @@ static int lm83_detect(struct i2c_client *new_client,
static int lm83_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
+ struct device *hwmon_dev;
struct lm83_data *data;
- int err;
data = devm_kzalloc(&new_client->dev, sizeof(struct lm83_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = new_client;
mutex_init(&data->update_lock);
/*
@@ -357,72 +350,37 @@ static int lm83_probe(struct i2c_client *new_client,
* at the same register as the LM83 temp3 entry - so we
* declare 1 and 3 common, and then 2 and 4 only for the LM83.
*/
-
- err = sysfs_create_group(&new_client->dev.kobj, &lm83_group);
- if (err)
- return err;
-
- if (id->driver_data == lm83) {
- err = sysfs_create_group(&new_client->dev.kobj,
- &lm83_group_opt);
- if (err)
- goto exit_remove_files;
- }
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
- sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
- return err;
-}
-
-static int lm83_remove(struct i2c_client *client)
-{
- struct lm83_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm83_group);
- sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
-
- return 0;
+ data->groups[0] = &lm83_group;
+ if (id->driver_data == lm83)
+ data->groups[1] = &lm83_group_opt;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+ new_client->name,
+ data, data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static struct lm83_data *lm83_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm83_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
- int nr;
-
- dev_dbg(&client->dev, "Updating lm83 data.\n");
- for (nr = 0; nr < 9; nr++) {
- data->temp[nr] =
- i2c_smbus_read_byte_data(client,
- LM83_REG_R_TEMP[nr]);
- }
- data->alarms =
- i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
- + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
- << 8);
-
- data->last_updated = jiffies;
- data->valid = 1;
- }
+/*
+ * Driver data (common to all clients)
+ */
- mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm83_id[] = {
+ { "lm83", lm83 },
+ { "lm82", lm82 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm83_id);
- return data;
-}
+static struct i2c_driver lm83_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "lm83",
+ },
+ .probe = lm83_probe,
+ .id_table = lm83_id,
+ .detect = lm83_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(lm83_driver);
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index b9022db6511a..d2060e245ff5 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -34,10 +34,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -93,46 +89,53 @@ static inline u8 ALARMS_FROM_REG(s16 reg)
return reg & 0x0007;
}
-/* Driver data (common to all clients) */
-static struct i2c_driver lm92_driver;
+enum temp_index {
+ t_input,
+ t_crit,
+ t_min,
+ t_max,
+ t_hyst,
+ t_num_regs
+};
+
+static const u8 regs[t_num_regs] = {
+ [t_input] = LM92_REG_TEMP,
+ [t_crit] = LM92_REG_TEMP_CRIT,
+ [t_min] = LM92_REG_TEMP_LOW,
+ [t_max] = LM92_REG_TEMP_HIGH,
+ [t_hyst] = LM92_REG_TEMP_HYST,
+};
/* Client data (each client gets its own) */
struct lm92_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
- s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst;
+ s16 temp[t_num_regs]; /* index with enum temp_index */
};
-
/*
* Sysfs attributes and callback functions
*/
static struct lm92_data *lm92_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm92_data *data = i2c_get_clientdata(client);
+ struct lm92_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ)
|| !data->valid) {
dev_dbg(&client->dev, "Updating lm92 data\n");
- data->temp1_input = i2c_smbus_read_word_swapped(client,
- LM92_REG_TEMP);
- data->temp1_hyst = i2c_smbus_read_word_swapped(client,
- LM92_REG_TEMP_HYST);
- data->temp1_crit = i2c_smbus_read_word_swapped(client,
- LM92_REG_TEMP_CRIT);
- data->temp1_min = i2c_smbus_read_word_swapped(client,
- LM92_REG_TEMP_LOW);
- data->temp1_max = i2c_smbus_read_word_swapped(client,
- LM92_REG_TEMP_HIGH);
-
+ for (i = 0; i < t_num_regs; i++) {
+ data->temp[i] =
+ i2c_smbus_read_word_swapped(client, regs[i]);
+ }
data->last_updated = jiffies;
data->valid = 1;
}
@@ -142,68 +145,60 @@ static struct lm92_data *lm92_update_device(struct device *dev)
return data;
}
-#define show_temp(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- struct lm92_data *data = lm92_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
-}
-show_temp(temp1_input);
-show_temp(temp1_crit);
-show_temp(temp1_min);
-show_temp(temp1_max);
-
-#define set_temp(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm92_data *data = i2c_get_clientdata(client); \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err) \
- return err; \
-\
- mutex_lock(&data->update_lock); \
- data->value = TEMP_TO_REG(val); \
- i2c_smbus_write_word_swapped(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm92_data *data = lm92_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
}
-set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
-set_temp(temp1_min, LM92_REG_TEMP_LOW);
-set_temp(temp1_max, LM92_REG_TEMP_HIGH);
-static ssize_t show_temp1_crit_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
- struct lm92_data *data = lm92_update_device(dev);
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit)
- - TEMP_FROM_REG(data->temp1_hyst));
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm92_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int nr = attr->index;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = TEMP_TO_REG(val);
+ i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
}
-static ssize_t show_temp1_max_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm92_data *data = lm92_update_device(dev);
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max)
- - TEMP_FROM_REG(data->temp1_hyst));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
+ - TEMP_FROM_REG(data->temp[t_hyst]));
}
-static ssize_t show_temp1_min_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_min_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct lm92_data *data = lm92_update_device(dev);
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min)
- + TEMP_FROM_REG(data->temp1_hyst));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
+ + TEMP_FROM_REG(data->temp[t_hyst]));
}
-static ssize_t set_temp1_crit_hyst(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_temp_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm92_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm92_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long val;
int err;
@@ -212,9 +207,9 @@ static ssize_t set_temp1_crit_hyst(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val;
+ data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val;
i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
- TEMP_TO_REG(data->temp1_hyst));
+ TEMP_TO_REG(data->temp[t_hyst]));
mutex_unlock(&data->update_lock);
return count;
}
@@ -223,7 +218,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm92_data *data = lm92_update_device(dev);
- return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
+ return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));
}
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
@@ -231,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
{
int bitnr = to_sensor_dev_attr(attr)->index;
struct lm92_data *data = lm92_update_device(dev);
- return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1);
+ return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit,
- set_temp1_crit);
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst,
- set_temp1_crit_hyst);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min,
- set_temp1_min);
-static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max,
- set_temp1_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_crit);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+ set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_min);
+static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_max);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
-
/*
* Detection and registration
*/
@@ -322,24 +316,21 @@ static int max6635_check(struct i2c_client *client)
return 1;
}
-static struct attribute *lm92_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp1_crit_hyst.attr,
- &dev_attr_temp1_min.attr,
+static struct attribute *lm92_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
&dev_attr_temp1_min_hyst.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&dev_attr_alarms.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group lm92_group = {
- .attrs = lm92_attributes,
-};
+ATTRIBUTE_GROUPS(lm92);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm92_detect(struct i2c_client *new_client,
@@ -371,46 +362,24 @@ static int lm92_detect(struct i2c_client *new_client,
static int lm92_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
+ struct device *hwmon_dev;
struct lm92_data *data;
- int err;
data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = new_client;
mutex_init(&data->update_lock);
/* Initialize the chipset */
lm92_init_client(new_client);
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &lm92_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- return 0;
-
-exit_remove:
- sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
- return err;
-}
-
-static int lm92_remove(struct i2c_client *client)
-{
- struct lm92_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm92_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+ new_client->name,
+ data, lm92_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
@@ -431,7 +400,6 @@ static struct i2c_driver lm92_driver = {
.name = "lm92",
},
.probe = lm92_probe,
- .remove = lm92_remove,
.id_table = lm92_id,
.detect = lm92_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index adf23165a6a7..6c2df576f253 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -2747,10 +2747,8 @@ static int lm93_probe(struct i2c_client *client,
}
data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL);
- if (!data) {
- dev_dbg(&client->dev, "out of memory!\n");
+ if (!data)
return -ENOMEM;
- }
i2c_set_clientdata(client, data);
/* housekeeping */
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
index c9cddf5f056b..3701b329b6ae 100644
--- a/drivers/hwmon/ltc2945.c
+++ b/drivers/hwmon/ltc2945.c
@@ -1,4 +1,4 @@
- /*
+/*
* Driver for Linear Technology LTC2945 I2C Power Monitor
*
* Copyright (c) 2014 Guenter Roeck
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
index eda077de8a9f..f67d71ee8386 100644
--- a/drivers/hwmon/max1111.c
+++ b/drivers/hwmon/max1111.c
@@ -192,10 +192,8 @@ static int max1111_probe(struct spi_device *spi)
return err;
data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL);
- if (data == NULL) {
- dev_err(&spi->dev, "failed to allocate memory\n");
+ if (data == NULL)
return -ENOMEM;
- }
switch (chip) {
case max1110:
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 4c23afe113e2..eda9cf599685 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -19,13 +19,8 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -76,38 +71,14 @@ static int temp_to_reg(int val)
return (val < 0 ? val+0x100*1000 : val) / 1000;
}
-/*
- * Functions declaration
- */
-
-static int max1619_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int max1619_detect(struct i2c_client *client,
- struct i2c_board_info *info);
-static void max1619_init_client(struct i2c_client *client);
-static int max1619_remove(struct i2c_client *client);
-static struct max1619_data *max1619_update_device(struct device *dev);
-
-/*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id max1619_id[] = {
- { "max1619", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, max1619_id);
-
-static struct i2c_driver max1619_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "max1619",
- },
- .probe = max1619_probe,
- .remove = max1619_remove,
- .id_table = max1619_id,
- .detect = max1619_detect,
- .address_list = normal_i2c,
+enum temp_index {
+ t_input1 = 0,
+ t_input2,
+ t_low2,
+ t_high2,
+ t_crit2,
+ t_hyst2,
+ t_num_regs
};
/*
@@ -115,60 +86,92 @@ static struct i2c_driver max1619_driver = {
*/
struct max1619_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
- u8 temp_input1; /* local */
- u8 temp_input2, temp_low2, temp_high2; /* remote */
- u8 temp_crit2;
- u8 temp_hyst2;
+ u8 temp[t_num_regs]; /* index with enum temp_index */
u8 alarms;
};
+static const u8 regs_read[t_num_regs] = {
+ [t_input1] = MAX1619_REG_R_LOCAL_TEMP,
+ [t_input2] = MAX1619_REG_R_REMOTE_TEMP,
+ [t_low2] = MAX1619_REG_R_REMOTE_LOW,
+ [t_high2] = MAX1619_REG_R_REMOTE_HIGH,
+ [t_crit2] = MAX1619_REG_R_REMOTE_CRIT,
+ [t_hyst2] = MAX1619_REG_R_TCRIT_HYST,
+};
+
+static const u8 regs_write[t_num_regs] = {
+ [t_low2] = MAX1619_REG_W_REMOTE_LOW,
+ [t_high2] = MAX1619_REG_W_REMOTE_HIGH,
+ [t_crit2] = MAX1619_REG_W_REMOTE_CRIT,
+ [t_hyst2] = MAX1619_REG_W_TCRIT_HYST,
+};
+
+static struct max1619_data *max1619_update_device(struct device *dev)
+{
+ struct max1619_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int config, i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+ dev_dbg(&client->dev, "Updating max1619 data.\n");
+ for (i = 0; i < t_num_regs; i++)
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ regs_read[i]);
+ data->alarms = i2c_smbus_read_byte_data(client,
+ MAX1619_REG_R_STATUS);
+ /* If OVERT polarity is low, reverse alarm bit */
+ config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
+ if (!(config & 0x20))
+ data->alarms ^= 0x02;
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
/*
* Sysfs stuff
*/
-#define show_temp(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- struct max1619_data *data = max1619_update_device(dev); \
- return sprintf(buf, "%d\n", temp_from_reg(data->value)); \
-}
-show_temp(temp_input1);
-show_temp(temp_input2);
-show_temp(temp_low2);
-show_temp(temp_high2);
-show_temp(temp_crit2);
-show_temp(temp_hyst2);
-
-#define set_temp2(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct max1619_data *data = i2c_get_clientdata(client); \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err) \
- return err; \
-\
- mutex_lock(&data->update_lock); \
- data->value = temp_to_reg(val); \
- i2c_smbus_write_byte_data(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct max1619_data *data = max1619_update_device(dev);
+
+ return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
}
-set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW);
-set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH);
-set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT);
-set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST);
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct max1619_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ long val;
+ int err = kstrtol(buf, 10, &val);
+ if (err)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ data->temp[attr->index] = temp_to_reg(val);
+ i2c_smbus_write_byte_data(client, regs_write[attr->index],
+ data->temp[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -185,29 +188,30 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
- set_temp_low2);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
- set_temp_high2);
-static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
- set_temp_crit2);
-static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
- set_temp_hyst2);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, t_input2);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_low2);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_high2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_crit2);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, t_hyst2);
+
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
-static struct attribute *max1619_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_crit.attr,
- &dev_attr_temp2_crit_hyst.attr,
+static struct attribute *max1619_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
&dev_attr_alarms.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
@@ -216,14 +220,7 @@ static struct attribute *max1619_attributes[] = {
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group max1619_group = {
- .attrs = max1619_attributes,
-};
-
-/*
- * Real code
- */
+ATTRIBUTE_GROUPS(max1619);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int max1619_detect(struct i2c_client *client,
@@ -261,41 +258,6 @@ static int max1619_detect(struct i2c_client *client,
return 0;
}
-static int max1619_probe(struct i2c_client *new_client,
- const struct i2c_device_id *id)
-{
- struct max1619_data *data;
- int err;
-
- data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- i2c_set_clientdata(new_client, data);
- mutex_init(&data->update_lock);
-
- /* Initialize the MAX1619 chip */
- max1619_init_client(new_client);
-
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &max1619_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
- return err;
-}
-
static void max1619_init_client(struct i2c_client *client)
{
u8 config;
@@ -311,48 +273,46 @@ static void max1619_init_client(struct i2c_client *client)
config & 0xBF); /* run */
}
-static int max1619_remove(struct i2c_client *client)
+static int max1619_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
{
- struct max1619_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &max1619_group);
-
- return 0;
-}
+ struct max1619_data *data;
+ struct device *hwmon_dev;
-static struct max1619_data *max1619_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct max1619_data *data = i2c_get_clientdata(client);
+ data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- mutex_lock(&data->update_lock);
+ data->client = new_client;
+ mutex_init(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
- dev_dbg(&client->dev, "Updating max1619 data.\n");
- data->temp_input1 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_LOCAL_TEMP);
- data->temp_input2 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_REMOTE_TEMP);
- data->temp_high2 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_REMOTE_HIGH);
- data->temp_low2 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_REMOTE_LOW);
- data->temp_crit2 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_REMOTE_CRIT);
- data->temp_hyst2 = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_TCRIT_HYST);
- data->alarms = i2c_smbus_read_byte_data(client,
- MAX1619_REG_R_STATUS);
+ /* Initialize the MAX1619 chip */
+ max1619_init_client(new_client);
- data->last_updated = jiffies;
- data->valid = 1;
- }
+ hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+ new_client->name,
+ data,
+ max1619_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
- mutex_unlock(&data->update_lock);
+static const struct i2c_device_id max1619_id[] = {
+ { "max1619", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max1619_id);
- return data;
-}
+static struct i2c_driver max1619_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "max1619",
+ },
+ .probe = max1619_probe,
+ .id_table = max1619_id,
+ .detect = max1619_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(max1619_driver);
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
index 96dccaf919d1..82128ad79a91 100644
--- a/drivers/hwmon/max197.c
+++ b/drivers/hwmon/max197.c
@@ -275,10 +275,8 @@ static int max197_probe(struct platform_device *pdev)
}
data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "devm_kzalloc failed\n");
+ if (!data)
return -ENOMEM;
- }
data->pdata = pdata;
mutex_init(&data->lock);
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
new file mode 100644
index 000000000000..7710f4694ba1
--- /dev/null
+++ b/drivers/hwmon/nct6683.c
@@ -0,0 +1,1457 @@
+/*
+ * nct6683 - Driver for the hardware monitoring functionality of
+ * Nuvoton NCT6683D eSIO
+ *
+ * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from nct6775 driver
+ * Copyright (C) 2012, 2013 Guenter Roeck <linux@roeck-us.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Supports the following chips:
+ *
+ * Chip #vin #fan #pwm #temp chip ID
+ * nct6683d 21(1) 16 8 32(1) 0xc730
+ *
+ * Notes:
+ * (1) Total number of vin and temp inputs is 32.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum kinds { nct6683 };
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards");
+
+static const char * const nct6683_device_names[] = {
+ "nct6683",
+};
+
+static const char * const nct6683_chip_names[] = {
+ "NCT6683D",
+};
+
+#define DRVNAME "nct6683"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define NCT6683_LD_ACPI 0x0a
+#define NCT6683_LD_HWM 0x0b
+#define NCT6683_LD_VID 0x0d
+
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_ENABLE 0x30 /* Logical device enable */
+#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+#define SIO_NCT6681_ID 0xb270 /* for later */
+#define SIO_NCT6683_ID 0xc730
+#define SIO_ID_MASK 0xFFF0
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+ outb(SIO_REG_LDSEL, ioreg);
+ outb(ld, ioreg + 1);
+}
+
+static inline int
+superio_enter(int ioreg)
+{
+ /*
+ * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+ */
+ if (!request_muxed_region(ioreg, 2, DRVNAME))
+ return -EBUSY;
+
+ outb(0x87, ioreg);
+ outb(0x87, ioreg);
+
+ return 0;
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+ outb(0xaa, ioreg);
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
+ release_region(ioreg, 2);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT (~7)
+#define IOREGION_OFFSET 4 /* Use EC port 1 */
+#define IOREGION_LENGTH 4
+
+#define EC_PAGE_REG 0
+#define EC_INDEX_REG 1
+#define EC_DATA_REG 2
+#define EC_EVENT_REG 3
+
+/* Common and NCT6683 specific data */
+
+#define NCT6683_NUM_REG_MON 32
+#define NCT6683_NUM_REG_FAN 16
+#define NCT6683_NUM_REG_PWM 8
+
+#define NCT6683_REG_MON(x) (0x100 + (x) * 2)
+#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2)
+#define NCT6683_REG_PWM(x) (0x160 + (x))
+
+#define NCT6683_REG_MON_STS(x) (0x174 + (x))
+#define NCT6683_REG_IDLE(x) (0x178 + (x))
+
+#define NCT6683_REG_FAN_STS(x) (0x17c + (x))
+#define NCT6683_REG_FAN_ERRSTS 0x17e
+#define NCT6683_REG_FAN_INITSTS 0x17f
+
+#define NCT6683_HWM_CFG 0x180
+
+#define NCT6683_REG_MON_CFG(x) (0x1a0 + (x))
+#define NCT6683_REG_FANIN_CFG(x) (0x1c0 + (x))
+#define NCT6683_REG_FANOUT_CFG(x) (0x1d0 + (x))
+
+#define NCT6683_REG_INTEL_TEMP_MAX(x) (0x901 + (x) * 16)
+#define NCT6683_REG_INTEL_TEMP_CRIT(x) (0x90d + (x) * 16)
+
+#define NCT6683_REG_TEMP_HYST(x) (0x330 + (x)) /* 8 bit */
+#define NCT6683_REG_TEMP_MAX(x) (0x350 + (x)) /* 8 bit */
+#define NCT6683_REG_MON_HIGH(x) (0x370 + (x) * 2) /* 8 bit */
+#define NCT6683_REG_MON_LOW(x) (0x371 + (x) * 2) /* 8 bit */
+
+#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */
+
+#define NCT6683_REG_CUSTOMER_ID 0x602
+#define NCT6683_CUSTOMER_ID_INTEL 0x805
+
+#define NCT6683_REG_BUILD_YEAR 0x604
+#define NCT6683_REG_BUILD_MONTH 0x605
+#define NCT6683_REG_BUILD_DAY 0x606
+#define NCT6683_REG_SERIAL 0x607
+#define NCT6683_REG_VERSION_HI 0x608
+#define NCT6683_REG_VERSION_LO 0x609
+
+#define NCT6683_REG_CR_CASEOPEN 0xe8
+#define NCT6683_CR_CASEOPEN_MASK (1 << 7)
+
+#define NCT6683_REG_CR_BEEP 0xe0
+#define NCT6683_CR_BEEP_MASK (1 << 6)
+
+static const char *const nct6683_mon_label[] = {
+ NULL, /* disabled */
+ "Local",
+ "Diode 0 (curr)",
+ "Diode 1 (curr)",
+ "Diode 2 (curr)",
+ "Diode 0 (volt)",
+ "Diode 1 (volt)",
+ "Diode 2 (volt)",
+ "Thermistor 14",
+ "Thermistor 15",
+ "Thermistor 16",
+ "Thermistor 0",
+ "Thermistor 1",
+ "Thermistor 2",
+ "Thermistor 3",
+ "Thermistor 4",
+ "Thermistor 5", /* 0x10 */
+ "Thermistor 6",
+ "Thermistor 7",
+ "Thermistor 8",
+ "Thermistor 9",
+ "Thermistor 10",
+ "Thermistor 11",
+ "Thermistor 12",
+ "Thermistor 13",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "PECI 0.0", /* 0x20 */
+ "PECI 1.0",
+ "PECI 2.0",
+ "PECI 3.0",
+ "PECI 0.1",
+ "PECI 1.1",
+ "PECI 2.1",
+ "PECI 3.1",
+ "PECI DIMM 0",
+ "PECI DIMM 1",
+ "PECI DIMM 2",
+ "PECI DIMM 3",
+ NULL, NULL, NULL, NULL,
+ "PCH CPU", /* 0x30 */
+ "PCH CHIP",
+ "PCH CHIP CPU MAX",
+ "PCH MCH",
+ "PCH DIMM 0",
+ "PCH DIMM 1",
+ "PCH DIMM 2",
+ "PCH DIMM 3",
+ "SMBus 0",
+ "SMBus 1",
+ "SMBus 2",
+ "SMBus 3",
+ "SMBus 4",
+ "SMBus 5",
+ "DIMM 0",
+ "DIMM 1",
+ "DIMM 2", /* 0x40 */
+ "DIMM 3",
+ "AMD TSI Addr 90h",
+ "AMD TSI Addr 92h",
+ "AMD TSI Addr 94h",
+ "AMD TSI Addr 96h",
+ "AMD TSI Addr 98h",
+ "AMD TSI Addr 9ah",
+ "AMD TSI Addr 9ch",
+ "AMD TSI Addr 9dh",
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ "Virtual 0", /* 0x50 */
+ "Virtual 1",
+ "Virtual 2",
+ "Virtual 3",
+ "Virtual 4",
+ "Virtual 5",
+ "Virtual 6",
+ "Virtual 7",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "VCC", /* 0x60 voltage sensors */
+ "VSB",
+ "AVSB",
+ "VTT",
+ "VBAT",
+ "VREF",
+ "VIN0",
+ "VIN1",
+ "VIN2",
+ "VIN3",
+ "VIN4",
+ "VIN5",
+ "VIN6",
+ "VIN7",
+ "VIN8",
+ "VIN9",
+ "VIN10",
+ "VIN11",
+ "VIN12",
+ "VIN13",
+ "VIN14",
+ "VIN15",
+ "VIN16",
+};
+
+#define NUM_MON_LABELS ARRAY_SIZE(nct6683_mon_label)
+#define MON_VOLTAGE_START 0x60
+
+/* ------------------------------------------------------- */
+
+struct nct6683_data {
+ int addr; /* IO base of EC space */
+ int sioreg; /* SIO register */
+ enum kinds kind;
+ u16 customer_id;
+
+ struct device *hwmon_dev;
+ const struct attribute_group *groups[6];
+
+ int temp_num; /* number of temperature attributes */
+ u8 temp_index[NCT6683_NUM_REG_MON];
+ u8 temp_src[NCT6683_NUM_REG_MON];
+
+ u8 in_num; /* number of voltage attributes */
+ u8 in_index[NCT6683_NUM_REG_MON];
+ u8 in_src[NCT6683_NUM_REG_MON];
+
+ struct mutex update_lock; /* used to protect sensor updates */
+ bool valid; /* true if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Voltage attribute values */
+ u8 in[3][NCT6683_NUM_REG_MON]; /* [0]=in, [1]=in_max, [2]=in_min */
+
+ /* Temperature attribute values */
+ s16 temp_in[NCT6683_NUM_REG_MON];
+ s8 temp[4][NCT6683_NUM_REG_MON];/* [0]=min, [1]=max, [2]=hyst,
+ * [3]=crit
+ */
+
+ /* Fan attribute values */
+ unsigned int rpm[NCT6683_NUM_REG_FAN];
+ u16 fan_min[NCT6683_NUM_REG_FAN];
+ u8 fanin_cfg[NCT6683_NUM_REG_FAN];
+ u8 fanout_cfg[NCT6683_NUM_REG_FAN];
+ u16 have_fan; /* some fan inputs can be disabled */
+
+ u8 have_pwm;
+ u8 pwm[NCT6683_NUM_REG_PWM];
+
+#ifdef CONFIG_PM
+ /* Remember extra register values over suspend/resume */
+ u8 hwm_cfg;
+#endif
+};
+
+struct nct6683_sio_data {
+ int sioreg;
+ enum kinds kind;
+};
+
+struct sensor_device_template {
+ struct device_attribute dev_attr;
+ union {
+ struct {
+ u8 nr;
+ u8 index;
+ } s;
+ int index;
+ } u;
+ bool s2; /* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+ union {
+ struct sensor_device_attribute a1;
+ struct sensor_device_attribute_2 a2;
+ } u;
+ char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
+ .attr = {.name = _template, .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
+ { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+ .u.index = _index, \
+ .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
+ _nr, _index) \
+ { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+ .u.s.index = _index, \
+ .u.s.nr = _nr, \
+ .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
+static struct sensor_device_template sensor_dev_template_##_name \
+ = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
+ _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
+ _nr, _index) \
+static struct sensor_device_template sensor_dev_template_##_name \
+ = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
+ _nr, _index)
+
+struct sensor_template_group {
+ struct sensor_device_template **templates;
+ umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+ int base;
+};
+
+static struct attribute_group *
+nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+ int repeat)
+{
+ struct sensor_device_attribute_2 *a2;
+ struct sensor_device_attribute *a;
+ struct sensor_device_template **t;
+ struct sensor_device_attr_u *su;
+ struct attribute_group *group;
+ struct attribute **attrs;
+ int i, j, count;
+
+ if (repeat <= 0)
+ return ERR_PTR(-EINVAL);
+
+ t = tg->templates;
+ for (count = 0; *t; t++, count++)
+ ;
+
+ if (count == 0)
+ return ERR_PTR(-EINVAL);
+
+ group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+ if (group == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+ GFP_KERNEL);
+ if (attrs == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+ GFP_KERNEL);
+ if (su == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ group->attrs = attrs;
+ group->is_visible = tg->is_visible;
+
+ for (i = 0; i < repeat; i++) {
+ t = tg->templates;
+ for (j = 0; *t != NULL; j++) {
+ snprintf(su->name, sizeof(su->name),
+ (*t)->dev_attr.attr.name, tg->base + i);
+ if ((*t)->s2) {
+ a2 = &su->u.a2;
+ a2->dev_attr.attr.name = su->name;
+ a2->nr = (*t)->u.s.nr + i;
+ a2->index = (*t)->u.s.index;
+ a2->dev_attr.attr.mode =
+ (*t)->dev_attr.attr.mode;
+ a2->dev_attr.show = (*t)->dev_attr.show;
+ a2->dev_attr.store = (*t)->dev_attr.store;
+ *attrs = &a2->dev_attr.attr;
+ } else {
+ a = &su->u.a1;
+ a->dev_attr.attr.name = su->name;
+ a->index = (*t)->u.index + i;
+ a->dev_attr.attr.mode =
+ (*t)->dev_attr.attr.mode;
+ a->dev_attr.show = (*t)->dev_attr.show;
+ a->dev_attr.store = (*t)->dev_attr.store;
+ *attrs = &a->dev_attr.attr;
+ }
+ attrs++;
+ su++;
+ t++;
+ }
+ }
+
+ return group;
+}
+
+/* LSB is 16 mV, except for the following sources, where it is 32 mV */
+#define MON_SRC_VCC 0x60
+#define MON_SRC_VSB 0x61
+#define MON_SRC_AVSB 0x62
+#define MON_SRC_VBAT 0x64
+
+static inline long in_from_reg(u16 reg, u8 src)
+{
+ int scale = 16;
+
+ if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
+ src == MON_SRC_VBAT)
+ scale <<= 1;
+ return reg * scale;
+}
+
+static inline u16 in_to_reg(u32 val, u8 src)
+{
+ int scale = 16;
+
+ if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
+ src == MON_SRC_VBAT)
+ scale <<= 1;
+
+ return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127);
+}
+
+static u16 nct6683_read(struct nct6683_data *data, u16 reg)
+{
+ int res;
+
+ outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */
+ outb_p(reg >> 8, data->addr + EC_PAGE_REG);
+ outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
+ res = inb_p(data->addr + EC_DATA_REG);
+ return res;
+}
+
+static u16 nct6683_read16(struct nct6683_data *data, u16 reg)
+{
+ return (nct6683_read(data, reg) << 8) | nct6683_read(data, reg + 1);
+}
+
+static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value)
+{
+ outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */
+ outb_p(reg >> 8, data->addr + EC_PAGE_REG);
+ outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
+ outb_p(value & 0xff, data->addr + EC_DATA_REG);
+}
+
+static int get_in_reg(struct nct6683_data *data, int nr, int index)
+{
+ int ch = data->in_index[index];
+ int reg = -EINVAL;
+
+ switch (nr) {
+ case 0:
+ reg = NCT6683_REG_MON(ch);
+ break;
+ case 1:
+ if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
+ reg = NCT6683_REG_MON_LOW(ch);
+ break;
+ case 2:
+ if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
+ reg = NCT6683_REG_MON_HIGH(ch);
+ break;
+ default:
+ break;
+ }
+ return reg;
+}
+
+static int get_temp_reg(struct nct6683_data *data, int nr, int index)
+{
+ int ch = data->temp_index[index];
+ int reg = -EINVAL;
+
+ switch (data->customer_id) {
+ case NCT6683_CUSTOMER_ID_INTEL:
+ switch (nr) {
+ default:
+ case 1: /* max */
+ reg = NCT6683_REG_INTEL_TEMP_MAX(ch);
+ break;
+ case 3: /* crit */
+ reg = NCT6683_REG_INTEL_TEMP_CRIT(ch);
+ break;
+ }
+ break;
+ default:
+ switch (nr) {
+ default:
+ case 0: /* min */
+ reg = NCT6683_REG_MON_LOW(ch);
+ break;
+ case 1: /* max */
+ reg = NCT6683_REG_TEMP_MAX(ch);
+ break;
+ case 2: /* hyst */
+ reg = NCT6683_REG_TEMP_HYST(ch);
+ break;
+ case 3: /* crit */
+ reg = NCT6683_REG_MON_HIGH(ch);
+ break;
+ }
+ break;
+ }
+ return reg;
+}
+
+static void nct6683_update_pwm(struct device *dev)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
+ if (!(data->have_pwm & (1 << i)))
+ continue;
+ data->pwm[i] = nct6683_read(data, NCT6683_REG_PWM(i));
+ }
+}
+
+static struct nct6683_data *nct6683_update_device(struct device *dev)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int i, j;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ /* Measured voltages and limits */
+ for (i = 0; i < data->in_num; i++) {
+ for (j = 0; j < 3; j++) {
+ int reg = get_in_reg(data, j, i);
+
+ if (reg >= 0)
+ data->in[j][i] =
+ nct6683_read(data, reg);
+ }
+ }
+
+ /* Measured temperatures and limits */
+ for (i = 0; i < data->temp_num; i++) {
+ u8 ch = data->temp_index[i];
+
+ data->temp_in[i] = nct6683_read16(data,
+ NCT6683_REG_MON(ch));
+ for (j = 0; j < 4; j++) {
+ int reg = get_temp_reg(data, j, i);
+
+ if (reg >= 0)
+ data->temp[j][i] =
+ nct6683_read(data, reg);
+ }
+ }
+
+ /* Measured fan speeds and limits */
+ for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
+ if (!(data->have_fan & (1 << i)))
+ continue;
+
+ data->rpm[i] = nct6683_read16(data,
+ NCT6683_REG_FAN_RPM(i));
+ data->fan_min[i] = nct6683_read16(data,
+ NCT6683_REG_FAN_MIN(i));
+ }
+
+ nct6683_update_pwm(dev);
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+static ssize_t
+show_in_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int nr = sattr->index;
+
+ return sprintf(buf, "%s\n", nct6683_mon_label[data->in_src[nr]]);
+}
+
+static ssize_t
+show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int index = sattr->index;
+ int nr = sattr->nr;
+
+ return sprintf(buf, "%ld\n",
+ in_from_reg(data->in[index][nr], data->in_index[index]));
+}
+
+static umode_t nct6683_in_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int nr = index % 4; /* attribute */
+
+ /*
+ * Voltage limits exist for Intel boards,
+ * but register location and encoding is unknown
+ */
+ if ((nr == 2 || nr == 3) &&
+ data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+ return 0;
+
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE(in_label, "in%d_label", S_IRUGO, show_in_label, NULL, 0);
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IRUGO, show_in_reg, NULL, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IRUGO, show_in_reg, NULL, 0, 2);
+
+static struct sensor_device_template *nct6683_attributes_in_template[] = {
+ &sensor_dev_template_in_label,
+ &sensor_dev_template_in_input,
+ &sensor_dev_template_in_min,
+ &sensor_dev_template_in_max,
+ NULL
+};
+
+static struct sensor_template_group nct6683_in_template_group = {
+ .templates = nct6683_attributes_in_template,
+ .is_visible = nct6683_in_is_visible,
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+
+ return sprintf(buf, "%d\n", data->rpm[sattr->index]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6683_data *data = nct6683_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+
+ return sprintf(buf, "%d\n", data->fan_min[nr]);
+}
+
+static ssize_t
+show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ ((data->fanin_cfg[sattr->index] >> 5) & 0x03) + 1);
+}
+
+static umode_t nct6683_fan_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int fan = index / 3; /* fan index */
+ int nr = index % 3; /* attribute index */
+
+ if (!(data->have_fan & (1 << fan)))
+ return 0;
+
+ /*
+ * Intel may have minimum fan speed limits,
+ * but register location and encoding are unknown.
+ */
+ if (nr == 2 && data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+ return 0;
+
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IRUGO, show_fan_pulses, NULL, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IRUGO, show_fan_min, NULL, 0);
+
+/*
+ * nct6683_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6683_attributes_fan_template[] = {
+ &sensor_dev_template_fan_input,
+ &sensor_dev_template_fan_pulses,
+ &sensor_dev_template_fan_min,
+ NULL
+};
+
+static struct sensor_template_group nct6683_fan_template_group = {
+ .templates = nct6683_attributes_fan_template,
+ .is_visible = nct6683_fan_is_visible,
+ .base = 1,
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int nr = sattr->index;
+
+ return sprintf(buf, "%s\n", nct6683_mon_label[data->temp_src[nr]]);
+}
+
+static ssize_t
+show_temp8(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int index = sattr->index;
+ int nr = sattr->nr;
+
+ return sprintf(buf, "%d\n", data->temp[index][nr] * 1000);
+}
+
+static ssize_t
+show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int nr = sattr->index;
+ int temp = data->temp[1][nr] - data->temp[2][nr];
+
+ return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t
+show_temp16(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6683_data *data = nct6683_update_device(dev);
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n", (data->temp_in[index] / 128) * 500);
+}
+
+/*
+ * Temperature sensor type is determined by temperature source
+ * and can not be modified.
+ * 0x02..0x07: Thermal diode
+ * 0x08..0x18: Thermistor
+ * 0x20..0x2b: Intel PECI
+ * 0x42..0x49: AMD TSI
+ * Others are unspecified (not visible)
+ */
+
+static int get_temp_type(u8 src)
+{
+ if (src >= 0x02 && src <= 0x07)
+ return 3; /* thermal diode */
+ else if (src >= 0x08 && src <= 0x18)
+ return 4; /* thermistor */
+ else if (src >= 0x20 && src <= 0x2b)
+ return 6; /* PECI */
+ else if (src >= 0x42 && src <= 0x49)
+ return 5;
+
+ return 0;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6683_data *data = nct6683_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%d\n", get_temp_type(data->temp_src[nr]));
+}
+
+static umode_t nct6683_temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int temp = index / 7; /* temp index */
+ int nr = index % 7; /* attribute index */
+
+ /*
+ * Intel does not have low temperature limits or temperature hysteresis
+ * registers, or at least register location and encoding is unknown.
+ */
+ if ((nr == 2 || nr == 4) &&
+ data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+ return 0;
+
+ if (nr == 6 && get_temp_type(data->temp_src[temp]) == 0)
+ return 0; /* type */
+
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE(temp_input, "temp%d_input", S_IRUGO, show_temp16, NULL, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_min, "temp%d_min", S_IRUGO, show_temp8, NULL, 0, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO, show_temp8, NULL, 0, 1);
+SENSOR_TEMPLATE(temp_max_hyst, "temp%d_max_hyst", S_IRUGO, show_temp_hyst, NULL,
+ 0);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO, show_temp8, NULL, 0, 3);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO, show_temp_type, NULL, 0);
+
+/*
+ * nct6683_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6683_attributes_temp_template[] = {
+ &sensor_dev_template_temp_input,
+ &sensor_dev_template_temp_label,
+ &sensor_dev_template_temp_min, /* 2 */
+ &sensor_dev_template_temp_max, /* 3 */
+ &sensor_dev_template_temp_max_hyst, /* 4 */
+ &sensor_dev_template_temp_crit, /* 5 */
+ &sensor_dev_template_temp_type, /* 6 */
+ NULL
+};
+
+static struct sensor_template_group nct6683_temp_template_group = {
+ .templates = nct6683_attributes_temp_template,
+ .is_visible = nct6683_temp_is_visible,
+ .base = 1,
+};
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6683_data *data = nct6683_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n", data->pwm[index]);
+}
+
+SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0);
+
+static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int pwm = index; /* pwm index */
+
+ if (!(data->have_pwm & (1 << pwm)))
+ return 0;
+
+ return attr->mode;
+}
+
+static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
+ &sensor_dev_template_pwm,
+ NULL
+};
+
+static struct sensor_template_group nct6683_pwm_template_group = {
+ .templates = nct6683_attributes_pwm_template,
+ .is_visible = nct6683_pwm_is_visible,
+ .base = 1,
+};
+
+static ssize_t
+show_global_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int ret;
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+
+ ret = superio_enter(data->sioreg);
+ if (ret)
+ goto error;
+ superio_select(data->sioreg, NCT6683_LD_HWM);
+ reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
+ superio_exit(data->sioreg);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", !!(reg & NCT6683_CR_BEEP_MASK));
+
+error:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t
+store_global_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ u8 reg;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ ret = superio_enter(data->sioreg);
+ if (ret) {
+ count = ret;
+ goto error;
+ }
+
+ superio_select(data->sioreg, NCT6683_LD_HWM);
+ reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
+ if (val)
+ reg |= NCT6683_CR_BEEP_MASK;
+ else
+ reg &= ~NCT6683_CR_BEEP_MASK;
+ superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg);
+ superio_exit(data->sioreg);
+error:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* Case open detection */
+
+static ssize_t
+show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int ret;
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+
+ ret = superio_enter(data->sioreg);
+ if (ret)
+ goto error;
+ superio_select(data->sioreg, NCT6683_LD_ACPI);
+ reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
+ superio_exit(data->sioreg);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", !(reg & NCT6683_CR_CASEOPEN_MASK));
+
+error:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ u8 reg;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ /*
+ * Use CR registers to clear caseopen status.
+ * Caseopen is activ low, clear by writing 1 into the register.
+ */
+
+ ret = superio_enter(data->sioreg);
+ if (ret) {
+ count = ret;
+ goto error;
+ }
+
+ superio_select(data->sioreg, NCT6683_LD_ACPI);
+ reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
+ reg |= NCT6683_CR_CASEOPEN_MASK;
+ superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
+ reg &= ~NCT6683_CR_CASEOPEN_MASK;
+ superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
+ superio_exit(data->sioreg);
+
+ data->valid = false; /* Force cache refresh */
+error:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+ clear_caseopen);
+static DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_global_beep,
+ store_global_beep);
+
+static struct attribute *nct6683_attributes_other[] = {
+ &dev_attr_intrusion0_alarm.attr,
+ &dev_attr_beep_enable.attr,
+ NULL
+};
+
+static const struct attribute_group nct6683_group_other = {
+ .attrs = nct6683_attributes_other,
+};
+
+/* Get the monitoring functions started */
+static inline void nct6683_init_device(struct nct6683_data *data)
+{
+ u8 tmp;
+
+ /* Start hardware monitoring if needed */
+ tmp = nct6683_read(data, NCT6683_HWM_CFG);
+ if (!(tmp & 0x80))
+ nct6683_write(data, NCT6683_HWM_CFG, tmp | 0x80);
+}
+
+/*
+ * There are a total of 24 fan inputs. Each can be configured as input
+ * or as output. A maximum of 16 inputs and 8 outputs is configurable.
+ */
+static void
+nct6683_setup_fans(struct nct6683_data *data)
+{
+ int i;
+ u8 reg;
+
+ for (i = 0; i < NCT6683_NUM_REG_FAN; i++) {
+ reg = nct6683_read(data, NCT6683_REG_FANIN_CFG(i));
+ if (reg & 0x80)
+ data->have_fan |= 1 << i;
+ data->fanin_cfg[i] = reg;
+ }
+ for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
+ reg = nct6683_read(data, NCT6683_REG_FANOUT_CFG(i));
+ if (reg & 0x80)
+ data->have_pwm |= 1 << i;
+ data->fanout_cfg[i] = reg;
+ }
+}
+
+/*
+ * Translation from monitoring register to temperature and voltage attributes
+ * ==========================================================================
+ *
+ * There are a total of 32 monitoring registers. Each can be assigned to either
+ * a temperature or voltage monitoring source.
+ * NCT6683_REG_MON_CFG(x) defines assignment for each monitoring source.
+ *
+ * Temperature and voltage attribute mapping is determined by walking through
+ * the NCT6683_REG_MON_CFG registers. If the assigned source is
+ * a temperature, temp_index[n] is set to the monitor register index, and
+ * temp_src[n] is set to the temperature source. If the assigned source is
+ * a voltage, the respective values are stored in in_index[] and in_src[],
+ * respectively.
+ */
+
+static void nct6683_setup_sensors(struct nct6683_data *data)
+{
+ u8 reg;
+ int i;
+
+ data->temp_num = 0;
+ data->in_num = 0;
+ for (i = 0; i < NCT6683_NUM_REG_MON; i++) {
+ reg = nct6683_read(data, NCT6683_REG_MON_CFG(i)) & 0x7f;
+ /* Ignore invalid assignments */
+ if (reg >= NUM_MON_LABELS)
+ continue;
+ /* Skip if disabled or reserved */
+ if (nct6683_mon_label[reg] == NULL)
+ continue;
+ if (reg < MON_VOLTAGE_START) {
+ data->temp_index[data->temp_num] = i;
+ data->temp_src[data->temp_num] = reg;
+ data->temp_num++;
+ } else {
+ data->in_index[data->in_num] = i;
+ data->in_src[data->in_num] = reg;
+ data->in_num++;
+ }
+ }
+}
+
+static int nct6683_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct nct6683_sio_data *sio_data = dev->platform_data;
+ struct attribute_group *group;
+ struct nct6683_data *data;
+ struct device *hwmon_dev;
+ struct resource *res;
+ int groups = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
+ return -EBUSY;
+
+ data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->kind = sio_data->kind;
+ data->sioreg = sio_data->sioreg;
+ data->addr = res->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
+
+ nct6683_init_device(data);
+ nct6683_setup_fans(data);
+ nct6683_setup_sensors(data);
+
+ /* Register sysfs hooks */
+
+ if (data->have_pwm) {
+ group = nct6683_create_attr_group(dev,
+ &nct6683_pwm_template_group,
+ fls(data->have_pwm));
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+ data->groups[groups++] = group;
+ }
+
+ if (data->in_num) {
+ group = nct6683_create_attr_group(dev,
+ &nct6683_in_template_group,
+ data->in_num);
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+ data->groups[groups++] = group;
+ }
+
+ if (data->have_fan) {
+ group = nct6683_create_attr_group(dev,
+ &nct6683_fan_template_group,
+ fls(data->have_fan));
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+ data->groups[groups++] = group;
+ }
+
+ if (data->temp_num) {
+ group = nct6683_create_attr_group(dev,
+ &nct6683_temp_template_group,
+ data->temp_num);
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+ data->groups[groups++] = group;
+ }
+ data->groups[groups++] = &nct6683_group_other;
+
+ dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n",
+ nct6683_chip_names[data->kind],
+ nct6683_read(data, NCT6683_REG_VERSION_HI),
+ nct6683_read(data, NCT6683_REG_VERSION_LO),
+ nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+ nct6683_read(data, NCT6683_REG_BUILD_DAY),
+ nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+ nct6683_device_names[data->kind], data, data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+#ifdef CONFIG_PM
+static int nct6683_suspend(struct device *dev)
+{
+ struct nct6683_data *data = nct6683_update_device(dev);
+
+ mutex_lock(&data->update_lock);
+ data->hwm_cfg = nct6683_read(data, NCT6683_HWM_CFG);
+ mutex_unlock(&data->update_lock);
+
+ return 0;
+}
+
+static int nct6683_resume(struct device *dev)
+{
+ struct nct6683_data *data = dev_get_drvdata(dev);
+
+ mutex_lock(&data->update_lock);
+
+ nct6683_write(data, NCT6683_HWM_CFG, data->hwm_cfg);
+
+ /* Force re-reading all values */
+ data->valid = false;
+ mutex_unlock(&data->update_lock);
+
+ return 0;
+}
+
+static const struct dev_pm_ops nct6683_dev_pm_ops = {
+ .suspend = nct6683_suspend,
+ .resume = nct6683_resume,
+ .freeze = nct6683_suspend,
+ .restore = nct6683_resume,
+};
+
+#define NCT6683_DEV_PM_OPS (&nct6683_dev_pm_ops)
+#else
+#define NCT6683_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nct6683_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ .pm = NCT6683_DEV_PM_OPS,
+ },
+ .probe = nct6683_probe,
+};
+
+static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
+{
+ const char *board_vendor;
+ int addr;
+ u16 val;
+ int err;
+
+ /*
+ * Only run on Intel boards unless the 'force' module parameter is set
+ */
+ if (!force) {
+ board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+ if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
+ return -ENODEV;
+ }
+
+ err = superio_enter(sioaddr);
+ if (err)
+ return err;
+
+ val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+ | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+
+ switch (val & SIO_ID_MASK) {
+ case SIO_NCT6683_ID:
+ sio_data->kind = nct6683;
+ break;
+ default:
+ if (val != 0xffff)
+ pr_debug("unsupported chip ID: 0x%04x\n", val);
+ goto fail;
+ }
+
+ /* We have a known chip, find the HWM I/O address */
+ superio_select(sioaddr, NCT6683_LD_HWM);
+ val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+ | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+ addr = val & IOREGION_ALIGNMENT;
+ if (addr == 0) {
+ pr_err("EC base I/O port unconfigured\n");
+ goto fail;
+ }
+
+ /* Activate logical device if needed */
+ val = superio_inb(sioaddr, SIO_REG_ENABLE);
+ if (!(val & 0x01)) {
+ pr_err("EC is disabled\n");
+ goto fail;
+ }
+
+ superio_exit(sioaddr);
+ pr_info("Found %s or compatible chip at %#x:%#x\n",
+ nct6683_chip_names[sio_data->kind], sioaddr, addr);
+ sio_data->sioreg = sioaddr;
+
+ return addr;
+
+fail:
+ superio_exit(sioaddr);
+ return -ENODEV;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the nct6683 driver. But since we use platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev[2];
+
+static int __init sensors_nct6683_init(void)
+{
+ struct nct6683_sio_data sio_data;
+ int sioaddr[2] = { 0x2e, 0x4e };
+ struct resource res;
+ bool found = false;
+ int address;
+ int i, err;
+
+ err = platform_driver_register(&nct6683_driver);
+ if (err)
+ return err;
+
+ /*
+ * initialize sio_data->kind and sio_data->sioreg.
+ *
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+ * nct6683 hardware monitor, and call probe()
+ */
+ for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ address = nct6683_find(sioaddr[i], &sio_data);
+ if (address <= 0)
+ continue;
+
+ found = true;
+
+ pdev[i] = platform_device_alloc(DRVNAME, address);
+ if (!pdev[i]) {
+ err = -ENOMEM;
+ goto exit_device_unregister;
+ }
+
+ err = platform_device_add_data(pdev[i], &sio_data,
+ sizeof(struct nct6683_sio_data));
+ if (err)
+ goto exit_device_put;
+
+ memset(&res, 0, sizeof(res));
+ res.name = DRVNAME;
+ res.start = address + IOREGION_OFFSET;
+ res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+ res.flags = IORESOURCE_IO;
+
+ err = acpi_check_resource_conflict(&res);
+ if (err) {
+ platform_device_put(pdev[i]);
+ pdev[i] = NULL;
+ continue;
+ }
+
+ err = platform_device_add_resources(pdev[i], &res, 1);
+ if (err)
+ goto exit_device_put;
+
+ /* platform_device_add calls probe() */
+ err = platform_device_add(pdev[i]);
+ if (err)
+ goto exit_device_put;
+ }
+ if (!found) {
+ err = -ENODEV;
+ goto exit_unregister;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev[i]);
+exit_device_unregister:
+ while (--i >= 0) {
+ if (pdev[i])
+ platform_device_unregister(pdev[i]);
+ }
+exit_unregister:
+ platform_driver_unregister(&nct6683_driver);
+ return err;
+}
+
+static void __exit sensors_nct6683_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ if (pdev[i])
+ platform_device_unregister(pdev[i]);
+ }
+ platform_driver_unregister(&nct6683_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT6683D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6683_init);
+module_exit(sensors_nct6683_exit);
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 38d5a6334053..59d9a3fc96b7 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -4160,7 +4160,7 @@ static int __init sensors_nct6775_init(void)
pdev[i] = platform_device_alloc(DRVNAME, address);
if (!pdev[i]) {
err = -ENOMEM;
- goto exit_device_put;
+ goto exit_device_unregister;
}
err = platform_device_add_data(pdev[i], &sio_data,
@@ -4198,9 +4198,11 @@ static int __init sensors_nct6775_init(void)
return 0;
exit_device_put:
- for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ platform_device_put(pdev[i]);
+exit_device_unregister:
+ while (--i >= 0) {
if (pdev[i])
- platform_device_put(pdev[i]);
+ platform_device_unregister(pdev[i]);
}
exit_unregister:
platform_driver_unregister(&nct6775_driver);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index d847e0a084e0..9e4684e747ea 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -1081,10 +1081,8 @@ static int pc87427_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data),
GFP_KERNEL);
- if (!data) {
- pr_err("Out of memory\n");
+ if (!data)
return -ENOMEM;
- }
data->address[0] = sio_data->address[0];
data->address[1] = sio_data->address[1];
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index 73bd64e8c30a..0674c13bbd4b 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -285,10 +285,8 @@ static int s3c_hwmon_probe(struct platform_device *dev)
}
hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL);
- if (hwmon == NULL) {
- dev_err(&dev->dev, "no memory\n");
+ if (hwmon == NULL)
return -ENOMEM;
- }
platform_set_drvdata(dev, hwmon);
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 6748b4583e7b..51719956cc03 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -51,6 +51,7 @@
#define TMP102_THIGH_REG 0x03
struct tmp102 {
+ struct i2c_client *client;
struct device *hwmon_dev;
struct thermal_zone_device *tz;
struct mutex lock;
@@ -77,9 +78,10 @@ static const u8 tmp102_reg[] = {
TMP102_THIGH_REG,
};
-static struct tmp102 *tmp102_update_device(struct i2c_client *client)
+static struct tmp102 *tmp102_update_device(struct device *dev)
{
- struct tmp102 *tmp102 = i2c_get_clientdata(client);
+ struct tmp102 *tmp102 = dev_get_drvdata(dev);
+ struct i2c_client *client = tmp102->client;
mutex_lock(&tmp102->lock);
if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
@@ -98,7 +100,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client)
static int tmp102_read_temp(void *dev, long *temp)
{
- struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+ struct tmp102 *tmp102 = tmp102_update_device(dev);
*temp = tmp102->temp[0];
@@ -110,7 +112,7 @@ static ssize_t tmp102_show_temp(struct device *dev,
char *buf)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
- struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+ struct tmp102 *tmp102 = tmp102_update_device(dev);
return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
}
@@ -120,8 +122,8 @@ static ssize_t tmp102_set_temp(struct device *dev,
const char *buf, size_t count)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
- struct i2c_client *client = to_i2c_client(dev);
- struct tmp102 *tmp102 = i2c_get_clientdata(client);
+ struct tmp102 *tmp102 = dev_get_drvdata(dev);
+ struct i2c_client *client = tmp102->client;
long val;
int status;
@@ -145,16 +147,13 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
tmp102_set_temp, 2);
-static struct attribute *tmp102_attributes[] = {
+static struct attribute *tmp102_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
NULL
};
-
-static const struct attribute_group tmp102_attr_group = {
- .attrs = tmp102_attributes,
-};
+ATTRIBUTE_GROUPS(tmp102);
#define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
@@ -162,72 +161,68 @@ static const struct attribute_group tmp102_attr_group = {
static int tmp102_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct tmp102 *tmp102;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_err(&client->dev,
+ dev_err(dev,
"adapter doesn't support SMBus word transactions\n");
return -ENODEV;
}
- tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL);
+ tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL);
if (!tmp102)
return -ENOMEM;
i2c_set_clientdata(client, tmp102);
+ tmp102->client = client;
status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
if (status < 0) {
- dev_err(&client->dev, "error reading config register\n");
+ dev_err(dev, "error reading config register\n");
return status;
}
tmp102->config_orig = status;
status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
TMP102_CONFIG);
if (status < 0) {
- dev_err(&client->dev, "error writing config register\n");
+ dev_err(dev, "error writing config register\n");
goto fail_restore_config;
}
status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
if (status < 0) {
- dev_err(&client->dev, "error reading config register\n");
+ dev_err(dev, "error reading config register\n");
goto fail_restore_config;
}
status &= ~TMP102_CONFIG_RD_ONLY;
if (status != TMP102_CONFIG) {
- dev_err(&client->dev, "config settings did not stick\n");
+ dev_err(dev, "config settings did not stick\n");
status = -ENODEV;
goto fail_restore_config;
}
tmp102->last_update = jiffies - HZ;
mutex_init(&tmp102->lock);
- status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
- if (status) {
- dev_dbg(&client->dev, "could not create sysfs files\n");
+ hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+ tmp102, tmp102_groups);
+ if (IS_ERR(hwmon_dev)) {
+ dev_dbg(dev, "unable to register hwmon device\n");
+ status = PTR_ERR(hwmon_dev);
goto fail_restore_config;
}
- tmp102->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(tmp102->hwmon_dev)) {
- dev_dbg(&client->dev, "unable to register hwmon device\n");
- status = PTR_ERR(tmp102->hwmon_dev);
- goto fail_remove_sysfs;
- }
-
- tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0,
- &client->dev,
+ tmp102->hwmon_dev = hwmon_dev;
+ tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
tmp102_read_temp, NULL);
if (IS_ERR(tmp102->tz))
tmp102->tz = NULL;
- dev_info(&client->dev, "initialized\n");
+ dev_info(dev, "initialized\n");
return 0;
-fail_remove_sysfs:
- sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
fail_restore_config:
i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
tmp102->config_orig);
@@ -238,9 +233,8 @@ static int tmp102_remove(struct i2c_client *client)
{
struct tmp102 *tmp102 = i2c_get_clientdata(client);
- thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz);
+ thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz);
hwmon_device_unregister(tmp102->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
/* Stop monitoring if device was stopped originally */
if (tmp102->config_orig & TMP102_CONF_SD) {
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index ae26b06fa819..7bab7a9bedc6 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -69,7 +69,7 @@ static const struct i2c_device_id tmp421_id[] = {
MODULE_DEVICE_TABLE(i2c, tmp421_id);
struct tmp421_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid;
unsigned long last_updated;
@@ -99,8 +99,8 @@ static int temp_from_u16(u16 reg)
static struct tmp421_data *tmp421_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct tmp421_data *data = i2c_get_clientdata(client);
+ struct tmp421_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int i;
mutex_lock(&data->update_lock);
@@ -198,6 +198,11 @@ static const struct attribute_group tmp421_group = {
.is_visible = tmp421_is_visible,
};
+static const struct attribute_group *tmp421_groups[] = {
+ &tmp421_group,
+ NULL
+};
+
static int tmp421_init_client(struct i2c_client *client)
{
int config, config_orig;
@@ -264,47 +269,26 @@ static int tmp421_detect(struct i2c_client *client,
static int tmp421_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct tmp421_data *data;
int err;
- data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->channels = id->driver_data;
+ data->client = client;
err = tmp421_init_client(client);
if (err)
return err;
- err = sysfs_create_group(&client->dev.kobj, &tmp421_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- data->hwmon_dev = NULL;
- goto exit_remove;
- }
- return 0;
-
-exit_remove:
- sysfs_remove_group(&client->dev.kobj, &tmp421_group);
- return err;
-}
-
-static int tmp421_remove(struct i2c_client *client)
-{
- struct tmp421_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &tmp421_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, tmp421_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static struct i2c_driver tmp421_driver = {
@@ -313,7 +297,6 @@ static struct i2c_driver tmp421_driver = {
.name = "tmp421",
},
.probe = tmp421_probe,
- .remove = tmp421_remove,
.id_table = tmp421_id,
.detect = tmp421_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index fb3e69341c1b..7d4658636064 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -252,7 +252,7 @@ static const struct attribute_group env_group = {
static int env_probe(struct platform_device *op)
{
- struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct env *p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
int err = -ENOMEM;
if (!p)
@@ -262,7 +262,7 @@ static int env_probe(struct platform_device *op)
p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
if (!p->regs)
- goto out_free;
+ goto out;
err = sysfs_create_group(&op->dev.kobj, &env_group);
if (err)
@@ -286,8 +286,6 @@ out_sysfs_remove_group:
out_iounmap:
of_iounmap(&op->resource[0], p->regs, REG_SIZE);
-out_free:
- kfree(p);
goto out;
}
@@ -299,7 +297,6 @@ static int env_remove(struct platform_device *op)
sysfs_remove_group(&op->dev.kobj, &env_group);
hwmon_device_unregister(p->hwmon_dev);
of_iounmap(&op->resource[0], p->regs, REG_SIZE);
- kfree(p);
}
return 0;
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 6b2f1a42b3ff..344b22ec2553 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -1152,10 +1152,8 @@ static int vt1211_probe(struct platform_device *pdev)
int i, err;
data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL);
- if (!data) {
- dev_err(dev, "Out of memory\n");
+ if (!data)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(dev, res->start, resource_size(res),