From 40e47125e6c5110383b0176d7b9d530f2936b1ae Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sun, 4 Mar 2012 23:16:11 +0900 Subject: Documentation: Fix multiple typo in Documentation Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Jiri Kosina --- Documentation/hwmon/adm1275 | 2 +- Documentation/hwmon/max16064 | 4 ++-- Documentation/hwmon/max34440 | 4 ++-- Documentation/hwmon/max8688 | 4 ++-- Documentation/hwmon/ucd9000 | 6 +++--- Documentation/hwmon/ucd9200 | 10 +++++----- Documentation/hwmon/zl6100 | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index ab70d96d2df..e5f982c845f 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -53,7 +53,7 @@ attributes are write-only, all other attributes are read-only. in1_label "vin1" or "vout1" depending on chip variant and configuration. in1_input Measured voltage. -in1_min Minumum Voltage. +in1_min Minimum Voltage. in1_max Maximum voltage. in1_min_alarm Voltage low alarm. in1_max_alarm Voltage high alarm. diff --git a/Documentation/hwmon/max16064 b/Documentation/hwmon/max16064 index f6e8bcbfacc..f8b478076f6 100644 --- a/Documentation/hwmon/max16064 +++ b/Documentation/hwmon/max16064 @@ -42,9 +42,9 @@ attributes are read-only. in[1-4]_label "vout[1-4]" in[1-4]_input Measured voltage. From READ_VOUT register. -in[1-4]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-4]_min Minimum Voltage. From VOUT_UV_WARN_LIMIT register. in[1-4]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. -in[1-4]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-4]_lcrit Critical minimum Voltage. VOUT_UV_FAULT_LIMIT register. in[1-4]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. in[1-4]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[1-4]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 index 8ab51536a1e..19743919ea5 100644 --- a/Documentation/hwmon/max34440 +++ b/Documentation/hwmon/max34440 @@ -48,9 +48,9 @@ attributes are read-only. in[1-6]_label "vout[1-6]". in[1-6]_input Measured voltage. From READ_VOUT register. -in[1-6]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-6]_min Minimum Voltage. From VOUT_UV_WARN_LIMIT register. in[1-6]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. -in[1-6]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-6]_lcrit Critical minimum Voltage. VOUT_UV_FAULT_LIMIT register. in[1-6]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. diff --git a/Documentation/hwmon/max8688 b/Documentation/hwmon/max8688 index 71ed10a3c94..fe849871df3 100644 --- a/Documentation/hwmon/max8688 +++ b/Documentation/hwmon/max8688 @@ -42,9 +42,9 @@ attributes are read-only. in1_label "vout1" in1_input Measured voltage. From READ_VOUT register. -in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in1_min Minimum Voltage. From VOUT_UV_WARN_LIMIT register. in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. -in1_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in1_lcrit Critical minimum Voltage. VOUT_UV_FAULT_LIMIT register. in1_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. diff --git a/Documentation/hwmon/ucd9000 b/Documentation/hwmon/ucd9000 index 40ca6db50c4..0df5f276505 100644 --- a/Documentation/hwmon/ucd9000 +++ b/Documentation/hwmon/ucd9000 @@ -70,9 +70,9 @@ attributes are read-only. in[1-12]_label "vout[1-12]". in[1-12]_input Measured voltage. From READ_VOUT register. -in[1-12]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-12]_min Minimum Voltage. From VOUT_UV_WARN_LIMIT register. in[1-12]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. -in[1-12]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-12]_lcrit Critical minimum Voltage. VOUT_UV_FAULT_LIMIT register. in[1-12]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. in[1-12]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[1-12]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. @@ -82,7 +82,7 @@ in[1-12]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. curr[1-12]_label "iout[1-12]". curr[1-12]_input Measured current. From READ_IOUT register. curr[1-12]_max Maximum current. From IOUT_OC_WARN_LIMIT register. -curr[1-12]_lcrit Critical minumum output current. From IOUT_UC_FAULT_LIMIT +curr[1-12]_lcrit Critical minimum output current. From IOUT_UC_FAULT_LIMIT register. curr[1-12]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. curr[1-12]_max_alarm Current high alarm. From IOUT_OC_WARNING status. diff --git a/Documentation/hwmon/ucd9200 b/Documentation/hwmon/ucd9200 index 3c58607f72f..fd7d07b1908 100644 --- a/Documentation/hwmon/ucd9200 +++ b/Documentation/hwmon/ucd9200 @@ -54,9 +54,9 @@ attributes are read-only. in1_label "vin". in1_input Measured voltage. From READ_VIN register. -in1_min Minumum Voltage. From VIN_UV_WARN_LIMIT register. +in1_min Minimum Voltage. From VIN_UV_WARN_LIMIT register. in1_max Maximum voltage. From VIN_OV_WARN_LIMIT register. -in1_lcrit Critical minumum Voltage. VIN_UV_FAULT_LIMIT register. +in1_lcrit Critical minimum Voltage. VIN_UV_FAULT_LIMIT register. in1_crit Critical maximum voltage. From VIN_OV_FAULT_LIMIT register. in1_min_alarm Voltage low alarm. From VIN_UV_WARNING status. in1_max_alarm Voltage high alarm. From VIN_OV_WARNING status. @@ -65,9 +65,9 @@ in1_crit_alarm Voltage critical high alarm. From VIN_OV_FAULT status. in[2-5]_label "vout[1-4]". in[2-5]_input Measured voltage. From READ_VOUT register. -in[2-5]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[2-5]_min Minimum Voltage. From VOUT_UV_WARN_LIMIT register. in[2-5]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. -in[2-5]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[2-5]_lcrit Critical minimum Voltage. VOUT_UV_FAULT_LIMIT register. in[2-5]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. in[2-5]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[2-5]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. @@ -80,7 +80,7 @@ curr1_input Measured current. From READ_IIN register. curr[2-5]_label "iout[1-4]". curr[2-5]_input Measured current. From READ_IOUT register. curr[2-5]_max Maximum current. From IOUT_OC_WARN_LIMIT register. -curr[2-5]_lcrit Critical minumum output current. From IOUT_UC_FAULT_LIMIT +curr[2-5]_lcrit Critical minimum output current. From IOUT_UC_FAULT_LIMIT register. curr[2-5]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. curr[2-5]_max_alarm Current high alarm. From IOUT_OC_WARNING status. diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100 index 51f76a189fe..5865a2470d4 100644 --- a/Documentation/hwmon/zl6100 +++ b/Documentation/hwmon/zl6100 @@ -108,7 +108,7 @@ in1_label "vin" in1_input Measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. -in1_lcrit Critical minumum input voltage. +in1_lcrit Critical minimum input voltage. in1_crit Critical maximum input voltage. in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. @@ -117,7 +117,7 @@ in1_crit_alarm Input voltage critical high alarm. in2_label "vout1" in2_input Measured output voltage. -in2_lcrit Critical minumum output Voltage. +in2_lcrit Critical minimum output Voltage. in2_crit Critical maximum output voltage. in2_lcrit_alarm Critical output voltage critical low alarm. in2_crit_alarm Critical output voltage critical high alarm. -- cgit v1.2.3-70-g09d2 From 9908ad4cd4bc3e6620e1819e7f9b43f109650e1b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 31 Jan 2012 09:27:11 -0500 Subject: hwmon: (lm80) Add detection of NatSemi/TI LM96080 Add detection of the National Semiconductor (now Texas Instruments) LM96080. It is functionally compatible with the LM80 but detection is completely different. Signed-off-by: Jean Delvare Cc: Guenter Roeck Cc: Frans Meulenbroeks Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm80 | 9 ++++++++- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/lm80.c | 44 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 45 insertions(+), 12 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/lm80 b/Documentation/hwmon/lm80 index cb5b407ba3e..a60b43efc32 100644 --- a/Documentation/hwmon/lm80 +++ b/Documentation/hwmon/lm80 @@ -7,6 +7,11 @@ Supported chips: Addresses scanned: I2C 0x28 - 0x2f Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ + * National Semiconductor LM96080 + Prefix: 'lm96080' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ Authors: Frodo Looijaard , @@ -17,7 +22,9 @@ Description This driver implements support for the National Semiconductor LM80. It is described as a 'Serial Interface ACPI-Compatible Microprocessor -System Hardware Monitor'. +System Hardware Monitor'. The LM96080 is a more recent incarnation, +it is pin and register compatible, with a few additional features not +yet supported by the driver. The LM80 implements one temperature sensor, two fan rotation speed sensors, seven voltage sensors, alarms, and some miscellaneous stuff. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index dad895fec62..1cd0e201819 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -598,11 +598,11 @@ config SENSORS_LM78 will be called lm78. config SENSORS_LM80 - tristate "National Semiconductor LM80" + tristate "National Semiconductor LM80 and LM96080" depends on I2C help If you say yes here you get support for National Semiconductor - LM80 sensor chips. + LM80 and LM96080 sensor chips. This driver can also be built as a module. If so, the module will be called lm80. diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index a996f2795db..e2c43e1774b 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -60,6 +60,10 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, #define LM80_REG_FANDIV 0x05 #define LM80_REG_RES 0x06 +#define LM96080_REG_CONV_RATE 0x07 +#define LM96080_REG_MAN_ID 0x3e +#define LM96080_REG_DEV_ID 0x3f + /* * Conversions. Rounding and limit checking is only done on the TO_REG @@ -147,6 +151,7 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); static const struct i2c_device_id lm80_id[] = { { "lm80", 0 }, + { "lm96080", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, lm80_id); @@ -490,23 +495,44 @@ static const struct attribute_group lm80_group = { static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; - int i, cur; + int i, cur, man_id, dev_id; + const char *name = NULL; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) + /* First check for unused bits, common to both chip types */ + if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) + || (lm80_read_value(client, LM80_REG_CONFIG) & 0x80)) return -ENODEV; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(client, i); - if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) - || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) + + /* + * The LM96080 has manufacturer and stepping/die rev registers so we + * can just check that. The LM80 does not have such registers so we + * have to use a more expensive trick. + */ + man_id = lm80_read_value(client, LM96080_REG_MAN_ID); + dev_id = lm80_read_value(client, LM96080_REG_DEV_ID); + if (man_id == 0x01 && dev_id == 0x08) { + /* Check more unused bits for confirmation */ + if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe) return -ENODEV; + + name = "lm96080"; + } else { + /* Check 6-bit addressing */ + for (i = 0x2a; i <= 0x3d; i++) { + cur = i2c_smbus_read_byte_data(client, i); + if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) + || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) + || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) + return -ENODEV; + } + + name = "lm80"; } - strlcpy(info->type, "lm80", I2C_NAME_SIZE); + strlcpy(info->type, name, I2C_NAME_SIZE); return 0; } -- cgit v1.2.3-70-g09d2 From 56aad5d143cbce620c079e1acf761b71f59758a0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Feb 2012 08:13:31 -0800 Subject: hwmon: (max34440) Add support for 'lowest' output voltage attribute MAX34440 and compatibles support reporting the lowest measured output voltage. Add support for it. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- Documentation/hwmon/max34440 | 1 + drivers/hwmon/pmbus/max34440.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 index 8ab51536a1e..36b335c461d 100644 --- a/Documentation/hwmon/max34440 +++ b/Documentation/hwmon/max34440 @@ -56,6 +56,7 @@ in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. in[1-6]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. in[1-6]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. +in[1-6]_lowest Historical minimum voltage. in[1-6]_highest Historical maximum voltage. in[1-6]_reset_history Write any value to reset history. diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 7d830c1e703..95ee9e195cb 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -30,6 +30,7 @@ enum chips { max34440, max34441 }; #define MAX34440_MFR_VOUT_PEAK 0xd4 #define MAX34440_MFR_IOUT_PEAK 0xd5 #define MAX34440_MFR_TEMPERATURE_PEAK 0xd6 +#define MAX34440_MFR_VOUT_MIN 0xd7 #define MAX34440_STATUS_OC_WARN (1 << 0) #define MAX34440_STATUS_OC_FAULT (1 << 1) @@ -41,6 +42,10 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) int ret; switch (reg) { + case PMBUS_VIRT_READ_VOUT_MIN: + ret = pmbus_read_word_data(client, page, + MAX34440_MFR_VOUT_MIN); + break; case PMBUS_VIRT_READ_VOUT_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_VOUT_PEAK); @@ -72,6 +77,10 @@ static int max34440_write_word_data(struct i2c_client *client, int page, switch (reg) { case PMBUS_VIRT_RESET_VOUT_HISTORY: + ret = pmbus_write_word_data(client, page, + MAX34440_MFR_VOUT_MIN, 0x7fff); + if (ret) + break; ret = pmbus_write_word_data(client, page, MAX34440_MFR_VOUT_PEAK, 0); break; -- cgit v1.2.3-70-g09d2 From c5f35c9d8285f4a065cb0fc2c57f7526e646b30f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 28 Feb 2012 10:24:54 -0800 Subject: hwmon: (pmbus) Add support for TI TPS40400 and TPS40422 TPS40400 and TPS40422 are supported by the generic PMBus driver. Add device IDs and data sheet references. Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus | 6 ++++++ drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/pmbus.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index d28b591753d..c2b157ba900 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -22,6 +22,12 @@ Supported chips: http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf + * Texas Instruments TPS40400, TPS40422 + Prefixes: 'tps40400', 'tps40422' + Addresses scanned: - + Datasheets: + http://www.ti.com/lit/gpn/tps40400 + http://www.ti.com/lit/gpn/tps40422 * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index cfec923f42b..7968c815f44 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -20,7 +20,7 @@ config SENSORS_PMBUS help If you say yes here you get hardware monitoring support for generic PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - NCP4200, and NCP4208. + NCP4200, NCP4208, TPS40400, and TPS40422. This driver can also be built as a module. If so, the module will be called pmbus. diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 34887408505..7d5161dd04f 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -191,6 +191,8 @@ static const struct i2c_device_id pmbus_id[] = { {"pdt006", 1}, {"pdt012", 1}, {"pmbus", 0}, + {"tps40400", 1}, + {"tps40422", 2}, {"udt020", 1}, {} }; -- cgit v1.2.3-70-g09d2 From 216334094a875ed350079fb0b1b057ca17eb8b8e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 28 Feb 2012 11:00:54 -0800 Subject: hwmon: (pmbus) Add support for Lineage Power MDT040 MDT040 is supported by the generic PMBus driver. Add device ID and reference to datasheet. Also mention Lineage Power device support in Kconfig. Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus | 3 ++- drivers/hwmon/pmbus/Kconfig | 3 ++- drivers/hwmon/pmbus/pmbus.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index c2b157ba900..f90f99920cc 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -15,13 +15,14 @@ Supported chips: http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF * Lineage Power - Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020' + Prefixes: 'mdt040', 'pdt003', 'pdt006', 'pdt012', 'udt020' Addresses scanned: - Datasheets: http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf + http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf * Texas Instruments TPS40400, TPS40422 Prefixes: 'tps40400', 'tps40422' Addresses scanned: - diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 7968c815f44..d1aa2dbd5b7 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -20,7 +20,8 @@ config SENSORS_PMBUS help If you say yes here you get hardware monitoring support for generic PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - NCP4200, NCP4208, TPS40400, and TPS40422. + MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, TPS40400, + and TPS40422. This driver can also be built as a module. If so, the module will be called pmbus. diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 7d5161dd04f..7e91700131a 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -185,6 +185,7 @@ static const struct i2c_device_id pmbus_id[] = { {"adp4000", 1}, {"bmr453", 1}, {"bmr454", 1}, + {"mdt040", 1}, {"ncp4200", 1}, {"ncp4208", 1}, {"pdt003", 1}, -- cgit v1.2.3-70-g09d2 From 590defe59ef9596dcd892d2d8395d730c510323d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Feb 2012 03:40:22 -0800 Subject: hwmon: (max34440) Add support for MAX34446 Signed-off-by: Guenter Roeck --- Documentation/hwmon/max34440 | 29 ++++++++++- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/max34440.c | 112 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 138 insertions(+), 7 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 index 36b335c461d..bbdf9bf5d8f 100644 --- a/Documentation/hwmon/max34440 +++ b/Documentation/hwmon/max34440 @@ -11,6 +11,11 @@ Supported chips: Prefixes: 'max34441' Addresses scanned: - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf + * Maxim MAX34446 + PMBus Power-Supply Data Logger + Prefixes: 'max34446' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf Author: Guenter Roeck @@ -19,8 +24,8 @@ Description ----------- This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel -Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager -and Intelligent Fan Controller. +Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager +and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -33,6 +38,13 @@ This driver does not auto-detect devices. You will have to instantiate the devices explicitly. Please see Documentation/i2c/instantiating-devices for details. +For MAX34446, the value of the currX_crit attribute determines if current or +voltage measurement is enabled for a given channel. Voltage measurement is +enabled if currX_crit is set to 0; current measurement is enabled if the +attribute is set to a positive value. Power measurement is only enabled if +channel 1 (3) is configured for voltage measurement, and channel 2 (4) is +configured for current measurement. + Platform data support --------------------- @@ -60,16 +72,27 @@ in[1-6]_lowest Historical minimum voltage. in[1-6]_highest Historical maximum voltage. in[1-6]_reset_history Write any value to reset history. + MAX34446 only supports in[1-4]. + curr[1-6]_label "iout[1-6]". curr[1-6]_input Measured current. From READ_IOUT register. curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register. curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status. curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. +curr[1-4]_average Historical average current (MAX34446 only). curr[1-6]_highest Historical maximum current. curr[1-6]_reset_history Write any value to reset history. in6 and curr6 attributes only exist for MAX34440. + MAX34446 only supports curr[1-4]. + +power[1,3]_label "pout[1,3]" +power[1,3]_input Measured power. +power[1,3]_average Historical average power. +power[1,3]_highest Historical maximum power. + + Power attributes only exist for MAX34446. temp[1-8]_input Measured temperatures. From READ_TEMPERATURE_1 register. temp1 is the chip's internal temperature. temp2..temp5 @@ -80,7 +103,9 @@ temp[1-8]_max Maximum temperature. From OT_WARN_LIMIT register. temp[1-8]_crit Critical high temperature. From OT_FAULT_LIMIT register. temp[1-8]_max_alarm Temperature high alarm. temp[1-8]_crit_alarm Temperature critical high alarm. +temp[1-8]_average Historical average temperature (MAX34446 only). temp[1-8]_highest Historical maximum temperature. temp[1-8]_reset_history Write any value to reset history. temp7 and temp8 attributes only exist for MAX34440. + MAX34446 only supports temp[1-3]. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index d1aa2dbd5b7..1f0d0110b6b 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -68,11 +68,11 @@ config SENSORS_MAX16064 be called max16064. config SENSORS_MAX34440 - tristate "Maxim MAX34440/MAX34441" + tristate "Maxim MAX34440 and compatibles" default n help If you say yes here you get hardware monitoring support for Maxim - MAX34440 and MAX34441. + MAX34440, MAX34441, and MAX34446. This driver can also be built as a module. If so, the module will be called max34440. diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 95ee9e195cb..2ada7b021fb 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -25,21 +25,35 @@ #include #include "pmbus.h" -enum chips { max34440, max34441 }; +enum chips { max34440, max34441, max34446 }; #define MAX34440_MFR_VOUT_PEAK 0xd4 #define MAX34440_MFR_IOUT_PEAK 0xd5 #define MAX34440_MFR_TEMPERATURE_PEAK 0xd6 #define MAX34440_MFR_VOUT_MIN 0xd7 +#define MAX34446_MFR_POUT_PEAK 0xe0 +#define MAX34446_MFR_POUT_AVG 0xe1 +#define MAX34446_MFR_IOUT_AVG 0xe2 +#define MAX34446_MFR_TEMPERATURE_AVG 0xe3 + #define MAX34440_STATUS_OC_WARN (1 << 0) #define MAX34440_STATUS_OC_FAULT (1 << 1) #define MAX34440_STATUS_OT_FAULT (1 << 5) #define MAX34440_STATUS_OT_WARN (1 << 6) +struct max34440_data { + int id; + struct pmbus_driver_info info; +}; + +#define to_max34440_data(x) container_of(x, struct max34440_data, info) + static int max34440_read_word_data(struct i2c_client *client, int page, int reg) { int ret; + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct max34440_data *data = to_max34440_data(info); switch (reg) { case PMBUS_VIRT_READ_VOUT_MIN: @@ -50,14 +64,43 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, page, MAX34440_MFR_VOUT_PEAK); break; + case PMBUS_VIRT_READ_IOUT_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_IOUT_AVG); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_IOUT_PEAK); break; + case PMBUS_VIRT_READ_POUT_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_POUT_AVG); + break; + case PMBUS_VIRT_READ_POUT_MAX: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_POUT_PEAK); + break; + case PMBUS_VIRT_READ_TEMP_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_TEMPERATURE_AVG); + break; case PMBUS_VIRT_READ_TEMP_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_TEMPERATURE_PEAK); break; + case PMBUS_VIRT_RESET_POUT_HISTORY: + if (data->id != max34446) + return -ENXIO; + ret = 0; + break; case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_TEMP_HISTORY: @@ -73,9 +116,19 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) static int max34440_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct max34440_data *data = to_max34440_data(info); int ret; switch (reg) { + case PMBUS_VIRT_RESET_POUT_HISTORY: + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_POUT_PEAK, 0); + if (ret) + break; + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_POUT_AVG, 0); + break; case PMBUS_VIRT_RESET_VOUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34440_MFR_VOUT_MIN, 0x7fff); @@ -87,11 +140,18 @@ static int max34440_write_word_data(struct i2c_client *client, int page, case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34440_MFR_IOUT_PEAK, 0); + if (!ret && data->id == max34446) + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_IOUT_AVG, 0); + break; case PMBUS_VIRT_RESET_TEMP_HISTORY: ret = pmbus_write_word_data(client, page, MAX34440_MFR_TEMPERATURE_PEAK, 0x8000); + if (!ret && data->id == max34446) + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_TEMPERATURE_AVG, 0); break; default: ret = -ENODATA; @@ -225,20 +285,66 @@ static struct pmbus_driver_info max34440_info[] = { .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, + [max34446] = { + .pages = 7, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_VOLTAGE_IN] = 1, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 3, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 1, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = 3, + .m[PSC_POWER] = 1, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = 3, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 2, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .read_byte_data = max34440_read_byte_data, + .read_word_data = max34440_read_word_data, + .write_word_data = max34440_write_word_data, + }, }; static int max34440_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); + struct max34440_data *data; + + data = devm_kzalloc(&client->dev, sizeof(struct max34440_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + data->id = id->driver_data; + data->info = max34440_info[id->driver_data]; + + return pmbus_do_probe(client, id, &data->info); } static const struct i2c_device_id max34440_id[] = { {"max34440", max34440}, {"max34441", max34441}, + {"max34446", max34446}, {} }; - MODULE_DEVICE_TABLE(i2c, max34440_id); /* This is the driver that will be inserted */ -- cgit v1.2.3-70-g09d2 From 927112696654f4c96a85aa8a494866cbc6ccfbe6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Feb 2012 03:40:53 -0800 Subject: hwmon: (adm1275) Add support for ADM1075 Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1275 | 30 +++++++++++---- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/adm1275.c | 88 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 13 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index ab70d96d2df..535ad23ea70 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -2,6 +2,10 @@ Kernel driver adm1275 ===================== Supported chips: + * Analog Devices ADM1075 + Prefix: 'adm1075' + Addresses scanned: - + Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1075.pdf * Analog Devices ADM1275 Prefix: 'adm1275' Addresses scanned: - @@ -17,13 +21,13 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276 -Hot-Swap Controller and Digital Power Monitor. +This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, +and ADM1276 Hot-Swap Controller and Digital Power Monitor. -ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be -removed from or inserted into a live backplane. They also feature current and -voltage readback via an integrated 12-bit analog-to-digital converter (ADC), -accessed using a PMBus interface. +ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit +board to be removed from or inserted into a live backplane. They also feature +current and voltage readback via an integrated 12-bit analog-to-digital +converter (ADC), accessed using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -36,6 +40,10 @@ This driver does not auto-detect devices. You will have to instantiate the devices explicitly. Please see Documentation/i2c/instantiating-devices for details. +The ADM1075, unlike many other PMBus devices, does not support internal voltage +or current scaling. Reported voltages, currents, and power are raw measurements, +and will typically have to be scaled. + Platform data support --------------------- @@ -51,7 +59,8 @@ The following attributes are supported. Limits are read-write, history reset attributes are write-only, all other attributes are read-only. in1_label "vin1" or "vout1" depending on chip variant and - configuration. + configuration. On ADM1075, vout1 reports the voltage on + the VAUX pin. in1_input Measured voltage. in1_min Minumum Voltage. in1_max Maximum voltage. @@ -74,3 +83,10 @@ curr1_crit Critical maximum current. Depending on the chip curr1_crit_alarm Critical current high alarm. curr1_highest Historical maximum current. curr1_reset_history Write any value to reset history. + +power1_label "pin1" +power1_input Input power. +power1_reset_history Write any value to reset history. + + Power attributes are supported on ADM1075 and ADM1276 + only. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 1f0d0110b6b..9246d0154f7 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -31,8 +31,8 @@ config SENSORS_ADM1275 default n help If you say yes here you get hardware monitoring support for Analog - Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power - Monitor. + Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital + Power Monitors. This driver can also be built as a module. If so, the module will be called adm1275. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 5e4421e57eb..60aad9570f0 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -23,7 +23,7 @@ #include #include "pmbus.h" -enum chips { adm1275, adm1276 }; +enum chips { adm1075, adm1275, adm1276 }; #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 @@ -32,6 +32,9 @@ enum chips { adm1275, adm1276 }; #define ADM1275_VIN_VOUT_SELECT (1 << 6) #define ADM1275_VRANGE (1 << 5) +#define ADM1075_IRANGE_50 (1 << 4) +#define ADM1075_IRANGE_25 (1 << 3) +#define ADM1075_IRANGE_MASK ((1 << 3) | (1 << 4)) #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 @@ -42,6 +45,14 @@ enum chips { adm1275, adm1276 }; #define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) +#define ADM1075_READ_VAUX 0xdd +#define ADM1075_VAUX_OV_WARN_LIMIT 0xde +#define ADM1075_VAUX_UV_WARN_LIMIT 0xdf +#define ADM1075_VAUX_STATUS 0xf6 + +#define ADM1075_VAUX_OV_WARN (1<<7) +#define ADM1075_VAUX_UV_WARN (1<<6) + struct adm1275_data { int id; bool have_oc_fault; @@ -74,6 +85,29 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) } ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; + case PMBUS_VOUT_OV_WARN_LIMIT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, + ADM1075_VAUX_OV_WARN_LIMIT); + break; + case PMBUS_VOUT_UV_WARN_LIMIT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, + ADM1075_VAUX_UV_WARN_LIMIT); + break; + case PMBUS_READ_VOUT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); break; @@ -84,7 +118,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; case PMBUS_VIRT_READ_PIN_MAX: - if (data->id != adm1276) { + if (data->id == adm1275) { ret = -ENXIO; break; } @@ -95,7 +129,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_RESET_VIN_HISTORY: break; case PMBUS_VIRT_RESET_PIN_HISTORY: - if (data->id != adm1276) + if (data->id == adm1275) ret = -ENXIO; break; default: @@ -163,6 +197,19 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; } break; + case PMBUS_STATUS_VOUT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = 0; + mfr_status = pmbus_read_byte_data(client, 0, + ADM1075_VAUX_STATUS); + if (mfr_status & ADM1075_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1075_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; + break; default: ret = -ENODATA; break; @@ -171,6 +218,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) } static const struct i2c_device_id adm1275_id[] = { + { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, { } @@ -251,7 +299,14 @@ static int adm1275_probe(struct i2c_client *client, info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (config & ADM1275_VRANGE) { + if (data->id == adm1075) { + info->m[PSC_VOLTAGE_IN] = 27169; + info->b[PSC_VOLTAGE_IN] = 0; + info->R[PSC_VOLTAGE_IN] = -1; + info->m[PSC_VOLTAGE_OUT] = 27169; + info->b[PSC_VOLTAGE_OUT] = 0; + info->R[PSC_VOLTAGE_OUT] = -1; + } else if (config & ADM1275_VRANGE) { info->m[PSC_VOLTAGE_IN] = 19199; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -2; @@ -271,6 +326,31 @@ static int adm1275_probe(struct i2c_client *client, data->have_oc_fault = true; switch (data->id) { + case adm1075: + info->format[PSC_POWER] = direct; + info->b[PSC_POWER] = 0; + info->R[PSC_POWER] = -1; + switch (config & ADM1075_IRANGE_MASK) { + case ADM1075_IRANGE_25: + info->m[PSC_POWER] = 8549; + info->m[PSC_CURRENT_OUT] = 806; + break; + case ADM1075_IRANGE_50: + info->m[PSC_POWER] = 4279; + info->m[PSC_CURRENT_OUT] = 404; + break; + default: + dev_err(&client->dev, "Invalid input current range"); + info->m[PSC_POWER] = 0; + info->m[PSC_CURRENT_OUT] = 0; + break; + } + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT; + if (config & ADM1275_VIN_VOUT_SELECT) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + break; case adm1275: if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= -- cgit v1.2.3-70-g09d2 From 3360a106f8b4f87d3f3b0f1fd06c0c66fe45a87b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 28 Feb 2012 13:18:47 -0800 Subject: hwmon: (zl6100) Add support for ZL9101M and ZL9117M ZL9101M and ZL9117M are compatible to ZL6100. Add support to the zl6100 driver. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- Documentation/hwmon/zl6100 | 8 ++++++++ drivers/hwmon/pmbus/Kconfig | 6 +++--- drivers/hwmon/pmbus/zl6100.c | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100 index a4e8d90f59f..2028c0a10c5 100644 --- a/Documentation/hwmon/zl6100 +++ b/Documentation/hwmon/zl6100 @@ -34,6 +34,14 @@ Supported chips: Prefix: 'zl6105' Addresses scanned: - Datasheet: http://www.intersil.com/data/fn/fn6906.pdf + * Intersil / Zilker Labs ZL9101M + Prefix: 'zl9101' + Addresses scanned: - + Datasheet: http://www.intersil.com/data/fn/fn7669.pdf + * Intersil / Zilker Labs ZL9117M + Prefix: 'zl9117' + Addresses scanned: - + Datasheet: http://www.intersil.com/data/fn/fn7914.pdf * Ericsson BMR450, BMR451 Prefix: 'bmr450', 'bmr451' Addresses scanned: - diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 9246d0154f7..2ca6a5a4f5a 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -114,9 +114,9 @@ config SENSORS_ZL6100 default n help If you say yes here you get hardware monitoring support for Intersil - ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 - Digital DC/DC Controllers, as well as for Ericsson BMR450, BMR451, - BMR462, BMR463, and BMR464. + ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105, + ZL9101M, and ZL9117M Digital DC/DC Controllers, as well as for + Ericsson BMR450, BMR451, BMR462, BMR463, and BMR464. This driver can also be built as a module. If so, the module will be called zl6100. diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index e5bb7355d48..fc5eed8e85b 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -28,7 +28,8 @@ #include #include "pmbus.h" -enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 }; +enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105, + zl9101, zl9117 }; struct zl6100_data { int id; @@ -152,6 +153,8 @@ static const struct i2c_device_id zl6100_id[] = { {"zl2106", zl2106}, {"zl6100", zl6100}, {"zl6105", zl6105}, + {"zl9101", zl9101}, + {"zl9117", zl9117}, { } }; MODULE_DEVICE_TABLE(i2c, zl6100_id); -- cgit v1.2.3-70-g09d2 From 86dda176344314526c7b65f1adce937b09d04f6d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 8 Mar 2012 08:20:24 -0800 Subject: hwmon: (jc42) Remove unnecessary device IDs We don't really use or need separate device IDs for the various JC42.4 compliant chips, so remove them and just stick with jc42. Also update a datasheet references for SE98A, STTS424, and STTS424E02. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- Documentation/hwmon/jc42 | 39 +++++++++------------------------------ drivers/hwmon/jc42.c | 18 ------------------ 2 files changed, 9 insertions(+), 48 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42 index 52729a756c1..66ecb9fc824 100644 --- a/Documentation/hwmon/jc42 +++ b/Documentation/hwmon/jc42 @@ -3,71 +3,50 @@ Kernel driver jc42 Supported chips: * Analog Devices ADT7408 - Prefix: 'adt7408' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf * Atmel AT30TS00 - Prefix: 'at30ts00' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.atmel.com/Images/doc8585.pdf * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2 - Prefix: 'tse2002', 'ts3000' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf * Maxim MAX6604 - Prefix: 'max6604' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843 - Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf - * NXP Semiconductors SE97, SE97B - Prefix: 'se97' - Addresses scanned: I2C 0x18 - 0x1f + * NXP Semiconductors SE97, SE97B, SE98, SE98A Datasheets: http://www.nxp.com/documents/data_sheet/SE97.pdf http://www.nxp.com/documents/data_sheet/SE97B.pdf - * NXP Semiconductors SE98 - Prefix: 'se98' - Addresses scanned: I2C 0x18 - 0x1f - Datasheets: http://www.nxp.com/documents/data_sheet/SE98.pdf + http://www.nxp.com/documents/data_sheet/SE98A.pdf * ON Semiconductor CAT34TS02, CAT6095 - Prefix: 'cat34ts02', 'cat6095' - Addresses scanned: I2C 0x18 - 0x1f Datasheet: http://www.onsemi.com/pub_link/Collateral/CAT34TS02-D.PDF http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF - * ST Microelectronics STTS424, STTS424E02 - Prefix: 'stts424' - Addresses scanned: I2C 0x18 - 0x1f - Datasheets: - http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf - http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf - * ST Microelectronics STTS2002, STTS3000 - Prefix: 'stts2002', 'stts3000' - Addresses scanned: I2C 0x18 - 0x1f + * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS3000 Datasheets: + http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157556.pdf + http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157558.pdf http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf * JEDEC JC 42.4 compliant temperature sensor chips - Prefix: 'jc42' - Addresses scanned: I2C 0x18 - 0x1f Datasheet: http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf + Common for all chips: + Prefix: 'jc42' + Addresses scanned: I2C 0x18 - 0x1f + Author: Guenter Roeck diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index a002bdac470..a9bfd6736d9 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -180,25 +180,7 @@ static int jc42_remove(struct i2c_client *client); static struct jc42_data *jc42_update_device(struct device *dev); static const struct i2c_device_id jc42_id[] = { - { "adt7408", 0 }, - { "at30ts00", 0 }, - { "cat94ts02", 0 }, - { "cat6095", 0 }, { "jc42", 0 }, - { "max6604", 0 }, - { "mcp9804", 0 }, - { "mcp9805", 0 }, - { "mcp98242", 0 }, - { "mcp98243", 0 }, - { "mcp9843", 0 }, - { "se97", 0 }, - { "se97b", 0 }, - { "se98", 0 }, - { "stts424", 0 }, - { "stts2002", 0 }, - { "stts3000", 0 }, - { "tse2002", 0 }, - { "ts3000", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, jc42_id); -- cgit v1.2.3-70-g09d2 From 312869ec935ab3bb67b7ba641a7d11230555aff5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 18 Mar 2012 13:05:08 +0100 Subject: hwmon: (sch56xx) Add support for the integrated watchdog (v2) Add support for the watchdog integrated into the SMSC SCH5627 and SCH5636 superio-s. Since the watchdog is part of the hwmon logical device and thus shares ioports with it, the watchdog driver is integrated into the existing hwmon drivers for these. Note that this version of the watchdog support for sch56xx superio-s implements the watchdog chardev interface itself, rather then relying on the recently added watchdog core / watchdog_dev. This is done because currently some needed functionality is missing from watchdog_dev, as soon as this functionality is added (which is being discussed on the linux-watchdog mailinglist), I'll convert this driver over to using watchdog_dev. Signed-off-by: Hans de Goede [guenter.roeck@ericsson.com: Added missing linux/slab.h include] Signed-off-by: Guenter Roeck --- Documentation/hwmon/sch5627 | 5 + Documentation/hwmon/sch5636 | 3 + drivers/hwmon/Kconfig | 6 +- drivers/hwmon/sch5627.c | 11 +- drivers/hwmon/sch5636.c | 11 +- drivers/hwmon/sch56xx-common.c | 519 ++++++++++++++++++++++++++++++++++++++++- drivers/hwmon/sch56xx-common.h | 10 +- 7 files changed, 558 insertions(+), 7 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/sch5627 b/Documentation/hwmon/sch5627 index 446a054e491..0551d266c51 100644 --- a/Documentation/hwmon/sch5627 +++ b/Documentation/hwmon/sch5627 @@ -16,6 +16,11 @@ Description SMSC SCH5627 Super I/O chips include complete hardware monitoring capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures. +The SMSC SCH5627 hardware monitoring part also contains an integrated +watchdog. In order for this watchdog to function some motherboard specific +initialization most be done by the BIOS, so if the watchdog is not enabled +by the BIOS the sch5627 driver will not register a watchdog device. + The hardware monitoring part of the SMSC SCH5627 is accessed by talking through an embedded microcontroller. An application note describing the protocol for communicating with the microcontroller is available upon diff --git a/Documentation/hwmon/sch5636 b/Documentation/hwmon/sch5636 index f83bd1c260f..7b0a01da071 100644 --- a/Documentation/hwmon/sch5636 +++ b/Documentation/hwmon/sch5636 @@ -26,6 +26,9 @@ temperatures. Note that the driver detects how many fan headers / temperature sensors are actually implemented on the motherboard, so you will likely see fewer temperature and fan inputs. +The Fujitsu Theseus hwmon solution also contains an integrated watchdog. +This watchdog is fully supported by the sch5636 driver. + An application note describing the Theseus' registers, as well as an application note describing the protocol for communicating with the microcontroller is available upon request. Please mail me if you want a copy. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 1cd0e201819..811e6c47e7e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1028,7 +1028,8 @@ config SENSORS_SCH5627 select SENSORS_SCH56XX_COMMON help If you say yes here you get support for the hardware monitoring - features of the SMSC SCH5627 Super-I/O chip. + features of the SMSC SCH5627 Super-I/O chip including support for + the integrated watchdog. This driver can also be built as a module. If so, the module will be called sch5627. @@ -1044,7 +1045,8 @@ config SENSORS_SCH5636 Currently this driver only supports the Fujitsu Theseus SCH5636 based hwmon solution. Say yes here if you want support for the Fujitsu - Theseus' hardware monitoring features. + Theseus' hardware monitoring features including support for the + integrated watchdog. This driver can also be built as a module. If so, the module will be called sch5636. diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 79b6dabe316..8ec6dfbccb6 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede * + * Copyright (C) 2010-2012 Hans de Goede * * * * 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 * @@ -79,6 +79,7 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { struct sch5627_data { unsigned short addr; struct device *hwmon_dev; + struct sch56xx_watchdog_data *watchdog; u8 control; u8 temp_max[SCH5627_NO_TEMPS]; u8 temp_crit[SCH5627_NO_TEMPS]; @@ -453,6 +454,9 @@ static int sch5627_remove(struct platform_device *pdev) { struct sch5627_data *data = platform_get_drvdata(pdev); + if (data->watchdog) + sch56xx_watchdog_unregister(data->watchdog); + if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); @@ -574,6 +578,11 @@ static int __devinit sch5627_probe(struct platform_device *pdev) goto error; } + /* Note failing to register the watchdog is not a fatal error */ + data->watchdog = sch56xx_watchdog_register(data->addr, + (build_code << 24) | (build_id << 8) | hwmon_rev, + &data->update_lock, 1); + return 0; error: diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 9d5236fb09b..906d4ed32d8 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011 Hans de Goede * + * Copyright (C) 2011-2012 Hans de Goede * * * * 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 * @@ -67,6 +67,7 @@ static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = { struct sch5636_data { unsigned short addr; struct device *hwmon_dev; + struct sch56xx_watchdog_data *watchdog; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -384,6 +385,9 @@ static int sch5636_remove(struct platform_device *pdev) struct sch5636_data *data = platform_get_drvdata(pdev); int i; + if (data->watchdog) + sch56xx_watchdog_unregister(data->watchdog); + if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); @@ -505,6 +509,11 @@ static int __devinit sch5636_probe(struct platform_device *pdev) goto error; } + /* Note failing to register the watchdog is not a fatal error */ + data->watchdog = sch56xx_watchdog_register(data->addr, + (revision[0] << 8) | revision[1], + &data->update_lock, 0); + return 0; error: diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index fac32ee0b10..ce52fc57d41 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede * + * Copyright (C) 2010-2012 Hans de Goede * * * * 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 * @@ -26,8 +26,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "sch56xx-common.h" +/* Insmod parameters */ +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) ")"); + #define SIO_SCH56XX_LD_EM 0x0C /* Embedded uController Logical Dev */ #define SIO_UNLOCK_KEY 0x55 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ @@ -40,13 +52,45 @@ #define SIO_SCH5627_ID 0xC6 /* Chipset ID */ #define SIO_SCH5636_ID 0xC7 /* Chipset ID */ -#define REGION_LENGTH 9 +#define REGION_LENGTH 10 #define SCH56XX_CMD_READ 0x02 #define SCH56XX_CMD_WRITE 0x03 +/* Watchdog registers */ +#define SCH56XX_REG_WDOG_PRESET 0x58B +#define SCH56XX_REG_WDOG_CONTROL 0x58C +#define SCH56XX_WDOG_TIME_BASE_SEC 0x01 +#define SCH56XX_REG_WDOG_OUTPUT_ENABLE 0x58E +#define SCH56XX_WDOG_OUTPUT_ENABLE 0x02 + +struct sch56xx_watchdog_data { + u16 addr; + u32 revision; + struct mutex *io_lock; + struct mutex watchdog_lock; + struct list_head list; /* member of the watchdog_data_list */ + struct kref kref; + struct miscdevice watchdog_miscdev; + unsigned long watchdog_is_open; + char watchdog_name[10]; /* must be unique to avoid sysfs conflict */ + char watchdog_expect_close; + u8 watchdog_preset; + u8 watchdog_control; + u8 watchdog_output_enable; +}; + static struct platform_device *sch56xx_pdev; +/* + * Somewhat ugly :( global data pointer list with all sch56xx devices, so that + * we can find our device data as when using misc_register there is no other + * method to get to ones device data from the open fop. + */ +static LIST_HEAD(watchdog_data_list); +/* Note this lock not only protect list access, but also data.kref access */ +static DEFINE_MUTEX(watchdog_data_mutex); + /* Super I/O functions */ static inline int superio_inb(int base, int reg) { @@ -224,6 +268,477 @@ int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, } EXPORT_SYMBOL(sch56xx_read_virtual_reg12); +/* + * Watchdog routines + */ + +/* + * Release our data struct when the platform device has been released *and* + * all references to our watchdog device are released. + */ +static void sch56xx_watchdog_release_resources(struct kref *r) +{ + struct sch56xx_watchdog_data *data = + container_of(r, struct sch56xx_watchdog_data, kref); + kfree(data); +} + +static int watchdog_set_timeout(struct sch56xx_watchdog_data *data, + int timeout) +{ + int ret, resolution; + u8 control; + + /* 1 second or 60 second resolution? */ + if (timeout <= 255) + resolution = 1; + else + resolution = 60; + + if (timeout < resolution || timeout > (resolution * 255)) + return -EINVAL; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + + if (resolution == 1) + control = data->watchdog_control | SCH56XX_WDOG_TIME_BASE_SEC; + else + control = data->watchdog_control & ~SCH56XX_WDOG_TIME_BASE_SEC; + + if (data->watchdog_control != control) { + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_CONTROL, + control); + mutex_unlock(data->io_lock); + if (ret) + goto leave; + + data->watchdog_control = control; + } + + /* + * Remember new timeout value, but do not write as that (re)starts + * the watchdog countdown. + */ + data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); + + ret = data->watchdog_preset * resolution; +leave: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_get_timeout(struct sch56xx_watchdog_data *data) +{ + int timeout; + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_control & SCH56XX_WDOG_TIME_BASE_SEC) + timeout = data->watchdog_preset; + else + timeout = data->watchdog_preset * 60; + mutex_unlock(&data->watchdog_lock); + + return timeout; +} + +static int watchdog_start(struct sch56xx_watchdog_data *data) +{ + int ret; + u8 val; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave_unlock_watchdog; + } + + /* + * The sch56xx's watchdog cannot really be started / stopped + * it is always running, but we can avoid the timer expiring + * from causing a system reset by clearing the output enable bit. + * + * The sch56xx's watchdog will set the watchdog event bit, bit 0 + * of the second interrupt source register (at base-address + 9), + * when the timer expires. + * + * This will only cause a system reset if the 0-1 flank happens when + * output enable is true. Setting output enable after the flank will + * not cause a reset, nor will the timer expiring a second time. + * This means we must clear the watchdog event bit in case it is set. + * + * The timer may still be running (after a recent watchdog_stop) and + * mere milliseconds away from expiring, so the timer must be reset + * first! + */ + + mutex_lock(data->io_lock); + + /* 1. Reset the watchdog countdown counter */ + ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET, + data->watchdog_preset); + if (ret) + goto leave; + + /* 2. Enable output (if not already enabled) */ + if (!(data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) { + val = data->watchdog_output_enable | + SCH56XX_WDOG_OUTPUT_ENABLE; + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + if (ret) + goto leave; + + data->watchdog_output_enable = val; + } + + /* 3. Clear the watchdog event bit if set */ + val = inb(data->addr + 9); + if (val & 0x01) + outb(0x01, data->addr + 9); + +leave: + mutex_unlock(data->io_lock); +leave_unlock_watchdog: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_trigger(struct sch56xx_watchdog_data *data) +{ + int ret; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + + /* Reset the watchdog countdown counter */ + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET, + data->watchdog_preset); + mutex_unlock(data->io_lock); +leave: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_stop_unlocked(struct sch56xx_watchdog_data *data) +{ + int ret = 0; + u8 val; + + if (!data->addr) + return -ENODEV; + + if (data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) { + val = data->watchdog_output_enable & + ~SCH56XX_WDOG_OUTPUT_ENABLE; + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + mutex_unlock(data->io_lock); + if (ret) + return ret; + + data->watchdog_output_enable = val; + } + + return ret; +} + +static int watchdog_stop(struct sch56xx_watchdog_data *data) +{ + int ret; + + mutex_lock(&data->watchdog_lock); + ret = watchdog_stop_unlocked(data); + mutex_unlock(&data->watchdog_lock); + + return ret; +} + +static int watchdog_release(struct inode *inode, struct file *filp) +{ + struct sch56xx_watchdog_data *data = filp->private_data; + + if (data->watchdog_expect_close) { + watchdog_stop(data); + data->watchdog_expect_close = 0; + } else { + watchdog_trigger(data); + pr_crit("unexpected close, not stopping watchdog!\n"); + } + + clear_bit(0, &data->watchdog_is_open); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); + + return 0; +} + +static int watchdog_open(struct inode *inode, struct file *filp) +{ + struct sch56xx_watchdog_data *pos, *data = NULL; + int ret, watchdog_is_open; + + /* + * We get called from drivers/char/misc.c with misc_mtx hold, and we + * call misc_register() from sch56xx_watchdog_probe() with + * watchdog_data_mutex hold, as misc_register() takes the misc_mtx + * lock, this is a possible deadlock, so we use mutex_trylock here. + */ + if (!mutex_trylock(&watchdog_data_mutex)) + return -ERESTARTSYS; + list_for_each_entry(pos, &watchdog_data_list, list) { + if (pos->watchdog_miscdev.minor == iminor(inode)) { + data = pos; + break; + } + } + /* Note we can never not have found data, so we don't check for this */ + watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); + if (!watchdog_is_open) + kref_get(&data->kref); + mutex_unlock(&watchdog_data_mutex); + + if (watchdog_is_open) + return -EBUSY; + + filp->private_data = data; + + /* Start the watchdog */ + ret = watchdog_start(data); + if (ret) { + watchdog_release(inode, filp); + return ret; + } + + return nonseekable_open(inode, filp); +} + +static ssize_t watchdog_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + struct sch56xx_watchdog_data *data = filp->private_data; + + if (count) { + if (!nowayout) { + size_t i; + + /* Clear it in case it was set with a previous write */ + data->watchdog_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + data->watchdog_expect_close = 1; + } + } + ret = watchdog_trigger(data); + if (ret) + return ret; + } + return count; +} + +static long watchdog_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .identity = "sch56xx watchdog" + }; + int i, ret = 0; + struct sch56xx_watchdog_data *data = filp->private_data; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ident.firmware_version = data->revision; + if (!nowayout) + ident.options |= WDIOF_MAGICCLOSE; + if (copy_to_user((void __user *)arg, &ident, sizeof(ident))) + ret = -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int __user *)arg); + break; + + case WDIOC_KEEPALIVE: + ret = watchdog_trigger(data); + break; + + case WDIOC_GETTIMEOUT: + i = watchdog_get_timeout(data); + ret = put_user(i, (int __user *)arg); + break; + + case WDIOC_SETTIMEOUT: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + ret = watchdog_set_timeout(data, i); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + + case WDIOC_SETOPTIONS: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + + if (i & WDIOS_DISABLECARD) + ret = watchdog_stop(data); + else if (i & WDIOS_ENABLECARD) + ret = watchdog_trigger(data); + else + ret = -EINVAL; + break; + + default: + ret = -ENOTTY; + } + return ret; +} + +static const struct file_operations watchdog_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = watchdog_open, + .release = watchdog_release, + .write = watchdog_write, + .unlocked_ioctl = watchdog_ioctl, +}; + +struct sch56xx_watchdog_data *sch56xx_watchdog_register( + u16 addr, u32 revision, struct mutex *io_lock, int check_enabled) +{ + struct sch56xx_watchdog_data *data; + int i, err, control, output_enable; + const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; + + /* Cache the watchdog registers */ + mutex_lock(io_lock); + control = + sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_CONTROL); + output_enable = + sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_OUTPUT_ENABLE); + mutex_unlock(io_lock); + + if (control < 0) + return NULL; + if (output_enable < 0) + return NULL; + if (check_enabled && !(output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) { + pr_warn("Watchdog not enabled by BIOS, not registering\n"); + return NULL; + } + + data = kzalloc(sizeof(struct sch56xx_watchdog_data), GFP_KERNEL); + if (!data) + return NULL; + + data->addr = addr; + data->revision = revision; + data->io_lock = io_lock; + data->watchdog_control = control; + data->watchdog_output_enable = output_enable; + mutex_init(&data->watchdog_lock); + INIT_LIST_HEAD(&data->list); + kref_init(&data->kref); + + err = watchdog_set_timeout(data, 60); + if (err < 0) + goto error; + + /* + * We take the data_mutex lock early so that watchdog_open() cannot + * run when misc_register() has completed, but we've not yet added + * our data to the watchdog_data_list. + */ + mutex_lock(&watchdog_data_mutex); + for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { + /* Register our watchdog part */ + snprintf(data->watchdog_name, sizeof(data->watchdog_name), + "watchdog%c", (i == 0) ? '\0' : ('0' + i)); + data->watchdog_miscdev.name = data->watchdog_name; + data->watchdog_miscdev.fops = &watchdog_fops; + data->watchdog_miscdev.minor = watchdog_minors[i]; + err = misc_register(&data->watchdog_miscdev); + if (err == -EBUSY) + continue; + if (err) + break; + + list_add(&data->list, &watchdog_data_list); + pr_info("Registered /dev/%s chardev major 10, minor: %d\n", + data->watchdog_name, watchdog_minors[i]); + break; + } + mutex_unlock(&watchdog_data_mutex); + + if (err) { + pr_err("Registering watchdog chardev: %d\n", err); + goto error; + } + if (i == ARRAY_SIZE(watchdog_minors)) { + pr_warn("Couldn't register watchdog (no free minor)\n"); + goto error; + } + + return data; + +error: + kfree(data); + return NULL; +} +EXPORT_SYMBOL(sch56xx_watchdog_register); + +void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data) +{ + mutex_lock(&watchdog_data_mutex); + misc_deregister(&data->watchdog_miscdev); + list_del(&data->list); + mutex_unlock(&watchdog_data_mutex); + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_is_open) { + pr_warn("platform device unregistered with watchdog " + "open! Stopping watchdog.\n"); + watchdog_stop_unlocked(data); + } + /* Tell the wdog start/stop/trigger functions our dev is gone */ + data->addr = 0; + data->io_lock = NULL; + mutex_unlock(&data->watchdog_lock); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); +} +EXPORT_SYMBOL(sch56xx_watchdog_unregister); + +/* + * platform dev find, add and remove functions + */ + static int __init sch56xx_find(int sioaddr, unsigned short *address, const char **name) { diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h index d5eaf3b9ebf..7475086eb97 100644 --- a/drivers/hwmon/sch56xx-common.h +++ b/drivers/hwmon/sch56xx-common.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede * + * Copyright (C) 2010-2012 Hans de Goede * * * * 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 * @@ -17,8 +17,16 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include + +struct sch56xx_watchdog_data; + int sch56xx_read_virtual_reg(u16 addr, u16 reg); int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val); int sch56xx_read_virtual_reg16(u16 addr, u16 reg); int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, int high_nibble); + +struct sch56xx_watchdog_data *sch56xx_watchdog_register( + u16 addr, u32 revision, struct mutex *io_lock, int check_enabled); +void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data); -- cgit v1.2.3-70-g09d2 From ae544f64cc7b0850471f62e6808068ef77b90763 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 23 Mar 2012 10:02:18 +0100 Subject: hwmon: (lm90) Add support for GMT G781 GMT G781 is a ADM1032-compatible temperature sensor chip. Add support to the LM90 driver. Cc: Mike Gorchak Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare --- Documentation/hwmon/lm90 | 4 ++++ drivers/hwmon/Kconfig | 3 ++- drivers/hwmon/lm90.c | 19 ++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 9cd14cfe651..b466974e142 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -118,6 +118,10 @@ Supported chips: Addresses scanned: I2C 0x48 through 0x4F Datasheet: Publicly available at NXP website http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf + * GMT G781 + Prefix: 'g781' + Addresses scanned: I2C 0x4c, 0x4d + Datasheet: Not publicly available from GMT Author: Jean Delvare diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 783a3144ffd..fc3f4e1cad2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -648,7 +648,8 @@ config SENSORS_LM90 LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, - Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips. + Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781 + sensor chips. This driver can also be built as a module. If so, the module will be called lm90. diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 22efae34c2f..3309a511e8e 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -57,6 +57,9 @@ * This driver also supports the SA56004 from Philips. This device is * pin-compatible with the LM86, the ED/EDP parts are also address-compatible. * + * This driver also supports the G781 from GMT. This device is compatible + * with the ADM1032. + * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and * concern all supported chipsets, unless mentioned otherwise. @@ -107,7 +110,7 @@ static const unsigned short normal_i2c[] = { 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, - max6646, w83l771, max6696, sa56004 }; + max6646, w83l771, max6696, sa56004, g781 }; /* * The LM90 registers @@ -184,6 +187,7 @@ static const struct i2c_device_id lm90_id[] = { { "adm1032", adm1032 }, { "adt7461", adt7461 }, { "adt7461a", adt7461 }, + { "g781", g781 }, { "lm90", lm90 }, { "lm86", lm86 }, { "lm89", lm86 }, @@ -229,6 +233,12 @@ static const struct lm90_params lm90_params[] = { .alert_alarms = 0x7c, .max_convrate = 10, }, + [g781] = { + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT + | LM90_HAVE_BROKEN_ALERT, + .alert_alarms = 0x7c, + .max_convrate = 8, + }, [lm86] = { .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, .alert_alarms = 0x7b, @@ -1289,6 +1299,13 @@ static int lm90_detect(struct i2c_client *client, && convrate <= 0x09) { name = "sa56004"; } + } else + if ((address == 0x4C || address == 0x4D) + && man_id == 0x47) { /* GMT */ + if (chip_id == 0x01 /* G781 */ + && (config1 & 0x3F) == 0x00 + && convrate <= 0x08) + name = "g781"; } if (!name) { /* identification failed */ -- cgit v1.2.3-70-g09d2 From 0c2732152a5813a870d0b96f0844f4dfe1436519 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-Koenig Date: Fri, 23 Mar 2012 10:02:19 +0100 Subject: hwmon: (mc13783-adc) Add support for the MC13892 PMIC Based on a patch by David Jander that mostly did s/mc13783/mc13xxx/ . Additionally use dev_get_drvdata instead of to_platform_device + platform_get_drvdata in mc13783_adc_read (spotted by Jean Delvare). Cc: David Jander Signed-off-by: Uwe Kleine-Koenig Signed-off-by: Jean Delvare --- Documentation/hwmon/mc13783-adc | 50 ++++++++++++++------ drivers/hwmon/Kconfig | 6 +-- drivers/hwmon/mc13783-adc.c | 101 ++++++++++++++++++++++++++++++---------- 3 files changed, 117 insertions(+), 40 deletions(-) (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/mc13783-adc b/Documentation/hwmon/mc13783-adc index 044531a8640..d0e7b3fa9e7 100644 --- a/Documentation/hwmon/mc13783-adc +++ b/Documentation/hwmon/mc13783-adc @@ -3,8 +3,11 @@ Kernel driver mc13783-adc Supported chips: * Freescale Atlas MC13783 - Prefix: 'mc13783_adc' + Prefix: 'mc13783' Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1 + * Freescale Atlas MC13892 + Prefix: 'mc13892' + Datasheet: http://cache.freescale.com/files/analog/doc/data_sheet/MC13892.pdf?fsrch=1&sr=1 Authors: Sascha Hauer @@ -13,20 +16,21 @@ Authors: Description ----------- -The Freescale MC13783 is a Power Management and Audio Circuit. Among -other things it contains a 10-bit A/D converter. The converter has 16 -channels which can be used in different modes. -The A/D converter has a resolution of 2.25mV. Channels 0-4 have -a dedicated meaning with chip internal scaling applied. Channels 5-7 -can be used as general purpose inputs or alternatively in a dedicated -mode. Channels 12-15 are occupied by the touchscreen if it's active. +The Freescale MC13783 and MC13892 are Power Management and Audio Circuits. +Among other things they contain a 10-bit A/D converter. The converter has 16 +(MC13783) resp. 12 (MC13892) channels which can be used in different modes. The +A/D converter has a resolution of 2.25mV. -Currently the driver only supports channels 2 and 5-15 with no alternative -modes for channels 5-7. +Some channels can be used as General Purpose inputs or in a dedicated mode with +a chip internal scaling applied . -See this table for the meaning of the different channels and their chip -internal scaling: +Currently the driver only supports the Application Supply channel (BP / BPSNS), +the General Purpose inputs and touchscreen. +See the following tables for the meaning of the different channels and their +chip internal scaling: + +MC13783: Channel Signal Input Range Scaling ------------------------------------------------------------------------------- 0 Battery Voltage (BATT) 2.50 - 4.65V -2.40V @@ -34,7 +38,7 @@ Channel Signal Input Range Scaling 2 Application Supply (BP) 2.50 - 4.65V -2.40V 3 Charger Voltage (CHRGRAW) 0 - 10V / /5 0 - 20V /10 -4 Charger Current (CHRGISNSP-CHRGISNSN) -0.25V - 0.25V x4 +4 Charger Current (CHRGISNSP-CHRGISNSN) -0.25 - 0.25V x4 5 General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.30V No 6 General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.30V / No / 1.50 - 3.50V -1.20V @@ -48,3 +52,23 @@ Channel Signal Input Range Scaling 13 General Purpose TSX2 / Touchscreen X-plate 2 0 - 2.30V No 14 General Purpose TSY1 / Touchscreen Y-plate 1 0 - 2.30V No 15 General Purpose TSY2 / Touchscreen Y-plate 2 0 - 2.30V No + +MC13892: +Channel Signal Input Range Scaling +------------------------------------------------------------------------------- +0 Battery Voltage (BATT) 0 - 4.8V /2 +1 Battery Current (BATT - BATTISNSCC) -60 - 60 mV x20 +2 Application Supply (BPSNS) 0 - 4.8V /2 +3 Charger Voltage (CHRGRAW) 0 - 12V / /5 + 0 - 20V /10 +4 Charger Current (CHRGISNS-BPSNS) / -0.3 - 0.3V / x4 / + Touchscreen X-plate 1 0 - 2.4V No +5 General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.4V No +6 General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.4V / No + Backup Voltage (LICELL) 0 - 3.6V x2/3 +7 General Purpose ADIN7 / UID / Die Temperature 0 - 2.4V / No / + 0 - 4.8V /2 +12 General Purpose TSX1 / Touchscreen X-plate 1 0 - 2.4V No +13 General Purpose TSX2 / Touchscreen X-plate 2 0 - 2.4V No +14 General Purpose TSY1 / Touchscreen Y-plate 1 0 - 2.4V No +15 General Purpose TSY2 / Touchscreen Y-plate 2 0 - 2.4V No diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index fc3f4e1cad2..7190a3f4a82 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1360,10 +1360,10 @@ config SENSORS_APPLESMC the awesome power of applesmc. config SENSORS_MC13783_ADC - tristate "Freescale MC13783 ADC" - depends on MFD_MC13783 + tristate "Freescale MC13783/MC13892 ADC" + depends on MFD_MC13XXX help - Support for the A/D converter on MC13783 PMIC. + Support for the A/D converter on MC13783 and MC13892 PMIC. if ACPI diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 04d13b31aac..6c6b240a782 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -1,5 +1,5 @@ /* - * Driver for the Freescale Semiconductor MC13783 adc. + * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs. * * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2009 Sascha Hauer, Pengutronix @@ -18,7 +18,7 @@ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include #include #include #include @@ -28,24 +28,30 @@ #include #include -#define MC13783_ADC_NAME "mc13783-adc" +#define DRIVER_NAME "mc13783-adc" + +/* platform device id driver data */ +#define MC13783_ADC_16CHANS 1 +#define MC13783_ADC_BPDIV2 2 struct mc13783_adc_priv { struct mc13xxx *mc13xxx; struct device *hwmon_dev; + char name[10]; }; static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute *devattr, char *buf) { - return sprintf(buf, "mc13783_adc\n"); + struct mc13783_adc_priv *priv = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", priv->name); } static int mc13783_adc_read(struct device *dev, struct device_attribute *devattr, unsigned int *val) { - struct platform_device *pdev = to_platform_device(dev); - struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); + struct mc13783_adc_priv *priv = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); unsigned int channel = attr->index; unsigned int sample[4]; @@ -68,16 +74,21 @@ static ssize_t mc13783_adc_read_bp(struct device *dev, struct device_attribute *devattr, char *buf) { unsigned val; + struct platform_device *pdev = to_platform_device(dev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; int ret = mc13783_adc_read(dev, devattr, &val); if (ret) return ret; - /* - * BP (channel 2) reports with offset 2.4V to the actual value to fit - * the input range of the ADC. unit = 2.25mV = 9/4 mV. - */ - val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400; + if (driver_data & MC13783_ADC_BPDIV2) + val = DIV_ROUND_CLOSEST(val * 9, 2); + else + /* + * BP (channel 2) reports with offset 2.4V to the actual value + * to fit the input range of the ADC. unit = 2.25mV = 9/4 mV. + */ + val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400; return sprintf(buf, "%u\n", val); } @@ -114,12 +125,21 @@ static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13); static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); -static struct attribute *mc13783_attr[] = { +static struct attribute *mc13783_attr_base[] = { &dev_attr_name.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group mc13783_group_base = { + .attrs = mc13783_attr_base, +}; + +/* these are only used if MC13783_ADC_16CHANS is provided in driver data */ +static struct attribute *mc13783_attr_16chans[] = { &sensor_dev_attr_in8_input.dev_attr.attr, &sensor_dev_attr_in9_input.dev_attr.attr, &sensor_dev_attr_in10_input.dev_attr.attr, @@ -127,8 +147,8 @@ static struct attribute *mc13783_attr[] = { NULL }; -static const struct attribute_group mc13783_group = { - .attrs = mc13783_attr, +static const struct attribute_group mc13783_group_16chans = { + .attrs = mc13783_attr_16chans, }; /* last four channels may be occupied by the touchscreen */ @@ -156,24 +176,37 @@ static int __init mc13783_adc_probe(struct platform_device *pdev) { struct mc13783_adc_priv *priv; int ret; + const struct platform_device_id *id = platform_get_device_id(pdev); + char *dash; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); + snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name); + dash = strchr(priv->name, '-'); + if (dash) + *dash = '\0'; platform_set_drvdata(pdev, priv); /* Register sysfs hooks */ - ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group); + ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base); if (ret) - goto out_err_create1; + goto out_err_create_base; + + if (id->driver_data & MC13783_ADC_16CHANS) { + ret = sysfs_create_group(&pdev->dev.kobj, + &mc13783_group_16chans); + if (ret) + goto out_err_create_16chans; + } if (!mc13783_adc_use_touchscreen(pdev)) { ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts); if (ret) - goto out_err_create2; + goto out_err_create_ts; } priv->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -184,17 +217,20 @@ static int __init mc13783_adc_probe(struct platform_device *pdev) goto out_err_register; } - return 0; out_err_register: if (!mc13783_adc_use_touchscreen(pdev)) sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); -out_err_create2: +out_err_create_ts: - sysfs_remove_group(&pdev->dev.kobj, &mc13783_group); -out_err_create1: + if (id->driver_data & MC13783_ADC_16CHANS) + sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); +out_err_create_16chans: + + sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); +out_err_create_base: platform_set_drvdata(pdev, NULL); kfree(priv); @@ -205,13 +241,17 @@ out_err_create1: static int __devexit mc13783_adc_remove(struct platform_device *pdev) { struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; hwmon_device_unregister(priv->hwmon_dev); if (!mc13783_adc_use_touchscreen(pdev)) sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); - sysfs_remove_group(&pdev->dev.kobj, &mc13783_group); + if (driver_data & MC13783_ADC_16CHANS) + sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); + + sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); platform_set_drvdata(pdev, NULL); kfree(priv); @@ -219,12 +259,26 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id mc13783_adc_idtable[] = { + { + .name = "mc13783-adc", + .driver_data = MC13783_ADC_16CHANS, + }, { + .name = "mc13892-adc", + .driver_data = MC13783_ADC_BPDIV2, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); + static struct platform_driver mc13783_adc_driver = { .remove = __devexit_p(mc13783_adc_remove), .driver = { .owner = THIS_MODULE, - .name = MC13783_ADC_NAME, + .name = DRIVER_NAME, }, + .id_table = mc13783_adc_idtable, }; static int __init mc13783_adc_init(void) @@ -243,4 +297,3 @@ module_exit(mc13783_adc_exit); MODULE_DESCRIPTION("MC13783 ADC driver"); MODULE_AUTHOR("Luotao Fu "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" MC13783_ADC_NAME); -- cgit v1.2.3-70-g09d2 From 5510e62a66bad22b104d5d854445523d7f5754f7 Mon Sep 17 00:00:00 2001 From: Xie Xiaobo Date: Fri, 23 Mar 2012 10:02:20 +0100 Subject: hwmon: Add MCP3021 ADC driver Add I2C driver for MCP3021 that is an ADC chip from Microchip. The MCP3021 is a successive approximation A/D converter (ADC) with 10-bit resolution. The driver export the value of Vin to sysfs, the voltage unit is mV. Through the sysfs interface, lm-sensors tool can also display Vin voltage. Signed-off-by: Mingkai Hu Signed-off-by: Xie Xiaobo Signed-off-by: Jean Delvare --- Documentation/hwmon/mcp3021 | 22 ++++++ drivers/hwmon/Kconfig | 10 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/mcp3021.c | 171 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 Documentation/hwmon/mcp3021 create mode 100644 drivers/hwmon/mcp3021.c (limited to 'Documentation/hwmon') diff --git a/Documentation/hwmon/mcp3021 b/Documentation/hwmon/mcp3021 new file mode 100644 index 00000000000..325fd87e81b --- /dev/null +++ b/Documentation/hwmon/mcp3021 @@ -0,0 +1,22 @@ +Kernel driver MCP3021 +====================== + +Supported chips: + * Microchip Technology MCP3021 + Prefix: 'mcp3021' + Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf + +Author: Mingkai Hu + +Description +----------- + +This driver implements support for the Microchip Technology MCP3021 chip. + +The Microchip Technology Inc. MCP3021 is a successive approximation A/D +converter (ADC) with 10-bit resolution. +This device provides one single-ended input with very low power consumption. +Communication to the MCP3021 is performed using a 2-wire I2C compatible +interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available. +The default I2C device address is 0x4d (contact the Microchip factory for +additional address options). diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7190a3f4a82..5b32d56dbb4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -813,6 +813,16 @@ config SENSORS_MAX6650 This driver can also be built as a module. If so, the module will be called max6650. +config SENSORS_MCP3021 + tristate "Microchip MCP3021" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the MCP3021 chip + that is a A/D converter (ADC) with 10-bit resolution. + + This driver can also be built as a module. If so, the module + will be called mcp3021. + config SENSORS_NTC_THERMISTOR tristate "NTC thermistor support" depends on EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8251ce8cd03..6d3f11f7181 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o obj-$(CONFIG_SENSORS_MAX6642) += max6642.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o +obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c new file mode 100644 index 00000000000..d0afc0cd3ff --- /dev/null +++ b/drivers/hwmon/mcp3021.c @@ -0,0 +1,171 @@ +/* + * mcp3021.c - driver for the Microchip MCP3021 chip + * + * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc. + * Author: Mingkai Hu + * + * This driver export the value of analog input voltage to sysfs, the + * voltage unit is mV. Through the sysfs interface, lm-sensors tool + * can also display the input voltage. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Vdd info */ +#define MCP3021_VDD_MAX 5500 +#define MCP3021_VDD_MIN 2700 +#define MCP3021_VDD_REF 3300 + +/* output format */ +#define MCP3021_SAR_SHIFT 2 +#define MCP3021_SAR_MASK 0x3ff + +#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ +#define MCP3021_OUTPUT_SCALE 4 + +/* + * Client data (each client gets its own) + */ +struct mcp3021_data { + struct device *hwmon_dev; + u32 vdd; /* device power supply */ +}; + +static int mcp3021_read16(struct i2c_client *client) +{ + int ret; + u16 reg; + __be16 buf; + + ret = i2c_master_recv(client, (char *)&buf, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + /* The output code of the MCP3021 is transmitted with MSB first. */ + reg = be16_to_cpu(buf); + + /* + * The ten-bit output code is composed of the lower 4-bit of the + * first byte and the upper 6-bit of the second byte. + */ + reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK; + + return reg; +} + +static inline u16 volts_from_reg(u16 vdd, u16 val) +{ + if (val == 0) + return 0; + + val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2; + + return val * DIV_ROUND_CLOSEST(vdd, + (1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE); +} + +static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mcp3021_data *data = i2c_get_clientdata(client); + int reg, in_input; + + reg = mcp3021_read16(client); + if (reg < 0) + return reg; + + in_input = volts_from_reg(data->vdd, reg); + return sprintf(buf, "%d\n", in_input); +} + +static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL); + +static int mcp3021_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + struct mcp3021_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + + if (client->dev.platform_data) { + data->vdd = *(u32 *)client->dev.platform_data; + if (data->vdd > MCP3021_VDD_MAX || + data->vdd < MCP3021_VDD_MIN) { + err = -EINVAL; + goto exit_free; + } + } else + data->vdd = MCP3021_VDD_REF; + + err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr); + if (err) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); +exit_free: + kfree(data); + return err; +} + +static int mcp3021_remove(struct i2c_client *client) +{ + struct mcp3021_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); + kfree(data); + + return 0; +} + +static const struct i2c_device_id mcp3021_id[] = { + { "mcp3021", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mcp3021_id); + +static struct i2c_driver mcp3021_driver = { + .driver = { + .name = "mcp3021", + }, + .probe = mcp3021_probe, + .remove = mcp3021_remove, + .id_table = mcp3021_id, +}; + +module_i2c_driver(mcp3021_driver); + +MODULE_AUTHOR("Mingkai Hu "); +MODULE_DESCRIPTION("Microchip MCP3021 driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2