Commit b8e445b6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:

 - Add support for trace events to hwmon core

 - Add support for NCT6797D, NCT6798D, MAX31725/6, LTM4686

 - Support all AMD Family 15h Model 6xh and Model 7xh processors in
   k10temp driver

 - Convert ina3221 driver to _info API

 - Fixes, cleanups, and improvements in various drivers

* tag 'hwmon-for-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (46 commits)
  hwmon: (pmbus) Fix page count auto-detection.
  hwmon: (pmbus) remove redundant 'default n' from Kconfig
  hwmon: (core) Add trace events to _attr_show/store functions
  hwmon: (ina3221) Use _info API to register hwmon device
  hwmon: (npcm-750-pwm-fan) Change initial pwm target to 255
  hwmon: (ina3221) Validate shunt resistor value from DT
  hwmon: (tmp421) make const array 'names' static
  hwmon: (core) Add hwmon_in_enable attribute
  hwmon: (ina3221) mark PM functions as __maybe_unused
  hwmon: (ina3221) Read channel input source info from DT
  dt-bindings: hwmon: Add ina3221 documentation
  hwmon: (ina3221) Add suspend and resume functions
  hwmon: (ina3221) Fix INA3221_CONFIG_MODE macros
  hwmon: (ina3221) Add INA3221_CONFIG to volatile_table
  MAINTAINERS: Update PMBUS maintainer entry
  hwmon: (pwm-fan) Set fan speed to 0 on suspend
  hwmon: (pwm-fan) Silence error on probe deferral
  hwmon: (scpi-hwmon) remove redundant continue
  hwmon: (nct6775) Add support for NCT6798D
  hwmon: (nct6775) Add support for NCT6797D
  ...
