提交 d1e0fe25 编写于 作者: L Linus Torvalds

Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging: (23 commits)
  hwmon: (lm75) Add support for the Texas Instruments TMP105
  hwmon: (ltc4245) Read only one GPIO pin
  hwmon: (dme1737) Add SCH5127 support
  hwmon: (tmp102) Don't always stop chip at exit
  hwmon: (tmp102) Fix suspend and resume functions
  hwmon: (tmp102) Various fixes
  hwmon: Driver for TI TMP102 temperature sensor
  hwmon: EMC1403 thermal sensor support
  hwmon: (applesmc) Add temperature sensor labels to sysfs interface
  hwmon: (applesmc) Add generic support for MacBook Pro 7
  hwmon: (applesmc) Add generic support for MacBook Pro 6
  hwmon: (applesmc) Add support for MacBook Pro 5,3 and 5,4
  hwmon: (tmp401) Reorganize code to get rid of static forward declarations
  hwmon: (tmp401) Use constants for sysfs file permissions
  hwmon: (adm1031) Allow setting update rate
  hwmon: Add description of the update_rate sysfs attribute
  hwmon: (lm90) Use programmed update rate
  hwmon: (f71882fg) Acquire I/O regions while we're working with them
  hwmon: (f71882fg) Code cleanup
  hwmon: (f71882fg) Use strict_stro(l|ul) instead of simple_strto$1
  ...
