diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 11:33:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 11:33:46 -0700 |
commit | d1e0fe252e1c410164127b3000613afeaf47e49f (patch) | |
tree | 6848bbd6b64d4bb5e64bbd9a17598f3500719776 | |
parent | cc106eb35ed4abea675bce0d8fe40a46ff0b4a72 (diff) | |
parent | 6d034059eef080a0cdda92b45baa18cb00a19835 (diff) |
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
...
-rw-r--r-- | Documentation/hwmon/dme1737 | 51 | ||||
-rw-r--r-- | Documentation/hwmon/lm63 | 7 | ||||
-rw-r--r-- | Documentation/hwmon/ltc4245 | 4 | ||||
-rw-r--r-- | Documentation/hwmon/sysfs-interface | 13 | ||||
-rw-r--r-- | Documentation/hwmon/tmp102 | 26 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 9 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 34 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 2 | ||||
-rw-r--r-- | drivers/hwmon/adm1031.c | 68 | ||||
-rw-r--r-- | drivers/hwmon/applesmc.c | 186 | ||||
-rw-r--r-- | drivers/hwmon/asus_atk0110.c | 7 | ||||
-rw-r--r-- | drivers/hwmon/dme1737.c | 328 | ||||
-rw-r--r-- | drivers/hwmon/emc1403.c | 344 | ||||
-rw-r--r-- | drivers/hwmon/f71882fg.c | 170 | ||||
-rw-r--r-- | drivers/hwmon/lm63.c | 16 | ||||
-rw-r--r-- | drivers/hwmon/lm75.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/lm90.c | 3 | ||||
-rw-r--r-- | drivers/hwmon/ltc4245.c | 18 | ||||
-rw-r--r-- | drivers/hwmon/tmp102.c | 321 | ||||
-rw-r--r-- | drivers/hwmon/tmp401.c | 255 | ||||
-rw-r--r-- | include/linux/acpi.h | 2 |
21 files changed, 1543 insertions, 323 deletions
diff --git a/Documentation/hwmon/dme1737 b/Documentation/hwmon/dme1737 index 001d2e70bc11..fc5df7654d63 100644 --- a/Documentation/hwmon/dme1737 +++ b/Documentation/hwmon/dme1737 @@ -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 diff --git a/Documentation/hwmon/lm63 b/Documentation/hwmon/lm63 index 31660bf97979..b9843eab1afb 100644 --- a/Documentation/hwmon/lm63 +++ b/Documentation/hwmon/lm63 @@ -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. diff --git a/Documentation/hwmon/ltc4245 b/Documentation/hwmon/ltc4245 index 02838a47d862..86b5880d8502 100644 --- a/Documentation/hwmon/ltc4245 +++ b/Documentation/hwmon/ltc4245 @@ -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) diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 3de6b0bcb147..d4e2917c6f18 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -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 * diff --git a/Documentation/hwmon/tmp102 b/Documentation/hwmon/tmp102 new file mode 100644 index 000000000000..8454a7763122 --- /dev/null +++ b/Documentation/hwmon/tmp102 @@ -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). diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 4bc1c4178f50..78418ce4fc78 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1207,6 +1207,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. * * handle is a pointer to the spinlock_t. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 6a9ac754ca5d..e19cf8eb6ccf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 86920fb34118..2138ceb1a713 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -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 diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 1644b92e7cc4..15c1a9616af3 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -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; diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index f085c18d2905..b6598aa557a0 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -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, diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 16c420240724..653db1bda934 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -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); diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 823dd28a902c..980c17d5eeae 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -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))) { diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c new file mode 100644 index 000000000000..0e4b5642638d --- /dev/null +++ b/drivers/hwmon/emc1403.c @@ -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"); diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index a95fa4256caa..537841ef44b9 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -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; } diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index bf81aff7051d..776aeb3019d2 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -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; } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 8ae2cfe2d827..56463428a419 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -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, }, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 7cc2708871ab..760ef72eea56 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -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"); diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 65c232a9d0c5..21d201befc2c 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -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, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c new file mode 100644 index 000000000000..8013895a1faf --- /dev/null +++ b/drivers/hwmon/tmp102.c @@ -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"); diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index d14a1af9f550..ad8d535235c5 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -92,17 +92,6 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; #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) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3da73f5f0ae9..2c60f1f70b38 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -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); |