mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 16:44:10 +08:00
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 ...
This commit is contained in:
commit
d1e0fe252e
@ -9,11 +9,15 @@ Supported chips:
|
||||
* SMSC SCH3112, SCH3114, SCH3116
|
||||
Prefix: 'sch311x'
|
||||
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
|
||||
Prefix: 'sch5027'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
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:
|
||||
Juerg Haefliger <juergh@gmail.com>
|
||||
@ -36,8 +40,8 @@ Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the hardware monitoring capabilities of the
|
||||
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
|
||||
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
|
||||
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x,
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
pwm[5-6] don't exist.
|
||||
For the SCH311x and SCH5127, fan[1-3] and pwm[1-3] are always present and
|
||||
fan[4-6] and pwm[5-6] don't exist.
|
||||
|
||||
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.
|
||||
The driver will therefore register itself as an I2C client driver if it detects
|
||||
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
|
||||
chip.
|
||||
accessible via SMBus, while the SCH311x and SCH5127 only provide access via
|
||||
the ISA bus. The driver will therefore register itself as an I2C client driver
|
||||
if it detects a DME1737, A8000, or SCH5027 and as a platform driver if it
|
||||
detects a SCH311x or SCH5127 chip.
|
||||
|
||||
|
||||
Voltage Monitoring
|
||||
@ -76,7 +80,7 @@ DME1737, A8000:
|
||||
in6: Vbat (+3.0V) 0V - 4.38V
|
||||
|
||||
SCH311x:
|
||||
in0: +2.5V 0V - 6.64V
|
||||
in0: +2.5V 0V - 3.32V
|
||||
in1: Vccp (processor core) 0V - 2V
|
||||
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||
in3: +5V 0V - 6.64V
|
||||
@ -93,6 +97,15 @@ SCH5027:
|
||||
in5: VTR (+3.3V standby) 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
|
||||
when crossed.
|
||||
|
||||
@ -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
|
||||
full-speed duty-cycle which is hard-
|
||||
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:
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
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>
|
||||
|
||||
@ -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'
|
||||
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
|
||||
in7_min_alarm 3v output undervoltage alarm
|
||||
in8_min_alarm Vee (-12v) output undervoltage alarm
|
||||
|
||||
in9_input GPIO #1 voltage data
|
||||
in10_input GPIO #2 voltage data
|
||||
in11_input GPIO #3 voltage data
|
||||
in9_input GPIO voltage data
|
||||
|
||||
power1_input 12v 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
|
||||
given driver if the chip has the feature.
|
||||
|
||||
|
||||
********
|
||||
* Name *
|
||||
********
|
||||
*********************
|
||||
* Global attributes *
|
||||
*********************
|
||||
|
||||
name The chip name.
|
||||
This should be a short, lowercase string, not containing
|
||||
@ -91,6 +91,13 @@ name The chip name.
|
||||
I2C devices get this attribute created automatically.
|
||||
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 *
|
||||
|
26
Documentation/hwmon/tmp102
Normal file
26
Documentation/hwmon/tmp102
Normal file
@ -0,0 +1,26 @@
|
||||
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,
|
||||
}
|
||||
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.
|
||||
*
|
||||
|
@ -447,13 +447,14 @@ config SENSORS_IT87
|
||||
will be called it87.
|
||||
|
||||
config SENSORS_LM63
|
||||
tristate "National Semiconductor LM63"
|
||||
tristate "National Semiconductor LM63 and LM64"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the National Semiconductor
|
||||
LM63 remote diode digital temperature sensor with integrated fan
|
||||
control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro)
|
||||
motherboard, among others.
|
||||
If you say yes here you get support for the National
|
||||
Semiconductor LM63 and LM64 remote diode digital temperature
|
||||
sensors with integrated fan control. Such chips are found
|
||||
on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
|
||||
others.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm63.
|
||||
@ -492,7 +493,8 @@ config SENSORS_LM75
|
||||
- NXP's LM75A
|
||||
- ST Microelectronics STDS75
|
||||
- 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
|
||||
specific I2C device tables.
|
||||
@ -749,6 +751,16 @@ config SENSORS_DME1737
|
||||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "SMSC LPC47M10x and compatibles"
|
||||
help
|
||||
@ -831,6 +843,16 @@ config SENSORS_THMC50
|
||||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "Texas Instruments TMP401 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
|
@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
|
||||
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
|
||||
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
|
||||
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
|
||||
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
|
||||
@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
|
||||
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
|
||||
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
|
||||
obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
|
||||
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
|
||||
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
|
||||
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
|
||||
#define ADM1031_REG_PWM (0x22)
|
||||
#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_MAX(nr) (0x14 + 4 * (nr))
|
||||
@ -61,6 +62,9 @@
|
||||
#define ADM1031_CONF2_TACH2_ENABLE 0x08
|
||||
#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan))
|
||||
|
||||
#define ADM1031_UPDATE_RATE_MASK 0x1c
|
||||
#define ADM1031_UPDATE_RATE_SHIFT 2
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
|
||||
|
||||
@ -75,6 +79,7 @@ struct adm1031_data {
|
||||
int chip_type;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned int update_rate; /* In milliseconds */
|
||||
/* The chan_select_table contains the possible configurations for
|
||||
* auto fan control.
|
||||
*/
|
||||
@ -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(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[] = {
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
@ -774,6 +830,7 @@ static struct attribute *adm1031_attributes[] = {
|
||||
|
||||
&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
|
||||
|
||||
&dev_attr_update_rate.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
|
||||
NULL
|
||||
@ -900,6 +957,7 @@ static void adm1031_init_client(struct i2c_client *client)
|
||||
{
|
||||
unsigned int read_val;
|
||||
unsigned int mask;
|
||||
int i;
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
|
||||
@ -919,18 +977,24 @@ static void adm1031_init_client(struct i2c_client *client)
|
||||
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)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
unsigned long next_update;
|
||||
int chan;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
next_update = data->last_updated + msecs_to_jiffies(data->update_rate);
|
||||
if (time_after(jiffies, next_update) || !data->valid) {
|
||||
|
||||
dev_dbg(&client->dev, "Starting adm1031 update\n");
|
||||
for (chan = 0;
|
||||
|
@ -148,6 +148,20 @@ static const char *temperature_sensors_sets[][41] = {
|
||||
/* Set 18: MacBook Pro 2,2 */
|
||||
{ "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
|
||||
"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 */
|
||||
@ -646,6 +660,17 @@ out:
|
||||
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 */
|
||||
static ssize_t applesmc_show_temperature(struct device *dev,
|
||||
struct device_attribute *devattr, char *sysfsbuf)
|
||||
@ -1113,6 +1138,86 @@ static const struct attribute_group fan_attribute_groups[] = {
|
||||
/*
|
||||
* 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,
|
||||
applesmc_show_temperature, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
|
||||
@ -1194,6 +1299,50 @@ static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
|
||||
static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
|
||||
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[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
@ -1241,6 +1390,10 @@ static struct attribute *temperature_attributes[] = {
|
||||
static const struct attribute_group temperature_attributes_group =
|
||||
{ .attrs = temperature_attributes };
|
||||
|
||||
static const struct attribute_group label_attributes_group = {
|
||||
.attrs = label_attributes
|
||||
};
|
||||
|
||||
/* Module stuff */
|
||||
|
||||
/*
|
||||
@ -1363,6 +1516,14 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
|
||||
{ .accelerometer = 0, .light = 0, .temperature_set = 17 },
|
||||
/* MacBook Pro 2,2: accelerometer, backlight and 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".
|
||||
@ -1376,6 +1537,22 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
|
||||
&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", {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
|
||||
@ -1518,7 +1695,8 @@ static int __init applesmc_init(void)
|
||||
for (i = 0;
|
||||
temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
|
||||
i++) {
|
||||
if (temperature_attributes[i] == NULL) {
|
||||
if (temperature_attributes[i] == NULL ||
|
||||
label_attributes[i] == NULL) {
|
||||
printk(KERN_ERR "applesmc: More temperature sensors "
|
||||
"in temperature_sensors_sets (at least %i)"
|
||||
"than available sysfs files in "
|
||||
@ -1530,6 +1708,10 @@ static int __init applesmc_init(void)
|
||||
temperature_attributes[i]);
|
||||
if (ret)
|
||||
goto out_temperature;
|
||||
ret = sysfs_create_file(&pdev->dev.kobj,
|
||||
label_attributes[i]);
|
||||
if (ret)
|
||||
goto out_temperature;
|
||||
}
|
||||
|
||||
if (applesmc_accelerometer) {
|
||||
@ -1580,6 +1762,7 @@ out_accelerometer:
|
||||
if (applesmc_accelerometer)
|
||||
applesmc_release_accelerometer();
|
||||
out_temperature:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
|
||||
out_fans:
|
||||
while (fans_handled)
|
||||
@ -1609,6 +1792,7 @@ static void __exit applesmc_exit(void)
|
||||
}
|
||||
if (applesmc_accelerometer)
|
||||
applesmc_release_accelerometer();
|
||||
sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
|
||||
while (fans_handled)
|
||||
sysfs_remove_group(&pdev->dev.kobj,
|
||||
|
@ -1411,6 +1411,13 @@ static int __init atk0110_init(void)
|
||||
{
|
||||
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);
|
||||
if (ret)
|
||||
pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
|
||||
|
@ -1,12 +1,14 @@
|
||||
/*
|
||||
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
|
||||
* SCH5027 Super-I/O chips integrated hardware monitoring features.
|
||||
* Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
|
||||
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
|
||||
* and SCH5127 Super-I/O chips integrated hardware monitoring
|
||||
* features.
|
||||
* Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com>
|
||||
*
|
||||
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
|
||||
* the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
|
||||
* if a SCH311x chip is found. Both types of chips have very similar hardware
|
||||
* monitoring capabilities but differ in the way they can be accessed.
|
||||
* if a SCH311x or SCH5127 chip is found. Both types of chips have very
|
||||
* similar hardware monitoring capabilities but differ in the way they can be
|
||||
* accessed.
|
||||
*
|
||||
* 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
|
||||
@ -57,7 +59,7 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
||||
|
||||
enum chips { dme1737, sch5027, sch311x };
|
||||
enum chips { dme1737, sch5027, sch311x, sch5127 };
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Registers
|
||||
@ -164,10 +166,29 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
|
||||
#define DME1737_VERSTEP_MASK 0xf8
|
||||
#define SCH311X_DEVICE 0x8c
|
||||
#define SCH5027_VERSTEP 0x69
|
||||
#define SCH5127_DEVICE 0x8e
|
||||
|
||||
/* Device ID values (global configuration register index 0x20) */
|
||||
#define DME1737_ID_1 0x77
|
||||
#define DME1737_ID_2 0x78
|
||||
#define SCH3112_ID 0x7c
|
||||
#define SCH3114_ID 0x7d
|
||||
#define SCH3116_ID 0x7f
|
||||
#define SCH5027_ID 0x89
|
||||
#define SCH5127_ID 0x86
|
||||
|
||||
/* Length of ISA address segment */
|
||||
#define DME1737_EXTENT 2
|
||||
|
||||
/* chip-dependent features */
|
||||
#define HAS_TEMP_OFFSET (1 << 0) /* bit 0 */
|
||||
#define HAS_VID (1 << 1) /* bit 1 */
|
||||
#define HAS_ZONE3 (1 << 2) /* bit 2 */
|
||||
#define HAS_ZONE_HYST (1 << 3) /* bit 3 */
|
||||
#define HAS_PWM_MIN (1 << 4) /* bit 4 */
|
||||
#define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */
|
||||
#define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Data structures and manipulation thereof
|
||||
* --------------------------------------------------------------------- */
|
||||
@ -187,8 +208,7 @@ struct dme1737_data {
|
||||
|
||||
u8 vid;
|
||||
u8 pwm_rr_en;
|
||||
u8 has_pwm;
|
||||
u8 has_fan;
|
||||
u32 has_features;
|
||||
|
||||
/* Register values */
|
||||
u16 in[7];
|
||||
@ -224,8 +244,11 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
|
||||
3300};
|
||||
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
|
||||
3300};
|
||||
static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
|
||||
3300};
|
||||
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
|
||||
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
|
||||
(type) == sch5127 ? IN_NOMINAL_SCH5127 : \
|
||||
IN_NOMINAL_DME1737)
|
||||
|
||||
/* Voltage input
|
||||
@ -568,7 +591,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||
|
||||
/* Sample register contents every 1 sec */
|
||||
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
||||
if (data->type == dme1737) {
|
||||
if (data->has_features & HAS_VID) {
|
||||
data->vid = dme1737_read(data, DME1737_REG_VID) &
|
||||
0x3f;
|
||||
}
|
||||
@ -599,7 +622,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||
DME1737_REG_TEMP_MIN(ix));
|
||||
data->temp_max[ix] = dme1737_read(data,
|
||||
DME1737_REG_TEMP_MAX(ix));
|
||||
if (data->type != sch5027) {
|
||||
if (data->has_features & HAS_TEMP_OFFSET) {
|
||||
data->temp_offset[ix] = dme1737_read(data,
|
||||
DME1737_REG_TEMP_OFFSET(ix));
|
||||
}
|
||||
@ -626,7 +649,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||
for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
|
||||
/* Skip reading registers if optional fans are not
|
||||
* present */
|
||||
if (!(data->has_fan & (1 << ix))) {
|
||||
if (!(data->has_features & HAS_FAN(ix))) {
|
||||
continue;
|
||||
}
|
||||
data->fan[ix] = dme1737_read(data,
|
||||
@ -650,7 +673,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||
for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
|
||||
/* Skip reading registers if optional PWMs are not
|
||||
* present */
|
||||
if (!(data->has_pwm & (1 << ix))) {
|
||||
if (!(data->has_features & HAS_PWM(ix))) {
|
||||
continue;
|
||||
}
|
||||
data->pwm[ix] = dme1737_read(data,
|
||||
@ -672,12 +695,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||
|
||||
/* Thermal zone registers */
|
||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
|
||||
data->zone_low[ix] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_LOW(ix));
|
||||
data->zone_abs[ix] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_ABS(ix));
|
||||
/* Skip reading registers if zone3 is not present */
|
||||
if ((ix == 2) && !(data->has_features & HAS_ZONE3)) {
|
||||
continue;
|
||||
}
|
||||
/* sch5127 zone2 registers are special */
|
||||
if ((ix == 1) && (data->type == sch5127)) {
|
||||
data->zone_low[1] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_LOW(2));
|
||||
data->zone_abs[1] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_ABS(2));
|
||||
} else {
|
||||
data->zone_low[ix] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_LOW(ix));
|
||||
data->zone_abs[ix] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_ABS(ix));
|
||||
}
|
||||
}
|
||||
if (data->type != sch5027) {
|
||||
if (data->has_features & HAS_ZONE_HYST) {
|
||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
||||
data->zone_hyst[ix] = dme1737_read(data,
|
||||
DME1737_REG_ZONE_HYST(ix));
|
||||
@ -1594,10 +1629,6 @@ static struct attribute *dme1737_attr[] ={
|
||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -1605,27 +1636,23 @@ static const struct attribute_group dme1737_group = {
|
||||
.attrs = dme1737_attr,
|
||||
};
|
||||
|
||||
/* The following struct holds misc attributes, which are not available in all
|
||||
* chips. Their creation depends on the chip type which is determined during
|
||||
* module load. */
|
||||
static struct attribute *dme1737_misc_attr[] = {
|
||||
/* Temperatures */
|
||||
/* The following struct holds temp offset attributes, which are not available
|
||||
* in all chips. The following chips support them:
|
||||
* DME1737, SCH311x */
|
||||
static struct attribute *dme1737_temp_offset_attr[] = {
|
||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||
/* Zones */
|
||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group dme1737_misc_group = {
|
||||
.attrs = dme1737_misc_attr,
|
||||
static const struct attribute_group dme1737_temp_offset_group = {
|
||||
.attrs = dme1737_temp_offset_attr,
|
||||
};
|
||||
|
||||
/* The following struct holds VID-related attributes. Their creation
|
||||
depends on the chip type which is determined during module load. */
|
||||
/* The following struct holds VID related attributes, which are not available
|
||||
* in all chips. The following chips support them:
|
||||
* DME1737 */
|
||||
static struct attribute *dme1737_vid_attr[] = {
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
@ -1636,6 +1663,36 @@ static const struct attribute_group dme1737_vid_group = {
|
||||
.attrs = dme1737_vid_attr,
|
||||
};
|
||||
|
||||
/* The following struct holds temp zone 3 related attributes, which are not
|
||||
* available in all chips. The following chips support them:
|
||||
* DME1737, SCH311x, SCH5027 */
|
||||
static struct attribute *dme1737_zone3_attr[] = {
|
||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group dme1737_zone3_group = {
|
||||
.attrs = dme1737_zone3_attr,
|
||||
};
|
||||
|
||||
|
||||
/* The following struct holds temp zone hysteresis related attributes, which
|
||||
* are not available in all chips. The following chips support them:
|
||||
* DME1737, SCH311x */
|
||||
static struct attribute *dme1737_zone_hyst_attr[] = {
|
||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group dme1737_zone_hyst_group = {
|
||||
.attrs = dme1737_zone_hyst_attr,
|
||||
};
|
||||
|
||||
/* The following structs hold the PWM attributes, some of which are optional.
|
||||
* Their creation depends on the chip configuration which is determined during
|
||||
* module load. */
|
||||
@ -1691,10 +1748,10 @@ static const struct attribute_group dme1737_pwm_group[] = {
|
||||
{ .attrs = dme1737_pwm6_attr },
|
||||
};
|
||||
|
||||
/* The following struct holds misc PWM attributes, which are not available in
|
||||
* all chips. Their creation depends on the chip type which is determined
|
||||
/* The following struct holds auto PWM min attributes, which are not available
|
||||
* in all chips. Their creation depends on the chip type which is determined
|
||||
* during module load. */
|
||||
static struct attribute *dme1737_pwm_misc_attr[] = {
|
||||
static struct attribute *dme1737_auto_pwm_min_attr[] = {
|
||||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
||||
@ -1764,14 +1821,25 @@ static struct attribute *dme1737_zone_chmod_attr[] = {
|
||||
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group dme1737_zone_chmod_group = {
|
||||
.attrs = dme1737_zone_chmod_attr,
|
||||
};
|
||||
|
||||
|
||||
/* The permissions of the following zone 3 attributes are changed to read-
|
||||
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
|
||||
static struct attribute *dme1737_zone3_chmod_attr[] = {
|
||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group dme1737_zone_chmod_group = {
|
||||
.attrs = dme1737_zone_chmod_attr,
|
||||
static const struct attribute_group dme1737_zone3_chmod_group = {
|
||||
.attrs = dme1737_zone3_chmod_attr,
|
||||
};
|
||||
|
||||
/* The permissions of the following PWM attributes are changed to read-
|
||||
@ -1887,30 +1955,35 @@ static void dme1737_remove_files(struct device *dev)
|
||||
int ix;
|
||||
|
||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
||||
if (data->has_fan & (1 << ix)) {
|
||||
if (data->has_features & HAS_FAN(ix)) {
|
||||
sysfs_remove_group(&dev->kobj,
|
||||
&dme1737_fan_group[ix]);
|
||||
}
|
||||
}
|
||||
|
||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
|
||||
if (data->has_pwm & (1 << ix)) {
|
||||
if (data->has_features & HAS_PWM(ix)) {
|
||||
sysfs_remove_group(&dev->kobj,
|
||||
&dme1737_pwm_group[ix]);
|
||||
if (data->type != sch5027 && ix < 3) {
|
||||
if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
|
||||
sysfs_remove_file(&dev->kobj,
|
||||
dme1737_pwm_misc_attr[ix]);
|
||||
dme1737_auto_pwm_min_attr[ix]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->type != sch5027) {
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
|
||||
if (data->has_features & HAS_TEMP_OFFSET) {
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
|
||||
}
|
||||
if (data->type == dme1737) {
|
||||
if (data->has_features & HAS_VID) {
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
|
||||
}
|
||||
|
||||
if (data->has_features & HAS_ZONE3) {
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
|
||||
}
|
||||
if (data->has_features & HAS_ZONE_HYST) {
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
|
||||
}
|
||||
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
||||
|
||||
if (!data->client) {
|
||||
@ -1934,23 +2007,31 @@ static int dme1737_create_files(struct device *dev)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* Create misc sysfs attributes */
|
||||
if ((data->type != sch5027) &&
|
||||
/* Create chip-dependent sysfs attributes */
|
||||
if ((data->has_features & HAS_TEMP_OFFSET) &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_misc_group))) {
|
||||
&dme1737_temp_offset_group))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* Create VID-related sysfs attributes */
|
||||
if ((data->type == dme1737) &&
|
||||
if ((data->has_features & HAS_VID) &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_vid_group))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
if ((data->has_features & HAS_ZONE3) &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_zone3_group))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
if ((data->has_features & HAS_ZONE_HYST) &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_zone_hyst_group))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* Create fan sysfs attributes */
|
||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
||||
if (data->has_fan & (1 << ix)) {
|
||||
if (data->has_features & HAS_FAN(ix)) {
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_fan_group[ix]))) {
|
||||
goto exit_remove;
|
||||
@ -1960,14 +2041,14 @@ static int dme1737_create_files(struct device *dev)
|
||||
|
||||
/* Create PWM sysfs attributes */
|
||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
|
||||
if (data->has_pwm & (1 << ix)) {
|
||||
if (data->has_features & HAS_PWM(ix)) {
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&dme1737_pwm_group[ix]))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
if (data->type != sch5027 && ix < 3 &&
|
||||
if ((data->has_features & HAS_PWM_MIN) && ix < 3 &&
|
||||
(err = sysfs_create_file(&dev->kobj,
|
||||
dme1737_pwm_misc_attr[ix]))) {
|
||||
dme1737_auto_pwm_min_attr[ix]))) {
|
||||
goto exit_remove;
|
||||
}
|
||||
}
|
||||
@ -1983,21 +2064,30 @@ static int dme1737_create_files(struct device *dev)
|
||||
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
|
||||
S_IRUGO | S_IWUSR);
|
||||
|
||||
/* Change permissions of misc sysfs attributes */
|
||||
if (data->type != sch5027) {
|
||||
dme1737_chmod_group(dev, &dme1737_misc_group,
|
||||
/* Change permissions of chip-dependent sysfs attributes */
|
||||
if (data->has_features & HAS_TEMP_OFFSET) {
|
||||
dme1737_chmod_group(dev, &dme1737_temp_offset_group,
|
||||
S_IRUGO | S_IWUSR);
|
||||
}
|
||||
if (data->has_features & HAS_ZONE3) {
|
||||
dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
|
||||
S_IRUGO | S_IWUSR);
|
||||
}
|
||||
if (data->has_features & HAS_ZONE_HYST) {
|
||||
dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
|
||||
S_IRUGO | S_IWUSR);
|
||||
}
|
||||
|
||||
/* Change permissions of PWM sysfs attributes */
|
||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
|
||||
if (data->has_pwm & (1 << ix)) {
|
||||
if (data->has_features & HAS_PWM(ix)) {
|
||||
dme1737_chmod_group(dev,
|
||||
&dme1737_pwm_chmod_group[ix],
|
||||
S_IRUGO | S_IWUSR);
|
||||
if (data->type != sch5027 && ix < 3) {
|
||||
if ((data->has_features & HAS_PWM_MIN) &&
|
||||
ix < 3) {
|
||||
dme1737_chmod_file(dev,
|
||||
dme1737_pwm_misc_attr[ix],
|
||||
dme1737_auto_pwm_min_attr[ix],
|
||||
S_IRUGO | S_IWUSR);
|
||||
}
|
||||
}
|
||||
@ -2005,7 +2095,7 @@ static int dme1737_create_files(struct device *dev)
|
||||
|
||||
/* Change permissions of pwm[1-3] if in manual mode */
|
||||
for (ix = 0; ix < 3; ix++) {
|
||||
if ((data->has_pwm & (1 << ix)) &&
|
||||
if ((data->has_features & HAS_PWM(ix)) &&
|
||||
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
|
||||
dme1737_chmod_file(dev,
|
||||
dme1737_pwm_chmod_attr[ix],
|
||||
@ -2052,20 +2142,20 @@ static int dme1737_init_device(struct device *dev)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Determine which optional fan and pwm features are enabled/present */
|
||||
/* Determine which optional fan and pwm features are enabled (only
|
||||
* valid for I2C devices) */
|
||||
if (client) { /* I2C chip */
|
||||
data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
|
||||
/* Check if optional fan3 input is enabled */
|
||||
if (data->config2 & 0x04) {
|
||||
data->has_fan |= (1 << 2);
|
||||
data->has_features |= HAS_FAN(2);
|
||||
}
|
||||
|
||||
/* Fan4 and pwm3 are only available if the client's I2C address
|
||||
* is the default 0x2e. Otherwise the I/Os associated with
|
||||
* these functions are used for addr enable/select. */
|
||||
if (client->addr == 0x2e) {
|
||||
data->has_fan |= (1 << 3);
|
||||
data->has_pwm |= (1 << 2);
|
||||
data->has_features |= HAS_FAN(3) | HAS_PWM(2);
|
||||
}
|
||||
|
||||
/* Determine which of the optional fan[5-6] and pwm[5-6]
|
||||
@ -2077,26 +2167,40 @@ static int dme1737_init_device(struct device *dev)
|
||||
dev_warn(dev, "Failed to query Super-IO for optional "
|
||||
"features.\n");
|
||||
}
|
||||
} else { /* ISA chip */
|
||||
/* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
|
||||
* don't exist in the ISA chip. */
|
||||
data->has_fan |= (1 << 2);
|
||||
data->has_pwm |= (1 << 2);
|
||||
}
|
||||
|
||||
/* Fan1, fan2, pwm1, and pwm2 are always present */
|
||||
data->has_fan |= 0x03;
|
||||
data->has_pwm |= 0x03;
|
||||
/* Fan[1-2] and pwm[1-2] are present in all chips */
|
||||
data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
|
||||
|
||||
/* Chip-dependent features */
|
||||
switch (data->type) {
|
||||
case dme1737:
|
||||
data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
|
||||
HAS_ZONE_HYST | HAS_PWM_MIN;
|
||||
break;
|
||||
case sch311x:
|
||||
data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
|
||||
HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
|
||||
break;
|
||||
case sch5027:
|
||||
data->has_features |= HAS_ZONE3;
|
||||
break;
|
||||
case sch5127:
|
||||
data->has_features |= HAS_FAN(2) | HAS_PWM(2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
|
||||
"fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
|
||||
(data->has_pwm & (1 << 2)) ? "yes" : "no",
|
||||
(data->has_pwm & (1 << 4)) ? "yes" : "no",
|
||||
(data->has_pwm & (1 << 5)) ? "yes" : "no",
|
||||
(data->has_fan & (1 << 2)) ? "yes" : "no",
|
||||
(data->has_fan & (1 << 3)) ? "yes" : "no",
|
||||
(data->has_fan & (1 << 4)) ? "yes" : "no",
|
||||
(data->has_fan & (1 << 5)) ? "yes" : "no");
|
||||
(data->has_features & HAS_PWM(2)) ? "yes" : "no",
|
||||
(data->has_features & HAS_PWM(4)) ? "yes" : "no",
|
||||
(data->has_features & HAS_PWM(5)) ? "yes" : "no",
|
||||
(data->has_features & HAS_FAN(2)) ? "yes" : "no",
|
||||
(data->has_features & HAS_FAN(3)) ? "yes" : "no",
|
||||
(data->has_features & HAS_FAN(4)) ? "yes" : "no",
|
||||
(data->has_features & HAS_FAN(5)) ? "yes" : "no");
|
||||
|
||||
reg = dme1737_read(data, DME1737_REG_TACH_PWM);
|
||||
/* Inform if fan-to-pwm mapping differs from the default */
|
||||
@ -2122,7 +2226,7 @@ static int dme1737_init_device(struct device *dev)
|
||||
for (ix = 0; ix < 3; ix++) {
|
||||
data->pwm_config[ix] = dme1737_read(data,
|
||||
DME1737_REG_PWM_CONFIG(ix));
|
||||
if ((data->has_pwm & (1 << ix)) &&
|
||||
if ((data->has_features & HAS_PWM(ix)) &&
|
||||
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
|
||||
dev_info(dev, "Switching pwm%d to "
|
||||
"manual mode.\n", ix + 1);
|
||||
@ -2142,7 +2246,7 @@ static int dme1737_init_device(struct device *dev)
|
||||
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
|
||||
|
||||
/* Set VRM */
|
||||
if (data->type == dme1737) {
|
||||
if (data->has_features & HAS_VID) {
|
||||
data->vrm = vid_which_vrm();
|
||||
}
|
||||
|
||||
@ -2163,10 +2267,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
|
||||
dme1737_sio_enter(sio_cip);
|
||||
|
||||
/* Check device ID
|
||||
* The DME1737 can return either 0x78 or 0x77 as its device ID.
|
||||
* The SCH5027 returns 0x89 as its device ID. */
|
||||
* We currently know about two kinds of DME1737 and SCH5027. */
|
||||
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
||||
if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
|
||||
if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
|
||||
reg == SCH5027_ID)) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
@ -2185,16 +2289,16 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
|
||||
* are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
|
||||
* to '10' if the respective feature is enabled. */
|
||||
if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
|
||||
data->has_fan |= (1 << 5);
|
||||
data->has_features |= HAS_FAN(5);
|
||||
}
|
||||
if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
|
||||
data->has_pwm |= (1 << 5);
|
||||
data->has_features |= HAS_PWM(5);
|
||||
}
|
||||
if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
|
||||
data->has_fan |= (1 << 4);
|
||||
data->has_features |= HAS_FAN(4);
|
||||
}
|
||||
if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
|
||||
data->has_pwm |= (1 << 4);
|
||||
data->has_features |= HAS_PWM(4);
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -2222,7 +2326,6 @@ static int dme1737_i2c_detect(struct i2c_client *client,
|
||||
if (company == DME1737_COMPANY_SMSC &&
|
||||
verstep == SCH5027_VERSTEP) {
|
||||
name = "sch5027";
|
||||
|
||||
} else if (company == DME1737_COMPANY_SMSC &&
|
||||
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
|
||||
name = "dme1737";
|
||||
@ -2329,10 +2432,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
|
||||
dme1737_sio_enter(sio_cip);
|
||||
|
||||
/* Check device ID
|
||||
* We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
|
||||
* SCH3116 (0x7f). */
|
||||
* We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 */
|
||||
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
||||
if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
|
||||
if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
|
||||
reg == SCH5127_ID)) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
@ -2424,23 +2527,42 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* Skip chip detection if module is loaded with force_id parameter */
|
||||
if (!force_id) {
|
||||
switch (force_id) {
|
||||
case SCH3112_ID:
|
||||
case SCH3114_ID:
|
||||
case SCH3116_ID:
|
||||
data->type = sch311x;
|
||||
break;
|
||||
case SCH5127_ID:
|
||||
data->type = sch5127;
|
||||
break;
|
||||
default:
|
||||
company = dme1737_read(data, DME1737_REG_COMPANY);
|
||||
device = dme1737_read(data, DME1737_REG_DEVICE);
|
||||
|
||||
if (!((company == DME1737_COMPANY_SMSC) &&
|
||||
(device == SCH311X_DEVICE))) {
|
||||
if ((company == DME1737_COMPANY_SMSC) &&
|
||||
(device == SCH311X_DEVICE)) {
|
||||
data->type = sch311x;
|
||||
} else if ((company == DME1737_COMPANY_SMSC) &&
|
||||
(device == SCH5127_DEVICE)) {
|
||||
data->type = sch5127;
|
||||
} else {
|
||||
err = -ENODEV;
|
||||
goto exit_kfree;
|
||||
}
|
||||
}
|
||||
data->type = sch311x;
|
||||
|
||||
/* Fill in the remaining client fields and initialize the mutex */
|
||||
data->name = "sch311x";
|
||||
if (data->type == sch5127) {
|
||||
data->name = "sch5127";
|
||||
} else {
|
||||
data->name = "sch311x";
|
||||
}
|
||||
|
||||
/* Initialize the mutex */
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
|
||||
dev_info(dev, "Found a %s chip at 0x%04x\n",
|
||||
data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
|
||||
|
||||
/* Initialize the chip */
|
||||
if ((err = dme1737_init_device(dev))) {
|
||||
|
344
drivers/hwmon/emc1403.c
Normal file
344
drivers/hwmon/emc1403.c
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* 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)
|
||||
static int superio_inw(int base, int reg)
|
||||
{
|
||||
int val;
|
||||
outb(reg++, base);
|
||||
val = inb(base + 1) << 8;
|
||||
outb(reg, base);
|
||||
val |= inb(base + 1);
|
||||
val = superio_inb(base, reg) << 8;
|
||||
val |= superio_inb(base, reg + 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void superio_enter(int base)
|
||||
{
|
||||
/* 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(ld, base + 1);
|
||||
@ -905,10 +903,8 @@ static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
outb(reg++, data->addr + ADDR_REG_OFFSET);
|
||||
val = inb(data->addr + DATA_REG_OFFSET) << 8;
|
||||
outb(reg, data->addr + ADDR_REG_OFFSET);
|
||||
val |= inb(data->addr + DATA_REG_OFFSET);
|
||||
val = f71882fg_read8(data, reg) << 8;
|
||||
val |= f71882fg_read8(data, reg + 1);
|
||||
|
||||
return 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)
|
||||
{
|
||||
outb(reg++, data->addr + ADDR_REG_OFFSET);
|
||||
outb(val >> 8, data->addr + DATA_REG_OFFSET);
|
||||
outb(reg, data->addr + ADDR_REG_OFFSET);
|
||||
outb(val & 255, data->addr + DATA_REG_OFFSET);
|
||||
f71882fg_write8(data, reg, val >> 8);
|
||||
f71882fg_write8(data, reg + 1, val & 0xff);
|
||||
}
|
||||
|
||||
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)
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* 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) {
|
||||
if (data->type == f71882fg || data->type == f71889fg) {
|
||||
data->in1_max =
|
||||
@ -1127,8 +1121,12 @@ static ssize_t store_fan_full_speed(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = SENSORS_LIMIT(val, 23, 1500000);
|
||||
val = fan_to_reg(val);
|
||||
@ -1157,8 +1155,12 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val;
|
||||
|
||||
err = strict_strtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
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
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
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);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1233,8 +1242,12 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val;
|
||||
|
||||
err = strict_strtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
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
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10) / 1000;
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val /= 1000;
|
||||
val = SENSORS_LIMIT(val, 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1333,10 +1352,16 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10) / 1000;
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
ssize_t ret = count;
|
||||
u8 reg;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -1372,8 +1397,14 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10) / 1000;
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val /= 1000;
|
||||
val = SENSORS_LIMIT(val, 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1427,8 +1458,12 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val;
|
||||
|
||||
err = strict_strtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
|
||||
@ -1490,8 +1525,13 @@ static ssize_t store_pwm(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = SENSORS_LIMIT(val, 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1551,8 +1591,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Special case for F8000 pwm channel 3 which only does auto mode */
|
||||
if (data->type == f8000 && nr == 2 && val != 2)
|
||||
@ -1626,9 +1670,14 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1674,10 +1723,16 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
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;
|
||||
long val = simple_strtol(buf, NULL, 10) / 1000;
|
||||
u8 reg;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm_auto_point_temp[nr][point] =
|
||||
@ -1716,8 +1771,12 @@ static ssize_t store_pwm_interpolate(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
unsigned long val;
|
||||
|
||||
err = strict_strtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm_auto_point_mapping[nr] =
|
||||
@ -1752,8 +1811,12 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int err, nr = to_sensor_dev_attr_2(devattr)->index;
|
||||
long val;
|
||||
|
||||
err = strict_strtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (val) {
|
||||
case 1:
|
||||
@ -1798,9 +1861,15 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
val = SENSORS_LIMIT(val, -128, 127);
|
||||
@ -2109,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
|
||||
int err = -ENODEV;
|
||||
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);
|
||||
|
||||
devid = superio_inw(sioaddr, SIO_REG_MANID);
|
||||
@ -2151,8 +2227,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
|
||||
}
|
||||
|
||||
*address = superio_inw(sioaddr, SIO_REG_ADDR);
|
||||
if (*address == 0)
|
||||
{
|
||||
if (*address == 0) {
|
||||
printk(KERN_WARNING DRVNAME ": Base address not set\n");
|
||||
goto exit;
|
||||
}
|
||||
@ -2164,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
|
||||
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
|
||||
exit:
|
||||
superio_exit(sioaddr);
|
||||
release_region(sioaddr, 2);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@
|
||||
* 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
|
||||
@ -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 void lm63_init_client(struct i2c_client *client);
|
||||
|
||||
enum chips { lm63, lm64 };
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static const struct i2c_device_id lm63_id[] = {
|
||||
{ "lm63", 0 },
|
||||
{ "lm63", lm63 },
|
||||
{ "lm64", lm64 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm63_id);
|
||||
@ -422,6 +425,7 @@ static int lm63_detect(struct i2c_client *new_client,
|
||||
struct i2c_adapter *adapter = new_client->adapter;
|
||||
u8 man_id, chip_id, reg_config1, reg_config2;
|
||||
u8 reg_alert_status, reg_alert_mask;
|
||||
int address = new_client->addr;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
@ -439,7 +443,6 @@ static int lm63_detect(struct i2c_client *new_client,
|
||||
LM63_REG_ALERT_MASK);
|
||||
|
||||
if (man_id != 0x01 /* National Semiconductor */
|
||||
|| chip_id != 0x41 /* LM63 */
|
||||
|| (reg_config1 & 0x18) != 0x00
|
||||
|| (reg_config2 & 0xF8) != 0x00
|
||||
|| (reg_alert_status & 0x20) != 0x00
|
||||
@ -450,7 +453,12 @@ static int lm63_detect(struct i2c_client *new_client,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
|
||||
if (chip_id == 0x41 && address == 0x4c)
|
||||
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;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
||||
tcn75,
|
||||
tmp100,
|
||||
tmp101,
|
||||
tmp105,
|
||||
tmp175,
|
||||
tmp275,
|
||||
tmp75,
|
||||
@ -220,6 +221,7 @@ static const struct i2c_device_id lm75_ids[] = {
|
||||
{ "tcn75", tcn75, },
|
||||
{ "tmp100", tmp100, },
|
||||
{ "tmp101", tmp101, },
|
||||
{ "tmp105", tmp105, },
|
||||
{ "tmp175", tmp175, },
|
||||
{ "tmp275", tmp275, },
|
||||
{ "tmp75", tmp75, },
|
||||
|
@ -982,7 +982,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
|
||||
|
||||
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;
|
||||
|
||||
dev_dbg(&client->dev, "Updating lm90 data.\n");
|
||||
|
@ -45,9 +45,7 @@ enum ltc4245_cmd {
|
||||
LTC4245_VEEIN = 0x19,
|
||||
LTC4245_VEESENSE = 0x1a,
|
||||
LTC4245_VEEOUT = 0x1b,
|
||||
LTC4245_GPIOADC1 = 0x1c,
|
||||
LTC4245_GPIOADC2 = 0x1d,
|
||||
LTC4245_GPIOADC3 = 0x1e,
|
||||
LTC4245_GPIOADC = 0x1c,
|
||||
};
|
||||
|
||||
struct ltc4245_data {
|
||||
@ -61,7 +59,7 @@ struct ltc4245_data {
|
||||
u8 cregs[0x08];
|
||||
|
||||
/* Voltage registers */
|
||||
u8 vregs[0x0f];
|
||||
u8 vregs[0x0d];
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Read voltage registers -- 0x10 to 0x1f */
|
||||
/* Read voltage registers -- 0x10 to 0x1c */
|
||||
for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
|
||||
val = i2c_smbus_read_byte_data(client, i+0x10);
|
||||
if (unlikely(val < 0))
|
||||
@ -128,9 +126,7 @@ static int ltc4245_get_voltage(struct device *dev, u8 reg)
|
||||
case LTC4245_VEEOUT:
|
||||
voltage = regval * -55;
|
||||
break;
|
||||
case LTC4245_GPIOADC1:
|
||||
case LTC4245_GPIOADC2:
|
||||
case LTC4245_GPIOADC3:
|
||||
case LTC4245_GPIOADC:
|
||||
voltage = regval * 10;
|
||||
break;
|
||||
default:
|
||||
@ -297,9 +293,7 @@ LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
|
||||
LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
|
||||
|
||||
/* GPIO voltages */
|
||||
LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC1);
|
||||
LTC4245_VOLTAGE(in10_input, LTC4245_GPIOADC2);
|
||||
LTC4245_VOLTAGE(in11_input, LTC4245_GPIOADC3);
|
||||
LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC);
|
||||
|
||||
/* Power Consumption (virtual) */
|
||||
LTC4245_POWER(power1_input, LTC4245_12VSENSE);
|
||||
@ -342,8 +336,6 @@ static struct attribute *ltc4245_attributes[] = {
|
||||
&sensor_dev_attr_in8_min_alarm.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_power2_input.dev_attr.attr,
|
||||
|
321
drivers/hwmon/tmp102.c
Normal file
321
drivers/hwmon/tmp102.c
Normal file
@ -0,0 +1,321 @@
|
||||
/* 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 };
|
||||
#define TMP401_DEVICE_ID 0x11
|
||||
#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)
|
||||
*/
|
||||
@ -113,18 +102,6 @@ static const struct i2c_device_id 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)
|
||||
*/
|
||||
@ -194,6 +171,71 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
|
||||
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,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -420,30 +462,36 @@ static ssize_t reset_temp_history(struct device *dev,
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute tmp401_attr[] = {
|
||||
SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
|
||||
SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0),
|
||||
SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
|
||||
SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0),
|
||||
SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst,
|
||||
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
|
||||
SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
store_temp_min, 0),
|
||||
SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
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),
|
||||
SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL,
|
||||
SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
|
||||
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),
|
||||
SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL,
|
||||
SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_LOCAL_CRIT),
|
||||
SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
|
||||
SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1),
|
||||
SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
|
||||
SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1),
|
||||
SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1),
|
||||
SENSOR_ATTR(temp2_fault, 0444, show_status, NULL,
|
||||
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
|
||||
SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
store_temp_min, 1),
|
||||
SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
store_temp_max, 1),
|
||||
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),
|
||||
SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL,
|
||||
SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
|
||||
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),
|
||||
SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL,
|
||||
SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_REMOTE_CRIT),
|
||||
};
|
||||
|
||||
@ -455,11 +503,11 @@ static struct sensor_device_attribute tmp401_attr[] = {
|
||||
* and remote channels.
|
||||
*/
|
||||
static struct sensor_device_attribute tmp411_attr[] = {
|
||||
SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0),
|
||||
SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0),
|
||||
SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1),
|
||||
SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1),
|
||||
SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0),
|
||||
SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
|
||||
SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
|
||||
SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
|
||||
SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
|
||||
SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -529,6 +577,27 @@ static int tmp401_detect(struct i2c_client *client,
|
||||
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,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -581,91 +650,17 @@ exit_remove:
|
||||
return err;
|
||||
}
|
||||
|
||||
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 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 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,
|
||||
};
|
||||
|
||||
static int __init tmp401_init(void)
|
||||
{
|
||||
|
@ -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,
|
||||
const char *name);
|
||||
|
||||
int acpi_resources_are_enforced(void);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
void __init acpi_no_s4_hw_signature(void);
|
||||
void __init acpi_old_suspend_ordering(void);
|
||||
|
Loading…
Reference in New Issue
Block a user