diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 63 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 4 | ||||
-rw-r--r-- | drivers/hwmon/ds1621.c | 172 | ||||
-rw-r--r-- | drivers/hwmon/fschmd.c | 229 | ||||
-rw-r--r-- | drivers/hwmon/hdaps.c | 66 | ||||
-rw-r--r-- | drivers/hwmon/hp_accel.c | 124 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 288 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.h | 20 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d_spi.c | 114 | ||||
-rw-r--r-- | drivers/hwmon/lm95241.c | 527 | ||||
-rw-r--r-- | drivers/hwmon/ltc4215.c | 364 | ||||
-rw-r--r-- | drivers/hwmon/pcf8591.c | 325 | ||||
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 170 |
13 files changed, 2028 insertions, 438 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b4eea0292c1..ce52bf2f235 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -343,12 +343,13 @@ config SENSORS_FSCPOS will be called fscpos. config SENSORS_FSCHMD - tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" + tristate "Fujitsu Siemens Computers sensor chips" depends on X86 && I2C help - If you say yes here you get support for various Fujitsu Siemens - Computers sensor chips, including support for the integrated - watchdog. + If you say yes here you get support for the following Fujitsu + Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, + Heimdall, Heracles, Hades and Syleus including support for the + integrated watchdog. This is a merged driver for FSC sensor chips replacing the fscpos, fscscy and fscher drivers and adding support for several other FSC @@ -570,6 +571,17 @@ config SENSORS_LM93 This driver can also be built as a module. If so, the module will be called lm93. +config SENSORS_LTC4215 + tristate "Linear Technology LTC4215" + depends on I2C && EXPERIMENTAL + default n + help + If you say yes here you get support for Linear Technology LTC4215 + Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4215. + config SENSORS_LTC4245 tristate "Linear Technology LTC4245" depends on I2C && EXPERIMENTAL @@ -581,6 +593,15 @@ config SENSORS_LTC4245 This driver can also be built as a module. If so, the module will be called ltc4245. +config SENSORS_LM95241 + tristate "National Semiconductor LM95241 sensor chip" + depends on I2C + help + If you say yes here you get support for LM95241 sensor chip. + + This driver can also be built as a module. If so, the module + will be called lm95241. + config SENSORS_MAX1111 tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip" depends on SPI_MASTER @@ -635,6 +656,20 @@ config SENSORS_PC87427 This driver can also be built as a module. If so, the module will be called pc87427. +config SENSORS_PCF8591 + tristate "Philips PCF8591 ADC/DAC" + depends on I2C + default n + help + If you say yes here you get support for Philips PCF8591 4-channel + ADC, 1-channel DAC chips. + + This driver can also be built as a module. If so, the module + will be called pcf8591. + + These devices are hard to detect and rarely found on mainstream + hardware. If unsure, say N. + config SENSORS_SIS5595 tristate "Silicon Integrated Systems Corp. SiS5595" depends on PCI @@ -827,7 +862,7 @@ config SENSORS_W83627HF will be called w83627hf. config SENSORS_W83627EHF - tristate "Winbond W83627EHF/DHG" + tristate "Winbond W83627EHF/EHG/DHG, W83667HG" select HWMON_VID help If you say yes here you get support for the hardware @@ -838,6 +873,8 @@ config SENSORS_W83627EHF chip suited for specific Intel processors that use PECI such as the Core 2 Duo. + This driver also supports the W83667HG chip. + This driver can also be built as a module. If so, the module will be called w83627ehf. @@ -895,6 +932,22 @@ config SENSORS_LIS3LV02D Say Y here if you have an applicable laptop and want to experience the awesome power of lis3lv02d. +config SENSORS_LIS3_SPI + tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" + depends on !ACPI && SPI_MASTER && INPUT + default n + help + This driver provides support for the LIS3LV02Dx accelerometer connected + via SPI. The accelerometer data is readable via + /sys/devices/platform/lis3lv02d. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. + + This driver can also be built as modules. If so, the core module + will be called lis3lv02d and a specific module for the SPI transport + is called lis3lv02d_spi. + config SENSORS_APPLESMC tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" depends on INPUT && X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2e80f37f39e..3a6b1f06f8f 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o +obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM75) += lm75.o @@ -64,12 +65,15 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_LM93) += lm93.o +obj-$(CONFIG_SENSORS_LM95241) += lm95241.o +obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o obj-$(CONFIG_SENSORS_MAX1111) += max1111.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o +obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 7415381601c..53f88f51181 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -81,71 +81,84 @@ struct ds1621_data { u8 conf; /* Register encoding, combined */ }; -static int ds1621_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int ds1621_detect(struct i2c_client *client, int kind, - struct i2c_board_info *info); -static void ds1621_init_client(struct i2c_client *client); -static int ds1621_remove(struct i2c_client *client); -static struct ds1621_data *ds1621_update_client(struct device *dev); - -static const struct i2c_device_id ds1621_id[] = { - { "ds1621", ds1621 }, - { "ds1625", ds1621 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ds1621_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver ds1621_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "ds1621", - }, - .probe = ds1621_probe, - .remove = ds1621_remove, - .id_table = ds1621_id, - .detect = ds1621_detect, - .address_data = &addr_data, -}; - -/* All registers are word-sized, except for the configuration register. +/* Temperature registers are word-sized. DS1621 uses a high-byte first convention, which is exactly opposite to the SMBus standard. */ -static int ds1621_read_value(struct i2c_client *client, u8 reg) +static int ds1621_read_temp(struct i2c_client *client, u8 reg) { - if (reg == DS1621_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); + int ret; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + return swab16(ret); } -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) +static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value) { - if (reg == DS1621_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); + return i2c_smbus_write_word_data(client, reg, swab16(value)); } static void ds1621_init_client(struct i2c_client *client) { - int reg = ds1621_read_value(client, DS1621_REG_CONF); + u8 conf, new_conf; + + new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); /* switch to continuous conversion mode */ - reg &= ~ DS1621_REG_CONFIG_1SHOT; + new_conf &= ~DS1621_REG_CONFIG_1SHOT; /* setup output polarity */ if (polarity == 0) - reg &= ~DS1621_REG_CONFIG_POLARITY; + new_conf &= ~DS1621_REG_CONFIG_POLARITY; else if (polarity == 1) - reg |= DS1621_REG_CONFIG_POLARITY; + new_conf |= DS1621_REG_CONFIG_POLARITY; - ds1621_write_value(client, DS1621_REG_CONF, reg); + if (conf != new_conf) + i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); /* start conversion */ i2c_smbus_write_byte(client, DS1621_COM_START); } +static struct ds1621_data *ds1621_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1621_data *data = i2c_get_clientdata(client); + u8 new_conf; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting ds1621 update\n"); + + data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); + + for (i = 0; i < ARRAY_SIZE(data->temp); i++) + data->temp[i] = ds1621_read_temp(client, + DS1621_REG_TEMP[i]); + + /* reset alarms if necessary */ + new_conf = data->conf; + if (data->temp[0] > data->temp[1]) /* input > min */ + new_conf &= ~DS1621_ALARM_TEMP_LOW; + if (data->temp[0] < data->temp[2]) /* input < max */ + new_conf &= ~DS1621_ALARM_TEMP_HIGH; + if (data->conf != new_conf) + i2c_smbus_write_byte_data(client, DS1621_REG_CONF, + new_conf); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) { @@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = ds1621_update_client(dev); + struct ds1621_data *data = i2c_get_clientdata(client); u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); mutex_lock(&data->update_lock); data->temp[attr->index] = val; - ds1621_write_value(client, DS1621_REG_TEMP[attr->index], - data->temp[attr->index]); + ds1621_write_temp(client, DS1621_REG_TEMP[attr->index], + data->temp[attr->index]); mutex_unlock(&data->update_lock); return count; } @@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind, /* The NVB bit should be low if no EEPROM write has been requested during the latest 10ms, which is highly improbable in our case. */ - conf = ds1621_read_value(client, DS1621_REG_CONF); - if (conf & DS1621_REG_CONFIG_NVB) + conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); + if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) return -ENODEV; /* The 7 lowest bits of a temperature should always be 0. */ for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { - temp = ds1621_read_value(client, DS1621_REG_TEMP[i]); - if (temp & 0x007f) + temp = i2c_smbus_read_word_data(client, + DS1621_REG_TEMP[i]); + if (temp < 0 || (temp & 0x7f00)) return -ENODEV; } } @@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id ds1621_id[] = { + { "ds1621", ds1621 }, + { "ds1625", ds1621 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1621_id); -static struct ds1621_data *ds1621_update_client(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); - u8 new_conf; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int i; - - dev_dbg(&client->dev, "Starting ds1621 update\n"); - - data->conf = ds1621_read_value(client, DS1621_REG_CONF); - - for (i = 0; i < ARRAY_SIZE(data->temp); i++) - data->temp[i] = ds1621_read_value(client, - DS1621_REG_TEMP[i]); - - /* reset alarms if necessary */ - new_conf = data->conf; - if (data->temp[0] > data->temp[1]) /* input > min */ - new_conf &= ~DS1621_ALARM_TEMP_LOW; - if (data->temp[0] < data->temp[2]) /* input < max */ - new_conf &= ~DS1621_ALARM_TEMP_HIGH; - if (data->conf != new_conf) - ds1621_write_value(client, DS1621_REG_CONF, - new_conf); - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - - return data; -} +/* This is the driver that will be inserted */ +static struct i2c_driver ds1621_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ds1621", + }, + .probe = ds1621_probe, + .remove = ds1621_remove, + .id_table = ds1621_id, + .detect = ds1621_detect, + .address_data = &addr_data, +}; static int __init ds1621_init(void) { diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d07f4ef7509..ea955edde87 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -1,6 +1,6 @@ /* fschmd.c * - * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> + * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.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 @@ -19,7 +19,7 @@ /* * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, - * Scylla, Heracles and Heimdall chips + * Scylla, Heracles, Heimdall, Hades and Syleus chips * * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 * (candidate) fschmd drivers: @@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); +I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl); /* * The FSCHMD registers and other defines @@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); #define FSCHMD_CONTROL_ALERT_LED 0x01 /* watchdog */ -#define FSCHMD_REG_WDOG_PRESET 0x28 -#define FSCHMD_REG_WDOG_STATE 0x23 -#define FSCHMD_REG_WDOG_CONTROL 0x21 +static const u8 FSCHMD_REG_WDOG_CONTROL[7] = + { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 }; +static const u8 FSCHMD_REG_WDOG_STATE[7] = + { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 }; +static const u8 FSCHMD_REG_WDOG_PRESET[7] = + { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a }; #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ @@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); #define FSCHMD_WDOG_STATE_CARDRESET 0x02 /* voltages, weird order is to keep the same order as the old drivers */ -static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; +static const u8 FSCHMD_REG_VOLT[7][6] = { + { 0x45, 0x42, 0x48 }, /* pos */ + { 0x45, 0x42, 0x48 }, /* her */ + { 0x45, 0x42, 0x48 }, /* scy */ + { 0x45, 0x42, 0x48 }, /* hrc */ + { 0x45, 0x42, 0x48 }, /* hmd */ + { 0x21, 0x20, 0x22 }, /* hds */ + { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ +}; + +static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; /* minimum pwm at which the fan is driven (pwm can by increased depending on the temp. Notice that for the scy some fans share there minimum speed. Also notice that with the scy the sensor order is different than with the other chips, this order was in the 2.4 driver and kept for consistency. */ -static const u8 FSCHMD_REG_FAN_MIN[5][6] = { +static const u8 FSCHMD_REG_FAN_MIN[7][7] = { { 0x55, 0x65 }, /* pos */ { 0x55, 0x65, 0xb5 }, /* her */ { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ + { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */ + { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ }; /* actual fan speed */ -static const u8 FSCHMD_REG_FAN_ACT[5][6] = { +static const u8 FSCHMD_REG_FAN_ACT[7][7] = { { 0x0e, 0x6b, 0xab }, /* pos */ { 0x0e, 0x6b, 0xbb }, /* her */ { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ + { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */ + { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ }; /* fan status registers */ -static const u8 FSCHMD_REG_FAN_STATE[5][6] = { +static const u8 FSCHMD_REG_FAN_STATE[7][7] = { { 0x0d, 0x62, 0xa2 }, /* pos */ { 0x0d, 0x62, 0xb2 }, /* her */ { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ + { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */ + { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ }; /* fan ripple / divider registers */ -static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { +static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = { { 0x0f, 0x6f, 0xaf }, /* pos */ { 0x0f, 0x6f, 0xbf }, /* her */ { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ + { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */ + { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ }; -static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; +static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 }; /* Fan status register bitmasks */ #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ -#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */ +#define FSCHMD_FAN_NOT_PRESENT 0x08 +#define FSCHMD_FAN_DISABLED 0x80 /* actual temperature registers */ -static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { +static const u8 FSCHMD_REG_TEMP_ACT[7][11] = { { 0x64, 0x32, 0x35 }, /* pos */ { 0x64, 0x32, 0x35 }, /* her */ { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ { 0x64, 0x32, 0x35 }, /* hrc */ { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ + { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */ + { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ + 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, }; /* temperature state registers */ -static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { +static const u8 FSCHMD_REG_TEMP_STATE[7][11] = { { 0x71, 0x81, 0x91 }, /* pos */ { 0x71, 0x81, 0x91 }, /* her */ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ { 0x71, 0x81, 0x91 }, /* hrc */ { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */ + { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ + 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, }; /* temperature high limit registers, FSC does not document these. Proven to be @@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers at these addresses, but doesn't want to confirm they are the same as with the fscher?? */ -static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { +static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { { 0, 0, 0 }, /* pos */ { 0x76, 0x86, 0x96 }, /* her */ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ { 0x76, 0x86, 0x96 }, /* hrc */ { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */ + { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ + 0xba, 0xca, 0xda, 0xea, 0xfa }, }; /* These were found through experimenting with an fscher, currently they are not used, but we keep them around for future reference. + On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), + AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence + the fan speed. static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ -static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; +static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; /* temp status register bitmasks */ #define FSCHMD_TEMP_WORKING 0x01 #define FSCHMD_TEMP_ALERT 0x02 +#define FSCHMD_TEMP_DISABLED 0x80 /* there only really is an alarm if the sensor is working and alert == 1 */ #define FSCHMD_TEMP_ALARM_MASK \ (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) @@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = { { "fscscy", fscscy }, { "fschrc", fschrc }, { "fschmd", fschmd }, + { "fschds", fschds }, + { "fscsyl", fscsyl }, { } }; MODULE_DEVICE_TABLE(i2c, fschmd_id); @@ -242,14 +279,14 @@ struct fschmd_data { u8 watchdog_control; /* watchdog control register */ u8 watchdog_state; /* watchdog status register */ u8 watchdog_preset; /* watchdog counter preset on trigger val */ - u8 volt[3]; /* 12, 5, battery voltage */ - u8 temp_act[5]; /* temperature */ - u8 temp_status[5]; /* status of sensor */ - u8 temp_max[5]; /* high temp limit, notice: undocumented! */ - u8 fan_act[6]; /* fans revolutions per second */ - u8 fan_status[6]; /* fan status */ - u8 fan_min[6]; /* fan min value for rps */ - u8 fan_ripple[6]; /* divider for rps */ + u8 volt[6]; /* voltage */ + u8 temp_act[11]; /* temperature */ + u8 temp_status[11]; /* status of sensor */ + u8 temp_max[11]; /* high temp limit, notice: undocumented! */ + u8 fan_act[7]; /* fans revolutions per second */ + u8 fan_status[7]; /* fan status */ + u8 fan_min[7]; /* fan min value for rps */ + u8 fan_ripple[7]; /* divider for rps */ }; /* Global variables to hold information read from special DMI tables, which are @@ -257,8 +294,8 @@ struct fschmd_data { protect these with a lock as they are only modified from our attach function which always gets called with the i2c-core lock held and never accessed before the attach function is done with them. */ -static int dmi_mult[3] = { 490, 200, 100 }; -static int dmi_offset[3] = { 0, 0, 0 }; +static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; +static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; static int dmi_vref = -1; /* Somewhat ugly :( global data pointer list with all fschmd devices, so that @@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { int index = to_sensor_dev_attr(devattr)->index; - int val = fschmd_update_device(dev)->fan_min[index]; + struct fschmd_data *data = fschmd_update_device(dev); + int val = data->fan_min[index]; - /* 0 = allow turning off, 1-255 = 50-100% */ - if (val) + /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ + if (val || data->kind == fscsyl - 1) val = val / 2 + 128; return sprintf(buf, "%d\n", val); @@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, struct fschmd_data *data = dev_get_drvdata(dev); unsigned long v = simple_strtoul(buf, NULL, 10); - /* register: 0 = allow turning off, 1-255 = 50-100% */ - if (v) { + /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ + if (v || data->kind == fscsyl - 1) { v = SENSORS_LIMIT(v, 128, 255); v = (v - 128) * 2 + 1; } @@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev, return count; } +static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); + static struct sensor_device_attribute fschmd_attr[] = { SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), - SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), + SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3), + SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4), + SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5), }; static struct sensor_device_attribute fschmd_temp_attr[] = { @@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = { SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), + SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5), + SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5), + SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5), + SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5), + SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6), + SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6), + SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6), + SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6), + SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7), + SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7), + SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7), + SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7), + SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8), + SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8), + SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8), + SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8), + SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9), + SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9), + SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9), + SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9), + SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10), + SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10), + SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10), + SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10), }; static struct sensor_device_attribute fschmd_fan_attr[] = { @@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 5), + SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6), + SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6), + SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6), + SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6), + SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 6), }; @@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout) data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); /* Write new timeout value */ - i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET, - data->watchdog_preset); + i2c_smbus_write_byte_data(data->client, + FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); /* Write new control register, do not trigger! */ - i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, + i2c_smbus_write_byte_data(data->client, + FSCHMD_REG_WDOG_CONTROL[data->kind], data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); ret = data->watchdog_preset * resolution; @@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data) } data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; - i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, - data->watchdog_control); + i2c_smbus_write_byte_data(data->client, + FSCHMD_REG_WDOG_CONTROL[data->kind], + data->watchdog_control); leave: mutex_unlock(&data->watchdog_lock); return ret; @@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data) data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; /* Don't store the stop flag in our watchdog control register copy, as its a write only bit (read always returns 0) */ - i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, + i2c_smbus_write_byte_data(data->client, + FSCHMD_REG_WDOG_CONTROL[data->kind], data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); leave: mutex_unlock(&data->watchdog_lock); @@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = { /* DMI decode routine to read voltage scaling factors from special DMI tables, which are available on FSC machines with an fscher or later chip. */ -static void fschmd_dmi_decode(const struct dmi_header *header) +static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) { int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; @@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header) dmi_mult[i] = mult[i] * 10; dmi_offset[i] = offset[i] * 10; } + /* According to the docs there should be separate dmi entries + for the mult's and offsets of in3-5 of the syl, but on + my test machine these are not present */ + dmi_mult[3] = dmi_mult[2]; + dmi_mult[4] = dmi_mult[1]; + dmi_mult[5] = dmi_mult[2]; + dmi_offset[3] = dmi_offset[2]; + dmi_offset[4] = dmi_offset[1]; + dmi_offset[5] = dmi_offset[2]; dmi_vref = vref; } } @@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; - const char * const client_names[5] = { "fscpos", "fscher", "fscscy", - "fschrc", "fschmd" }; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind, kind = fschrc; else if (!strcmp(id, "HMD")) kind = fschmd; + else if (!strcmp(id, "HDS")) + kind = fschds; + else if (!strcmp(id, "SYL")) + kind = fscsyl; else return -ENODEV; } - strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); + strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE); return 0; } @@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct fschmd_data *data; - const char * const names[5] = { "Poseidon", "Hermes", "Scylla", - "Heracles", "Heimdall" }; + const char * const names[7] = { "Poseidon", "Hermes", "Scylla", + "Heracles", "Heimdall", "Hades", "Syleus" }; const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; int i, err; enum chips kind = id->driver_data; @@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client, /* Read the special DMI table for fscher and newer chips */ if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { - dmi_walk(fschmd_dmi_decode); + dmi_walk(fschmd_dmi_decode, NULL); if (dmi_vref == -1) { dev_warn(&client->dev, "Couldn't get voltage scaling factors from " @@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client, } } + /* i2c kind goes from 1-6, we want from 0-5 to address arrays */ + data->kind = kind - 1; + /* Read in some never changing registers */ data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); data->global_control = i2c_smbus_read_byte_data(client, FSCHMD_REG_CONTROL); data->watchdog_control = i2c_smbus_read_byte_data(client, - FSCHMD_REG_WDOG_CONTROL); + FSCHMD_REG_WDOG_CONTROL[data->kind]); data->watchdog_state = i2c_smbus_read_byte_data(client, - FSCHMD_REG_WDOG_STATE); + FSCHMD_REG_WDOG_STATE[data->kind]); data->watchdog_preset = i2c_smbus_read_byte_data(client, - FSCHMD_REG_WDOG_PRESET); + FSCHMD_REG_WDOG_PRESET[data->kind]); - /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ - data->kind = kind - 1; + err = device_create_file(&client->dev, &dev_attr_alert_led); + if (err) + goto exit_detach; - for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { + for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { err = device_create_file(&client->dev, &fschmd_attr[i].dev_attr); if (err) @@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client, show_temp_max) continue; + if (kind == fscsyl) { + if (i % 4 == 0) + data->temp_status[i / 4] = + i2c_smbus_read_byte_data(client, + FSCHMD_REG_TEMP_STATE + [data->kind][i / 4]); + if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED) + continue; + } + err = device_create_file(&client->dev, &fschmd_temp_attr[i].dev_attr); if (err) @@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client, "pwm3_auto_point1_pwm")) continue; + if (kind == fscsyl) { + if (i % 5 == 0) + data->fan_status[i / 5] = + i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_STATE + [data->kind][i / 5]); + if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED) + continue; + } + err = device_create_file(&client->dev, &fschmd_fan_attr[i].dev_attr); if (err) @@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client) if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); - for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) + device_remove_file(&client->dev, &dev_attr_alert_led); + for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++) device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) device_remove_file(&client->dev, @@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) data->temp_act[i] < data->temp_max[i]) i2c_smbus_write_byte_data(client, FSCHMD_REG_TEMP_STATE[data->kind][i], - FSCHMD_TEMP_ALERT); + data->temp_status[i]); } for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { @@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) data->fan_act[i]) i2c_smbus_write_byte_data(client, FSCHMD_REG_FAN_STATE[data->kind][i], - FSCHMD_FAN_ALARM); + data->fan_status[i]); } |