parents cff22949 e7c6a556
Texas Instruments INA3221 Device Tree Bindings
1) ina3221 node
Required properties:
- compatible: Must be "ti,ina3221"
- reg: I2C address
Optional properties:
= The node contains optional child nodes for three channels =
= Each child node describes the information of input source =
- #address-cells: Required only if a child node is present. Must be 1.
- #size-cells: Required only if a child node is present. Must be 0.
2) child nodes
Required properties:
- reg: Must be 0, 1 or 2, corresponding to IN1, IN2 or IN3 port of INA3221
Optional properties:
- label: Name of the input source
- shunt-resistor-micro-ohms: Shunt resistor value in micro-Ohm
Example:
ina3221@40 {
compatible = "ti,ina3221";
reg = <0x40>;
#address-cells = <1>;
#size-cells = <0>;
input@0 {
reg = <0x0>;
status = "disabled";
};
input@1 {
reg = <0x1>;
shunt-resistor-micro-ohms = <5000>;
};
input@2 {
reg = <0x2>;
label = "VDD_5V";
shunt-resistor-micro-ohms = <5000>;
};
};
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
* "lltc,ltm2987" * "lltc,ltm2987"
* "lltc,ltm4675" * "lltc,ltm4675"
* "lltc,ltm4676" * "lltc,ltm4676"
* "lltc,ltm4686"
- reg: I2C slave address - reg: I2C slave address
Optional properties: Optional properties:
...@@ -30,6 +31,7 @@ Valid names of regulators depend on number of supplies supported per device: ...@@ -30,6 +31,7 @@ Valid names of regulators depend on number of supplies supported per device:
* ltc3880, ltc3882, ltc3886 : vout0 - vout1 * ltc3880, ltc3882, ltc3886 : vout0 - vout1
* ltc3883 : vout0 * ltc3883 : vout0
* ltm4676 : vout0 - vout1 * ltm4676 : vout0 - vout1
* ltm4686 : vout0 - vout1
Example: Example:
ltc2978@5e { ltc2978@5e {
......
...@@ -21,6 +21,8 @@ and power are calculated host-side from these. ...@@ -21,6 +21,8 @@ and power are calculated host-side from these.
Sysfs entries Sysfs entries
------------- -------------
in[123]_label Voltage channel labels
in[123]_enable Voltage channel enable controls
in[123]_input Bus voltage(mV) channels in[123]_input Bus voltage(mV) channels
curr[123]_input Current(mA) measurement channels curr[123]_input Current(mA) measurement channels
shunt[123]_resistor Shunt resistance(uOhm) channels shunt[123]_resistor Shunt resistance(uOhm) channels
......
...@@ -17,8 +17,8 @@ Supported chips: ...@@ -17,8 +17,8 @@ Supported chips:
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the Maxim website Datasheet: Publicly available at the Maxim website
http://www.maximintegrated.com/ http://www.maximintegrated.com/
* Maxim MAX6625, MAX6626 * Maxim MAX6625, MAX6626, MAX31725, MAX31726
Prefixes: 'max6625', 'max6626' Prefixes: 'max6625', 'max6626', 'max31725', 'max31726'
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the Maxim website Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/ http://www.maxim-ic.com/
...@@ -86,7 +86,7 @@ The LM75 is essentially an industry standard; there may be other ...@@ -86,7 +86,7 @@ The LM75 is essentially an industry standard; there may be other
LM75 clones not listed here, with or without various enhancements, LM75 clones not listed here, with or without various enhancements,
that are supported. The clones are not detected by the driver, unless that are supported. The clones are not detected by the driver, unless
they reproduce the exact register tricks of the original LM75, and must they reproduce the exact register tricks of the original LM75, and must
therefore be instantiated explicitly. Higher resolution up to 12-bit therefore be instantiated explicitly. Higher resolution up to 16-bit
is supported by this driver, other specific enhancements are not. is supported by this driver, other specific enhancements are not.
The LM77 is not supported, contrary to what we pretended for a long time. The LM77 is not supported, contrary to what we pretended for a long time.
......
...@@ -55,6 +55,10 @@ Supported chips: ...@@ -55,6 +55,10 @@ Supported chips:
Prefix: 'ltm4676' Prefix: 'ltm4676'
Addresses scanned: - Addresses scanned: -
Datasheet: http://www.linear.com/product/ltm4676 Datasheet: http://www.linear.com/product/ltm4676
* Analog Devices LTM4686
Prefix: 'ltm4686'
Addresses scanned: -
Datasheet: http://www.analog.com/ltm4686
Author: Guenter Roeck <linux@roeck-us.net> Author: Guenter Roeck <linux@roeck-us.net>
...@@ -76,6 +80,7 @@ additional components on a single die. The chip is instantiated and reported ...@@ -76,6 +80,7 @@ additional components on a single die. The chip is instantiated and reported
as two separate chips on two different I2C bus addresses. as two separate chips on two different I2C bus addresses.
LTM4675 is a dual 9A or single 18A μModule regulator LTM4675 is a dual 9A or single 18A μModule regulator
LTM4676 is a dual 13A or single 26A uModule regulator. LTM4676 is a dual 13A or single 26A uModule regulator.
LTM4686 is a dual 10A or single 20A uModule regulator.
Usage Notes Usage Notes
......
...@@ -2,12 +2,12 @@ Kernel driver mc13783-adc ...@@ -2,12 +2,12 @@ Kernel driver mc13783-adc
========================= =========================
Supported chips: Supported chips:
* Freescale Atlas MC13783 * Freescale MC13783
Prefix: 'mc13783' Prefix: 'mc13783'
Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1 Datasheet: https://www.nxp.com/docs/en/data-sheet/MC13783.pdf
* Freescale Atlas MC13892 * Freescale MC13892
Prefix: 'mc13892' Prefix: 'mc13892'
Datasheet: http://cache.freescale.com/files/analog/doc/data_sheet/MC13892.pdf?fsrch=1&sr=1 Datasheet: https://www.nxp.com/docs/en/data-sheet/MC13892.pdf
Authors: Authors:
Sascha Hauer <s.hauer@pengutronix.de> Sascha Hauer <s.hauer@pengutronix.de>
......
...@@ -6468,6 +6468,7 @@ F: Documentation/devicetree/bindings/hwmon/ ...@@ -6468,6 +6468,7 @@ F: Documentation/devicetree/bindings/hwmon/
F: Documentation/hwmon/ F: Documentation/hwmon/
F: drivers/hwmon/ F: drivers/hwmon/
F: include/linux/hwmon*.h F: include/linux/hwmon*.h
F: include/trace/events/hwmon*.h
HARDWARE RANDOM NUMBER GENERATOR CORE HARDWARE RANDOM NUMBER GENERATOR CORE
M: Matt Mackall <mpm@selenic.com> M: Matt Mackall <mpm@selenic.com>
...@@ -8860,13 +8861,6 @@ S: Maintained ...@@ -8860,13 +8861,6 @@ S: Maintained
F: Documentation/hwmon/max16065 F: Documentation/hwmon/max16065
F: drivers/hwmon/max16065.c F: drivers/hwmon/max16065.c
MAX20751 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/max20751
F: drivers/hwmon/max20751.c
MAX2175 SDR TUNER DRIVER MAX2175 SDR TUNER DRIVER
M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com> M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
...@@ -11601,7 +11595,26 @@ W: http://hwmon.wiki.kernel.org/ ...@@ -11601,7 +11595,26 @@ W: http://hwmon.wiki.kernel.org/
W: http://www.roeck-us.net/linux/drivers/ W: http://www.roeck-us.net/linux/drivers/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
F: Documentation/devicetree/bindings/hwmon/max31785.txt
F: Documentation/devicetree/bindings/hwmon/ltc2978.txt
F: Documentation/hwmon/adm1275
F: Documentation/hwmon/ibm-cffps
F: Documentation/hwmon/ir35221
F: Documentation/hwmon/lm25066
F: Documentation/hwmon/ltc2978
F: Documentation/hwmon/ltc3815
F: Documentation/hwmon/max16064
F: Documentation/hwmon/max20751
F: Documentation/hwmon/max31785
F: Documentation/hwmon/max34440
F: Documentation/hwmon/max8688
F: Documentation/hwmon/pmbus F: Documentation/hwmon/pmbus
F: Documentation/hwmon/pmbus-core
F: Documentation/hwmon/tps40422
F: Documentation/hwmon/ucd9000
F: Documentation/hwmon/ucd9200
F: Documentation/hwmon/zl6100
F: drivers/hwmon/pmbus/ F: drivers/hwmon/pmbus/
F: include/linux/pmbus.h F: include/linux/pmbus.h
......
...@@ -852,7 +852,7 @@ static int aspeed_create_pwm_cooling(struct device *dev, ...@@ -852,7 +852,7 @@ static int aspeed_create_pwm_cooling(struct device *dev,
dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
return ret; return ret;
} }
snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_port); snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child, cdev->tcdev = thermal_of_cooling_device_register(child,
cdev->name, cdev->name,
......
...@@ -1210,10 +1210,8 @@ static int atk_register_hwmon(struct atk_data *data) ...@@ -1210,10 +1210,8 @@ static int atk_register_hwmon(struct atk_data *data)
data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110", data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110",
data, data,
data->attr_groups); data->attr_groups);
if (IS_ERR(data->hwmon_dev))
return PTR_ERR(data->hwmon_dev);
return 0; return PTR_ERR_OR_ZERO(data->hwmon_dev);
} }
static int atk_probe_if(struct atk_data *data) static int atk_probe_if(struct atk_data *data)
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#define CREATE_TRACE_POINTS
#include <trace/events/hwmon.h>
#define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_PREFIX "hwmon"
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
...@@ -171,6 +174,13 @@ static int hwmon_thermal_add_sensor(struct device *dev, ...@@ -171,6 +174,13 @@ static int hwmon_thermal_add_sensor(struct device *dev,
} }
#endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */ #endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */
static int hwmon_attr_base(enum hwmon_sensor_types type)
{
if (type == hwmon_in)
return 0;
return 1;
}
/* sysfs attribute management */ /* sysfs attribute management */
static ssize_t hwmon_attr_show(struct device *dev, static ssize_t hwmon_attr_show(struct device *dev,
...@@ -185,6 +195,9 @@ static ssize_t hwmon_attr_show(struct device *dev, ...@@ -185,6 +195,9 @@ static ssize_t hwmon_attr_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type),
hattr->name, val);
return sprintf(buf, "%ld\n", val); return sprintf(buf, "%ld\n", val);
} }
...@@ -193,6 +206,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev, ...@@ -193,6 +206,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
char *buf) char *buf)
{ {
struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
enum hwmon_sensor_types type = hattr->type;
const char *s; const char *s;
int ret; int ret;
...@@ -201,6 +215,9 @@ static ssize_t hwmon_attr_show_string(struct device *dev, ...@@ -201,6 +215,9 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type),
hattr->name, s);
return sprintf(buf, "%s\n", s); return sprintf(buf, "%s\n", s);
} }
...@@ -221,14 +238,10 @@ static ssize_t hwmon_attr_store(struct device *dev, ...@@ -221,14 +238,10 @@ static ssize_t hwmon_attr_store(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
return count; trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type),
} hattr->name, val);
static int hwmon_attr_base(enum hwmon_sensor_types type) return count;
{
if (type == hwmon_in)
return 0;
return 1;
} }
static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
...@@ -356,6 +369,7 @@ static const char * const hwmon_in_attr_templates[] = { ...@@ -356,6 +369,7 @@ static const char * const hwmon_in_attr_templates[] = {
[hwmon_in_max_alarm] = "in%d_max_alarm", [hwmon_in_max_alarm] = "in%d_max_alarm",
[hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm", [hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm",
[hwmon_in_crit_alarm] = "in%d_crit_alarm", [hwmon_in_crit_alarm] = "in%d_crit_alarm",
[hwmon_in_enable] = "in%d_enable",
}; };
static const char * const hwmon_curr_attr_templates[] = { static const char * const hwmon_curr_attr_templates[] = {
......
...@@ -458,9 +458,6 @@ static int populate_attr_groups(struct platform_device *pdev) ...@@ -458,9 +458,6 @@ static int populate_attr_groups(struct platform_device *pdev)
for_each_child_of_node(opal, np) { for_each_child_of_node(opal, np) {
const char *label; const char *label;
if (np->name == NULL)
continue;
type = get_sensor_type(np); type = get_sensor_type(np);
if (type == MAX_SENSOR_TYPE) if (type == MAX_SENSOR_TYPE)
continue; continue;
...@@ -589,9 +586,6 @@ static int create_device_attrs(struct platform_device *pdev) ...@@ -589,9 +586,6 @@ static int create_device_attrs(struct platform_device *pdev)
const char *label; const char *label;
enum sensors type; enum sensors type;
if (np->name == NULL)
continue;
type = get_sensor_type(np); type = get_sensor_type(np);
if (type == MAX_SENSOR_TYPE) if (type == MAX_SENSOR_TYPE)
continue; continue;
...@@ -603,8 +597,8 @@ static int create_device_attrs(struct platform_device *pdev) ...@@ -603,8 +597,8 @@ static int create_device_attrs(struct platform_device *pdev)
if (of_property_read_u32(np, "sensor-id", &sensor_id) && if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
of_property_read_u32(np, "sensor-data", &sensor_id)) { of_property_read_u32(np, "sensor-data", &sensor_id)) {
dev_info(&pdev->dev, dev_info(&pdev->dev,
"'sensor-id' missing in the node '%s'\n", "'sensor-id' missing in the node '%pOFn'\n",
np->name); np);
continue; continue;
} }
......
...@@ -65,13 +65,9 @@ static int iio_hwmon_probe(struct platform_device *pdev) ...@@ -65,13 +65,9 @@ static int iio_hwmon_probe(struct platform_device *pdev)
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1; int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
enum iio_chan_type type; enum iio_chan_type type;
struct iio_channel *channels; struct iio_channel *channels;
const char *name = "iio_hwmon";
struct device *hwmon_dev; struct device *hwmon_dev;
char *sname; char *sname;
if (dev->of_node && dev->of_node->name)
name = dev->of_node->name;
channels = devm_iio_channel_get_all(dev); channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) { if (IS_ERR(channels)) {
if (PTR_ERR(channels) == -ENODEV) if (PTR_ERR(channels) == -ENODEV)
...@@ -141,11 +137,15 @@ static int iio_hwmon_probe(struct platform_device *pdev) ...@@ -141,11 +137,15 @@ static int iio_hwmon_probe(struct platform_device *pdev)
st->attr_group.attrs = st->attrs; st->attr_group.attrs = st->attrs;
st->groups[0] = &st->attr_group; st->groups[0] = &st->attr_group;
sname = devm_kstrdup(dev, name, GFP_KERNEL); if (dev->of_node) {
if (!sname) sname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
return -ENOMEM; if (!sname)
return -ENOMEM;
strreplace(sname, '-', '_');
} else {
sname = "iio_hwmon";
}
strreplace(sname, '-', '_');
hwmon_dev = devm_hwmon_device_register_with_groups(dev, sname, st, hwmon_dev = devm_hwmon_device_register_with_groups(dev, sname, st,
st->groups); st->groups);
return PTR_ERR_OR_ZERO(hwmon_dev); return PTR_ERR_OR_ZERO(hwmon_dev);
......
...@@ -38,9 +38,12 @@ ...@@ -38,9 +38,12 @@
#define INA3221_WARN3 0x0c #define INA3221_WARN3 0x0c
#define INA3221_MASK_ENABLE 0x0f #define INA3221_MASK_ENABLE 0x0f
#define INA3221_CONFIG_MODE_SHUNT BIT(1) #define INA3221_CONFIG_MODE_MASK GENMASK(2, 0)
#define INA3221_CONFIG_MODE_BUS BIT(2) #define INA3221_CONFIG_MODE_POWERDOWN 0
#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) #define INA3221_CONFIG_MODE_SHUNT BIT(0)
#define INA3221_CONFIG_MODE_BUS BIT(1)
#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2)
#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x))
#define INA3221_RSHUNT_DEFAULT 10000 #define INA3221_RSHUNT_DEFAULT 10000
...@@ -74,30 +77,37 @@ enum ina3221_channels { ...@@ -74,30 +77,37 @@ enum ina3221_channels {
INA3221_NUM_CHANNELS INA3221_NUM_CHANNELS
}; };
static const unsigned int register_channel[] = { /**
[INA3221_SHUNT1] = INA3221_CHANNEL1, * struct ina3221_input - channel input source specific information
[INA3221_SHUNT2] = INA3221_CHANNEL2, * @label: label of channel input source
[INA3221_SHUNT3] = INA3221_CHANNEL3, * @shunt_resistor: shunt resistor value of channel input source
[INA3221_CRIT1] = INA3221_CHANNEL1, * @disconnected: connection status of channel input source
[INA3221_CRIT2] = INA3221_CHANNEL2, */
[INA3221_CRIT3] = INA3221_CHANNEL3, struct ina3221_input {
[INA3221_WARN1] = INA3221_CHANNEL1, const char *label;
[INA3221_WARN2] = INA3221_CHANNEL2, int shunt_resistor;
[INA3221_WARN3] = INA3221_CHANNEL3, bool disconnected;
}; };
/** /**
* struct ina3221_data - device specific information * struct ina3221_data - device specific information
* @regmap: Register map of the device * @regmap: Register map of the device
* @fields: Register fields of the device * @fields: Register fields of the device
* @shunt_resistors: Array of resistor values per channel * @inputs: Array of channel input source specific structures
* @reg_config: Register value of INA3221_CONFIG
*/ */
struct ina3221_data { struct ina3221_data {
struct regmap *regmap; struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS]; struct regmap_field *fields[F_MAX_FIELDS];
int shunt_resistors[INA3221_NUM_CHANNELS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS];
u32 reg_config;
}; };
static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel)
{
return ina->reg_config & INA3221_CONFIG_CHx_EN(channel);
}
static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
int *val) int *val)
{ {
...@@ -113,107 +123,284 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, ...@@ -113,107 +123,284 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
return 0; return 0;
} }
static ssize_t ina3221_show_bus_voltage(struct device *dev, static const u8 ina3221_in_reg[] = {
struct device_attribute *attr, INA3221_BUS1,
char *buf) INA3221_BUS2,
INA3221_BUS3,
INA3221_SHUNT1,
INA3221_SHUNT2,
INA3221_SHUNT3,
};
static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val)
{ {
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); const bool is_shunt = channel > INA3221_CHANNEL3;
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int reg = sd_attr->index; u8 reg = ina3221_in_reg[channel];
int val, voltage_mv, ret; int regval, ret;
ret = ina3221_read_value(ina, reg, &val); /* Translate shunt channel index to sensor channel index */
if (ret) channel %= INA3221_NUM_CHANNELS;
return ret;
switch (attr) {
case hwmon_in_input:
if (!ina3221_is_enabled(ina, channel))
return -ENODATA;
ret = ina3221_read_value(ina, reg, &regval);
if (ret)
return ret;
/*
* Scale of shunt voltage (uV): LSB is 40uV
* Scale of bus voltage (mV): LSB is 8mV
*/
*val = regval * (is_shunt ? 40 : 8);
return 0;
case hwmon_in_enable:
*val = ina3221_is_enabled(ina, channel);
return 0;
default:
return -EOPNOTSUPP;
}
}
voltage_mv = val * 8; static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS] = {
[hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, INA3221_SHUNT3 },
[hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3 },
[hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, INA3221_CRIT3 },
[hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3 },
[hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3 },
};
return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv); static int ina3221_read_curr(struct device *dev, u32 attr,
int channel, long *val)
{
struct ina3221_data *ina = dev_get_drvdata(dev);
struct ina3221_input *input = &ina->inputs[channel];
int resistance_uo = input->shunt_resistor;
u8 reg = ina3221_curr_reg[attr][channel];
int regval, voltage_nv, ret;
switch (attr) {
case hwmon_curr_input:
if (!ina3221_is_enabled(ina, channel))
return -ENODATA;
/* fall through */
case hwmon_curr_crit:
case hwmon_curr_max:
ret = ina3221_read_value(ina, reg, &regval);
if (ret)
return ret;
/* Scale of shunt voltage: LSB is 40uV (40000nV) */
voltage_nv = regval * 40000;
/* Return current in mA */
*val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
return 0;
case hwmon_curr_crit_alarm:
case hwmon_curr_max_alarm:
ret = regmap_field_read(ina->fields[reg], &regval);
if (ret)
return ret;
*val = regval;
return 0;
default:
return -EOPNOTSUPP;
}
} }
static ssize_t ina3221_show_shunt_voltage(struct device *dev, static int ina3221_write_curr(struct device *dev, u32 attr,
struct device_attribute *attr, int channel, long val)
char *buf)
{ {
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int reg = sd_attr->index; struct ina3221_input *input = &ina->inputs[channel];
int val, voltage_uv, ret; int resistance_uo = input->shunt_resistor;
u8 reg = ina3221_curr_reg[attr][channel];
int regval, current_ma, voltage_uv;
ret = ina3221_read_value(ina, reg, &val); /* clamp current */
if (ret) current_ma = clamp_val(val,
return ret; INT_MIN / resistance_uo,
voltage_uv = val * 40; INT_MAX / resistance_uo);
voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv); /* clamp voltage */
voltage_uv = clamp_val(voltage_uv, -163800, 163800);
/* 1 / 40uV(scale) << 3(register shift) = 5 */
regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
return regmap_write(ina->regmap, reg, regval);
} }
static ssize_t ina3221_show_current(struct device *dev, static int ina3221_write_enable(struct device *dev, int channel, bool enable)
struct device_attribute *attr, char *buf)
{ {
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int reg = sd_attr->index; u16 config, mask = INA3221_CONFIG_CHx_EN(channel);
unsigned int channel = register_channel[reg]; int ret;
int resistance_uo = ina->shunt_resistors[channel];
int val, current_ma, voltage_nv, ret;
ret = ina3221_read_value(ina, reg, &val); config = enable ? mask : 0;
/* Enable or disable the channel */
ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config);
if (ret) if (ret)
return ret; return ret;
voltage_nv = val * 40000;
current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); /* Cache the latest config register value */
ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
if (ret)
return ret;
return snprintf(buf, PAGE_SIZE, "%d\n", current_ma); return 0;
} }
static ssize_t ina3221_set_current(struct device *dev, static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
struct device_attribute *attr, u32 attr, int channel, long *val)
const char *buf, size_t count) {
switch (type) {
case hwmon_in:
/* 0-align channel ID */
return ina3221_read_in(dev, attr, channel - 1, val);
case hwmon_curr:
return ina3221_read_curr(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
switch (type) {
case hwmon_in:
/* 0-align channel ID */
return ina3221_write_enable(dev, channel - 1, val);
case hwmon_curr:
return ina3221_write_curr(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{ {
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int reg = sd_attr->index; int index = channel - 1;
unsigned int channel = register_channel[reg];
int resistance_uo = ina->shunt_resistors[channel];
int val, current_ma, voltage_uv, ret;
ret = kstrtoint(buf, 0, &current_ma); *str = ina->inputs[index].label;
if (ret)
return ret;
/* clamp current */ return 0;
current_ma = clamp_val(current_ma, }
INT_MIN / resistance_uo,
INT_MAX / resistance_uo);
voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); static umode_t ina3221_is_visible(const void *drvdata,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
const struct ina3221_data *ina = drvdata;
const struct ina3221_input *input = NULL;
switch (type) {
case hwmon_in:
/* Ignore in0_ */
if (channel == 0)
return 0;
switch (attr) {
case hwmon_in_label:
if (channel - 1 <= INA3221_CHANNEL3)
input = &ina->inputs[channel - 1];
/* Hide label node if label is not provided */
return (input && input->label) ? 0444 : 0;
case hwmon_in_input:
return 0444;
case hwmon_in_enable:
return 0644;
default:
return 0;
}
case hwmon_curr:
switch (attr) {
case hwmon_curr_input:
case hwmon_curr_crit_alarm:
case hwmon_curr_max_alarm:
return 0444;
case hwmon_curr_crit:
case hwmon_curr_max:
return 0644;
default:
return 0;
}
default:
return 0;
}
}
/* clamp voltage */ static const u32 ina3221_in_config[] = {
voltage_uv = clamp_val(voltage_uv, -163800, 163800); /* 0: dummy, skipped in is_visible */
HWMON_I_INPUT,
/* 1-3: input voltage Channels */
HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
/* 4-6: shunt voltage Channels */
HWMON_I_INPUT,
HWMON_I_INPUT,
HWMON_I_INPUT,
0
};
/* 1 / 40uV(scale) << 3(register shift) = 5 */ static const struct hwmon_channel_info ina3221_in = {
val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; .type = hwmon_in,
.config = ina3221_in_config,
};
ret = regmap_write(ina->regmap, reg, val); #define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \
if (ret) HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \
return ret; HWMON_C_MAX | HWMON_C_MAX_ALARM)
return count; static const u32 ina3221_curr_config[] = {
} INA3221_HWMON_CURR_CONFIG,
INA3221_HWMON_CURR_CONFIG,
INA3221_HWMON_CURR_CONFIG,
0
};
static const struct hwmon_channel_info ina3221_curr = {
.type = hwmon_curr,
.config = ina3221_curr_config,
};
static const struct hwmon_channel_info *ina3221_info[] = {
&ina3221_in,
&ina3221_curr,
NULL
};
static const struct hwmon_ops ina3221_hwmon_ops = {
.is_visible = ina3221_is_visible,
.read_string = ina3221_read_string,
.read = ina3221_read,
.write = ina3221_write,
};
static const struct hwmon_chip_info ina3221_chip_info = {
.ops = &ina3221_hwmon_ops,
.info = ina3221_info,
};
/* Extra attribute groups */
static ssize_t ina3221_show_shunt(struct device *dev, static ssize_t ina3221_show_shunt(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int channel = sd_attr->index; unsigned int channel = sd_attr->index;
unsigned int resistance_uo; struct ina3221_input *input = &ina->inputs[channel];
resistance_uo = ina->shunt_resistors[channel];
return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo); return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor);
} }
static ssize_t ina3221_set_shunt(struct device *dev, static ssize_t ina3221_set_shunt(struct device *dev,
...@@ -223,6 +410,7 @@ static ssize_t ina3221_set_shunt(struct device *dev, ...@@ -223,6 +410,7 @@ static ssize_t ina3221_set_shunt(struct device *dev,
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev); struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int channel = sd_attr->index; unsigned int channel = sd_attr->index;
struct ina3221_input *input = &ina->inputs[channel];
int val; int val;
int ret; int ret;
...@@ -232,43 +420,11 @@ static ssize_t ina3221_set_shunt(struct device *dev, ...@@ -232,43 +420,11 @@ static ssize_t ina3221_set_shunt(struct device *dev,
val = clamp_val(val, 1, INT_MAX); val = clamp_val(val, 1, INT_MAX);
ina->shunt_resistors[channel] = val; input->shunt_resistor = val;
return count; return count;
} }
static ssize_t ina3221_show_alert(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int field = sd_attr->index;
unsigned int regval;
int ret;
ret = regmap_field_read(ina->fields[field], &regval);
if (ret)
return ret;
return snprintf(buf, PAGE_SIZE, "%d\n", regval);
}
/* bus voltage */
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO,
ina3221_show_bus_voltage, NULL, INA3221_BUS1);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO,
ina3221_show_bus_voltage, NULL, INA3221_BUS2);
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO,
ina3221_show_bus_voltage, NULL, INA3221_BUS3);
/* calculated current */
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO,
ina3221_show_current, NULL, INA3221_SHUNT1);
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO,
ina3221_show_current, NULL, INA3221_SHUNT2);
static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO,
ina3221_show_current, NULL, INA3221_SHUNT3);
/* shunt resistance */ /* shunt resistance */
static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1); ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
...@@ -277,83 +433,16 @@ static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR, ...@@ -277,83 +433,16 @@ static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3); ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3);
/* critical current */
static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_CRIT1);
static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_CRIT2);
static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_CRIT3);
/* critical current alert */
static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_CF1);
static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_CF2);
static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_CF3);
/* warning current */
static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_WARN1);
static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_WARN2);
static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR,
ina3221_show_current, ina3221_set_current, INA3221_WARN3);
/* warning current alert */
static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_WF1);
static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_WF2);
static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO,
ina3221_show_alert, NULL, F_WF3);
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO,
ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1);
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2);
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
static struct attribute *ina3221_attrs[] = { static struct attribute *ina3221_attrs[] = {
/* channel 1 */
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_shunt1_resistor.dev_attr.attr, &sensor_dev_attr_shunt1_resistor.dev_attr.attr,
&sensor_dev_attr_curr1_crit.dev_attr.attr,
&sensor_dev_attr_curr1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_curr1_max.dev_attr.attr,
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
/* channel 2 */
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_curr2_input.dev_attr.attr,
&sensor_dev_attr_shunt2_resistor.dev_attr.attr, &sensor_dev_attr_shunt2_resistor.dev_attr.attr,
&sensor_dev_attr_curr2_crit.dev_attr.attr,
&sensor_dev_attr_curr2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_curr2_max.dev_attr.attr,
&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
/* channel 3 */
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_curr3_input.dev_attr.attr,
&sensor_dev_attr_shunt3_resistor.dev_attr.attr, &sensor_dev_attr_shunt3_resistor.dev_attr.attr,
&sensor_dev_attr_curr3_crit.dev_attr.attr,
&sensor_dev_attr_curr3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_curr3_max.dev_attr.attr,
&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(ina3221); ATTRIBUTE_GROUPS(ina3221);
static const struct regmap_range ina3221_yes_ranges[] = { static const struct regmap_range ina3221_yes_ranges[] = {
regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3), regmap_reg_range(INA3221_CONFIG, INA3221_BUS3),
regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
}; };
...@@ -370,6 +459,66 @@ static const struct regmap_config ina3221_regmap_config = { ...@@ -370,6 +459,66 @@ static const struct regmap_config ina3221_regmap_config = {
.volatile_table = &ina3221_volatile_table, .volatile_table = &ina3221_volatile_table,
}; };
static int ina3221_probe_child_from_dt(struct device *dev,
struct device_node *child,
struct ina3221_data *ina)
{
struct ina3221_input *input;
u32 val;
int ret;
ret = of_property_read_u32(child, "reg", &val);
if (ret) {
dev_err(dev, "missing reg property of %s\n", child->name);
return ret;
} else if (val > INA3221_CHANNEL3) {
dev_err(dev, "invalid reg %d of %s\n", val, child->name);
return ret;
}
input = &ina->inputs[val];
/* Log the disconnected channel input */
if (!of_device_is_available(child)) {
input->disconnected = true;
return 0;
}
/* Save the connected input label if available */
of_property_read_string(child, "label", &input->label);
/* Overwrite default shunt resistor value optionally */
if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) {
if (val < 1 || val > INT_MAX) {
dev_err(dev, "invalid shunt resistor value %u of %s\n",
val, child->name);
return -EINVAL;
}
input->shunt_resistor = val;
}
return 0;
}
static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
{
const struct device_node *np = dev->of_node;
struct device_node *child;
int ret;
/* Compatible with non-DT platforms */
if (!np)
return 0;
for_each_child_of_node(np, child) {
ret = ina3221_probe_child_from_dt(dev, child, ina);
if (ret)
return ret;
}
return 0;
}
static int ina3221_probe(struct i2c_client *client, static int ina3221_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -399,7 +548,13 @@ static int ina3221_probe(struct i2c_client *client, ...@@ -399,7 +548,13 @@ static int ina3221_probe(struct i2c_client *client,
} }
for (i = 0; i < INA3221_NUM_CHANNELS; i++) for (i = 0; i < INA3221_NUM_CHANNELS; i++)
ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT; ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT;
ret = ina3221_probe_from_dt(dev, ina);
if (ret) {
dev_err(dev, "Unable to probe from device tree\n");
return ret;
}
ret = regmap_field_write(ina->fields[F_RST], true); ret = regmap_field_write(ina->fields[F_RST], true);
if (ret) { if (ret) {
...@@ -407,9 +562,25 @@ static int ina3221_probe(struct i2c_client *client, ...@@ -407,9 +562,25 @@ static int ina3221_probe(struct i2c_client *client,
return ret; return ret;
} }
hwmon_dev = devm_hwmon_device_register_with_groups(dev, /* Sync config register after reset */
client->name, ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
ina, ina3221_groups); if (ret)
return ret;
/* Disable channels if their inputs are disconnected */
for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
if (ina->inputs[i].disconnected)
ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i);
}
ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
if (ret)
return ret;
dev_set_drvdata(dev, ina);
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina,
&ina3221_chip_info,
ina3221_groups);
if (IS_ERR(hwmon_dev)) { if (IS_ERR(hwmon_dev)) {
dev_err(dev, "Unable to register hwmon device\n"); dev_err(dev, "Unable to register hwmon device\n");
return PTR_ERR(hwmon_dev); return PTR_ERR(hwmon_dev);
...@@ -418,6 +589,60 @@ static int ina3221_probe(struct i2c_client *client, ...@@ -418,6 +589,60 @@ static int ina3221_probe(struct i2c_client *client,
return 0; return 0;
} }
static int __maybe_unused ina3221_suspend(struct device *dev)
{
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret;
/* Save config register value and enable cache-only */
ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
if (ret)
return ret;
/* Set to power-down mode for power saving */
ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
INA3221_CONFIG_MODE_MASK,
INA3221_CONFIG_MODE_POWERDOWN);
if (ret)
return ret;
regcache_cache_only(ina->regmap, true);
regcache_mark_dirty(ina->regmap);
return 0;
}
static int __maybe_unused ina3221_resume(struct device *dev)
{
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret;
regcache_cache_only(ina->regmap, false);
/* Software reset the chip */
ret = regmap_field_write(ina->fields[F_RST], true);
if (ret) {
dev_err(dev, "Unable to reset device\n");
return ret;
}
/* Restore cached register values to hardware */
ret = regcache_sync(ina->regmap);
if (ret)
return ret;
/* Restore config register value to hardware */
ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
if (ret)
return ret;
return 0;
}
static const struct dev_pm_ops ina3221_pm = {
SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume)
};
static const struct of_device_id ina3221_of_match_table[] = { static const struct of_device_id ina3221_of_match_table[] = {
{ .compatible = "ti,ina3221", }, { .compatible = "ti,ina3221", },
{ /* sentinel */ } { /* sentinel */ }
...@@ -435,6 +660,7 @@ static struct i2c_driver ina3221_i2c_driver = { ...@@ -435,6 +660,7 @@ static struct i2c_driver ina3221_i2c_driver = {
.driver = { .driver = {
.name = INA3221_DRIVER_NAME, .name = INA3221_DRIVER_NAME,
.of_match_table = ina3221_of_match_table, .of_match_table = ina3221_of_match_table,
.pm = &ina3221_pm,
}, },
.id_table = ina3221_ids, .id_table = ina3221_ids,
}; };
......
...@@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev, ...@@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev,
data->pdev = pdev; data->pdev = pdev;
if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 || if (boot_cpu_data.x86 == 0x15 &&
boot_cpu_data.x86_model == 0x70)) { ((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
(boot_cpu_data.x86_model & 0xf0) == 0x70)) {
data->read_htcreg = read_htcreg_nb_f15; data->read_htcreg = read_htcreg_nb_f15;
data->read_tempreg = read_tempreg_nb_f15; data->read_tempreg = read_tempreg_nb_f15;
} else if (boot_cpu_data.x86 == 0x17) { } else if (boot_cpu_data.x86 == 0x17) {
......
...@@ -47,6 +47,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ ...@@ -47,6 +47,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
lm75b, lm75b,
max6625, max6625,
max6626, max6626,
max31725,
mcp980x, mcp980x,
stds75, stds75,
tcn75, tcn75,
...@@ -64,7 +65,6 @@ enum lm75_type { /* keep sorted in alphabetical order */ ...@@ -64,7 +65,6 @@ enum lm75_type { /* keep sorted in alphabetical order */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* The LM75 registers */ /* The LM75 registers */
#define LM75_REG_TEMP 0x00 #define LM75_REG_TEMP 0x00
#define LM75_REG_CONF 0x01 #define LM75_REG_CONF 0x01
...@@ -76,7 +76,7 @@ struct lm75_data { ...@@ -76,7 +76,7 @@ struct lm75_data {
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap; struct regmap *regmap;
u8 orig_conf; u8 orig_conf;
u8 resolution; /* In bits, between 9 and 12 */ u8 resolution; /* In bits, between 9 and 16 */
u8 resolution_limits; u8 resolution_limits;
unsigned int sample_time; /* In ms */ unsigned int sample_time; /* In ms */
}; };
...@@ -339,6 +339,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -339,6 +339,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->resolution_limits = 9; data->resolution_limits = 9;
data->sample_time = MSEC_PER_SEC / 4; data->sample_time = MSEC_PER_SEC / 4;
break; break;
case max31725:
data->resolution = 16;
data->sample_time = MSEC_PER_SEC / 8;
break;
case tcn75: case tcn75:
data->resolution = 9; data->resolution = 9;
data->sample_time = MSEC_PER_SEC / 8; data->sample_time = MSEC_PER_SEC / 8;
...@@ -415,6 +419,8 @@ static const struct i2c_device_id lm75_ids[] = { ...@@ -415,6 +419,8 @@ static const struct i2c_device_id lm75_ids[] = {
{ "lm75b", lm75b, }, { "lm75b", lm75b, },
{ "max6625", max6625, }, { "max6625", max6625, },
{ "max6626", max6626, }, { "max6626", max6626, },
{ "max31725", max31725, },
{ "max31726", max31725, },
{ "mcp980x", mcp980x, }, { "mcp980x", mcp980x, },
{ "stds75", stds75, }, { "stds75", stds75, },
{ "tcn75", tcn75, }, { "tcn75", tcn75, },
...@@ -471,6 +477,14 @@ static const struct of_device_id lm75_of_match[] = { ...@@ -471,6 +477,14 @@ static const struct of_device_id lm75_of_match[] = {
.compatible = "maxim,max6626", .compatible = "maxim,max6626",
.data = (void *)max6626 .data = (void *)max6626
}, },
{
.compatible = "maxim,max31725",
.data = (void *)max31725
},
{
.compatible = "maxim,max31726",
.data = (void *)max31725
},
{ {
.compatible = "maxim,mcp980x", .compatible = "maxim,mcp980x",
.data = (void *)mcp980x .data = (void *)mcp980x
......
...@@ -127,8 +127,8 @@ static struct lm92_data *lm92_update_device(struct device *dev) ...@@ -127,8 +127,8 @@ static struct lm92_data *lm92_update_device(struct device *dev)
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) if (time_after(jiffies, data->last_updated + HZ) ||
|| !data->valid) { !data->valid) {
dev_dbg(&client->dev, "Updating lm92 data\n"); dev_dbg(&client->dev, "Updating lm92 data\n");
for (i = 0; i < t_num_regs; i++) { for (i = 0; i < t_num_regs; i++) {
data->temp[i] = data->temp[i] =
...@@ -153,7 +153,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, ...@@ -153,7 +153,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
} }
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm92_data *data = dev_get_drvdata(dev); struct lm92_data *data = dev_get_drvdata(dev);
...@@ -161,7 +161,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, ...@@ -161,7 +161,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
int nr = attr->index; int nr = attr->index;
long val; long val;
int err; int err;
err = kstrtol(buf, 10, &val); err = kstrtol(buf, 10, &val);
if (err) if (err)
return err; return err;
...@@ -178,6 +178,7 @@ static ssize_t show_temp_hyst(struct device *dev, ...@@ -178,6 +178,7 @@ static ssize_t show_temp_hyst(struct device *dev,
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm92_data *data = lm92_update_device(dev); struct lm92_data *data = lm92_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
- TEMP_FROM_REG(data->temp[t_hyst])); - TEMP_FROM_REG(data->temp[t_hyst]));
} }
...@@ -186,6 +187,7 @@ static ssize_t temp1_min_hyst_show(struct device *dev, ...@@ -186,6 +187,7 @@ static ssize_t temp1_min_hyst_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct lm92_data *data = lm92_update_device(dev); struct lm92_data *data = lm92_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
+ TEMP_FROM_REG(data->temp[t_hyst])); + TEMP_FROM_REG(data->temp[t_hyst]));
} }
...@@ -206,7 +208,7 @@ static ssize_t set_temp_hyst(struct device *dev, ...@@ -206,7 +208,7 @@ static ssize_t set_temp_hyst(struct device *dev,
val = clamp_val(val, -120000, 220000); val = clamp_val(val, -120000, 220000);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->temp[t_hyst] = data->temp[t_hyst] =
TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val); TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val);
i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
data->temp[t_hyst]); data->temp[t_hyst]);
...@@ -218,6 +220,7 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, ...@@ -218,6 +220,7 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct lm92_data *data = lm92_update_device(dev); struct lm92_data *data = lm92_update_device(dev);
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));
} }
...@@ -324,7 +327,6 @@ static int lm92_probe(struct i2c_client *new_client, ...@@ -324,7 +327,6 @@ static int lm92_probe(struct i2c_client *new_client,
return PTR_ERR_OR_ZERO(hwmon_dev); return PTR_ERR_OR_ZERO(hwmon_dev);
} }
/* /*
* Module and driver stuff * Module and driver stuff
*/ */
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs. * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
* *
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2009 Sascha Hauer, Pengutronix * Copyright (C) 2009 Sascha Hauer, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <linux/mfd/mc13xxx.h> #include <linux/mfd/mc13xxx.h>
......
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
* nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
* nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
* nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
* nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3
* (0xd451)
* nct6798d 14 7 7 2+6 0xd458 0xc1 0x5ca3
* (0xd459)
* *
* #temp lists the number of monitored temperature sources (first value) plus * #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value). * the number of directly connectable temperature sensors (second value).
...@@ -69,7 +73,7 @@ ...@@ -69,7 +73,7 @@
#define USE_ALTERNATE #define USE_ALTERNATE
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
nct6795, nct6796 }; nct6795, nct6796, nct6797, nct6798 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */ /* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = { static const char * const nct6775_device_names[] = {
...@@ -82,6 +86,8 @@ static const char * const nct6775_device_names[] = { ...@@ -82,6 +86,8 @@ static const char * const nct6775_device_names[] = {
"nct6793", "nct6793",
"nct6795", "nct6795",
"nct6796", "nct6796",
"nct6797",
"nct6798",
}; };
static const char * const nct6775_sio_names[] __initconst = { static const char * const nct6775_sio_names[] __initconst = {
...@@ -94,6 +100,8 @@ static const char * const nct6775_sio_names[] __initconst = { ...@@ -94,6 +100,8 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6793D", "NCT6793D",
"NCT6795D", "NCT6795D",
"NCT6796D", "NCT6796D",
"NCT6797D",
"NCT6798D",
}; };
static unsigned short force_id; static unsigned short force_id;
...@@ -129,7 +137,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); ...@@ -129,7 +137,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6793_ID 0xd120 #define SIO_NCT6793_ID 0xd120
#define SIO_NCT6795_ID 0xd350 #define SIO_NCT6795_ID 0xd350
#define SIO_NCT6796_ID 0xd420 #define SIO_NCT6796_ID 0xd420
#define SIO_ID_MASK 0xFFF0 #define SIO_NCT6797_ID 0xd450
#define SIO_NCT6798_ID 0xd458
#define SIO_ID_MASK 0xFFF8
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
...@@ -504,7 +514,7 @@ static const s8 NCT6779_BEEP_BITS[] = { ...@@ -504,7 +514,7 @@ static const s8 NCT6779_BEEP_BITS[] = {
static const u16 NCT6779_REG_FAN[] = { static const u16 NCT6779_REG_FAN[] = {
0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce }; 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = { static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
0x644, 0x645, 0x646, 0x647, 0x648, 0x649 }; 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = { static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 }; 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
...@@ -704,10 +714,10 @@ static const char *const nct6795_temp_label[] = { ...@@ -704,10 +714,10 @@ static const char *const nct6795_temp_label[] = {
"PCH_CHIP_TEMP", "PCH_CHIP_TEMP",
"PCH_CPU_TEMP", "PCH_CPU_TEMP",
"PCH_MCH_TEMP", "PCH_MCH_TEMP",
"PCH_DIM0_TEMP", "Agent0 Dimm0",
"PCH_DIM1_TEMP", "Agent0 Dimm1",
"PCH_DIM2_TEMP", "Agent1 Dimm0",
"PCH_DIM3_TEMP", "Agent1 Dimm1",
"BYTE_TEMP0", "BYTE_TEMP0",
"BYTE_TEMP1", "BYTE_TEMP1",
"PECI Agent 0 Calibration", "PECI Agent 0 Calibration",
...@@ -742,10 +752,10 @@ static const char *const nct6796_temp_label[] = { ...@@ -742,10 +752,10 @@ static const char *const nct6796_temp_label[] = {
"PCH_CHIP_TEMP", "PCH_CHIP_TEMP",
"PCH_CPU_TEMP", "PCH_CPU_TEMP",
"PCH_MCH_TEMP", "PCH_MCH_TEMP",
"PCH_DIM0_TEMP", "Agent0 Dimm0",
"PCH_DIM1_TEMP", "Agent0 Dimm1",
"PCH_DIM2_TEMP", "Agent1 Dimm0",
"PCH_DIM3_TEMP", "Agent1 Dimm1",
"BYTE_TEMP0", "BYTE_TEMP0",
"BYTE_TEMP1", "BYTE_TEMP1",
"PECI Agent 0 Calibration", "PECI Agent 0 Calibration",
...@@ -757,6 +767,44 @@ static const char *const nct6796_temp_label[] = { ...@@ -757,6 +767,44 @@ static const char *const nct6796_temp_label[] = {
#define NCT6796_TEMP_MASK 0xbfff0ffe #define NCT6796_TEMP_MASK 0xbfff0ffe
#define NCT6796_VIRT_TEMP_MASK 0x80000c00 #define NCT6796_VIRT_TEMP_MASK 0x80000c00
static const char *const nct6798_temp_label[] = {
"",
"SYSTIN",
"CPUTIN",
"AUXTIN0",
"AUXTIN1",
"AUXTIN2",
"AUXTIN3",
"AUXTIN4",
"SMBUSMASTER 0",
"SMBUSMASTER 1",
"Virtual_TEMP",
"Virtual_TEMP",
"",
"",
"",
"",
"PECI Agent 0",
"PECI Agent 1",
"PCH_CHIP_CPU_MAX_TEMP",
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
"Agent0 Dimm0",
"Agent0 Dimm1",
"Agent1 Dimm0",
"Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
"",
"",
"",
"Virtual_TEMP"
};
#define NCT6798_TEMP_MASK 0x8fff0ffe
#define NCT6798_VIRT_TEMP_MASK 0x80000c00
/* NCT6102D/NCT6106D specific data */ /* NCT6102D/NCT6106D specific data */
#define NCT6106_REG_VBAT 0x318 #define NCT6106_REG_VBAT 0x318
...@@ -1288,6 +1336,8 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) ...@@ -1288,6 +1336,8 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
return reg == 0x150 || reg == 0x153 || reg == 0x155 || return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
(reg & 0xfff0) == 0x4c0 || (reg & 0xfff0) == 0x4c0 ||
reg == 0x402 || reg == 0x402 ||
...@@ -1643,6 +1693,8 @@ static void nct6775_update_pwm_limits(struct device *dev) ...@@ -1643,6 +1693,8 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]); data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK) if (reg & data->CRITICAL_PWM_ENABLE_MASK)
...@@ -2847,6 +2899,8 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr, ...@@ -2847,6 +2899,8 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr,
* Fan speed tolerance is a tricky beast, since the associated register is * Fan speed tolerance is a tricky beast, since the associated register is
* a tick counter, but the value is reported and configured as rpm. * a tick counter, but the value is reported and configured as rpm.
* Compute resulting low and high rpm values and report the difference. * Compute resulting low and high rpm values and report the difference.
* A fan speed tolerance only makes sense if a fan target speed has been
* configured, so only display values other than 0 if that is the case.
*/ */
static ssize_t static ssize_t
show_speed_tolerance(struct device *dev, struct device_attribute *attr, show_speed_tolerance(struct device *dev, struct device_attribute *attr,
...@@ -2855,19 +2909,23 @@ show_speed_tolerance(struct device *dev, struct device_attribute *attr, ...@@ -2855,19 +2909,23 @@ show_speed_tolerance(struct device *dev, struct device_attribute *attr,
struct nct6775_data *data = nct6775_update_device(dev); struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index; int nr = sattr->index;
int low = data->target_speed[nr] - data->target_speed_tolerance[nr]; int target = data->target_speed[nr];
int high = data->target_speed[nr] + data->target_speed_tolerance[nr]; int tolerance = 0;
int tolerance;
if (target) {
if (low <= 0) int low = target - data->target_speed_tolerance[nr];
low = 1; int high = target + data->target_speed_tolerance[nr];
if (high > 0xffff)
high = 0xffff; if (low <= 0)
if (high < low) low = 1;
high = low; if (high > 0xffff)
high = 0xffff;
tolerance = (fan_from_reg16(low, data->fan_div[nr]) if (high < low)
- fan_from_reg16(high, data->fan_div[nr])) / 2; high = low;
tolerance = (fan_from_reg16(low, data->fan_div[nr])
- fan_from_reg16(high, data->fan_div[nr])) / 2;
}
return sprintf(buf, "%d\n", tolerance); return sprintf(buf, "%d\n", tolerance);
} }
...@@ -3071,6 +3129,8 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, ...@@ -3071,6 +3129,8 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val); val);
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
...@@ -3430,7 +3490,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3430,7 +3490,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
bool pwm3pin = false, pwm4pin = false, pwm5pin = false; bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
bool pwm6pin = false, pwm7pin = false; bool pwm6pin = false, pwm7pin = false;
int sioreg = data->sioreg; int sioreg = data->sioreg;
int regval;
/* Store SIO_REG_ENABLE for use during resume */ /* Store SIO_REG_ENABLE for use during resume */
superio_select(sioreg, NCT6775_LD_HWM); superio_select(sioreg, NCT6775_LD_HWM);
...@@ -3438,10 +3497,10 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3438,10 +3497,10 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
/* fan4 and fan5 share some pins with the GPIO and serial flash */ /* fan4 and fan5 share some pins with the GPIO and serial flash */
if (data->kind == nct6775) { if (data->kind == nct6775) {
regval = superio_inb(sioreg, 0x2c); int cr2c = superio_inb(sioreg, 0x2c);
fan3pin = regval & BIT(6); fan3pin = cr2c & BIT(6);
pwm3pin = regval & BIT(7); pwm3pin = cr2c & BIT(7);
/* On NCT6775, fan4 shares pins with the fdc interface */ /* On NCT6775, fan4 shares pins with the fdc interface */
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
...@@ -3486,85 +3545,130 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3486,85 +3545,130 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
fan4min = fan4pin; fan4min = fan4pin;
pwm3pin = fan3pin; pwm3pin = fan3pin;
} else if (data->kind == nct6106) { } else if (data->kind == nct6106) {
regval = superio_inb(sioreg, 0x24); int cr24 = superio_inb(sioreg, 0x24);
fan3pin = !(regval & 0x80);
pwm3pin = regval & 0x08;
} else {
/* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
int regval_1b, regval_2a, regval_2f;
bool dsw_en;
regval = superio_inb(sioreg, 0x1c);
fan3pin = !(regval & BIT(5)); fan3pin = !(cr24 & 0x80);
fan4pin = !(regval & BIT(6)); pwm3pin = cr24 & 0x08;
fan5pin = !(regval & BIT(7)); } else {
/*
pwm3pin = !(regval & BIT(0)); * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
pwm4pin = !(regval & BIT(1)); * NCT6797D, NCT6798D
pwm5pin = !(regval & BIT(2)); */
int cr1a = superio_inb(sioreg, 0x1a);
int cr1b = superio_inb(sioreg, 0x1b);
int cr1c = superio_inb(sioreg, 0x1c);
int cr1d = superio_inb(sioreg, 0x1d);
int cr2a = superio_inb(sioreg, 0x2a);
int cr2b = superio_inb(sioreg, 0x2b);
int cr2d = superio_inb(sioreg, 0x2d);
int cr2f = superio_inb(sioreg, 0x2f);
bool dsw_en = cr2f & BIT(3);
bool ddr4_en = cr2f & BIT(4);
int cre0;
int creb;
int cred;
superio_select(sioreg, NCT6775_LD_12);
cre0 = superio_inb(sioreg, 0xe0);
creb = superio_inb(sioreg, 0xeb);
cred = superio_inb(sioreg, 0xed);
fan3pin = !(cr1c & BIT(5));
fan4pin = !(cr1c & BIT(6));
fan5pin = !(cr1c & BIT(7));
pwm3pin = !(cr1c & BIT(0));
pwm4pin = !(cr1c & BIT(1));
pwm5pin = !(cr1c & BIT(2));
regval = superio_inb(sioreg, 0x2d);
switch (data->kind) { switch (data->kind) {
case nct6791: case nct6791:
fan6pin = cr2d & BIT(1);
pwm6pin = cr2d & BIT(0);
break;
case nct6792: case nct6792:
fan6pin = regval & BIT(1); fan6pin = !dsw_en && (cr2d & BIT(1));
pwm6pin = regval & BIT(0); pwm6pin = !dsw_en && (cr2d & BIT(0));
break; break;
case nct6793: case nct6793:
fan5pin |= cr1b & BIT(5);
fan5pin |= creb & BIT(5);
fan6pin = creb & BIT(3);
pwm5pin |= cr2d & BIT(7);
pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
pwm6pin = !dsw_en && (cr2d & BIT(0));
pwm6pin |= creb & BIT(2);
break;
case nct6795: case nct6795:
fan5pin |= cr1b & BIT(5);
fan5pin |= creb & BIT(5);
fan6pin = (cr2a & BIT(4)) &&
(!dsw_en || (cred & BIT(4)));
fan6pin |= creb & BIT(3);
pwm5pin |= cr2d & BIT(7);
pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
pwm6pin |= creb & BIT(2);
break;
case nct6796: case nct6796:
regval_1b = superio_inb(sioreg, 0x1b); fan5pin |= cr1b & BIT(5);
regval_2a = superio_inb(sioreg, 0x2a); fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
regval_2f = superio_inb(sioreg, 0x2f); fan5pin |= creb & BIT(5);
dsw_en = regval_2f & BIT(3);
if (!pwm5pin) fan6pin = (cr2a & BIT(4)) &&
pwm5pin = regval & BIT(7); (!dsw_en || (cred & BIT(4)));
fan6pin |= creb & BIT(3);
if (!fan5pin) fan7pin = !(cr2b & BIT(2));
fan5pin = regval_1b & BIT(5);
superio_select(sioreg, NCT6775_LD_12); pwm5pin |= cr2d & BIT(7);
if (data->kind != nct6796) { pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
int regval_eb = superio_inb(sioreg, 0xeb); pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
if (!dsw_en) { pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
fan6pin = regval & BIT(1); pwm6pin |= creb & BIT(2);
pwm6pin = regval & BIT(0);
}
if (!fan5pin) pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
fan5pin = regval_eb & BIT(5); break;
if (!pwm5pin) case nct6797:
pwm5pin = (regval_eb & BIT(4)) && fan5pin |= !ddr4_en && (cr1b & BIT(5));
!(regval_2a & BIT(0)); fan5pin |= creb & BIT(5);
if (!fan6pin)
fan6pin = regval_eb & BIT(3);
if (!pwm6pin)
pwm6pin = regval_eb & BIT(2);
}
if (data->kind == nct6795 || data->kind == nct6796) { fan6pin = cr2a & BIT(4);
int regval_ed = superio_inb(sioreg, 0xed); fan6pin |= creb & BIT(3);
if (!fan6pin) fan7pin = cr1a & BIT(1);
fan6pin = (regval_2a & BIT(4)) &&
(!dsw_en ||
(dsw_en && (regval_ed & BIT(4))));
if (!pwm6pin)
pwm6pin = (regval_2a & BIT(3)) &&
(regval_ed & BIT(2));
}
if (data->kind == nct6796) { pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
int regval_1d = superio_inb(sioreg, 0x1d); pwm5pin |= !ddr4_en && (cr2d & BIT(7));
int regval_2b = superio_inb(sioreg, 0x2b);
fan7pin = !(regval_2b & BIT(2)); pwm6pin = creb & BIT(2);
pwm7pin = !(regval_1d & (BIT(2) | BIT(3))); pwm6pin |= cred & BIT(2);
}
pwm7pin = cr1d & BIT(4);
break;
case nct6798:
fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
fan6pin |= cr2a & BIT(4);
fan6pin |= creb & BIT(5);
fan7pin = cr1b & BIT(5);
fan7pin |= !(cr2b & BIT(2));
fan7pin |= creb & BIT(3);
pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
pwm7pin |= cr2d & BIT(7);
pwm7pin |= creb & BIT(2);
break; break;
default: /* NCT6779D */ default: /* NCT6779D */
break; break;
...@@ -3943,8 +4047,12 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3943,8 +4047,12 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
data->in_num = 15; data->in_num = 15;
data->pwm_num = (data->kind == nct6796) ? 7 : 6; data->pwm_num = (data->kind == nct6796 ||
data->kind == nct6797 ||
data->kind == nct6798) ? 7 : 6;
data->auto_pwm_num = 4; data->auto_pwm_num = 4;
data->has_fan_div = false; data->has_fan_div = false;
data->temp_fixed_num = 6; data->temp_fixed_num = 6;
...@@ -3978,6 +4086,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3978,6 +4086,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK; data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
break; break;
case nct6795: case nct6795:
case nct6797:
data->temp_label = nct6795_temp_label; data->temp_label = nct6795_temp_label;
data->temp_mask = NCT6795_TEMP_MASK; data->temp_mask = NCT6795_TEMP_MASK;
data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK; data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
...@@ -3987,6 +4096,11 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3987,6 +4096,11 @@ static int nct6775_probe(struct platform_device *pdev)
data->temp_mask = NCT6796_TEMP_MASK; data->temp_mask = NCT6796_TEMP_MASK;
data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK; data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
break; break;
case nct6798:
data->temp_label = nct6798_temp_label;
data->temp_mask = NCT6798_TEMP_MASK;
data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
break;
} }
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
...@@ -4256,6 +4370,8 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4256,6 +4370,8 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
break; break;
} }
...@@ -4291,6 +4407,8 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4291,6 +4407,8 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796: case nct6796:
case nct6797:
case nct6798:
tmp |= 0x7e; tmp |= 0x7e;
break; break;
} }
...@@ -4493,6 +4611,12 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) ...@@ -4493,6 +4611,12 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6796_ID: case SIO_NCT6796_ID:
sio_data->kind = nct6796; sio_data->kind = nct6796;
break; break;
case SIO_NCT6797_ID:
sio_data->kind = nct6797;
break;
case SIO_NCT6798_ID:
sio_data->kind = nct6798;
break;
default: default:
if (val != 0xffff) if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val); pr_debug("unsupported chip ID: 0x%04x\n", val);
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
/* Define the Counter Register, value = 100 for match 100% */ /* Define the Counter Register, value = 100 for match 100% */
#define NPCM7XX_PWM_COUNTER_DEFAULT_NUM 255 #define NPCM7XX_PWM_COUNTER_DEFAULT_NUM 255
#define NPCM7XX_PWM_CMR_DEFAULT_NUM 127 #define NPCM7XX_PWM_CMR_DEFAULT_NUM 255
#define NPCM7XX_PWM_CMR_MAX 255 #define NPCM7XX_PWM_CMR_MAX 255
/* default all PWM channels PRESCALE2 = 1 */ /* default all PWM channels PRESCALE2 = 1 */
...@@ -861,7 +861,7 @@ static int npcm7xx_create_pwm_cooling(struct device *dev, ...@@ -861,7 +861,7 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
return ret; return ret;
} }
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%s%d", child->name, snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
pwm_port); pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child, cdev->tcdev = thermal_of_cooling_device_register(child,
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
menuconfig PMBUS menuconfig PMBUS
tristate "PMBus support" tristate "PMBus support"
depends on I2C depends on I2C
default n
help help
Say yes here if you want to enable PMBus support. Say yes here if you want to enable PMBus support.
...@@ -28,7 +27,6 @@ config SENSORS_PMBUS ...@@ -28,7 +27,6 @@ config SENSORS_PMBUS
config SENSORS_ADM1275 config SENSORS_ADM1275
tristate "Analog Devices ADM1275 and compatibles" tristate "Analog Devices ADM1275 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for Analog If you say yes here you get hardware monitoring support for Analog
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293, Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
...@@ -49,7 +47,6 @@ config SENSORS_IBM_CFFPS ...@@ -49,7 +47,6 @@ config SENSORS_IBM_CFFPS
config SENSORS_IR35221 config SENSORS_IR35221
tristate "Infineon IR35221" tristate "Infineon IR35221"
default n
help help
If you say yes here you get hardware monitoring support for the If you say yes here you get hardware monitoring support for the
Infineon IR35221 controller. Infineon IR35221 controller.
...@@ -59,7 +56,6 @@ config SENSORS_IR35221 ...@@ -59,7 +56,6 @@ config SENSORS_IR35221
config SENSORS_LM25066 config SENSORS_LM25066
tristate "National Semiconductor LM25066 and compatibles" tristate "National Semiconductor LM25066 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for National If you say yes here you get hardware monitoring support for National
Semiconductor LM25056, LM25066, LM5064, and LM5066. Semiconductor LM25056, LM25066, LM5064, and LM5066.
...@@ -69,7 +65,6 @@ config SENSORS_LM25066 ...@@ -69,7 +65,6 @@ config SENSORS_LM25066
config SENSORS_LTC2978 config SENSORS_LTC2978
tristate "Linear Technologies LTC2978 and compatibles" tristate "Linear Technologies LTC2978 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for Linear If you say yes here you get hardware monitoring support for Linear
Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
...@@ -83,11 +78,11 @@ config SENSORS_LTC2978_REGULATOR ...@@ -83,11 +78,11 @@ config SENSORS_LTC2978_REGULATOR
depends on SENSORS_LTC2978 && REGULATOR depends on SENSORS_LTC2978 && REGULATOR
help help
If you say yes here you get regulator support for Linear If you say yes here you get regulator support for Linear
Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676. Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676
and LTM4686.
config SENSORS_LTC3815 config SENSORS_LTC3815
tristate "Linear Technologies LTC3815" tristate "Linear Technologies LTC3815"
default n
help help
If you say yes here you get hardware monitoring support for Linear If you say yes here you get hardware monitoring support for Linear
Technology LTC3815. Technology LTC3815.
...@@ -97,7 +92,6 @@ config SENSORS_LTC3815 ...@@ -97,7 +92,6 @@ config SENSORS_LTC3815
config SENSORS_MAX16064 config SENSORS_MAX16064
tristate "Maxim MAX16064" tristate "Maxim MAX16064"
default n
help help
If you say yes here you get hardware monitoring support for Maxim If you say yes here you get hardware monitoring support for Maxim
MAX16064. MAX16064.
...@@ -107,7 +101,6 @@ config SENSORS_MAX16064 ...@@ -107,7 +101,6 @@ config SENSORS_MAX16064
config SENSORS_MAX20751 config SENSORS_MAX20751
tristate "Maxim MAX20751" tristate "Maxim MAX20751"
default n
help help
If you say yes here you get hardware monitoring support for Maxim If you say yes here you get hardware monitoring support for Maxim
MAX20751. MAX20751.
...@@ -117,7 +110,6 @@ config SENSORS_MAX20751 ...@@ -117,7 +110,6 @@ config SENSORS_MAX20751
config SENSORS_MAX31785 config SENSORS_MAX31785
tristate "Maxim MAX31785 and compatibles" tristate "Maxim MAX31785 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for Maxim If you say yes here you get hardware monitoring support for Maxim
MAX31785. MAX31785.
...@@ -127,7 +119,6 @@ config SENSORS_MAX31785 ...@@ -127,7 +119,6 @@ config SENSORS_MAX31785
config SENSORS_MAX34440 config SENSORS_MAX34440
tristate "Maxim MAX34440 and compatibles" tristate "Maxim MAX34440 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for Maxim If you say yes here you get hardware monitoring support for Maxim
MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461. MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461.
...@@ -137,7 +128,6 @@ config SENSORS_MAX34440 ...@@ -137,7 +128,6 @@ config SENSORS_MAX34440
config SENSORS_MAX8688 config SENSORS_MAX8688
tristate "Maxim MAX8688" tristate "Maxim MAX8688"
default n
help help
If you say yes here you get hardware monitoring support for Maxim If you say yes here you get hardware monitoring support for Maxim
MAX8688. MAX8688.
...@@ -147,7 +137,6 @@ config SENSORS_MAX8688 ...@@ -147,7 +137,6 @@ config SENSORS_MAX8688
config SENSORS_TPS40422 config SENSORS_TPS40422
tristate "TI TPS40422" tristate "TI TPS40422"
default n
help help
If you say yes here you get hardware monitoring support for TI If you say yes here you get hardware monitoring support for TI
TPS40422. TPS40422.
...@@ -166,7 +155,6 @@ config SENSORS_TPS53679 ...@@ -166,7 +155,6 @@ config SENSORS_TPS53679
config SENSORS_UCD9000 config SENSORS_UCD9000
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910" tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
default n
help help
If you say yes here you get hardware monitoring support for TI If you say yes here you get hardware monitoring support for TI
UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System
...@@ -177,7 +165,6 @@ config SENSORS_UCD9000 ...@@ -177,7 +165,6 @@ config SENSORS_UCD9000
config SENSORS_UCD9200 config SENSORS_UCD9200
tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
default n
help help
If you say yes here you get hardware monitoring support for TI If you say yes here you get hardware monitoring support for TI
UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248 UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
...@@ -188,7 +175,6 @@ config SENSORS_UCD9200 ...@@ -188,7 +175,6 @@ config SENSORS_UCD9200
config SENSORS_ZL6100 config SENSORS_ZL6100
tristate "Intersil ZL6100 and compatibles" tristate "Intersil ZL6100 and compatibles"
default n
help help
If you say yes here you get hardware monitoring support for Intersil If you say yes here you get hardware monitoring support for Intersil
ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105, ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (c) 2011 Ericsson AB. * Copyright (c) 2011 Ericsson AB.
* Copyright (c) 2013, 2014, 2015 Guenter Roeck * Copyright (c) 2013, 2014, 2015 Guenter Roeck
* Copyright (c) 2015 Linear Technology * Copyright (c) 2015 Linear Technology
* Copyright (c) 2018 Analog Devices Inc.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
#include "pmbus.h" #include "pmbus.h"
enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 }; ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 };
/* Common for all chips */ /* Common for all chips */
#define LTC2978_MFR_VOUT_PEAK 0xdd #define LTC2978_MFR_VOUT_PEAK 0xdd
...@@ -81,6 +82,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, ...@@ -81,6 +82,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
#define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV1 0x4400
#define LTM4676_ID_REV2 0x4480 #define LTM4676_ID_REV2 0x4480
#define LTM4676A_ID 0x47e0 #define LTM4676A_ID 0x47e0
#define LTM4686_ID 0x4770
#define LTC2974_NUM_PAGES 4 #define LTC2974_NUM_PAGES 4
#define LTC2978_NUM_PAGES 8 #define LTC2978_NUM_PAGES 8
...@@ -512,6 +514,7 @@ static const struct i2c_device_id ltc2978_id[] = { ...@@ -512,6 +514,7 @@ static const struct i2c_device_id ltc2978_id[] = {
{"ltm2987", ltm2987}, {"ltm2987", ltm2987},
{"ltm4675", ltm4675}, {"ltm4675", ltm4675},
{"ltm4676", ltm4676}, {"ltm4676", ltm4676},
{"ltm4686", ltm4686},
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, ltc2978_id); MODULE_DEVICE_TABLE(i2c, ltc2978_id);
...@@ -588,6 +591,8 @@ static int ltc2978_get_id(struct i2c_client *client) ...@@ -588,6 +591,8 @@ static int ltc2978_get_id(struct i2c_client *client)
else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
chip_id == LTM4676A_ID) chip_id == LTM4676A_ID)
return ltm4676; return ltm4676;
else if (chip_id == LTM4686_ID)
return ltm4686;
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
return -ENODEV; return -ENODEV;
...@@ -684,6 +689,7 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -684,6 +689,7 @@ static int ltc2978_probe(struct i2c_client *client,
case ltc3887: case ltc3887:
case ltm4675: case ltm4675:
case ltm4676: case ltm4676:
case ltm4686:
data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3880_read_word_data; info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES; info->pages = LTC3880_NUM_PAGES;
...@@ -770,6 +776,7 @@ static const struct of_device_id ltc2978_of_match[] = { ...@@ -770,6 +776,7 @@ static const struct of_device_id ltc2978_of_match[] = {
{ .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm2987" },
{ .compatible = "lltc,ltm4675" }, { .compatible = "lltc,ltm4675" },
{ .compatible = "lltc,ltm4676" }, { .compatible = "lltc,ltm4676" },
{ .compatible = "lltc,ltm4686" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, ltc2978_of_match); MODULE_DEVICE_TABLE(of, ltc2978_of_match);
......
...@@ -118,6 +118,8 @@ static int pmbus_identify(struct i2c_client *client, ...@@ -118,6 +118,8 @@ static int pmbus_identify(struct i2c_client *client,
} else { } else {
info->pages = 1; info->pages = 1;
} }
pmbus_clear_faults(client);
} }
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
......
...@@ -2015,7 +2015,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, ...@@ -2015,7 +2015,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
client->flags |= I2C_CLIENT_PEC; client->flags |= I2C_CLIENT_PEC;
pmbus_clear_faults(client); if (data->info->pages)
pmbus_clear_faults(client);
else
pmbus_clear_fault_page(client, -1);
if (info->identify) { if (info->identify) {
ret = (*info->identify)(client, info); ret = (*info->identify)(client, info);
......
...@@ -221,8 +221,12 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -221,8 +221,12 @@ static int pwm_fan_probe(struct platform_device *pdev)
ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
if (IS_ERR(ctx->pwm)) { if (IS_ERR(ctx->pwm)) {
dev_err(&pdev->dev, "Could not get PWM\n"); ret = PTR_ERR(ctx->pwm);
return PTR_ERR(ctx->pwm);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get PWM: %d\n", ret);
return ret;
} }
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
...@@ -290,9 +294,19 @@ static int pwm_fan_remove(struct platform_device *pdev) ...@@ -290,9 +294,19 @@ static int pwm_fan_remove(struct platform_device *pdev)
static int pwm_fan_suspend(struct device *dev) static int pwm_fan_suspend(struct device *dev)
{ {
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
struct pwm_args args;
int ret;
pwm_get_args(ctx->pwm, &args);
if (ctx->pwm_value) {
ret = pwm_config(ctx->pwm, 0, args.period);
if (ret < 0)
return ret;
if (ctx->pwm_value)
pwm_disable(ctx->pwm); pwm_disable(ctx->pwm);
}
return 0; return 0;
} }
......
...@@ -56,7 +56,7 @@ scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, ...@@ -56,7 +56,7 @@ scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
const struct scmi_sensors *scmi_sensors = drvdata; const struct scmi_sensors *scmi_sensors = drvdata;
sensor = *(scmi_sensors->info[type] + channel); sensor = *(scmi_sensors->info[type] + channel);
if (sensor && sensor->name) if (sensor)
return S_IRUGO; return S_IRUGO;
return 0; return 0;
......
...@@ -286,10 +286,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) ...@@ -286,10 +286,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
* any thermal zones or if the thermal subsystem is * any thermal zones or if the thermal subsystem is
* not configured. * not configured.
*/ */
if (IS_ERR(z)) { if (IS_ERR(z))
devm_kfree(dev, zone); devm_kfree(dev, zone);
continue;
}
} }
return 0; return 0;
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* sht15.c - support for the SHT15 Temperature and Humidity Sensor * sht15.c - support for the SHT15 Temperature and Humidity Sensor
* *
...@@ -9,10 +10,6 @@ ...@@ -9,10 +10,6 @@
* *
* Copyright (c) 2007 Wouter Horre * Copyright (c) 2007 Wouter Horre
* *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* For further information, see the Documentation/hwmon/sht15 file. * For further information, see the Documentation/hwmon/sht15 file.
*/ */
......
...@@ -226,8 +226,10 @@ static int tmp421_detect(struct i2c_client *client, ...@@ -226,8 +226,10 @@ static int tmp421_detect(struct i2c_client *client,
{ {
enum chips kind; enum chips kind;
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
const char * const names[] = { "TMP421", "TMP422", "TMP423", static const char * const names[] = {
"TMP441", "TMP442" }; "TMP421", "TMP422", "TMP423",
"TMP441", "TMP442"
};
int addr = client->addr; int addr = client->addr;
u8 reg; u8 reg;
......
...@@ -118,6 +118,7 @@ enum hwmon_in_attributes { ...@@ -118,6 +118,7 @@ enum hwmon_in_attributes {
hwmon_in_max_alarm, hwmon_in_max_alarm,
hwmon_in_lcrit_alarm, hwmon_in_lcrit_alarm,
hwmon_in_crit_alarm, hwmon_in_crit_alarm,
hwmon_in_enable,
}; };
#define HWMON_I_INPUT BIT(hwmon_in_input) #define HWMON_I_INPUT BIT(hwmon_in_input)
...@@ -135,6 +136,7 @@ enum hwmon_in_attributes { ...@@ -135,6 +136,7 @@ enum hwmon_in_attributes {
#define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm) #define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm)
#define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm) #define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm)
#define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm) #define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm)
#define HWMON_I_ENABLE BIT(hwmon_in_enable)
enum hwmon_curr_attributes { enum hwmon_curr_attributes {
hwmon_curr_input, hwmon_curr_input,
......
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hwmon
#if !defined(_TRACE_HWMON_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HWMON_H
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS(hwmon_attr_class,
TP_PROTO(int index, const char *attr_name, long val),
TP_ARGS(index, attr_name, val),
TP_STRUCT__entry(
__field(int, index)
__string(attr_name, attr_name)
__field(long, val)
),
TP_fast_assign(
__entry->index = index;
__assign_str(attr_name, attr_name);
__entry->val = val;
),
TP_printk("index=%d, attr_name=%s, val=%ld",
__entry->index, __get_str(attr_name), __entry->val)
);
DEFINE_EVENT(hwmon_attr_class, hwmon_attr_show,
TP_PROTO(int index, const char *attr_name, long val),
TP_ARGS(index, attr_name, val)
);
DEFINE_EVENT(hwmon_attr_class, hwmon_attr_store,
TP_PROTO(int index, const char *attr_name, long val),
TP_ARGS(index, attr_name, val)
);
TRACE_EVENT(hwmon_attr_show_string,
TP_PROTO(int index, const char *attr_name, const char *s),
TP_ARGS(index, attr_name, s),
TP_STRUCT__entry(
__field(int, index)
__string(attr_name, attr_name)
__string(label, s)
),
TP_fast_assign(
__entry->index = index;
__assign_str(attr_name, attr_name);
__assign_str(label, s);
),
TP_printk("index=%d, attr_name=%s, val=%s",
__entry->index, __get_str(attr_name), __get_str(label))
);
#endif /* _TRACE_HWMON_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment