Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging into next
Pull hwmon updates from Guenter Roeck:
"New driver for NCT6683D
New chip support to existing drivers:
- add support for STTS2004 and AT30TSE004 to jc42 driver
- add support for EMC1402/EMC1412/EMC1422 to emc1403 driver
Other notable changes:
- document hwmon kernel API
- convert jc42, lm70, lm75, lm77, lm83, lm92, max1619, tmp421, and
tmp102 drivers to use new hwmon API functions
- replace function macros in lm80, lm92, and jc42 drivers with real
code
- convert emc1403 driver to use regmap, add support for additional
attributes, and add device IDs for EMC1412, EMC1413, and EMC1414
- various additional cleanup and minor bug fixes in several drivers"
* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (60 commits)
hwmon: (nct6775) Fix probe unwind paths to properly unregister platform devices
hwmon: (nct6683) Fix probe unwind paths to properly unregister platform devices
hwmon: (ultra45_env) Introduce managed version of kzalloc
hwmon: Driver for NCT6683D
hwmon: (lm80) Rearrange code to avoid forward declarations
hwmon: (lm80) Convert fan display function macros into functions
hwmon: (lm80) Convert voltage display function macros into functions
hwmon: (lm80) Convert temperature display function macros into functions
hwmon: (lm80) Normalize all temperature values to 16 bit
hwmon: (lm80) Simplify TEMP_FROM_REG
hwmon: (lm83) Convert to use devm_hwmon_device_register_with_groups
hwmon: (lm83) Rearange code to avoid forward declarations
hwmon: (lm83) Drop FSF address
hwmon: (max1619) Convert to use devm_hwmon_device_register_with_groups
hwmon: (max1619) Drop function macros
hwmon: (max1619) Rearrange code to avoid forward declarations
hwmon: (max1619) Drop FSF address
hwmon: (max1619) Fix critical alarm display
hwmon: (jc42) Add support for STTS2004 and AT30TSE004
hwmon: (jc42) Convert function macros into functions
...
This commit is contained in:
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
+186
-83
@@ -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;
|
||||
mutex_init(&data->mutex);
|
||||
data->hyst_valid = jiffies - 1; /* Expired */
|
||||
data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
data->groups[0] = &emc1403_group;
|
||||
if (id->driver_data)
|
||||
data->groups[1] = &emc1404_group;
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" },
|
||||
{ },
|
||||
|
||||
@@ -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", },
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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", },
|
||||
{ }
|
||||
};
|
||||
|
||||
+146
-183
@@ -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,80 +223,82 @@ static int jc42_temp_from_reg(s16 reg)
|
||||
return reg * 125 / 2;
|
||||
}
|
||||
|
||||
/* sysfs stuff */
|
||||
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;
|
||||
|
||||
/* 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)); \
|
||||
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);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%d\n",
|
||||
jc42_temp_from_reg(data->temp[attr->index]));
|
||||
}
|
||||
|
||||
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_crit);
|
||||
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);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max_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 jc42_data *data = jc42_update_device(dev);
|
||||
int temp, hyst;
|
||||
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;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
temp = jc42_temp_from_reg(data->temp_max);
|
||||
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
|
||||
>> JC42_CFG_HYST_SHIFT];
|
||||
return sprintf(buf, "%d\n", temp - hyst);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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; \
|
||||
}
|
||||
|
||||
set(temp_min, JC42_REG_TEMP_LOWER);
|
||||
set(temp_max, JC42_REG_TEMP_UPPER);
|
||||
set(temp_crit, JC42_REG_TEMP_CRITICAL);
|
||||
|
||||
/*
|
||||
* JC42.4 compliant chips only support four hysteresis values.
|
||||
* Pick best choice and go from there.
|
||||
@@ -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,53 +496,57 @@ 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);
|
||||
|
||||
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;
|
||||
|
||||
val = i2c_smbus_read_word_swapped(client,
|
||||
JC42_REG_TEMP_CRITICAL);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->temp_crit = val;
|
||||
|
||||
val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->temp_min = val;
|
||||
|
||||
val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->temp_max = val;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
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 */
|
||||
|
||||
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);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
|
||||
+14
-48
@@ -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);
|
||||
|
||||
+20
-31
@@ -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);
|
||||
|
||||
+155
-233
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 struct lm77_data *lm77_update_device(struct device *dev)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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); \
|
||||
}
|
||||
|
||||
show(temp_input);
|
||||
show(temp_crit);
|
||||
show(temp_min);
|
||||
show(temp_max);
|
||||
|
||||
/* 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 lm77_data *data = lm77_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst);
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp[attr->index]);
|
||||
}
|
||||
static ssize_t show_temp_min_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_min + data->temp_hyst);
|
||||
int nr = attr->index;
|
||||
int temp;
|
||||
|
||||
temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
|
||||
data->temp[nr] - data->temp[t_hyst];
|
||||
|
||||
return sprintf(buf, "%d\n", temp);
|
||||
}
|
||||
static ssize_t show_temp_max_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 lm77_data *data = lm77_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_max - data->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 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; \
|
||||
}
|
||||
|
||||
set(temp_min, LM77_REG_TEMP_MIN);
|
||||
set(temp_max, LM77_REG_TEMP_MAX);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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 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 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_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,68 +318,6 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->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);
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
@@ -407,42 +326,45 @@ static void lm77_init_client(struct i2c_client *client)
|
||||
lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
|
||||
}
|
||||
|
||||
static struct lm77_data *lm77_update_device(struct device *dev)
|
||||
static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm77_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct lm77_data *data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
}
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
/* Initialize the LM77 chip */
|
||||
lm77_init_client(client);
|
||||
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, lm77_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_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,
|
||||
.id_table = lm77_id,
|
||||
.detect = lm77_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(lm77_driver);
|
||||
|
||||
MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>");
|
||||
|
||||
+305
-337
@@ -86,27 +86,42 @@ 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;
|
||||
|
||||
temp >>= 4;
|
||||
if (temp < 0x0800)
|
||||
res = 625 * (long) temp;
|
||||
else
|
||||
res = ((long) temp - 0x01000) * 625;
|
||||
|
||||
return res / 10;
|
||||
}
|
||||
|
||||
#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \
|
||||
(val) - 0x100 : (val)) * 1000)
|
||||
|
||||
#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \
|
||||
((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
|
||||
#define TEMP_FROM_REG(reg) ((reg) * 125 / 32)
|
||||
#define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \
|
||||
-128000, 127000), 1000) << 8)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
|
||||
enum temp_index {
|
||||
t_input = 0,
|
||||
t_hot_max,
|
||||
t_hot_hyst,
|
||||
t_os_max,
|
||||
t_os_hyst,
|
||||
t_num_temp
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum in_index {
|
||||
i_input = 0,
|
||||
i_max,
|
||||
i_min,
|
||||
i_num_in
|
||||
};
|
||||
|
||||
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])); \
|
||||
}
|
||||
show_in(min, in_min)
|
||||
show_in(max, in_max)
|
||||
show_in(input, in)
|
||||
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;
|
||||
|
||||
#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; \
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index]));
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
#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; \
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
static const struct i2c_device_id lm80_id[] = {
|
||||
{ "lm80", 0 },
|
||||
{ "lm96080", 1 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm80_id);
|
||||
|
||||
/* 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;
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
+62
-104
@@ -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>
|
||||
@@ -110,46 +106,13 @@ static const u8 LM83_REG_W_HIGH[] = {
|
||||
LM83_REG_W_TCRIT,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
data->groups[0] = &lm83_group;
|
||||
if (id->driver_data == lm83)
|
||||
data->groups[1] = &lm83_group_opt;
|
||||
|
||||
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;
|
||||
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 int lm83_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm83_data *data = i2c_get_clientdata(client);
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
|
||||
static const struct i2c_device_id lm83_id[] = {
|
||||
{ "lm83", lm83 },
|
||||
{ "lm82", lm82 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm83_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
+104
-136
@@ -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);
|
||||
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);
|
||||
|
||||
#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; \
|
||||
}
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
static ssize_t show_temp1_max_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_max)
|
||||
- TEMP_FROM_REG(data->temp1_hyst));
|
||||
}
|
||||
static ssize_t show_temp1_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[attr->index]));
|
||||
}
|
||||
|
||||
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(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;
|
||||
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_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->temp[attr->index])
|
||||
- TEMP_FROM_REG(data->temp[t_hyst]));
|
||||
}
|
||||
|
||||
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->temp[t_min])
|
||||
+ TEMP_FROM_REG(data->temp[t_hyst]));
|
||||
}
|
||||
|
||||
static ssize_t set_temp_hyst(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Driver for Linear Technology LTC2945 I2C Power Monitor
|
||||
*
|
||||
* Copyright (c) 2014 Guenter Roeck
|
||||
|
||||
@@ -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:
|
||||
|
||||
+132
-172
@@ -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);
|
||||
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);
|
||||
|
||||
#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; \
|
||||
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);
|
||||
struct max1619_data *data;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &max1619_group);
|
||||
data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
data->client = new_client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the MAX1619 chip */
|
||||
max1619_init_client(new_client);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
|
||||
new_client->name,
|
||||
data,
|
||||
max1619_groups);
|
||||
return PTR_ERR_OR_ZERO(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);
|
||||
static const struct i2c_device_id max1619_id[] = {
|
||||
{ "max1619", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max1619_id);
|
||||
|
||||
mutex_lock(&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);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+28
-34
@@ -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) {
|
||||
|
||||
+15
-32
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user