...@@ -9,11 +9,15 @@ Supported chips: ...@@ -9,11 +9,15 @@ Supported chips:
* SMSC SCH3112, SCH3114, SCH3116 * SMSC SCH3112, SCH3114, SCH3116
Prefix: 'sch311x' Prefix: 'sch311x'
Addresses scanned: none, address read from Super-I/O config space Addresses scanned: none, address read from Super-I/O config space
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf Datasheet: Available on the Internet
* SMSC SCH5027 * SMSC SCH5027
Prefix: 'sch5027' Prefix: 'sch5027'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Provided by SMSC upon request and under NDA Datasheet: Provided by SMSC upon request and under NDA
* SMSC SCH5127
Prefix: 'sch5127'
Addresses scanned: none, address read from Super-I/O config space
Datasheet: Provided by SMSC upon request and under NDA
Authors: Authors:
Juerg Haefliger <juergh@gmail.com> Juerg Haefliger <juergh@gmail.com>
...@@ -36,8 +40,8 @@ Description ...@@ -36,8 +40,8 @@ Description
----------- -----------
This driver implements support for the hardware monitoring capabilities of the This driver implements support for the hardware monitoring capabilities of the
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x,
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors and SCH5127 Super-I/O chips. These chips feature monitoring of 3 temp sensors
temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement 1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
...@@ -48,14 +52,14 @@ Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on ...@@ -48,14 +52,14 @@ Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
the configuration of the chip. The driver will detect which features are the configuration of the chip. The driver will detect which features are
present during initialization and create the sysfs attributes accordingly. present during initialization and create the sysfs attributes accordingly.
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and For the SCH311x and SCH5127, fan[1-3] and pwm[1-3] are always present and
pwm[5-6] don't exist. fan[4-6] and pwm[5-6] don't exist.
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
accessible via SMBus, while the SCH311x only provides access via the ISA bus. accessible via SMBus, while the SCH311x and SCH5127 only provide access via
The driver will therefore register itself as an I2C client driver if it detects the ISA bus. The driver will therefore register itself as an I2C client driver
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x if it detects a DME1737, A8000, or SCH5027 and as a platform driver if it
chip. detects a SCH311x or SCH5127 chip.
Voltage Monitoring Voltage Monitoring
...@@ -76,7 +80,7 @@ DME1737, A8000: ...@@ -76,7 +80,7 @@ DME1737, A8000:
in6: Vbat (+3.0V) 0V - 4.38V in6: Vbat (+3.0V) 0V - 4.38V
SCH311x: SCH311x:
in0: +2.5V 0V - 6.64V in0: +2.5V 0V - 3.32V
in1: Vccp (processor core) 0V - 2V in1: Vccp (processor core) 0V - 2V
in2: VCC (internal +3.3V) 0V - 4.38V in2: VCC (internal +3.3V) 0V - 4.38V
in3: +5V 0V - 6.64V in3: +5V 0V - 6.64V
...@@ -93,6 +97,15 @@ SCH5027: ...@@ -93,6 +97,15 @@ SCH5027:
in5: VTR (+3.3V standby) 0V - 4.38V in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V in6: Vbat (+3.0V) 0V - 4.38V
SCH5127:
in0: +2.5 0V - 3.32V
in1: Vccp (processor core) 0V - 3V
in2: VCC (internal +3.3V) 0V - 4.38V
in3: V2_IN 0V - 1.5V
in4: V1_IN 0V - 1.5V
in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V
Each voltage input has associated min and max limits which trigger an alarm Each voltage input has associated min and max limits which trigger an alarm
when crossed. when crossed.
...@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the ...@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the
pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the
full-speed duty-cycle which is hard- full-speed duty-cycle which is hard-
wired to 255 (100% duty-cycle). wired to 255 (100% duty-cycle).
Chip Differences
----------------
Feature dme1737 sch311x sch5027 sch5127
-------------------------------------------------------
temp[1-3]_offset yes yes
vid yes
zone3 yes yes yes
zone[1-3]_hyst yes yes
pwm min/off yes yes
fan3 opt yes opt yes
pwm3 opt yes opt yes
fan4 opt opt
fan5 opt opt
pwm5 opt opt
fan6 opt opt
pwm6 opt opt
...@@ -7,6 +7,11 @@ Supported chips: ...@@ -7,6 +7,11 @@ Supported chips:
Addresses scanned: I2C 0x4c Addresses scanned: I2C 0x4c
Datasheet: Publicly available at the National Semiconductor website Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/pf/LM/LM63.html http://www.national.com/pf/LM/LM63.html
* National Semiconductor LM64
Prefix: 'lm64'
Addresses scanned: I2C 0x18 and 0x4e
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/pf/LM/LM64.html
Author: Jean Delvare <khali@linux-fr.org> Author: Jean Delvare <khali@linux-fr.org>
...@@ -55,3 +60,5 @@ The lm63 driver will not update its values more frequently than every ...@@ -55,3 +60,5 @@ The lm63 driver will not update its values more frequently than every
second; reading them more often will do no harm, but will return 'old' second; reading them more often will do no harm, but will return 'old'
values. values.
The LM64 is effectively an LM63 with GPIO lines. The driver does not
support these GPIO lines at present.
...@@ -72,9 +72,7 @@ in6_min_alarm 5v output undervoltage alarm ...@@ -72,9 +72,7 @@ in6_min_alarm 5v output undervoltage alarm
in7_min_alarm 3v output undervoltage alarm in7_min_alarm 3v output undervoltage alarm
in8_min_alarm Vee (-12v) output undervoltage alarm in8_min_alarm Vee (-12v) output undervoltage alarm
in9_input GPIO #1 voltage data in9_input GPIO voltage data
in10_input GPIO #2 voltage data
in11_input GPIO #3 voltage data
power1_input 12v power usage (mW) power1_input 12v power usage (mW)
power2_input 5v power usage (mW) power2_input 5v power usage (mW)
......
...@@ -80,9 +80,9 @@ All entries (except name) are optional, and should only be created in a ...@@ -80,9 +80,9 @@ All entries (except name) are optional, and should only be created in a
given driver if the chip has the feature. given driver if the chip has the feature.
******** *********************
* Name * * Global attributes *
******** *********************
name The chip name. name The chip name.
This should be a short, lowercase string, not containing This should be a short, lowercase string, not containing
...@@ -91,6 +91,13 @@ name The chip name. ...@@ -91,6 +91,13 @@ name The chip name.
I2C devices get this attribute created automatically. I2C devices get this attribute created automatically.
RO RO
update_rate The rate at which the chip will update readings.
Unit: millisecond
RW
Some devices have a variable update rate. This attribute
can be used to change the update rate to the desired
frequency.
************ ************
* Voltages * * Voltages *
......
Kernel driver tmp102
====================
Supported chips:
* Texas Instruments TMP102
Prefix: 'tmp102'
Addresses scanned: none
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html
Author:
Steven King <sfking@fdwdc.com>
Description
-----------
The Texas Instruments TMP102 implements one temperature sensor. Limits can be
set through the Overtemperature Shutdown register and Hysteresis register. The
sensor is accurate to 0.5 degree over the range of -25 to +85 C, and to 1.0
degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The
operating temperature has a minimum of -55 C and a maximum of +150 C.
The TMP102 has a programmable update rate that can select between 8, 4, 1, and
0.5 Hz. (Currently the driver only supports the default of 4 Hz).
The driver provides the common sysfs-interface for temperatures (see
Documentation/hwmon/sysfs-interface under Temperatures).
...@@ -1206,6 +1206,15 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n, ...@@ -1206,6 +1206,15 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
} }
EXPORT_SYMBOL(acpi_check_mem_region); EXPORT_SYMBOL(acpi_check_mem_region);
/*
* Let drivers know whether the resource checks are effective
*/
int acpi_resources_are_enforced(void)
{
return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT;
}
EXPORT_SYMBOL(acpi_resources_are_enforced);
/* /*
* Acquire a spinlock. * Acquire a spinlock.
* *
......
...@@ -447,13 +447,14 @@ config SENSORS_IT87 ...@@ -447,13 +447,14 @@ config SENSORS_IT87
will be called it87. will be called it87.
config SENSORS_LM63 config SENSORS_LM63
tristate "National Semiconductor LM63" tristate "National Semiconductor LM63 and LM64"
depends on I2C depends on I2C
help help
If you say yes here you get support for the National Semiconductor If you say yes here you get support for the National
LM63 remote diode digital temperature sensor with integrated fan Semiconductor LM63 and LM64 remote diode digital temperature
control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) sensors with integrated fan control. Such chips are found
motherboard, among others. on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
others.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called lm63. will be called lm63.
...@@ -492,7 +493,8 @@ config SENSORS_LM75 ...@@ -492,7 +493,8 @@ config SENSORS_LM75
- NXP's LM75A - NXP's LM75A
- ST Microelectronics STDS75 - ST Microelectronics STDS75
- TelCom (now Microchip) TCN75 - TelCom (now Microchip) TCN75
- Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275 - Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
TMP275
This driver supports driver model based binding through board This driver supports driver model based binding through board
specific I2C device tables. specific I2C device tables.
...@@ -749,6 +751,16 @@ config SENSORS_DME1737 ...@@ -749,6 +751,16 @@ config SENSORS_DME1737
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called dme1737. will be called dme1737.
config SENSORS_EMC1403
tristate "SMSC EMC1403 thermal sensor"
depends on I2C
help
If you say yes here you get support for the SMSC EMC1403
temperature monitoring chip.
Threshold values can be configured using sysfs.
Data from the different diodes are accessible via sysfs.
config SENSORS_SMSC47M1 config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles" tristate "SMSC LPC47M10x and compatibles"
help help
...@@ -831,6 +843,16 @@ config SENSORS_THMC50 ...@@ -831,6 +843,16 @@ config SENSORS_THMC50
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called thmc50. will be called thmc50.
config SENSORS_TMP102
tristate "Texas Instruments TMP102"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for Texas Instruments TMP102
sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp102.
config SENSORS_TMP401 config SENSORS_TMP401
tristate "Texas Instruments TMP401 and compatibles" tristate "Texas Instruments TMP401 and compatibles"
depends on I2C && EXPERIMENTAL depends on I2C && EXPERIMENTAL
......
...@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o ...@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
...@@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o ...@@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) #define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
#define ADM1031_REG_PWM (0x22) #define ADM1031_REG_PWM (0x22)
#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) #define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr))
#define ADM1031_REG_FAN_FILTER (0x23)
#define ADM1031_REG_TEMP_OFFSET(nr) (0x0d + (nr)) #define ADM1031_REG_TEMP_OFFSET(nr) (0x0d + (nr))
#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) #define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr))
...@@ -61,6 +62,9 @@ ...@@ -61,6 +62,9 @@
#define ADM1031_CONF2_TACH2_ENABLE 0x08 #define ADM1031_CONF2_TACH2_ENABLE 0x08
#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) #define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan))
#define ADM1031_UPDATE_RATE_MASK 0x1c
#define ADM1031_UPDATE_RATE_SHIFT 2
/* Addresses to scan */ /* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
...@@ -75,6 +79,7 @@ struct adm1031_data { ...@@ -75,6 +79,7 @@ struct adm1031_data {
int chip_type; int chip_type;
char valid; /* !=0 if following fields are valid */ char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */ unsigned long last_updated; /* In jiffies */
unsigned int update_rate; /* In milliseconds */
/* The chan_select_table contains the possible configurations for /* The chan_select_table contains the possible configurations for
* auto fan control. * auto fan control.
*/ */
...@@ -738,6 +743,57 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12); ...@@ -738,6 +743,57 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13); static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
/* Update Rate */
static const unsigned int update_rates[] = {
16000, 8000, 4000, 2000, 1000, 500, 250, 125,
};
static ssize_t show_update_rate(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%u\n", data->update_rate);
}
static ssize_t set_update_rate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
unsigned long val;
int i, err;
u8 reg;
err = strict_strtoul(buf, 10, &val);
if (err)
return err;
/* find the nearest update rate from the table */
for (i = 0; i < ARRAY_SIZE(update_rates) - 1; i++) {
if (val >= update_rates[i])
break;
}
/* if not found, we point to the last entry (lowest update rate) */
/* set the new update rate while preserving other settings */
reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
reg &= ~ADM1031_UPDATE_RATE_MASK;
reg |= i << ADM1031_UPDATE_RATE_SHIFT;
adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
mutex_lock(&data->update_lock);
data->update_rate = update_rates[i];
mutex_unlock(&data->update_lock);
return count;
}
static DEVICE_ATTR(update_rate, S_IRUGO | S_IWUSR, show_update_rate,
set_update_rate);
static struct attribute *adm1031_attributes[] = { static struct attribute *adm1031_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr,
...@@ -774,6 +830,7 @@ static struct attribute *adm1031_attributes[] = { ...@@ -774,6 +830,7 @@ static struct attribute *adm1031_attributes[] = {
&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr, &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
&dev_attr_update_rate.attr,
&dev_attr_alarms.attr, &dev_attr_alarms.attr,
NULL NULL
...@@ -900,6 +957,7 @@ static void adm1031_init_client(struct i2c_client *client) ...@@ -900,6 +957,7 @@ static void adm1031_init_client(struct i2c_client *client)
{ {
unsigned int read_val; unsigned int read_val;
unsigned int mask; unsigned int mask;
int i;
struct adm1031_data *data = i2c_get_clientdata(client); struct adm1031_data *data = i2c_get_clientdata(client);
mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
...@@ -919,18 +977,24 @@ static void adm1031_init_client(struct i2c_client *client) ...@@ -919,18 +977,24 @@ static void adm1031_init_client(struct i2c_client *client)
ADM1031_CONF1_MONITOR_ENABLE); ADM1031_CONF1_MONITOR_ENABLE);
} }
/* Read the chip's update rate */
mask = ADM1031_UPDATE_RATE_MASK;
read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
data->update_rate = update_rates[i];
} }
static struct adm1031_data *adm1031_update_device(struct device *dev) static struct adm1031_data *adm1031_update_device(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client); struct adm1031_data *data = i2c_get_clientdata(client);
unsigned long next_update;
int chan; int chan;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) next_update = data->last_updated + msecs_to_jiffies(data->update_rate);
|| !data->valid) { if (time_after(jiffies, next_update) || !data->valid) {
dev_dbg(&client->dev, "Starting adm1031 update\n"); dev_dbg(&client->dev, "Starting adm1031 update\n");
for (chan = 0; for (chan = 0;
......
...@@ -148,6 +148,20 @@ static const char *temperature_sensors_sets[][41] = { ...@@ -148,6 +148,20 @@ static const char *temperature_sensors_sets[][41] = {
/* Set 18: MacBook Pro 2,2 */ /* Set 18: MacBook Pro 2,2 */
{ "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0", { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
"Th0H", "Th1H", "Tm0P", "Ts0P", NULL }, "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
/* Set 19: Macbook Pro 5,3 */
{ "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
"TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
"Tm0P", "Ts0P", "Ts0S", NULL },
/* Set 20: MacBook Pro 5,4 */
{ "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
"TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
/* Set 21: MacBook Pro 6,2 */
{ "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
"TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
"Ts0P", "Ts0S", NULL },
/* Set 22: MacBook Pro 7,1 */
{ "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
"TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
}; };
/* List of keys used to read/write fan speeds */ /* List of keys used to read/write fan speeds */
...@@ -646,6 +660,17 @@ static ssize_t applesmc_light_show(struct device *dev, ...@@ -646,6 +660,17 @@ static ssize_t applesmc_light_show(struct device *dev,
return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right); return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
} }
/* Displays sensor key as label */
static ssize_t applesmc_show_sensor_label(struct device *dev,
struct device_attribute *devattr, char *sysfsbuf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
const char *key =
temperature_sensors_sets[applesmc_temperature_set][attr->index];
return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
}
/* Displays degree Celsius * 1000 */ /* Displays degree Celsius * 1000 */
static ssize_t applesmc_show_temperature(struct device *dev, static ssize_t applesmc_show_temperature(struct device *dev,
struct device_attribute *devattr, char *sysfsbuf) struct device_attribute *devattr, char *sysfsbuf)
...@@ -1113,6 +1138,86 @@ static const struct attribute_group fan_attribute_groups[] = { ...@@ -1113,6 +1138,86 @@ static const struct attribute_group fan_attribute_groups[] = {
/* /*
* Temperature sensors sysfs entries. * Temperature sensors sysfs entries.
*/ */
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 3);
static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 4);
static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 7);
static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 8);
static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 9);
static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 10);
static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 11);
static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 12);
static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 13);
static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 14);
static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 15);
static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 16);
static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 17);
static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 18);
static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 19);
static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 20);
static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 21);
static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 22);
static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 23);
static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 24);
static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 25);
static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 26);
static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 27);
static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 28);
static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 29);
static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 30);
static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 31);
static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 32);
static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 33);
static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 34);
static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 35);
static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 36);
static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 37);
static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 38);
static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
applesmc_show_sensor_label, NULL, 39);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
applesmc_show_temperature, NULL, 0); applesmc_show_temperature, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
...@@ -1194,6 +1299,50 @@ static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO, ...@@ -1194,6 +1299,50 @@ static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO, static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
applesmc_show_temperature, NULL, 39); applesmc_show_temperature, NULL, 39);
static struct attribute *label_attributes[] = {
&sensor_dev_attr_temp1_label.dev_attr.attr,
&sensor_dev_attr_temp2_label.dev_attr.attr,
&sensor_dev_attr_temp3_label.dev_attr.attr,
&sensor_dev_attr_temp4_label.dev_attr.attr,
&sensor_dev_attr_temp5_label.dev_attr.attr,
&sensor_dev_attr_temp6_label.dev_attr.attr,
&sensor_dev_attr_temp7_label.dev_attr.attr,
&sensor_dev_attr_temp8_label.dev_attr.attr,
&sensor_dev_attr_temp9_label.dev_attr.attr,
&sensor_dev_attr_temp10_label.dev_attr.attr,
&sensor_dev_attr_temp11_label.dev_attr.attr,
&sensor_dev_attr_temp12_label.dev_attr.attr,
&sensor_dev_attr_temp13_label.dev_attr.attr,
&sensor_dev_attr_temp14_label.dev_attr.attr,
&sensor_dev_attr_temp15_label.dev_attr.attr,
&sensor_dev_attr_temp16_label.dev_attr.attr,
&sensor_dev_attr_temp17_label.dev_attr.attr,
&sensor_dev_attr_temp18_label.dev_attr.attr,
&sensor_dev_attr_temp19_label.dev_attr.attr,
&sensor_dev_attr_temp20_label.dev_attr.attr,
&sensor_dev_attr_temp21_label.dev_attr.attr,
&sensor_dev_attr_temp22_label.dev_attr.attr,
&sensor_dev_attr_temp23_label.dev_attr.attr,
&sensor_dev_attr_temp24_label.dev_attr.attr,
&sensor_dev_attr_temp25_label.dev_attr.attr,
&sensor_dev_attr_temp26_label.dev_attr.attr,
&sensor_dev_attr_temp27_label.dev_attr.attr,
&sensor_dev_attr_temp28_label.dev_attr.attr,
&sensor_dev_attr_temp29_label.dev_attr.attr,
&sensor_dev_attr_temp30_label.dev_attr.attr,
&sensor_dev_attr_temp31_label.dev_attr.attr,
&sensor_dev_attr_temp32_label.dev_attr.attr,
&sensor_dev_attr_temp33_label.dev_attr.attr,
&sensor_dev_attr_temp34_label.dev_attr.attr,
&sensor_dev_attr_temp35_label.dev_attr.attr,
&sensor_dev_attr_temp36_label.dev_attr.attr,
&sensor_dev_attr_temp37_label.dev_attr.attr,
&sensor_dev_attr_temp38_label.dev_attr.attr,
&sensor_dev_attr_temp39_label.dev_attr.attr,
&sensor_dev_attr_temp40_label.dev_attr.attr,
NULL
};
static struct attribute *temperature_attributes[] = { static struct attribute *temperature_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr,
...@@ -1241,6 +1390,10 @@ static struct attribute *temperature_attributes[] = { ...@@ -1241,6 +1390,10 @@ static struct attribute *temperature_attributes[] = {
static const struct attribute_group temperature_attributes_group = static const struct attribute_group temperature_attributes_group =
{ .attrs = temperature_attributes }; { .attrs = temperature_attributes };
static const struct attribute_group label_attributes_group = {
.attrs = label_attributes
};
/* Module stuff */ /* Module stuff */
/* /*
...@@ -1363,6 +1516,14 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { ...@@ -1363,6 +1516,14 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
{ .accelerometer = 0, .light = 0, .temperature_set = 17 }, { .accelerometer = 0, .light = 0, .temperature_set = 17 },
/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */ /* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
{ .accelerometer = 1, .light = 1, .temperature_set = 18 }, { .accelerometer = 1, .light = 1, .temperature_set = 18 },
/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
{ .accelerometer = 1, .light = 1, .temperature_set = 19 },
/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
{ .accelerometer = 1, .light = 1, .temperature_set = 20 },
/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
{ .accelerometer = 1, .light = 1, .temperature_set = 21 },
/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
{ .accelerometer = 1, .light = 1, .temperature_set = 22 },
}; };
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
...@@ -1376,6 +1537,22 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { ...@@ -1376,6 +1537,22 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
&applesmc_dmi_data[7]}, &applesmc_dmi_data[7]},
{ applesmc_dmi_match, "Apple MacBook Pro 7", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
&applesmc_dmi_data[22]},
{ applesmc_dmi_match, "Apple MacBook Pro 5,4", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
&applesmc_dmi_data[20]},
{ applesmc_dmi_match, "Apple MacBook Pro 5,3", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
&applesmc_dmi_data[19]},
{ applesmc_dmi_match, "Apple MacBook Pro 6", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
&applesmc_dmi_data[21]},
{ applesmc_dmi_match, "Apple MacBook Pro 5", { { applesmc_dmi_match, "Apple MacBook Pro 5", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") }, DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
...@@ -1518,7 +1695,8 @@ static int __init applesmc_init(void) ...@@ -1518,7 +1695,8 @@ static int __init applesmc_init(void)
for (i = 0; for (i = 0;
temperature_sensors_sets[applesmc_temperature_set][i] != NULL; temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
i++) { i++) {
if (temperature_attributes[i] == NULL) { if (temperature_attributes[i] == NULL ||
label_attributes[i] == NULL) {
printk(KERN_ERR "applesmc: More temperature sensors " printk(KERN_ERR "applesmc: More temperature sensors "
"in temperature_sensors_sets (at least %i)" "in temperature_sensors_sets (at least %i)"
"than available sysfs files in " "than available sysfs files in "
...@@ -1530,6 +1708,10 @@ static int __init applesmc_init(void) ...@@ -1530,6 +1708,10 @@ static int __init applesmc_init(void)
temperature_attributes[i]); temperature_attributes[i]);
if (ret) if (ret)
goto out_temperature; goto out_temperature;
ret = sysfs_create_file(&pdev->dev.kobj,
label_attributes[i]);
if (ret)
goto out_temperature;
} }
if (applesmc_accelerometer) { if (applesmc_accelerometer) {
...@@ -1580,6 +1762,7 @@ static int __init applesmc_init(void) ...@@ -1580,6 +1762,7 @@ static int __init applesmc_init(void)
if (applesmc_accelerometer) if (applesmc_accelerometer)
applesmc_release_accelerometer(); applesmc_release_accelerometer();
out_temperature: out_temperature:
sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
out_fans: out_fans:
while (fans_handled) while (fans_handled)
...@@ -1609,6 +1792,7 @@ static void __exit applesmc_exit(void) ...@@ -1609,6 +1792,7 @@ static void __exit applesmc_exit(void)
} }
if (applesmc_accelerometer) if (applesmc_accelerometer)
applesmc_release_accelerometer(); applesmc_release_accelerometer();
sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
while (fans_handled) while (fans_handled)
sysfs_remove_group(&pdev->dev.kobj, sysfs_remove_group(&pdev->dev.kobj,
......
...@@ -1411,6 +1411,13 @@ static int __init atk0110_init(void) ...@@ -1411,6 +1411,13 @@ static int __init atk0110_init(void)
{ {
int ret; int ret;
/* Make sure it's safe to access the device through ACPI */
if (!acpi_resources_are_enforced()) {
pr_err("atk: Resources not safely usable due to "
"acpi_enforce_resources kernel parameter\n");
return -EBUSY;
}
ret = acpi_bus_register_driver(&atk_driver); ret = acpi_bus_register_driver(&atk_driver);
if (ret) if (ret)
pr_info("atk: acpi_bus_register_driver failed: %d\n", ret); pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
......
此差异已折叠。
/*
* emc1403.c - SMSC Thermal Driver
*
* Copyright (C) 2008 Intel Corp
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* TODO
* - cache alarm and critical limit registers
* - add emc1404 support
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
#define THERMAL_PID_REG 0xfd
#define THERMAL_SMSC_ID_REG 0xfe
#define THERMAL_REVISION_REG 0xff
struct thermal_data {
struct device *hwmon_dev;
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;
};
static ssize_t show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
int retval = i2c_smbus_read_byte_data(client, sda->index);
if (retval < 0)
return retval;
return sprintf(buf, "%d000\n", retval);
}
static ssize_t show_bit(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
int retval = i2c_smbus_read_byte_data(client, sda->nr);
if (retval < 0)
return retval;
retval &= sda->index;
return sprintf(buf, "%d\n", retval ? 1 : 0);
}
static ssize_t store_temp(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct i2c_client *client = to_i2c_client(dev);
unsigned long val;
int retval;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
retval = i2c_smbus_write_byte_data(client, sda->index,
DIV_ROUND_CLOSEST(val, 1000));
if (retval < 0)
return retval;
return count;
}
static ssize_t show_hyst(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct thermal_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
int retval;
int hyst;
retval = i2c_smbus_read_byte_data(client, sda->index);
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);
}
static ssize_t store_hyst(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct thermal_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
int retval;
int hyst;
unsigned long val;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
mutex_lock(&data->mutex);
retval = i2c_smbus_read_byte_data(client, sda->index);
if (retval < 0)
goto fail;
hyst = val - retval * 1000;
hyst = DIV_ROUND_CLOSEST(hyst, 1000);
if (hyst < 0 || hyst > 255) {
retval = -ERANGE;
goto fail;
}
retval = i2c_smbus_write_byte_data(client, 0x21, hyst);
if (retval == 0) {
retval = count;
data->cached_hyst = hyst;
data->hyst_valid = jiffies + HZ;
}
fail:
mutex_unlock(&data->mutex);
return retval;
}
/*
* Sensors. We pass the actual i2c register to the methods.
*/
static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x06);
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x05);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x20);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0x00);
static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO,
show_bit, NULL, 0x36, 0x01);
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_crit_hyst, S_IRUGO | S_IWUSR,
show_hyst, store_hyst, 0x20);
static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x08);
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x07);
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_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(temp3_min, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x16);
static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
show_temp, store_temp, 0x15);
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_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 struct attribute *mid_att_thermal[] = {
&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_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_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_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_crit_hyst.dev_attr.attr,
NULL
};
static const struct attribute_group m_thermal_gr = {
.attrs = mid_att_thermal
};
static int emc1403_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
int id;
/* Check if thermal chip is SMSC and EMC1403 */
id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
if (id != 0x5d)
return -ENODEV;
/* Note: 0x25 is the 1404 which is very similar and this
driver could be extended */
id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
if (id != 0x21)
return -ENODEV;
id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
if (id != 0x01)
return -ENODEV;
strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
return 0;
}
static int emc1403_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int res;
struct thermal_data *data;
data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
if (data == NULL) {
dev_warn(&client->dev, "out of memory");
return -ENOMEM;
}
i2c_set_clientdata(client, data);
mutex_init(&data->mutex);
data->hyst_valid = jiffies - 1; /* Expired */
res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
if (res) {
dev_warn(&client->dev, "create group failed\n");
hwmon_device_unregister(data->hwmon_dev);
goto thermal_error1;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
res = PTR_ERR(data->hwmon_dev);
dev_warn(&client->dev, "register hwmon dev failed\n");
goto thermal_error2;
}
dev_info(&client->dev, "EMC1403 Thermal chip found\n");
return res;
thermal_error2:
sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
thermal_error1:
kfree(data);
return res;
}
static int emc1403_remove(struct i2c_client *client)
{
struct thermal_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
kfree(data);
return 0;
}
static const unsigned short emc1403_address_list[] = {
0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END
};
static const struct i2c_device_id emc1403_idtable[] = {
{ "emc1403", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
static struct i2c_driver sensor_emc1403 = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "emc1403",
},
.detect = emc1403_detect,
.probe = emc1403_probe,
.remove = emc1403_remove,
.id_table = emc1403_idtable,
.address_list = emc1403_address_list,
};
static int __init sensor_emc1403_init(void)
{
return i2c_add_driver(&sensor_emc1403);
}
static void __exit sensor_emc1403_exit(void)
{
i2c_del_driver(&sensor_emc1403);
}
module_init(sensor_emc1403_init);
module_exit(sensor_emc1403_exit);
MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
MODULE_DESCRIPTION("emc1403 Thermal Driver");
MODULE_LICENSE("GPL v2");
...@@ -856,21 +856,19 @@ static inline int superio_inb(int base, int reg) ...@@ -856,21 +856,19 @@ static inline int superio_inb(int base, int reg)
static int superio_inw(int base, int reg) static int superio_inw(int base, int reg)
{ {
int val; int val;
outb(reg++, base); val = superio_inb(base, reg) << 8;
val = inb(base + 1) << 8; val |= superio_inb(base, reg + 1);
outb(reg, base);
val |= inb(base + 1);
return val; return val;
} }
static inline void superio_enter(int base) static inline void superio_enter(int base)
{ {
/* according to the datasheet the key must be send twice! */ /* according to the datasheet the key must be send twice! */
outb( SIO_UNLOCK_KEY, base); outb(SIO_UNLOCK_KEY, base);
outb( SIO_UNLOCK_KEY, base); outb(SIO_UNLOCK_KEY, base);
} }
static inline void superio_select( int base, int ld) static inline void superio_select(int base, int ld)
{ {
outb(SIO_REG_LDSEL, base); outb(SIO_REG_LDSEL, base);
outb(ld, base + 1); outb(ld, base + 1);
...@@ -905,10 +903,8 @@ static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg) ...@@ -905,10 +903,8 @@ static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
{ {
u16 val; u16 val;
outb(reg++, data->addr + ADDR_REG_OFFSET); val = f71882fg_read8(data, reg) << 8;
val = inb(data->addr + DATA_REG_OFFSET) << 8; val |= f71882fg_read8(data, reg + 1);
outb(reg, data->addr + ADDR_REG_OFFSET);
val |= inb(data->addr + DATA_REG_OFFSET);
return val; return val;
} }
...@@ -921,10 +917,8 @@ static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val) ...@@ -921,10 +917,8 @@ static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
{ {
outb(reg++, data->addr + ADDR_REG_OFFSET); f71882fg_write8(data, reg, val >> 8);
outb(val >> 8, data->addr + DATA_REG_OFFSET); f71882fg_write8(data, reg + 1, val & 0xff);
outb(reg, data->addr + ADDR_REG_OFFSET);
outb(val & 255, data->addr + DATA_REG_OFFSET);
} }
static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
...@@ -945,7 +939,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) ...@@ -945,7 +939,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
/* Update once every 60 seconds */ /* Update once every 60 seconds */
if ( time_after(jiffies, data->last_limits + 60 * HZ ) || if (time_after(jiffies, data->last_limits + 60 * HZ) ||
!data->valid) { !data->valid) {
if (data->type == f71882fg || data->type == f71889fg) { if (data->type == f71882fg || data->type == f71889fg) {
data->in1_max = data->in1_max =
...@@ -1127,8 +1121,12 @@ static ssize_t store_fan_full_speed(struct device *dev, ...@@ -1127,8 +1121,12 @@ static ssize_t store_fan_full_speed(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10); long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val = SENSORS_LIMIT(val, 23, 1500000); val = SENSORS_LIMIT(val, 23, 1500000);
val = fan_to_reg(val); val = fan_to_reg(val);
...@@ -1157,8 +1155,12 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute ...@@ -1157,8 +1155,12 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long val;
err = strict_strtoul(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
...@@ -1206,7 +1208,14 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute ...@@ -1206,7 +1208,14 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10) / 8; int err;
long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 8;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1233,8 +1242,12 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute ...@@ -1233,8 +1242,12 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long val;
err = strict_strtoul(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
...@@ -1299,8 +1312,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute ...@@ -1299,8 +1312,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10) / 1000; long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 1000;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1333,10 +1352,16 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute ...@@ -1333,10 +1352,16 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10) / 1000;
ssize_t ret = count; ssize_t ret = count;
u8 reg; u8 reg;
long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 1000;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1372,8 +1397,14 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute ...@@ -1372,8 +1397,14 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10) / 1000; long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 1000;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1427,8 +1458,12 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute ...@@ -1427,8 +1458,12 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long val;
err = strict_strtoul(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
...@@ -1490,8 +1525,13 @@ static ssize_t store_pwm(struct device *dev, ...@@ -1490,8 +1525,13 @@ static ssize_t store_pwm(struct device *dev,
size_t count) size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10); long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1551,8 +1591,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute ...@@ -1551,8 +1591,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count) *devattr, const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10); long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
/* Special case for F8000 pwm channel 3 which only does auto mode */ /* Special case for F8000 pwm channel 3 which only does auto mode */
if (data->type == f8000 && nr == 2 && val != 2) if (data->type == f8000 && nr == 2 && val != 2)
...@@ -1626,9 +1670,14 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev, ...@@ -1626,9 +1670,14 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int pwm = to_sensor_dev_attr_2(devattr)->index; int err, pwm = to_sensor_dev_attr_2(devattr)->index;
int point = to_sensor_dev_attr_2(devattr)->nr; int point = to_sensor_dev_attr_2(devattr)->nr;
long val = simple_strtol(buf, NULL, 10); long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1674,10 +1723,16 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, ...@@ -1674,10 +1723,16 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
int point = to_sensor_dev_attr_2(devattr)->nr; int point = to_sensor_dev_attr_2(devattr)->nr;
long val = simple_strtol(buf, NULL, 10) / 1000;
u8 reg; u8 reg;
long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 1000;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->pwm_auto_point_temp[nr][point] = data->pwm_auto_point_temp[nr][point] =
...@@ -1716,8 +1771,12 @@ static ssize_t store_pwm_interpolate(struct device *dev, ...@@ -1716,8 +1771,12 @@ static ssize_t store_pwm_interpolate(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long val;
err = strict_strtoul(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->pwm_auto_point_mapping[nr] = data->pwm_auto_point_mapping[nr] =
...@@ -1752,8 +1811,12 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, ...@@ -1752,8 +1811,12 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int nr = to_sensor_dev_attr_2(devattr)->index; int err, nr = to_sensor_dev_attr_2(devattr)->index;
long val = simple_strtol(buf, NULL, 10); long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
switch (val) { switch (val) {
case 1: case 1:
...@@ -1798,9 +1861,15 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, ...@@ -1798,9 +1861,15 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct f71882fg_data *data = dev_get_drvdata(dev); struct f71882fg_data *data = dev_get_drvdata(dev);
int pwm = to_sensor_dev_attr_2(devattr)->index; int err, pwm = to_sensor_dev_attr_2(devattr)->index;
int point = to_sensor_dev_attr_2(devattr)->nr; int point = to_sensor_dev_attr_2(devattr)->nr;
long val = simple_strtol(buf, NULL, 10) / 1000; long val;
err = strict_strtol(buf, 10, &val);
if (err)
return err;
val /= 1000;
if (data->type == f71889fg) if (data->type == f71889fg)
val = SENSORS_LIMIT(val, -128, 127); val = SENSORS_LIMIT(val, -128, 127);
...@@ -2109,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, ...@@ -2109,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
int err = -ENODEV; int err = -ENODEV;
u16 devid; u16 devid;
/* Don't step on other drivers' I/O space by accident */
if (!request_region(sioaddr, 2, DRVNAME)) {
printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
(int)sioaddr);
return -EBUSY;
}
superio_enter(sioaddr); superio_enter(sioaddr);
devid = superio_inw(sioaddr, SIO_REG_MANID); devid = superio_inw(sioaddr, SIO_REG_MANID);
...@@ -2151,8 +2227,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, ...@@ -2151,8 +2227,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
} }
*address = superio_inw(sioaddr, SIO_REG_ADDR); *address = superio_inw(sioaddr, SIO_REG_ADDR);
if (*address == 0) if (*address == 0) {
{
printk(KERN_WARNING DRVNAME ": Base address not set\n"); printk(KERN_WARNING DRVNAME ": Base address not set\n");
goto exit; goto exit;
} }
...@@ -2164,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, ...@@ -2164,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
(int)superio_inb(sioaddr, SIO_REG_DEVREV)); (int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit: exit:
superio_exit(sioaddr); superio_exit(sioaddr);
release_region(sioaddr, 2);
return err; return err;
} }
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
* Address is fully defined internally and cannot be changed. * Address is fully defined internally and cannot be changed.
*/ */
static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
/* /*
* The LM63 registers * The LM63 registers
...@@ -131,12 +131,15 @@ static struct lm63_data *lm63_update_device(struct device *dev); ...@@ -131,12 +131,15 @@ static struct lm63_data *lm63_update_device(struct device *dev);
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
static void lm63_init_client(struct i2c_client *client); static void lm63_init_client(struct i2c_client *client);
enum chips { lm63, lm64 };
/* /*
* Driver data (common to all clients) * Driver data (common to all clients)
*/ */
static const struct i2c_device_id lm63_id[] = { static const struct i2c_device_id lm63_id[] = {
{ "lm63", 0 }, { "lm63", lm63 },
{ "lm64", lm64 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, lm63_id); MODULE_DEVICE_TABLE(i2c, lm63_id);
...@@ -422,6 +425,7 @@ static int lm63_detect(struct i2c_client *new_client, ...@@ -422,6 +425,7 @@ static int lm63_detect(struct i2c_client *new_client,
struct i2c_adapter *adapter = new_client->adapter; struct i2c_adapter *adapter = new_client->adapter;
u8 man_id, chip_id, reg_config1, reg_config2; u8 man_id, chip_id, reg_config1, reg_config2;
u8 reg_alert_status, reg_alert_mask; u8 reg_alert_status, reg_alert_mask;
int address = new_client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV; return -ENODEV;
...@@ -439,7 +443,6 @@ static int lm63_detect(struct i2c_client *new_client, ...@@ -439,7 +443,6 @@ static int lm63_detect(struct i2c_client *new_client,
LM63_REG_ALERT_MASK); LM63_REG_ALERT_MASK);
if (man_id != 0x01 /* National Semiconductor */ if (man_id != 0x01 /* National Semiconductor */
|| chip_id != 0x41 /* LM63 */
|| (reg_config1 & 0x18) != 0x00 || (reg_config1 & 0x18) != 0x00
|| (reg_config2 & 0xF8) != 0x00 || (reg_config2 & 0xF8) != 0x00
|| (reg_alert_status & 0x20) != 0x00 || (reg_alert_status & 0x20) != 0x00
...@@ -450,7 +453,12 @@ static int lm63_detect(struct i2c_client *new_client, ...@@ -450,7 +453,12 @@ static int lm63_detect(struct i2c_client *new_client,
return -ENODEV; return -ENODEV;
} }
if (chip_id == 0x41 && address == 0x4c)
strlcpy(info->type, "lm63", I2C_NAME_SIZE); strlcpy(info->type, "lm63", I2C_NAME_SIZE);
else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
strlcpy(info->type, "lm64", I2C_NAME_SIZE);
else
return -ENODEV;
return 0; return 0;
} }
......
...@@ -46,6 +46,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ ...@@ -46,6 +46,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
tcn75, tcn75,
tmp100, tmp100,
tmp101, tmp101,
tmp105,
tmp175, tmp175,
tmp275, tmp275,
tmp75, tmp75,
...@@ -220,6 +221,7 @@ static const struct i2c_device_id lm75_ids[] = { ...@@ -220,6 +221,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "tcn75", tcn75, }, { "tcn75", tcn75, },
{ "tmp100", tmp100, }, { "tmp100", tmp100, },
{ "tmp101", tmp101, }, { "tmp101", tmp101, },
{ "tmp105", tmp105, },
{ "tmp175", tmp175, }, { "tmp175", tmp175, },
{ "tmp275", tmp275, }, { "tmp275", tmp275, },
{ "tmp75", tmp75, }, { "tmp75", tmp75, },
......
...@@ -982,7 +982,8 @@ static struct lm90_data *lm90_update_device(struct device *dev) ...@@ -982,7 +982,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
|| !data->valid) {
u8 h, l; u8 h, l;
dev_dbg(&client->dev, "Updating lm90 data.\n"); dev_dbg(&client->dev, "Updating lm90 data.\n");
......
...@@ -45,9 +45,7 @@ enum ltc4245_cmd { ...@@ -45,9 +45,7 @@ enum ltc4245_cmd {
LTC4245_VEEIN = 0x19, LTC4245_VEEIN = 0x19,
LTC4245_VEESENSE = 0x1a, LTC4245_VEESENSE = 0x1a,
LTC4245_VEEOUT = 0x1b, LTC4245_VEEOUT = 0x1b,
LTC4245_GPIOADC1 = 0x1c, LTC4245_GPIOADC = 0x1c,
LTC4245_GPIOADC2 = 0x1d,
LTC4245_GPIOADC3 = 0x1e,
}; };
struct ltc4245_data { struct ltc4245_data {
...@@ -61,7 +59,7 @@ struct ltc4245_data { ...@@ -61,7 +59,7 @@ struct ltc4245_data {
u8 cregs[0x08]; u8 cregs[0x08];
/* Voltage registers */ /* Voltage registers */
u8 vregs[0x0f]; u8 vregs[0x0d];
}; };
static struct ltc4245_data *ltc4245_update_device(struct device *dev) static struct ltc4245_data *ltc4245_update_device(struct device *dev)
...@@ -86,7 +84,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev) ...@@ -86,7 +84,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
data->cregs[i] = val; data->cregs[i] = val;
} }
/* Read voltage registers -- 0x10 to 0x1f */ /* Read voltage registers -- 0x10 to 0x1c */
for (i = 0; i < ARRAY_SIZE(data->vregs); i++) { for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
val = i2c_smbus_read_byte_data(client, i+0x10); val = i2c_smbus_read_byte_data(client, i+0x10);
if (unlikely(val < 0)) if (unlikely(val < 0))
...@@ -128,9 +126,7 @@ static int ltc4245_get_voltage(struct device *dev, u8 reg) ...@@ -128,9 +126,7 @@ static int ltc4245_get_voltage(struct device *dev, u8 reg)
case LTC4245_VEEOUT: case LTC4245_VEEOUT:
voltage = regval * -55; voltage = regval * -55;
break; break;
case LTC4245_GPIOADC1: case LTC4245_GPIOADC:
case LTC4245_GPIOADC2:
case LTC4245_GPIOADC3:
voltage = regval * 10; voltage = regval * 10;
break; break;
default: default:
...@@ -297,9 +293,7 @@ LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2); ...@@ -297,9 +293,7 @@ LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2); LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
/* GPIO voltages */ /* GPIO voltages */
LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC1); LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC);
LTC4245_VOLTAGE(in10_input, LTC4245_GPIOADC2);
LTC4245_VOLTAGE(in11_input, LTC4245_GPIOADC3);
/* Power Consumption (virtual) */ /* Power Consumption (virtual) */
LTC4245_POWER(power1_input, LTC4245_12VSENSE); LTC4245_POWER(power1_input, LTC4245_12VSENSE);
...@@ -342,8 +336,6 @@ static struct attribute *ltc4245_attributes[] = { ...@@ -342,8 +336,6 @@ static struct attribute *ltc4245_attributes[] = {
&sensor_dev_attr_in8_min_alarm.dev_attr.attr, &sensor_dev_attr_in8_min_alarm.dev_attr.attr,
&sensor_dev_attr_in9_input.dev_attr.attr, &sensor_dev_attr_in9_input.dev_attr.attr,
&sensor_dev_attr_in10_input.dev_attr.attr,
&sensor_dev_attr_in11_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_power2_input.dev_attr.attr, &sensor_dev_attr_power2_input.dev_attr.attr,
......
/* Texas Instruments TMP102 SMBus temperature sensor driver
*
* Copyright (C) 2010 Steven King <sfking@fdwdc.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/device.h>
#define DRIVER_NAME "tmp102"
#define TMP102_TEMP_REG 0x00
#define TMP102_CONF_REG 0x01
/* note: these bit definitions are byte swapped */
#define TMP102_CONF_SD 0x0100
#define TMP102_CONF_TM 0x0200
#define TMP102_CONF_POL 0x0400
#define TMP102_CONF_F0 0x0800
#define TMP102_CONF_F1 0x1000
#define TMP102_CONF_R0 0x2000
#define TMP102_CONF_R1 0x4000
#define TMP102_CONF_OS 0x8000
#define TMP102_CONF_EM 0x0010
#define TMP102_CONF_AL 0x0020
#define TMP102_CONF_CR0 0x0040
#define TMP102_CONF_CR1 0x0080
#define TMP102_TLOW_REG 0x02
#define TMP102_THIGH_REG 0x03
struct tmp102 {
struct device *hwmon_dev;
struct mutex lock;
u16 config_orig;
unsigned long last_update;
int temp[3];
};
/* SMBus specifies low byte first, but the TMP102 returns high byte first,
* so we have to swab16 the values */
static inline int tmp102_read_reg(struct i2c_client *client, u8 reg)
{
int result = i2c_smbus_read_word_data(client, reg);
return result < 0 ? result : swab16(result);
}
static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
{
return i2c_smbus_write_word_data(client, reg, swab16(val));
}
/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
static inline int tmp102_reg_to_mC(s16 val)
{
return ((val & ~0x01) * 1000) / 128;
}
/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
static inline u16 tmp102_mC_to_reg(int val)
{
return (val * 128) / 1000;
}
static const u8 tmp102_reg[] = {
TMP102_TEMP_REG,
TMP102_TLOW_REG,
TMP102_THIGH_REG,
};
static struct tmp102 *tmp102_update_device(struct i2c_client *client)
{
struct tmp102 *tmp102 = i2c_get_clientdata(client);
mutex_lock(&tmp102->lock);
if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
int i;
for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
int status = tmp102_read_reg(client, tmp102_reg[i]);
if (status > -1)
tmp102->temp[i] = tmp102_reg_to_mC(status);
}
tmp102->last_update = jiffies;
}
mutex_unlock(&tmp102->lock);
return tmp102;
}
static ssize_t tmp102_show_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
}
static ssize_t tmp102_set_temp(struct device *dev,
struct device_attribute *attr,
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);
long val;
int status;
if (strict_strtol(buf, 10, &val) < 0)
return -EINVAL;
val = SENSORS_LIMIT(val, -256000, 255000);
mutex_lock(&tmp102->lock);
tmp102->temp[sda->index] = val;
status = tmp102_write_reg(client, tmp102_reg[sda->index],
tmp102_mC_to_reg(val));
mutex_unlock(&tmp102->lock);
return status ? : count;
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
tmp102_set_temp, 1);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
tmp102_set_temp, 2);
static struct attribute *tmp102_attributes[] = {
&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,
};
#define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
static int __devinit tmp102_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tmp102 *tmp102;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
dev_err(&client->dev, "adapter doesnt support SMBus word "
"transactions\n");
return -ENODEV;
}
tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
if (!tmp102) {
dev_dbg(&client->dev, "kzalloc failed\n");
return -ENOMEM;
}
i2c_set_clientdata(client, tmp102);
status = tmp102_read_reg(client, TMP102_CONF_REG);
if (status < 0) {
dev_err(&client->dev, "error reading config register\n");
goto fail_free;
}
tmp102->config_orig = status;
status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
if (status < 0) {
dev_err(&client->dev, "error writing config register\n");
goto fail_restore_config;
}
status = tmp102_read_reg(client, TMP102_CONF_REG);
if (status < 0) {
dev_err(&client->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");
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");
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;
}
dev_info(&client->dev, "initialized\n");
return 0;
fail_remove_sysfs:
sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
fail_restore_config:
tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig);
fail_free:
i2c_set_clientdata(client, NULL);
kfree(tmp102);
return status;
}
static int __devexit tmp102_remove(struct i2c_client *client)
{
struct tmp102 *tmp102 = i2c_get_clientdata(client);
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) {
int config;
config = tmp102_read_reg(client, TMP102_CONF_REG);
if (config >= 0)
tmp102_write_reg(client, TMP102_CONF_REG,
config | TMP102_CONF_SD);
}
i2c_set_clientdata(client, NULL);
kfree(tmp102);
return 0;
}
#ifdef CONFIG_PM
static int tmp102_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int config;
config = tmp102_read_reg(client, TMP102_CONF_REG);
if (config < 0)
return config;
config |= TMP102_CONF_SD;
return tmp102_write_reg(client, TMP102_CONF_REG, config);
}
static int tmp102_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int config;
config = tmp102_read_reg(client, TMP102_CONF_REG);
if (config < 0)
return config;
config &= ~TMP102_CONF_SD;
return tmp102_write_reg(client, TMP102_CONF_REG, config);
}
static const struct dev_pm_ops tmp102_dev_pm_ops = {
.suspend = tmp102_suspend,
.resume = tmp102_resume,
};
#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
#else
#define TMP102_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static const struct i2c_device_id tmp102_id[] = {
{ "tmp102", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp102_id);
static struct i2c_driver tmp102_driver = {
.driver.name = DRIVER_NAME,
.driver.pm = TMP102_DEV_PM_OPS,
.probe = tmp102_probe,
.remove = __devexit_p(tmp102_remove),
.id_table = tmp102_id,
};
static int __init tmp102_init(void)
{
return i2c_add_driver(&tmp102_driver);
}
module_init(tmp102_init);
static void __exit tmp102_exit(void)
{
i2c_del_driver(&tmp102_driver);
}
module_exit(tmp102_exit);
MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
MODULE_LICENSE("GPL");
...@@ -91,17 +91,6 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; ...@@ -91,17 +91,6 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 };
#define TMP401_DEVICE_ID 0x11 #define TMP401_DEVICE_ID 0x11
#define TMP411_DEVICE_ID 0x12 #define TMP411_DEVICE_ID 0x12
/*
* Functions declarations
*/
static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int tmp401_detect(struct i2c_client *client,
struct i2c_board_info *info);
static int tmp401_remove(struct i2c_client *client);
static struct tmp401_data *tmp401_update_device(struct device *dev);
/* /*
* Driver data (common to all clients) * Driver data (common to all clients)
*/ */
...@@ -113,18 +102,6 @@ static const struct i2c_device_id tmp401_id[] = { ...@@ -113,18 +102,6 @@ static const struct i2c_device_id tmp401_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, tmp401_id); MODULE_DEVICE_TABLE(i2c, tmp401_id);
static struct i2c_driver tmp401_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "tmp401",
},
.probe = tmp401_probe,
.remove = tmp401_remove,
.id_table = tmp401_id,
.detect = tmp401_detect,
.address_list = normal_i2c,
};
/* /*
* Client data (each client gets its own) * Client data (each client gets its own)
*/ */
...@@ -194,6 +171,71 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config) ...@@ -194,6 +171,71 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
return (temp + 500) / 1000; return (temp + 500) / 1000;
} }
static struct tmp401_data *tmp401_update_device_reg16(
struct i2c_client *client, struct tmp401_data *data)
{
int i;
for (i = 0; i < 2; i++) {
/*
* High byte must be read first immediately followed
* by the low byte
*/
data->temp[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_MSB[i]) << 8;
data->temp[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_LSB[i]);
data->temp_low[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
data->temp_low[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_LOW_LIMIT_LSB[i]);
data->temp_high[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
data->temp_high[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_HIGH_LIMIT_LSB[i]);
data->temp_crit[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_CRIT_LIMIT[i]);
if (data->kind == tmp411) {
data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
TMP411_TEMP_LOWEST_MSB[i]) << 8;
data->temp_lowest[i] |= i2c_smbus_read_byte_data(
client, TMP411_TEMP_LOWEST_LSB[i]);
data->temp_highest[i] = i2c_smbus_read_byte_data(
client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
data->temp_highest[i] |= i2c_smbus_read_byte_data(
client, TMP411_TEMP_HIGHEST_LSB[i]);
}
}
return data;
}
static struct tmp401_data *tmp401_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct tmp401_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
data->config = i2c_smbus_read_byte_data(client,
TMP401_CONFIG_READ);
tmp401_update_device_reg16(client, data);
data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
TMP401_TEMP_CRIT_HYST);
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static ssize_t show_temp_value(struct device *dev, static ssize_t show_temp_value(struct device *dev,
struct device_attribute *devattr, char *buf) struct device_attribute *devattr, char *buf)
{ {
...@@ -420,30 +462,36 @@ static ssize_t reset_temp_history(struct device *dev, ...@@ -420,30 +462,36 @@ static ssize_t reset_temp_history(struct device *dev,
} }
static struct sensor_device_attribute tmp401_attr[] = { static struct sensor_device_attribute tmp401_attr[] = {
SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), store_temp_min, 0),
SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0), SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst, store_temp_max, 0),
SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
store_temp_crit, 0),
SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
store_temp_crit_hyst, 0), store_temp_crit_hyst, 0),
SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_LOCAL_LOW), TMP401_STATUS_LOCAL_LOW),
SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_LOCAL_HIGH), TMP401_STATUS_LOCAL_HIGH),
SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_LOCAL_CRIT), TMP401_STATUS_LOCAL_CRIT),
SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1), SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), store_temp_min, 1),
SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1), SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1), store_temp_max, 1),
SENSOR_ATTR(temp2_fault, 0444, show_status, NULL, SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
store_temp_crit, 1),
SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
TMP401_STATUS_REMOTE_OPEN), TMP401_STATUS_REMOTE_OPEN),
SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_REMOTE_LOW), TMP401_STATUS_REMOTE_LOW),
SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_REMOTE_HIGH), TMP401_STATUS_REMOTE_HIGH),
SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL, SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
TMP401_STATUS_REMOTE_CRIT), TMP401_STATUS_REMOTE_CRIT),
}; };
...@@ -455,11 +503,11 @@ static struct sensor_device_attribute tmp401_attr[] = { ...@@ -455,11 +503,11 @@ static struct sensor_device_attribute tmp401_attr[] = {
* and remote channels. * and remote channels.
*/ */
static struct sensor_device_attribute tmp411_attr[] = { static struct sensor_device_attribute tmp411_attr[] = {
SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0), SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0), SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1), SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1), SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0), SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
}; };
/* /*
...@@ -529,6 +577,27 @@ static int tmp401_detect(struct i2c_client *client, ...@@ -529,6 +577,27 @@ static int tmp401_detect(struct i2c_client *client,
return 0; return 0;
} }
static int tmp401_remove(struct i2c_client *client)
{
struct tmp401_data *data = i2c_get_clientdata(client);
int i;
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
if (data->kind == tmp411) {
for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
device_remove_file(&client->dev,
&tmp411_attr[i].dev_attr);
}
kfree(data);
return 0;
}
static int tmp401_probe(struct i2c_client *client, static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -581,91 +650,17 @@ static int tmp401_probe(struct i2c_client *client, ...@@ -581,91 +650,17 @@ static int tmp401_probe(struct i2c_client *client,
return err; return err;
} }
static int tmp401_remove(struct i2c_client *client) static struct i2c_driver tmp401_driver = {
{ .class = I2C_CLASS_HWMON,
struct tmp401_data *data = i2c_get_clientdata(client); .driver = {
int i; .name = "tmp401",
},
if (data->hwmon_dev) .probe = tmp401_probe,
hwmon_device_unregister(data->hwmon_dev); .remove = tmp401_remove,
.id_table = tmp401_id,
for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) .detect = tmp401_detect,
device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); .address_list = normal_i2c,
};
if (data->kind == tmp411) {
for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
device_remove_file(&client->dev,
&tmp411_attr[i].dev_attr);
}
kfree(data);
return 0;
}
static struct tmp401_data *tmp401_update_device_reg16(
struct i2c_client *client, struct tmp401_data *data)
{
int i;
for (i = 0; i < 2; i++) {
/*
* High byte must be read first immediately followed
* by the low byte
*/
data->temp[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_MSB[i]) << 8;
data->temp[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_LSB[i]);
data->temp_low[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
data->temp_low[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_LOW_LIMIT_LSB[i]);
data->temp_high[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
data->temp_high[i] |= i2c_smbus_read_byte_data(client,
TMP401_TEMP_HIGH_LIMIT_LSB[i]);
data->temp_crit[i] = i2c_smbus_read_byte_data(client,
TMP401_TEMP_CRIT_LIMIT[i]);
if (data->kind == tmp411) {
data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
TMP411_TEMP_LOWEST_MSB[i]) << 8;
data->temp_lowest[i] |= i2c_smbus_read_byte_data(
client, TMP411_TEMP_LOWEST_LSB[i]);
data->temp_highest[i] = i2c_smbus_read_byte_data(
client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
data->temp_highest[i] |= i2c_smbus_read_byte_data(
client, TMP411_TEMP_HIGHEST_LSB[i]);
}
}
return data;
}
static struct tmp401_data *tmp401_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct tmp401_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
data->config = i2c_smbus_read_byte_data(client,
TMP401_CONFIG_READ);
tmp401_update_device_reg16(client, data);
data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
TMP401_TEMP_CRIT_HYST);
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static int __init tmp401_init(void) static int __init tmp401_init(void)
{ {
......
...@@ -248,6 +248,8 @@ int acpi_check_region(resource_size_t start, resource_size_t n, ...@@ -248,6 +248,8 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
int acpi_check_mem_region(resource_size_t start, resource_size_t n, int acpi_check_mem_region(resource_size_t start, resource_size_t n,
const char *name); const char *name);
int acpi_resources_are_enforced(void);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
void __init acpi_no_s4_hw_signature(void); void __init acpi_no_s4_hw_signature(void);
void __init acpi_old_suspend_ordering(void); void __init acpi_old_suspend_ordering(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册