diff --git a/Documentation/devicetree/bindings/hwmon/nsa320-mcu.txt b/Documentation/devicetree/bindings/hwmon/nsa320-mcu.txt new file mode 100644 index 000000000000..0863e067c85b --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/nsa320-mcu.txt @@ -0,0 +1,20 @@ +Bindings for the fan / temperature monitor microcontroller used on +the Zyxel NSA 320 and several subsequent models. + +Required properties: +- compatible : "zyxel,nsa320-mcu" +- data-gpios : The GPIO pin connected to the data line on the MCU +- clk-gpios : The GPIO pin connected to the clock line on the MCU +- act-gpios : The GPIO pin connected to the active line on the MCU + +Example: + + hwmon { + compatible = "zyxel,nsa320-mcu"; + pinctrl-0 = <&pmx_mcu_data &pmx_mcu_clk &pmx_mcu_act>; + pinctrl-names = "default"; + + data-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + clk-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + act-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt index a04a80f9cc70..c3b9c4cfe8df 100644 --- a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt +++ b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt @@ -10,6 +10,7 @@ Requires node properties: "murata,ncp03wb473" "murata,ncp15wl333" "murata,ncp03wf104" + "murata,ncp15xh103" /* Usage of vendor name "ntc" is deprecated */ "ntc,ncp15wb473" diff --git a/Documentation/devicetree/bindings/iio/iio-bindings.txt b/Documentation/devicetree/bindings/iio/iio-bindings.txt index 0b447d9ad196..68d6f8ce063b 100644 --- a/Documentation/devicetree/bindings/iio/iio-bindings.txt +++ b/Documentation/devicetree/bindings/iio/iio-bindings.txt @@ -82,7 +82,7 @@ vdd channel is connected to output 0 of the &ref device. ... - iio_hwmon { + iio-hwmon { compatible = "iio-hwmon"; io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, <&adc 5>, diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index d697229e3c18..791bc0bd91e6 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -14,6 +14,10 @@ Supported chips: Prefix: 'adm1276' Addresses scanned: - Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf + * Analog Devices ADM1278 + Prefix: 'adm1278' + Addresses scanned: - + Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1278.pdf * Analog Devices ADM1293/ADM1294 Prefix: 'adm1293', 'adm1294' Addresses scanned: - @@ -25,13 +29,15 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, -ADM1276, ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. +This driver supports hardware monitoring for Analog Devices ADM1075, ADM1275, +ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and Digital +Power Monitors. -ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 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, ADM1276, ADM1278, ADM1293, and ADM1294 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. @@ -96,3 +102,14 @@ power1_reset_history Write any value to reset history. Power attributes are supported on ADM1075, ADM1276, ADM1293, and ADM1294. + +temp1_input Chip temperature. + Temperature attributes are only available on ADM1278. +temp1_max Maximum chip temperature. +temp1_max_alarm Temperature alarm. +temp1_crit Critical chip temperature. +temp1_crit_alarm Critical temperature high alarm. +temp1_highest Highest observed temperature. +temp1_reset_history Write any value to reset history. + + Temperature attributes are supported on ADM1278. diff --git a/Documentation/hwmon/lm25066 b/Documentation/hwmon/lm25066 index b34c3de5c1bc..2cb20ebb234d 100644 --- a/Documentation/hwmon/lm25066 +++ b/Documentation/hwmon/lm25066 @@ -36,7 +36,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for National Semiconductor / TI LM25056, +This driver supports hardware monitoring for National Semiconductor / TI LM25056, LM25063, LM25066, LM5064, and LM5066 Power Management, Monitoring, Control, and Protection ICs. diff --git a/Documentation/hwmon/ltc2990 b/Documentation/hwmon/ltc2990 new file mode 100644 index 000000000000..c25211e90bdc --- /dev/null +++ b/Documentation/hwmon/ltc2990 @@ -0,0 +1,43 @@ +Kernel driver ltc2990 +===================== + +Supported chips: + * Linear Technology LTC2990 + Prefix: 'ltc2990' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc2990 + +Author: Mike Looijmans + + +Description +----------- + +LTC2990 is a Quad I2C Voltage, Current and Temperature Monitor. +The chip's inputs can measure 4 voltages, or two inputs together (1+2 and 3+4) +can be combined to measure a differential voltage, which is typically used to +measure current through a series resistor, or a temperature. + +This driver currently uses the 2x differential mode only. In order to support +other modes, the driver will need to be expanded. + + +Usage Notes +----------- + +This driver does not probe for PMBus devices. You will have to instantiate +devices explicitly. + + +Sysfs attributes +---------------- + +The "curr*_input" measurements actually report the voltage drop across the +input pins in microvolts. This is equivalent to the current through a 1mOhm +sense resistor. Divide the reported value by the actual sense resistor value +in mOhm to get the actual value. + +in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V) +temp1_input Internal chip temperature in millidegrees Celcius +curr1_input Current in mA across v1-v2 assuming a 1mOhm sense resistor. +curr2_input Current in mA across v3-v4 assuming a 1mOhm sense resistor. diff --git a/Documentation/hwmon/max16064 b/Documentation/hwmon/max16064 index d59cc7829bec..265370f5cb82 100644 --- a/Documentation/hwmon/max16064 +++ b/Documentation/hwmon/max16064 @@ -13,7 +13,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Maxim MAX16064 Quad Power-Supply +This driver supports hardware monitoring for Maxim MAX16064 Quad Power-Supply Controller with Active-Voltage Output Control and PMBus Interface. The driver is a client driver to the core PMBus driver. diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 index 37cbf472a19d..f5b1fcaa9e4e 100644 --- a/Documentation/hwmon/max34440 +++ b/Documentation/hwmon/max34440 @@ -33,7 +33,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel +This driver supports hardware monitoring for Maxim MAX34440 PMBus 6-Channel Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger. It also supports the MAX34460 and MAX34461 PMBus Voltage Monitor & Sequencers. diff --git a/Documentation/hwmon/max8688 b/Documentation/hwmon/max8688 index e78078638b91..ca233bec7a8a 100644 --- a/Documentation/hwmon/max8688 +++ b/Documentation/hwmon/max8688 @@ -13,7 +13,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Maxim MAX8688 Digital Power-Supply +This driver supports hardware monitoring for Maxim MAX8688 Digital Power-Supply Controller/Monitor with PMBus Interface. The driver is a client driver to the core PMBus driver. Please see diff --git a/Documentation/hwmon/nsa320 b/Documentation/hwmon/nsa320 new file mode 100644 index 000000000000..fdbd6947799b --- /dev/null +++ b/Documentation/hwmon/nsa320 @@ -0,0 +1,53 @@ +Kernel driver nsa320_hwmon +========================== + +Supported chips: + * Holtek HT46R065 microcontroller with onboard firmware that configures + it to act as a hardware monitor. + Prefix: 'nsa320' + Addresses scanned: none + Datasheet: Not available, driver was reverse engineered based upon the + Zyxel kernel source + +Author: + Adam Baker + +Description +----------- + +This chip is known to be used in the Zyxel NSA320 and NSA325 NAS Units and +also in some variants of the NSA310 but the driver has only been tested +on the NSA320. In all of these devices it is connected to the same 3 GPIO +lines which are used to provide chip select, clock and data lines. The +interface behaves similarly to SPI but at much lower speeds than are normally +used for SPI. + +Following each chip select pulse the chip will generate a single 32 bit word +that contains 0x55 as a marker to indicate that data is being read correctly, +followed by an 8 bit fan speed in 100s of RPM and a 16 bit temperature in +tenths of a degree. + + +sysfs-Interface +--------------- + +temp1_input - temperature input +fan1_input - fan speed + +Notes +----- + +The access timings used in the driver are the same as used in the Zyxel +provided kernel. Testing has shown that if the delay between chip select and +the first clock pulse is reduced from 100 ms to just under 10ms then the chip +will not produce any output. If the duration of either phase of the clock +is reduced from 100 us to less than 15 us then data pulses are likely to be +read twice corrupting the output. The above analysis is based upon a sample +of one unit but suggests that the Zyxel provided delay values include a +reasonable tolerance. + +The driver incorporates a limit that it will not check for updated values +faster than once a second. This is because the hardware takes a relatively long +time to read the data from the device and when it does it reads both temp and +fan speed. As the most likely case for two accesses in quick succession is +to read both of these values avoiding a second read delay is desirable. diff --git a/Documentation/hwmon/ntc_thermistor b/Documentation/hwmon/ntc_thermistor index 1d4cc847c6fe..8b9ff23edc32 100644 --- a/Documentation/hwmon/ntc_thermistor +++ b/Documentation/hwmon/ntc_thermistor @@ -3,9 +3,9 @@ Kernel driver ntc_thermistor Supported thermistors from Murata: * Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, - NCP15WL333, NCP03WF104 + NCP15WL333, NCP03WF104, NCP15XH103 Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', - 'ncp15wl333', 'ncp03wf104' + 'ncp15wl333', 'ncp03wf104', 'ncp15xh103' Datasheet: Publicly available at Murata Supported thermistors from EPCOS: diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index b397675e876d..dfd9c65996c0 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -43,7 +43,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for various PMBus compliant devices. +This driver supports hardware monitoring for various PMBus compliant devices. It supports voltage, current, power, and temperature sensors as supported by the device. diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100 index 33908a4d68ff..477a94b131ae 100644 --- a/Documentation/hwmon/zl6100 +++ b/Documentation/hwmon/zl6100 @@ -60,7 +60,7 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware montoring for Intersil / Zilker Labs ZL6100 and +This driver supports hardware monitoring for Intersil / Zilker Labs ZL6100 and compatible digital DC-DC controllers. The driver is a client driver to the core PMBus driver. Please see diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 1c6c07538a78..302d1168f424 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -569,7 +569,7 @@ usb0: usb@80080000 { }; }; - iio_hwmon { + iio-hwmon { compatible = "iio-hwmon"; io-channels = <&lradc 8>; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index fae7b9069fc4..f637ec900cc8 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -1256,7 +1256,7 @@ etn_switch: switch@800f8000 { }; }; - iio_hwmon { + iio-hwmon { compatible = "iio-hwmon"; io-channels = <&lradc 8>; }; diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index a9ceb5bac40e..4539f8d909a5 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -629,5 +629,10 @@ i2c3: i2c@400e7000 { status = "disabled"; }; }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 16>, <&adc1 16>; + }; }; }; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 60fb80bd353d..5c2d13a687aa 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -685,6 +685,20 @@ config SENSORS_LTC2945 This driver can also be built as a module. If so, the module will be called ltc2945. +config SENSORS_LTC2990 + tristate "Linear Technology LTC2990 (current monitoring mode only)" + depends on I2C + help + If you say yes here you get support for Linear Technology LTC2990 + I2C System Monitor. The LTC2990 supports a combination of voltage, + current and temperature monitoring, but in addition to the Vcc supply + voltage and chip temperature, this driver currently only supports + reading two currents by measuring two differential voltages across + series resistors. + + This driver can also be built as a module. If so, the module will + be called ltc2990. + config SENSORS_LTC4151 tristate "Linear Technology LTC4151" depends on I2C @@ -1127,7 +1141,7 @@ config SENSORS_NTC_THERMISTOR Currently, this driver supports NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333, - and NCP03WF104 from Murata and B57330V2103 from EPCOS. + NCP03WF104 and NCP15XH103 from Murata and B57330V2103 from EPCOS. This driver can also be built as a module. If so, the module will be called ntc-thermistor. @@ -1176,6 +1190,21 @@ config SENSORS_NCT7904 This driver can also be built as a module. If so, the module will be called nct7904. +config SENSORS_NSA320 + tristate "ZyXEL NSA320 and compatible fan speed and temperature sensors" + depends on GPIOLIB && OF + depends on MACH_KIRKWOOD || COMPILE_TEST + help + If you say yes here you get support for hardware monitoring + for the ZyXEL NSA320 Media Server and other compatible devices + (probably the NSA325 and some NSA310 variants). + + The sensor data is taken from a Holtek HT46R065 microcontroller + connected to GPIO lines. + + This driver can also be built as a module. If so, the module + will be called nsa320-hwmon. + config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 30c94df31465..58cc3acba7e7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o obj-$(CONFIG_SENSORS_LM95241) += lm95241.o obj-$(CONFIG_SENSORS_LM95245) += lm95245.o obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o +obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o @@ -123,6 +124,7 @@ obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o +obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o @@ -149,7 +151,7 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o -obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o +obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 17ae2eb26ce2..b550ba5fa58a 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -67,6 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) enum iio_chan_type type; struct iio_channel *channels; const char *name = "iio_hwmon"; + char *sname; if (dev->of_node && dev->of_node->name) name = dev->of_node->name; @@ -144,7 +145,15 @@ static int iio_hwmon_probe(struct platform_device *pdev) st->attr_group.attrs = st->attrs; st->groups[0] = &st->attr_group; - st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st, + + sname = devm_kstrdup(dev, name, GFP_KERNEL); + if (!sname) { + ret = -ENOMEM; + goto error_release_channels; + } + + strreplace(sname, '-', '_'); + st->hwmon_dev = hwmon_device_register_with_groups(dev, sname, st, st->groups); if (IS_ERR(st->hwmon_dev)) { ret = PTR_ERR(st->hwmon_dev); diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c new file mode 100644 index 000000000000..8f8fe059ab48 --- /dev/null +++ b/drivers/hwmon/ltc2990.c @@ -0,0 +1,161 @@ +/* + * Driver for Linear Technology LTC2990 power monitor + * + * Copyright (C) 2014 Topic Embedded Products + * Author: Mike Looijmans + * + * License: GPLv2 + * + * This driver assumes the chip is wired as a dual current monitor, and + * reports the voltage drop across two series resistors. It also reports + * the chip's internal temperature and Vcc power supply voltage. + */ + +#include +#include +#include +#include +#include +#include + +#define LTC2990_STATUS 0x00 +#define LTC2990_CONTROL 0x01 +#define LTC2990_TRIGGER 0x02 +#define LTC2990_TINT_MSB 0x04 +#define LTC2990_V1_MSB 0x06 +#define LTC2990_V2_MSB 0x08 +#define LTC2990_V3_MSB 0x0A +#define LTC2990_V4_MSB 0x0C +#define LTC2990_VCC_MSB 0x0E + +#define LTC2990_CONTROL_KELVIN BIT(7) +#define LTC2990_CONTROL_SINGLE BIT(6) +#define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3) +#define LTC2990_CONTROL_MODE_CURRENT 0x06 +#define LTC2990_CONTROL_MODE_VOLTAGE 0x07 + +/* convert raw register value to sign-extended integer in 16-bit range */ +static int ltc2990_voltage_to_int(int raw) +{ + if (raw & BIT(14)) + return -(0x4000 - (raw & 0x3FFF)) << 2; + else + return (raw & 0x3FFF) << 2; +} + +/* Return the converted value from the given register in uV or mC */ +static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result) +{ + int val; + + val = i2c_smbus_read_word_swapped(i2c, reg); + if (unlikely(val < 0)) + return val; + + switch (reg) { + case LTC2990_TINT_MSB: + /* internal temp, 0.0625 degrees/LSB, 13-bit */ + val = (val & 0x1FFF) << 3; + *result = (val * 1000) >> 7; + break; + case LTC2990_V1_MSB: + case LTC2990_V3_MSB: + /* Vx-Vy, 19.42uV/LSB. Depends on mode. */ + *result = ltc2990_voltage_to_int(val) * 1942 / (4 * 100); + break; + case LTC2990_VCC_MSB: + /* Vcc, 305.18μV/LSB, 2.5V offset */ + *result = (ltc2990_voltage_to_int(val) * 30518 / + (4 * 100 * 1000)) + 2500; + break; + default: + return -EINVAL; /* won't happen, keep compiler happy */ + } + + return 0; +} + +static ssize_t ltc2990_show_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value; + int ret; + + ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value); + if (unlikely(ret < 0)) + return ret; + + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TINT_MSB); +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_V1_MSB); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_V3_MSB); +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_VCC_MSB); + +static struct attribute *ltc2990_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ltc2990); + +static int ltc2990_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret; + struct device *hwmon_dev; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + /* Setup continuous mode, current monitor */ + ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL, + LTC2990_CONTROL_MEASURE_ALL | + LTC2990_CONTROL_MODE_CURRENT); + if (ret < 0) { + dev_err(&i2c->dev, "Error: Failed to set control mode.\n"); + return ret; + } + /* Trigger once to start continuous conversion */ + ret = i2c_smbus_write_byte_data(i2c, LTC2990_TRIGGER, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Error: Failed to start acquisition.\n"); + return ret; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev, + i2c->name, + i2c, + ltc2990_groups); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id ltc2990_i2c_id[] = { + { "ltc2990", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id); + +static struct i2c_driver ltc2990_i2c_driver = { + .driver = { + .name = "ltc2990", + }, + .probe = ltc2990_i2c_probe, + .id_table = ltc2990_i2c_id, +}; + +module_i2c_driver(ltc2990_i2c_driver); + +MODULE_DESCRIPTION("LTC2990 Sensor Driver"); +MODULE_AUTHOR("Topic Embedded Products"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/nsa320-hwmon.c b/drivers/hwmon/nsa320-hwmon.c new file mode 100644 index 000000000000..0517a265741f --- /dev/null +++ b/drivers/hwmon/nsa320-hwmon.c @@ -0,0 +1,215 @@ +/* + * drivers/hwmon/nsa320-hwmon.c + * + * ZyXEL NSA320 Media Servers + * hardware monitoring + * + * Copyright (C) 2016 Adam Baker + * based on a board file driver + * Copyright (C) 2012 Peter Schildmann + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Tests for error return values rely upon this value being < 0x80 */ +#define MAGIC_NUMBER 0x55 + +/* + * The Zyxel hwmon MCU is a Holtek HT46R065 that is factory programmed + * to perform temperature and fan speed monitoring. It is read by taking + * the active pin low. The 32 bit output word is then clocked onto the + * data line. The MSB of the data word is a magic nuber to indicate it + * has been read correctly, the next byte is the fan speed (in hundreds + * of RPM) and the last two bytes are the temperature (in tenths of a + * degree) + */ + +struct nsa320_hwmon { + struct mutex update_lock; /* lock GPIO operations */ + unsigned long last_updated; /* jiffies */ + unsigned long mcu_data; + struct gpio_desc *act; + struct gpio_desc *clk; + struct gpio_desc *data; +}; + +enum nsa320_inputs { + NSA320_TEMP = 0, + NSA320_FAN = 1, +}; + +static const char * const nsa320_input_names[] = { + [NSA320_TEMP] = "System Temperature", + [NSA320_FAN] = "Chassis Fan", +}; + +/* + * Although this protocol looks similar to SPI the long delay + * between the active (aka chip select) signal and the shorter + * delay between clock pulses are needed for reliable operation. + * The delays provided are taken from the manufacturer kernel, + * testing suggest they probably incorporate a reasonable safety + * margin. (The single device tested became unreliable if the + * delay was reduced to 1/10th of this value.) + */ +static s32 nsa320_hwmon_update(struct device *dev) +{ + u32 mcu_data; + u32 mask; + struct nsa320_hwmon *hwmon = dev_get_drvdata(dev); + + mutex_lock(&hwmon->update_lock); + + mcu_data = hwmon->mcu_data; + + if (time_after(jiffies, hwmon->last_updated + HZ) || mcu_data == 0) { + gpiod_set_value(hwmon->act, 1); + msleep(100); + + mcu_data = 0; + for (mask = BIT(31); mask; mask >>= 1) { + gpiod_set_value(hwmon->clk, 0); + usleep_range(100, 200); + gpiod_set_value(hwmon->clk, 1); + usleep_range(100, 200); + if (gpiod_get_value(hwmon->data)) + mcu_data |= mask; + } + + gpiod_set_value(hwmon->act, 0); + dev_dbg(dev, "Read raw MCU data %08x\n", mcu_data); + + if ((mcu_data >> 24) != MAGIC_NUMBER) { + dev_dbg(dev, "Read invalid MCU data %08x\n", mcu_data); + mcu_data = -EIO; + } else { + hwmon->mcu_data = mcu_data; + hwmon->last_updated = jiffies; + } + } + + mutex_unlock(&hwmon->update_lock); + + return mcu_data; +} + +static ssize_t show_label(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int channel = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%s\n", nsa320_input_names[channel]); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + s32 mcu_data = nsa320_hwmon_update(dev); + + if (mcu_data < 0) + return mcu_data; + + return sprintf(buf, "%d\n", (mcu_data & 0xffff) * 100); +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + s32 mcu_data = nsa320_hwmon_update(dev); + + if (mcu_data < 0) + return mcu_data; + + return sprintf(buf, "%d\n", ((mcu_data & 0xff0000) >> 16) * 100); +} + +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, NSA320_TEMP); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, show_label, NULL, NSA320_FAN); +static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL); + +static struct attribute *nsa320_attrs[] = { + &sensor_dev_attr_temp1_label.dev_attr.attr, + &dev_attr_temp1_input.attr, + &sensor_dev_attr_fan1_label.dev_attr.attr, + &dev_attr_fan1_input.attr, + NULL +}; + +ATTRIBUTE_GROUPS(nsa320); + +static const struct of_device_id of_nsa320_hwmon_match[] = { + { .compatible = "zyxel,nsa320-mcu", }, + { }, +}; + +static int nsa320_hwmon_probe(struct platform_device *pdev) +{ + struct nsa320_hwmon *hwmon; + struct device *classdev; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + /* Look up the GPIO pins to use */ + hwmon->act = devm_gpiod_get(&pdev->dev, "act", GPIOD_OUT_LOW); + if (IS_ERR(hwmon->act)) + return PTR_ERR(hwmon->act); + + hwmon->clk = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_HIGH); + if (IS_ERR(hwmon->clk)) + return PTR_ERR(hwmon->clk); + + hwmon->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN); + if (IS_ERR(hwmon->data)) + return PTR_ERR(hwmon->data); + + mutex_init(&hwmon->update_lock); + + classdev = devm_hwmon_device_register_with_groups(&pdev->dev, + "nsa320", hwmon, nsa320_groups); + + return PTR_ERR_OR_ZERO(classdev); + +} + +/* All allocations use devres so remove() is not needed. */ + +static struct platform_driver nsa320_hwmon_driver = { + .probe = nsa320_hwmon_probe, + .driver = { + .name = "nsa320-hwmon", + .of_match_table = of_match_ptr(of_nsa320_hwmon_match), + }, +}; + +module_platform_driver(nsa320_hwmon_driver); + +MODULE_DEVICE_TABLE(of, of_nsa320_hwmon_match); +MODULE_AUTHOR("Peter Schildmann "); +MODULE_AUTHOR("Adam Baker "); +MODULE_DESCRIPTION("NSA320 Hardware Monitoring"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:nsa320-hwmon"); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index feed30646d91..faa6e8dfbaaf 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -54,6 +54,7 @@ static const struct platform_device_id ntc_thermistor_id[] = { { "ncp15wl333", TYPE_NCPXXWL333 }, { "b57330v2103", TYPE_B57330V2103}, { "ncp03wf104", TYPE_NCPXXWF104 }, + { "ncp15xh103", TYPE_NCPXXXH103 }, { }, }; @@ -173,6 +174,43 @@ static const struct ntc_compensation ncpXXwf104[] = { { .temp_c = 125, .ohm = 2522 }, }; +static const struct ntc_compensation ncpXXxh103[] = { + { .temp_c = -40, .ohm = 247565 }, + { .temp_c = -35, .ohm = 181742 }, + { .temp_c = -30, .ohm = 135128 }, + { .temp_c = -25, .ohm = 101678 }, + { .temp_c = -20, .ohm = 77373 }, + { .temp_c = -15, .ohm = 59504 }, + { .temp_c = -10, .ohm = 46222 }, + { .temp_c = -5, .ohm = 36244 }, + { .temp_c = 0, .ohm = 28674 }, + { .temp_c = 5, .ohm = 22878 }, + { .temp_c = 10, .ohm = 18399 }, + { .temp_c = 15, .ohm = 14910 }, + { .temp_c = 20, .ohm = 12169 }, + { .temp_c = 25, .ohm = 10000 }, + { .temp_c = 30, .ohm = 8271 }, + { .temp_c = 35, .ohm = 6883 }, + { .temp_c = 40, .ohm = 5762 }, + { .temp_c = 45, .ohm = 4851 }, + { .temp_c = 50, .ohm = 4105 }, + { .temp_c = 55, .ohm = 3492 }, + { .temp_c = 60, .ohm = 2985 }, + { .temp_c = 65, .ohm = 2563 }, + { .temp_c = 70, .ohm = 2211 }, + { .temp_c = 75, .ohm = 1915 }, + { .temp_c = 80, .ohm = 1666 }, + { .temp_c = 85, .ohm = 1454 }, + { .temp_c = 90, .ohm = 1275 }, + { .temp_c = 95, .ohm = 1121 }, + { .temp_c = 100, .ohm = 990 }, + { .temp_c = 105, .ohm = 876 }, + { .temp_c = 110, .ohm = 779 }, + { .temp_c = 115, .ohm = 694 }, + { .temp_c = 120, .ohm = 620 }, + { .temp_c = 125, .ohm = 556 }, +}; + /* * The following compensation table is from the specification of EPCOS NTC * Thermistors Datasheet @@ -260,6 +298,8 @@ static const struct of_device_id ntc_match[] = { .data = &ntc_thermistor_id[5]}, { .compatible = "murata,ncp03wf104", .data = &ntc_thermistor_id[6] }, + { .compatible = "murata,ncp15xh103", + .data = &ntc_thermistor_id[7] }, /* Usage of vendor name "ntc" is deprecated */ { .compatible = "ntc,ncp15wb473", @@ -609,6 +649,10 @@ static int ntc_thermistor_probe(struct platform_device *pdev) data->comp = ncpXXwf104; data->n_comp = ARRAY_SIZE(ncpXXwf104); break; + case TYPE_NCPXXXH103: + data->comp = ncpXXxh103; + data->n_comp = ARRAY_SIZE(ncpXXxh103); + break; default: dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n", pdev_id->driver_data, pdev_id->name); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 7e5cc3d025ef..054d3d863802 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 ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap - Controller and Digital Power Monitors. + Devices ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 + 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 188af4c89f40..3baa4f4a8c5e 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -24,7 +24,7 @@ #include #include "pmbus.h" -enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; +enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 }; #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) @@ -41,6 +41,10 @@ enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; #define ADM1075_IRANGE_25 BIT(3) #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) +#define ADM1278_TEMP1_EN BIT(3) +#define ADM1278_VIN_EN BIT(2) +#define ADM1278_VOUT_EN BIT(1) + #define ADM1293_IRANGE_25 0 #define ADM1293_IRANGE_50 BIT(6) #define ADM1293_IRANGE_100 BIT(7) @@ -54,6 +58,7 @@ enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; #define ADM1293_VAUX_EN BIT(1) +#define ADM1278_PEAK_TEMP 0xd7 #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 @@ -80,6 +85,7 @@ struct adm1275_data { bool have_iout_min; bool have_pin_min; bool have_pin_max; + bool have_temp_max; struct pmbus_driver_info info; }; @@ -113,6 +119,13 @@ static const struct coefficients adm1276_coefficients[] = { [4] = { 2115, 0, -1 }, /* power, vrange not set */ }; +static const struct coefficients adm1278_coefficients[] = { + [0] = { 19599, 0, -2 }, /* voltage */ + [1] = { 800, 20475, -1 }, /* current */ + [2] = { 6123, 0, -2 }, /* power */ + [3] = { 42, 31880, -1 }, /* temperature */ +}; + static const struct coefficients adm1293_coefficients[] = { [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ @@ -196,6 +209,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); break; + case PMBUS_VIRT_READ_TEMP_MAX: + if (!data->have_temp_max) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP); + break; case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_VIN_HISTORY: @@ -204,6 +222,10 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) if (!data->have_pin_max) return -ENXIO; break; + case PMBUS_VIRT_RESET_TEMP_HISTORY: + if (!data->have_temp_max) + return -ENXIO; + break; default: ret = -ENODATA; break; @@ -245,6 +267,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, ret = pmbus_write_word_data(client, 0, ADM1293_PIN_MIN, 0); break; + case PMBUS_VIRT_RESET_TEMP_HISTORY: + ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); + break; default: ret = -ENODATA; break; @@ -312,6 +337,7 @@ static const struct i2c_device_id adm1275_id[] = { { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, + { "adm1278", adm1278 }, { "adm1293", adm1293 }, { "adm1294", adm1294 }, { } @@ -329,6 +355,7 @@ static int adm1275_probe(struct i2c_client *client, const struct i2c_device_id *mid; const struct coefficients *coefficients; int vindex = -1, voindex = -1, cindex = -1, pindex = -1; + int tindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -386,6 +413,7 @@ static int adm1275_probe(struct i2c_client *client, info->format[PSC_VOLTAGE_OUT] = direct; info->format[PSC_CURRENT_OUT] = direct; info->format[PSC_POWER] = direct; + info->format[PSC_TEMPERATURE] = direct; info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; info->read_word_data = adm1275_read_word_data; @@ -460,6 +488,27 @@ static int adm1275_probe(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; + case adm1278: + data->have_vout = true; + data->have_pin_max = true; + data->have_temp_max = true; + + coefficients = adm1278_coefficients; + vindex = 0; + cindex = 1; + pindex = 2; + tindex = 3; + + info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; + if (config & ADM1278_TEMP1_EN) + info->func[0] |= + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + if (config & ADM1278_VIN_EN) + info->func[0] |= PMBUS_HAVE_VIN; + if (config & ADM1278_VOUT_EN) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + break; case adm1293: case adm1294: data->have_iout_min = true; @@ -537,6 +586,11 @@ static int adm1275_probe(struct i2c_client *client, info->b[PSC_POWER] = coefficients[pindex].b; info->R[PSC_POWER] = coefficients[pindex].R; } + if (tindex >= 0) { + info->m[PSC_TEMPERATURE] = coefficients[tindex].m; + info->b[PSC_TEMPERATURE] = coefficients[tindex].b; + info->R[PSC_TEMPERATURE] = coefficients[tindex].R; + } return pmbus_do_probe(client, id, info); } diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress-hwmon.c similarity index 100% rename from drivers/hwmon/vexpress.c rename to drivers/hwmon/vexpress-hwmon.c diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h index aed170588b74..698d0d59db76 100644 --- a/include/linux/platform_data/ntc_thermistor.h +++ b/include/linux/platform_data/ntc_thermistor.h @@ -28,6 +28,7 @@ enum ntc_thermistor_type { TYPE_NCPXXWL333, TYPE_B57330V2103, TYPE_NCPXXWF104, + TYPE_NCPXXXH103, }; struct ntc_thermistor_platform_data {