forked from Minki/linux
hwmon updates for v4.20
- 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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIbBAABAgAGBQJbyVR3AAoJEMsfJm/On5mB7zgP92NONVqvIBBFRj7ohjhz4iya y/8ITclQvxMzgrBTuYS9avA9NACKtaerfpiS8m4XjrKAt66/x2h6yTGRVKEDTqXA Qs9OZG83tocBYqZ3EI3FtMhbx3eOIdCj+v34ARNqPZSXJGkpiKa+9BmjR2VuMCtG ONcnk66os4g7rjgsBqYUqCkAQkse/Oys6iMPpg4VfZlL6/sKWCglsQVCqplW7dFR wxZtJqKYHNE4sddtT67cVaxKcuNdt96EmEoJCGirH0B2wW7FPefR4sYO9cmykDi+ J6b7VErHWSi75LrXVZaXHllkau3NvZDCoGyVbVPu98w4TzjylCXciskOmXdTQkso 57I2aPMUa4VLde27p/a3MLUXhswFng2w62rz2l/BLlWq4KbTorPZxnKrHT8EpU7T eQrLC5Q+mdJCRdhcDQEcx8+SKtdO9UFLUFD5xb2D74ZJ4N2DYYFa62Vr9I6Mk+AV aZa5wLQW6W5UY8+AcbhK2AJE60LiPaJsuobiLLwZ/5cB2M33Hgi0ySDkq/Y4fFjA t/D5iWDVhbwbK15baJyJEAlNQAM+Nr284RGfWTfHhqKxmx3/fIKw5OBjsRzIP5KV NN5JA8s8tuLP10MIY+jXRTu2knkTKQXgWp8YLuS8gI0meCiGt2fZ8kXXW5b9T5+F sH7cZuCGf+PRkEeYp8o= =Urmz -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
b8e445b689
44
Documentation/devicetree/bindings/hwmon/ina3221.txt
Normal file
44
Documentation/devicetree/bindings/hwmon/ina3221.txt
Normal file
@ -0,0 +1,44 @@
|
||||
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:
|
||||
* "lltc,ltm2987"
|
||||
* "lltc,ltm4675"
|
||||
* "lltc,ltm4676"
|
||||
* "lltc,ltm4686"
|
||||
- reg: I2C slave address
|
||||
|
||||
Optional properties:
|
||||
@ -30,6 +31,7 @@ Valid names of regulators depend on number of supplies supported per device:
|
||||
* ltc3880, ltc3882, ltc3886 : vout0 - vout1
|
||||
* ltc3883 : vout0
|
||||
* ltm4676 : vout0 - vout1
|
||||
* ltm4686 : vout0 - vout1
|
||||
|
||||
Example:
|
||||
ltc2978@5e {
|
||||
|
@ -21,6 +21,8 @@ and power are calculated host-side from these.
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
in[123]_label Voltage channel labels
|
||||
in[123]_enable Voltage channel enable controls
|
||||
in[123]_input Bus voltage(mV) channels
|
||||
curr[123]_input Current(mA) measurement channels
|
||||
shunt[123]_resistor Shunt resistance(uOhm) channels
|
||||
|
@ -17,8 +17,8 @@ Supported chips:
|
||||
Addresses scanned: none
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maximintegrated.com/
|
||||
* Maxim MAX6625, MAX6626
|
||||
Prefixes: 'max6625', 'max6626'
|
||||
* Maxim MAX6625, MAX6626, MAX31725, MAX31726
|
||||
Prefixes: 'max6625', 'max6626', 'max31725', 'max31726'
|
||||
Addresses scanned: none
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maxim-ic.com/
|
||||
@ -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,
|
||||
that are supported. The clones are not detected by the driver, unless
|
||||
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.
|
||||
|
||||
The LM77 is not supported, contrary to what we pretended for a long time.
|
||||
|
@ -55,6 +55,10 @@ Supported chips:
|
||||
Prefix: 'ltm4676'
|
||||
Addresses scanned: -
|
||||
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>
|
||||
|
||||
@ -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.
|
||||
LTM4675 is a dual 9A or single 18A μModule regulator
|
||||
LTM4676 is a dual 13A or single 26A uModule regulator.
|
||||
LTM4686 is a dual 10A or single 20A uModule regulator.
|
||||
|
||||
|
||||
Usage Notes
|
||||
|
@ -2,12 +2,12 @@ Kernel driver mc13783-adc
|
||||
=========================
|
||||
|
||||
Supported chips:
|
||||
* Freescale Atlas MC13783
|
||||
* Freescale MC13783
|
||||
Prefix: 'mc13783'
|
||||
Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1
|
||||
* Freescale Atlas MC13892
|
||||
Datasheet: https://www.nxp.com/docs/en/data-sheet/MC13783.pdf
|
||||
* Freescale 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:
|
||||
Sascha Hauer <s.hauer@pengutronix.de>
|
||||
|
27
MAINTAINERS
27
MAINTAINERS
@ -6468,6 +6468,7 @@ F: Documentation/devicetree/bindings/hwmon/
|
||||
F: Documentation/hwmon/
|
||||
F: drivers/hwmon/
|
||||
F: include/linux/hwmon*.h
|
||||
F: include/trace/events/hwmon*.h
|
||||
|
||||
HARDWARE RANDOM NUMBER GENERATOR CORE
|
||||
M: Matt Mackall <mpm@selenic.com>
|
||||
@ -8860,13 +8861,6 @@ S: Maintained
|
||||
F: Documentation/hwmon/max16065
|
||||
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
|
||||
M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -11601,7 +11595,26 @@ W: http://hwmon.wiki.kernel.org/
|
||||
W: http://www.roeck-us.net/linux/drivers/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
|
||||
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-core
|
||||
F: Documentation/hwmon/tps40422
|
||||
F: Documentation/hwmon/ucd9000
|
||||
F: Documentation/hwmon/ucd9200
|
||||
F: Documentation/hwmon/zl6100
|
||||
F: drivers/hwmon/pmbus/
|
||||
F: include/linux/pmbus.h
|
||||
|
||||
|
@ -852,7 +852,7 @@ static int aspeed_create_pwm_cooling(struct device *dev,
|
||||
dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
|
||||
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->name,
|
||||
|
@ -1210,10 +1210,8 @@ static int atk_register_hwmon(struct atk_data *data)
|
||||
data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110",
|
||||
data,
|
||||
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)
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/hwmon.h>
|
||||
|
||||
#define HWMON_ID_PREFIX "hwmon"
|
||||
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
|
||||
|
||||
@ -171,6 +174,13 @@ static int hwmon_thermal_add_sensor(struct device *dev,
|
||||
}
|
||||
#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 */
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type),
|
||||
hattr->name, val);
|
||||
|
||||
return sprintf(buf, "%ld\n", val);
|
||||
}
|
||||
|
||||
@ -193,6 +206,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
|
||||
enum hwmon_sensor_types type = hattr->type;
|
||||
const char *s;
|
||||
int ret;
|
||||
|
||||
@ -201,6 +215,9 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type),
|
||||
hattr->name, s);
|
||||
|
||||
return sprintf(buf, "%s\n", s);
|
||||
}
|
||||
|
||||
@ -221,14 +238,10 @@ static ssize_t hwmon_attr_store(struct device *dev,
|
||||
if (ret < 0)
|
||||
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)
|
||||
{
|
||||
if (type == hwmon_in)
|
||||
return 0;
|
||||
return 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
|
||||
@ -356,6 +369,7 @@ static const char * const hwmon_in_attr_templates[] = {
|
||||
[hwmon_in_max_alarm] = "in%d_max_alarm",
|
||||
[hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm",
|
||||
[hwmon_in_crit_alarm] = "in%d_crit_alarm",
|
||||
[hwmon_in_enable] = "in%d_enable",
|
||||
};
|
||||
|
||||
static const char * const hwmon_curr_attr_templates[] = {
|
||||
|
@ -458,9 +458,6 @@ static int populate_attr_groups(struct platform_device *pdev)
|
||||
for_each_child_of_node(opal, np) {
|
||||
const char *label;
|
||||
|
||||
if (np->name == NULL)
|
||||
continue;
|
||||
|
||||
type = get_sensor_type(np);
|
||||
if (type == MAX_SENSOR_TYPE)
|
||||
continue;
|
||||
@ -589,9 +586,6 @@ static int create_device_attrs(struct platform_device *pdev)
|
||||
const char *label;
|
||||
enum sensors type;
|
||||
|
||||
if (np->name == NULL)
|
||||
continue;
|
||||
|
||||
type = get_sensor_type(np);
|
||||
if (type == MAX_SENSOR_TYPE)
|
||||
continue;
|
||||
@ -603,8 +597,8 @@ static int create_device_attrs(struct platform_device *pdev)
|
||||
if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
|
||||
of_property_read_u32(np, "sensor-data", &sensor_id)) {
|
||||
dev_info(&pdev->dev,
|
||||
"'sensor-id' missing in the node '%s'\n",
|
||||
np->name);
|
||||
"'sensor-id' missing in the node '%pOFn'\n",
|
||||
np);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
enum iio_chan_type type;
|
||||
struct iio_channel *channels;
|
||||
const char *name = "iio_hwmon";
|
||||
struct device *hwmon_dev;
|
||||
char *sname;
|
||||
|
||||
if (dev->of_node && dev->of_node->name)
|
||||
name = dev->of_node->name;
|
||||
|
||||
channels = devm_iio_channel_get_all(dev);
|
||||
if (IS_ERR(channels)) {
|
||||
if (PTR_ERR(channels) == -ENODEV)
|
||||
@ -141,11 +137,15 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
st->attr_group.attrs = st->attrs;
|
||||
st->groups[0] = &st->attr_group;
|
||||
|
||||
sname = devm_kstrdup(dev, name, GFP_KERNEL);
|
||||
if (!sname)
|
||||
return -ENOMEM;
|
||||
if (dev->of_node) {
|
||||
sname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
|
||||
if (!sname)
|
||||
return -ENOMEM;
|
||||
strreplace(sname, '-', '_');
|
||||
} else {
|
||||
sname = "iio_hwmon";
|
||||
}
|
||||
|
||||
strreplace(sname, '-', '_');
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, sname, st,
|
||||
st->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
|
@ -38,9 +38,12 @@
|
||||
#define INA3221_WARN3 0x0c
|
||||
#define INA3221_MASK_ENABLE 0x0f
|
||||
|
||||
#define INA3221_CONFIG_MODE_SHUNT BIT(1)
|
||||
#define INA3221_CONFIG_MODE_BUS BIT(2)
|
||||
#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3)
|
||||
#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0)
|
||||
#define INA3221_CONFIG_MODE_POWERDOWN 0
|
||||
#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
|
||||
|
||||
@ -74,30 +77,37 @@ enum ina3221_channels {
|
||||
INA3221_NUM_CHANNELS
|
||||
};
|
||||
|
||||
static const unsigned int register_channel[] = {
|
||||
[INA3221_SHUNT1] = INA3221_CHANNEL1,
|
||||
[INA3221_SHUNT2] = INA3221_CHANNEL2,
|
||||
[INA3221_SHUNT3] = INA3221_CHANNEL3,
|
||||
[INA3221_CRIT1] = INA3221_CHANNEL1,
|
||||
[INA3221_CRIT2] = INA3221_CHANNEL2,
|
||||
[INA3221_CRIT3] = INA3221_CHANNEL3,
|
||||
[INA3221_WARN1] = INA3221_CHANNEL1,
|
||||
[INA3221_WARN2] = INA3221_CHANNEL2,
|
||||
[INA3221_WARN3] = INA3221_CHANNEL3,
|
||||
/**
|
||||
* struct ina3221_input - channel input source specific information
|
||||
* @label: label of channel input source
|
||||
* @shunt_resistor: shunt resistor value of channel input source
|
||||
* @disconnected: connection status of channel input source
|
||||
*/
|
||||
struct ina3221_input {
|
||||
const char *label;
|
||||
int shunt_resistor;
|
||||
bool disconnected;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ina3221_data - device specific information
|
||||
* @regmap: Register map 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 regmap *regmap;
|
||||
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,
|
||||
int *val)
|
||||
{
|
||||
@ -113,78 +123,104 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ina3221_show_bus_voltage(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static const u8 ina3221_in_reg[] = {
|
||||
INA3221_BUS1,
|
||||
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);
|
||||
unsigned int reg = sd_attr->index;
|
||||
int val, voltage_mv, ret;
|
||||
u8 reg = ina3221_in_reg[channel];
|
||||
int regval, ret;
|
||||
|
||||
ret = ina3221_read_value(ina, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Translate shunt channel index to sensor channel index */
|
||||
channel %= INA3221_NUM_CHANNELS;
|
||||
|
||||
voltage_mv = val * 8;
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
if (!ina3221_is_enabled(ina, channel))
|
||||
return -ENODATA;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv);
|
||||
ret = ina3221_read_value(ina, reg, ®val);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ina3221_show_shunt_voltage(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
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 },
|
||||
};
|
||||
|
||||
static int ina3221_read_curr(struct device *dev, u32 attr,
|
||||
int channel, long *val)
|
||||
{
|
||||
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
unsigned int reg = sd_attr->index;
|
||||
int val, voltage_uv, ret;
|
||||
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;
|
||||
|
||||
ret = ina3221_read_value(ina, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
voltage_uv = val * 40;
|
||||
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, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
|
||||
/* 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], ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = regval;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ina3221_show_current(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static int ina3221_write_curr(struct device *dev, u32 attr,
|
||||
int channel, long val)
|
||||
{
|
||||
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
unsigned int reg = sd_attr->index;
|
||||
unsigned int channel = register_channel[reg];
|
||||
int resistance_uo = ina->shunt_resistors[channel];
|
||||
int val, current_ma, voltage_nv, ret;
|
||||
|
||||
ret = ina3221_read_value(ina, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
voltage_nv = val * 40000;
|
||||
|
||||
current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
|
||||
}
|
||||
|
||||
static ssize_t ina3221_set_current(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
unsigned int reg = sd_attr->index;
|
||||
unsigned int channel = register_channel[reg];
|
||||
int resistance_uo = ina->shunt_resistors[channel];
|
||||
int val, current_ma, voltage_uv, ret;
|
||||
|
||||
ret = kstrtoint(buf, 0, ¤t_ma);
|
||||
if (ret)
|
||||
return ret;
|
||||
struct ina3221_input *input = &ina->inputs[channel];
|
||||
int resistance_uo = input->shunt_resistor;
|
||||
u8 reg = ina3221_curr_reg[attr][channel];
|
||||
int regval, current_ma, voltage_uv;
|
||||
|
||||
/* clamp current */
|
||||
current_ma = clamp_val(current_ma,
|
||||
current_ma = clamp_val(val,
|
||||
INT_MIN / resistance_uo,
|
||||
INT_MAX / resistance_uo);
|
||||
|
||||
@ -194,26 +230,177 @@ static ssize_t ina3221_set_current(struct device *dev,
|
||||
voltage_uv = clamp_val(voltage_uv, -163800, 163800);
|
||||
|
||||
/* 1 / 40uV(scale) << 3(register shift) = 5 */
|
||||
val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
|
||||
regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
|
||||
|
||||
ret = regmap_write(ina->regmap, reg, val);
|
||||
return regmap_write(ina->regmap, reg, regval);
|
||||
}
|
||||
|
||||
static int ina3221_write_enable(struct device *dev, int channel, bool enable)
|
||||
{
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
u16 config, mask = INA3221_CONFIG_CHx_EN(channel);
|
||||
int ret;
|
||||
|
||||
config = enable ? mask : 0;
|
||||
|
||||
/* Enable or disable the channel */
|
||||
ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
/* Cache the latest config register value */
|
||||
ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ina3221_read(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_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 ina3221_data *ina = dev_get_drvdata(dev);
|
||||
int index = channel - 1;
|
||||
|
||||
*str = ina->inputs[index].label;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static const u32 ina3221_in_config[] = {
|
||||
/* 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
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ina3221_in = {
|
||||
.type = hwmon_in,
|
||||
.config = ina3221_in_config,
|
||||
};
|
||||
|
||||
#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \
|
||||
HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \
|
||||
HWMON_C_MAX | HWMON_C_MAX_ALARM)
|
||||
|
||||
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,
|
||||
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 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,
|
||||
@ -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 ina3221_data *ina = dev_get_drvdata(dev);
|
||||
unsigned int channel = sd_attr->index;
|
||||
struct ina3221_input *input = &ina->inputs[channel];
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
@ -232,43 +420,11 @@ static ssize_t ina3221_set_shunt(struct device *dev,
|
||||
|
||||
val = clamp_val(val, 1, INT_MAX);
|
||||
|
||||
ina->shunt_resistors[channel] = val;
|
||||
input->shunt_resistor = val;
|
||||
|
||||
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], ®val);
|
||||
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 */
|
||||
static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
|
||||
ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
|
||||
@ -277,83 +433,16 @@ static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
|
||||
static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
|
||||
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[] = {
|
||||
/* 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_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_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_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,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ina3221);
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
@ -370,6 +459,66 @@ static const struct regmap_config ina3221_regmap_config = {
|
||||
.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,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -399,7 +548,13 @@ static int ina3221_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
@ -407,9 +562,25 @@ static int ina3221_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name,
|
||||
ina, ina3221_groups);
|
||||
/* Sync config register after reset */
|
||||
ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
|
||||
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)) {
|
||||
dev_err(dev, "Unable to register hwmon device\n");
|
||||
return PTR_ERR(hwmon_dev);
|
||||
@ -418,6 +589,60 @@ static int ina3221_probe(struct i2c_client *client,
|
||||
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[] = {
|
||||
{ .compatible = "ti,ina3221", },
|
||||
{ /* sentinel */ }
|
||||
@ -435,6 +660,7 @@ static struct i2c_driver ina3221_i2c_driver = {
|
||||
.driver = {
|
||||
.name = INA3221_DRIVER_NAME,
|
||||
.of_match_table = ina3221_of_match_table,
|
||||
.pm = &ina3221_pm,
|
||||
},
|
||||
.id_table = ina3221_ids,
|
||||
};
|
||||
|
@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev,
|
||||
|
||||
data->pdev = pdev;
|
||||
|
||||
if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
|
||||
boot_cpu_data.x86_model == 0x70)) {
|
||||
if (boot_cpu_data.x86 == 0x15 &&
|
||||
((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
|
||||
(boot_cpu_data.x86_model & 0xf0) == 0x70)) {
|
||||
data->read_htcreg = read_htcreg_nb_f15;
|
||||
data->read_tempreg = read_tempreg_nb_f15;
|
||||
} else if (boot_cpu_data.x86 == 0x17) {
|
||||
|
@ -47,6 +47,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
||||
lm75b,
|
||||
max6625,
|
||||
max6626,
|
||||
max31725,
|
||||
mcp980x,
|
||||
stds75,
|
||||
tcn75,
|
||||
@ -64,7 +65,6 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
||||
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
||||
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
|
||||
|
||||
|
||||
/* The LM75 registers */
|
||||
#define LM75_REG_TEMP 0x00
|
||||
#define LM75_REG_CONF 0x01
|
||||
@ -76,7 +76,7 @@ struct lm75_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
u8 orig_conf;
|
||||
u8 resolution; /* In bits, between 9 and 12 */
|
||||
u8 resolution; /* In bits, between 9 and 16 */
|
||||
u8 resolution_limits;
|
||||
unsigned int sample_time; /* In ms */
|
||||
};
|
||||
@ -339,6 +339,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
data->resolution_limits = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case max31725:
|
||||
data->resolution = 16;
|
||||
data->sample_time = MSEC_PER_SEC / 8;
|
||||
break;
|
||||
case tcn75:
|
||||
data->resolution = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 8;
|
||||
@ -415,6 +419,8 @@ static const struct i2c_device_id lm75_ids[] = {
|
||||
{ "lm75b", lm75b, },
|
||||
{ "max6625", max6625, },
|
||||
{ "max6626", max6626, },
|
||||
{ "max31725", max31725, },
|
||||
{ "max31726", max31725, },
|
||||
{ "mcp980x", mcp980x, },
|
||||
{ "stds75", stds75, },
|
||||
{ "tcn75", tcn75, },
|
||||
@ -471,6 +477,14 @@ static const struct of_device_id lm75_of_match[] = {
|
||||
.compatible = "maxim,max6626",
|
||||
.data = (void *)max6626
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,max31725",
|
||||
.data = (void *)max31725
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,max31726",
|
||||
.data = (void *)max31725
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,mcp980x",
|
||||
.data = (void *)mcp980x
|
||||
|
@ -127,8 +127,8 @@ static struct lm92_data *lm92_update_device(struct device *dev)
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ)
|
||||
|| !data->valid) {
|
||||
if (time_after(jiffies, data->last_updated + HZ) ||
|
||||
!data->valid) {
|
||||
dev_dbg(&client->dev, "Updating lm92 data\n");
|
||||
for (i = 0; i < t_num_regs; i++) {
|
||||
data->temp[i] =
|
||||
@ -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,
|
||||
const char *buf, size_t count)
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm92_data *data = dev_get_drvdata(dev);
|
||||
@ -161,7 +161,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
int nr = attr->index;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
@ -178,6 +178,7 @@ static ssize_t show_temp_hyst(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
|
||||
- TEMP_FROM_REG(data->temp[t_hyst]));
|
||||
}
|
||||
@ -186,6 +187,7 @@ static ssize_t temp1_min_hyst_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
|
||||
+ TEMP_FROM_REG(data->temp[t_hyst]));
|
||||
}
|
||||
@ -206,7 +208,7 @@ static ssize_t set_temp_hyst(struct device *dev,
|
||||
|
||||
val = clamp_val(val, -120000, 220000);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[t_hyst] =
|
||||
data->temp[t_hyst] =
|
||||
TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val);
|
||||
i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
|
||||
data->temp[t_hyst]);
|
||||
@ -218,6 +220,7 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
|
||||
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,
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Module and driver stuff
|
||||
*/
|
||||
|
@ -1,21 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
|
||||
*
|
||||
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2009 Sascha Hauer, Pengutronix
|
||||
*
|
||||
* 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>
|
||||
|
@ -42,6 +42,10 @@
|
||||
* nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
|
||||
* nct6795d 14 6 6 2+6 0xd350 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
|
||||
* the number of directly connectable temperature sensors (second value).
|
||||
@ -69,7 +73,7 @@
|
||||
#define USE_ALTERNATE
|
||||
|
||||
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] */
|
||||
static const char * const nct6775_device_names[] = {
|
||||
@ -82,6 +86,8 @@ static const char * const nct6775_device_names[] = {
|
||||
"nct6793",
|
||||
"nct6795",
|
||||
"nct6796",
|
||||
"nct6797",
|
||||
"nct6798",
|
||||
};
|
||||
|
||||
static const char * const nct6775_sio_names[] __initconst = {
|
||||
@ -94,6 +100,8 @@ static const char * const nct6775_sio_names[] __initconst = {
|
||||
"NCT6793D",
|
||||
"NCT6795D",
|
||||
"NCT6796D",
|
||||
"NCT6797D",
|
||||
"NCT6798D",
|
||||
};
|
||||
|
||||
static unsigned short force_id;
|
||||
@ -129,7 +137,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
|
||||
#define SIO_NCT6793_ID 0xd120
|
||||
#define SIO_NCT6795_ID 0xd350
|
||||
#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 };
|
||||
|
||||
@ -504,7 +514,7 @@ static const s8 NCT6779_BEEP_BITS[] = {
|
||||
static const u16 NCT6779_REG_FAN[] = {
|
||||
0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
|
||||
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[] = {
|
||||
0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
|
||||
@ -704,10 +714,10 @@ static const char *const nct6795_temp_label[] = {
|
||||
"PCH_CHIP_TEMP",
|
||||
"PCH_CPU_TEMP",
|
||||
"PCH_MCH_TEMP",
|
||||
"PCH_DIM0_TEMP",
|
||||
"PCH_DIM1_TEMP",
|
||||
"PCH_DIM2_TEMP",
|
||||
"PCH_DIM3_TEMP",
|
||||
"Agent0 Dimm0",
|
||||
"Agent0 Dimm1",
|
||||
"Agent1 Dimm0",
|
||||
"Agent1 Dimm1",
|
||||
"BYTE_TEMP0",
|
||||
"BYTE_TEMP1",
|
||||
"PECI Agent 0 Calibration",
|
||||
@ -742,10 +752,10 @@ static const char *const nct6796_temp_label[] = {
|
||||
"PCH_CHIP_TEMP",
|
||||
"PCH_CPU_TEMP",
|
||||
"PCH_MCH_TEMP",
|
||||
"PCH_DIM0_TEMP",
|
||||
"PCH_DIM1_TEMP",
|
||||
"PCH_DIM2_TEMP",
|
||||
"PCH_DIM3_TEMP",
|
||||
"Agent0 Dimm0",
|
||||
"Agent0 Dimm1",
|
||||
"Agent1 Dimm0",
|
||||
"Agent1 Dimm1",
|
||||
"BYTE_TEMP0",
|
||||
"BYTE_TEMP1",
|
||||
"PECI Agent 0 Calibration",
|
||||
@ -757,6 +767,44 @@ static const char *const nct6796_temp_label[] = {
|
||||
#define NCT6796_TEMP_MASK 0xbfff0ffe
|
||||
#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 */
|
||||
|
||||
#define NCT6106_REG_VBAT 0x318
|
||||
@ -1288,6 +1336,8 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
|
||||
(reg & 0xfff0) == 0x4c0 ||
|
||||
reg == 0x402 ||
|
||||
@ -1643,6 +1693,8 @@ static void nct6775_update_pwm_limits(struct device *dev)
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
reg = nct6775_read_value(data,
|
||||
data->REG_CRITICAL_PWM_ENABLE[i]);
|
||||
if (reg & data->CRITICAL_PWM_ENABLE_MASK)
|
||||
@ -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
|
||||
* a tick counter, but the value is reported and configured as rpm.
|
||||
* 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
|
||||
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 sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
||||
int nr = sattr->index;
|
||||
int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
|
||||
int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
|
||||
int tolerance;
|
||||
int target = data->target_speed[nr];
|
||||
int tolerance = 0;
|
||||
|
||||
if (low <= 0)
|
||||
low = 1;
|
||||
if (high > 0xffff)
|
||||
high = 0xffff;
|
||||
if (high < low)
|
||||
high = low;
|
||||
if (target) {
|
||||
int low = target - data->target_speed_tolerance[nr];
|
||||
int high = target + data->target_speed_tolerance[nr];
|
||||
|
||||
tolerance = (fan_from_reg16(low, data->fan_div[nr])
|
||||
- fan_from_reg16(high, data->fan_div[nr])) / 2;
|
||||
if (low <= 0)
|
||||
low = 1;
|
||||
if (high > 0xffff)
|
||||
high = 0xffff;
|
||||
if (high < low)
|
||||
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);
|
||||
}
|
||||
@ -3071,6 +3129,8 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
|
||||
val);
|
||||
reg = nct6775_read_value(data,
|
||||
@ -3430,7 +3490,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
||||
bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
|
||||
bool pwm6pin = false, pwm7pin = false;
|
||||
int sioreg = data->sioreg;
|
||||
int regval;
|
||||
|
||||
/* Store SIO_REG_ENABLE for use during resume */
|
||||
superio_select(sioreg, NCT6775_LD_HWM);
|
||||
@ -3438,10 +3497,10 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
||||
|
||||
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
||||
if (data->kind == nct6775) {
|
||||
regval = superio_inb(sioreg, 0x2c);
|
||||
int cr2c = superio_inb(sioreg, 0x2c);
|
||||
|
||||
fan3pin = regval & BIT(6);
|
||||
pwm3pin = regval & BIT(7);
|
||||
fan3pin = cr2c & BIT(6);
|
||||
pwm3pin = cr2c & BIT(7);
|
||||
|
||||
/* On NCT6775, fan4 shares pins with the fdc interface */
|
||||
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
|
||||
@ -3486,85 +3545,130 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
||||
fan4min = fan4pin;
|
||||
pwm3pin = fan3pin;
|
||||
} else if (data->kind == nct6106) {
|
||||
regval = superio_inb(sioreg, 0x24);
|
||||
fan3pin = !(regval & 0x80);
|
||||
pwm3pin = regval & 0x08;
|
||||
int cr24 = superio_inb(sioreg, 0x24);
|
||||
|
||||
fan3pin = !(cr24 & 0x80);
|
||||
pwm3pin = cr24 & 0x08;
|
||||
} else {
|
||||
/* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
|
||||
int regval_1b, regval_2a, regval_2f;
|
||||
bool dsw_en;
|
||||
/*
|
||||
* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
|
||||
* NCT6797D, NCT6798D
|
||||
*/
|
||||
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;
|
||||
|
||||
regval = superio_inb(sioreg, 0x1c);
|
||||
superio_select(sioreg, NCT6775_LD_12);
|
||||
cre0 = superio_inb(sioreg, 0xe0);
|
||||
creb = superio_inb(sioreg, 0xeb);
|
||||
cred = superio_inb(sioreg, 0xed);
|
||||
|
||||
fan3pin = !(regval & BIT(5));
|
||||
fan4pin = !(regval & BIT(6));
|
||||
fan5pin = !(regval & BIT(7));
|
||||
fan3pin = !(cr1c & BIT(5));
|
||||
fan4pin = !(cr1c & BIT(6));
|
||||
fan5pin = !(cr1c & BIT(7));
|
||||
|
||||
pwm3pin = !(regval & BIT(0));
|
||||
pwm4pin = !(regval & BIT(1));
|
||||
pwm5pin = !(regval & BIT(2));
|
||||
pwm3pin = !(cr1c & BIT(0));
|
||||
pwm4pin = !(cr1c & BIT(1));
|
||||
pwm5pin = !(cr1c & BIT(2));
|
||||
|
||||
regval = superio_inb(sioreg, 0x2d);
|
||||
switch (data->kind) {
|
||||
case nct6791:
|
||||
fan6pin = cr2d & BIT(1);
|
||||
pwm6pin = cr2d & BIT(0);
|
||||
break;
|
||||
case nct6792:
|
||||
fan6pin = regval & BIT(1);
|
||||
pwm6pin = regval & BIT(0);
|
||||
fan6pin = !dsw_en && (cr2d & BIT(1));
|
||||
pwm6pin = !dsw_en && (cr2d & BIT(0));
|
||||
break;
|
||||
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:
|
||||
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:
|
||||
regval_1b = superio_inb(sioreg, 0x1b);
|
||||
regval_2a = superio_inb(sioreg, 0x2a);
|
||||
regval_2f = superio_inb(sioreg, 0x2f);
|
||||
dsw_en = regval_2f & BIT(3);
|
||||
fan5pin |= cr1b & BIT(5);
|
||||
fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
|
||||
fan5pin |= creb & BIT(5);
|
||||
|
||||
if (!pwm5pin)
|
||||
pwm5pin = regval & BIT(7);
|
||||
fan6pin = (cr2a & BIT(4)) &&
|
||||
(!dsw_en || (cred & BIT(4)));
|
||||
fan6pin |= creb & BIT(3);
|
||||
|
||||
if (!fan5pin)
|
||||
fan5pin = regval_1b & BIT(5);
|
||||
fan7pin = !(cr2b & BIT(2));
|
||||
|
||||
superio_select(sioreg, NCT6775_LD_12);
|
||||
if (data->kind != nct6796) {
|
||||
int regval_eb = superio_inb(sioreg, 0xeb);
|
||||
pwm5pin |= cr2d & BIT(7);
|
||||
pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
|
||||
pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
|
||||
|
||||
if (!dsw_en) {
|
||||
fan6pin = regval & BIT(1);
|
||||
pwm6pin = regval & BIT(0);
|
||||
}
|
||||
pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
|
||||
pwm6pin |= creb & BIT(2);
|
||||
|
||||
if (!fan5pin)
|
||||
fan5pin = regval_eb & BIT(5);
|
||||
if (!pwm5pin)
|
||||
pwm5pin = (regval_eb & BIT(4)) &&
|
||||
!(regval_2a & BIT(0));
|
||||
if (!fan6pin)
|
||||
fan6pin = regval_eb & BIT(3);
|
||||
if (!pwm6pin)
|
||||
pwm6pin = regval_eb & BIT(2);
|
||||
}
|
||||
pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
|
||||
break;
|
||||
case nct6797:
|
||||
fan5pin |= !ddr4_en && (cr1b & BIT(5));
|
||||
fan5pin |= creb & BIT(5);
|
||||
|
||||
if (data->kind == nct6795 || data->kind == nct6796) {
|
||||
int regval_ed = superio_inb(sioreg, 0xed);
|
||||
fan6pin = cr2a & BIT(4);
|
||||
fan6pin |= creb & BIT(3);
|
||||
|
||||
if (!fan6pin)
|
||||
fan6pin = (regval_2a & BIT(4)) &&
|
||||
(!dsw_en ||
|
||||
(dsw_en && (regval_ed & BIT(4))));
|
||||
if (!pwm6pin)
|
||||
pwm6pin = (regval_2a & BIT(3)) &&
|
||||
(regval_ed & BIT(2));
|
||||
}
|
||||
fan7pin = cr1a & BIT(1);
|
||||
|
||||
if (data->kind == nct6796) {
|
||||
int regval_1d = superio_inb(sioreg, 0x1d);
|
||||
int regval_2b = superio_inb(sioreg, 0x2b);
|
||||
pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
|
||||
pwm5pin |= !ddr4_en && (cr2d & BIT(7));
|
||||
|
||||
fan7pin = !(regval_2b & BIT(2));
|
||||
pwm7pin = !(regval_1d & (BIT(2) | BIT(3)));
|
||||
}
|
||||
pwm6pin = creb & BIT(2);
|
||||
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;
|
||||
default: /* NCT6779D */
|
||||
break;
|
||||
@ -3943,8 +4047,12 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
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->has_fan_div = false;
|
||||
data->temp_fixed_num = 6;
|
||||
@ -3978,6 +4086,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
|
||||
break;
|
||||
case nct6795:
|
||||
case nct6797:
|
||||
data->temp_label = nct6795_temp_label;
|
||||
data->temp_mask = NCT6795_TEMP_MASK;
|
||||
data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
|
||||
@ -3987,6 +4096,11 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
data->temp_mask = NCT6796_TEMP_MASK;
|
||||
data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
|
||||
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;
|
||||
@ -4256,6 +4370,8 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4291,6 +4407,8 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6797:
|
||||
case nct6798:
|
||||
tmp |= 0x7e;
|
||||
break;
|
||||
}
|
||||
@ -4493,6 +4611,12 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
||||
case SIO_NCT6796_ID:
|
||||
sio_data->kind = nct6796;
|
||||
break;
|
||||
case SIO_NCT6797_ID:
|
||||
sio_data->kind = nct6797;
|
||||
break;
|
||||
case SIO_NCT6798_ID:
|
||||
sio_data->kind = nct6798;
|
||||
break;
|
||||
default:
|
||||
if (val != 0xffff)
|
||||
pr_debug("unsupported chip ID: 0x%04x\n", val);
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
/* Define the Counter Register, value = 100 for match 100% */
|
||||
#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
|
||||
|
||||
/* default all PWM channels PRESCALE2 = 1 */
|
||||
@ -861,7 +861,7 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
|
||||
dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
|
||||
return ret;
|
||||
}
|
||||
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%s%d", child->name,
|
||||
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
|
||||
pwm_port);
|
||||
|
||||
cdev->tcdev = thermal_of_cooling_device_register(child,
|
||||
|
@ -5,7 +5,6 @@
|
||||
menuconfig PMBUS
|
||||
tristate "PMBus support"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
Say yes here if you want to enable PMBus support.
|
||||
|
||||
@ -28,7 +27,6 @@ config SENSORS_PMBUS
|
||||
|
||||
config SENSORS_ADM1275
|
||||
tristate "Analog Devices ADM1275 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Analog
|
||||
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
|
||||
@ -49,7 +47,6 @@ config SENSORS_IBM_CFFPS
|
||||
|
||||
config SENSORS_IR35221
|
||||
tristate "Infineon IR35221"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for the
|
||||
Infineon IR35221 controller.
|
||||
@ -59,7 +56,6 @@ config SENSORS_IR35221
|
||||
|
||||
config SENSORS_LM25066
|
||||
tristate "National Semiconductor LM25066 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for National
|
||||
Semiconductor LM25056, LM25066, LM5064, and LM5066.
|
||||
@ -69,7 +65,6 @@ config SENSORS_LM25066
|
||||
|
||||
config SENSORS_LTC2978
|
||||
tristate "Linear Technologies LTC2978 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Linear
|
||||
Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
|
||||
@ -83,11 +78,11 @@ config SENSORS_LTC2978_REGULATOR
|
||||
depends on SENSORS_LTC2978 && REGULATOR
|
||||
help
|
||||
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
|
||||
tristate "Linear Technologies LTC3815"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Linear
|
||||
Technology LTC3815.
|
||||
@ -97,7 +92,6 @@ config SENSORS_LTC3815
|
||||
|
||||
config SENSORS_MAX16064
|
||||
tristate "Maxim MAX16064"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX16064.
|
||||
@ -107,7 +101,6 @@ config SENSORS_MAX16064
|
||||
|
||||
config SENSORS_MAX20751
|
||||
tristate "Maxim MAX20751"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX20751.
|
||||
@ -117,7 +110,6 @@ config SENSORS_MAX20751
|
||||
|
||||
config SENSORS_MAX31785
|
||||
tristate "Maxim MAX31785 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX31785.
|
||||
@ -127,7 +119,6 @@ config SENSORS_MAX31785
|
||||
|
||||
config SENSORS_MAX34440
|
||||
tristate "Maxim MAX34440 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461.
|
||||
@ -137,7 +128,6 @@ config SENSORS_MAX34440
|
||||
|
||||
config SENSORS_MAX8688
|
||||
tristate "Maxim MAX8688"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX8688.
|
||||
@ -147,7 +137,6 @@ config SENSORS_MAX8688
|
||||
|
||||
config SENSORS_TPS40422
|
||||
tristate "TI TPS40422"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for TI
|
||||
TPS40422.
|
||||
@ -166,7 +155,6 @@ config SENSORS_TPS53679
|
||||
|
||||
config SENSORS_UCD9000
|
||||
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for TI
|
||||
UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System
|
||||
@ -177,7 +165,6 @@ config SENSORS_UCD9000
|
||||
|
||||
config SENSORS_UCD9200
|
||||
tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for TI
|
||||
UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
|
||||
@ -188,7 +175,6 @@ config SENSORS_UCD9200
|
||||
|
||||
config SENSORS_ZL6100
|
||||
tristate "Intersil ZL6100 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Intersil
|
||||
ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105,
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2011 Ericsson AB.
|
||||
* Copyright (c) 2013, 2014, 2015 Guenter Roeck
|
||||
* Copyright (c) 2015 Linear Technology
|
||||
* Copyright (c) 2018 Analog Devices Inc.
|
||||
*
|
||||
* 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
|
||||
@ -28,7 +29,7 @@
|
||||
#include "pmbus.h"
|
||||
|
||||
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 */
|
||||
#define LTC2978_MFR_VOUT_PEAK 0xdd
|
||||
@ -81,6 +82,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
|
||||
#define LTM4676_ID_REV1 0x4400
|
||||
#define LTM4676_ID_REV2 0x4480
|
||||
#define LTM4676A_ID 0x47e0
|
||||
#define LTM4686_ID 0x4770
|
||||
|
||||
#define LTC2974_NUM_PAGES 4
|
||||
#define LTC2978_NUM_PAGES 8
|
||||
@ -512,6 +514,7 @@ static const struct i2c_device_id ltc2978_id[] = {
|
||||
{"ltm2987", ltm2987},
|
||||
{"ltm4675", ltm4675},
|
||||
{"ltm4676", ltm4676},
|
||||
{"ltm4686", ltm4686},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
||||
@ -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 ||
|
||||
chip_id == LTM4676A_ID)
|
||||
return ltm4676;
|
||||
else if (chip_id == LTM4686_ID)
|
||||
return ltm4686;
|
||||
|
||||
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
|
||||
return -ENODEV;
|
||||
@ -684,6 +689,7 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
case ltc3887:
|
||||
case ltm4675:
|
||||
case ltm4676:
|
||||
case ltm4686:
|
||||
data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
|
||||
info->read_word_data = ltc3880_read_word_data;
|
||||
info->pages = LTC3880_NUM_PAGES;
|
||||
@ -770,6 +776,7 @@ static const struct of_device_id ltc2978_of_match[] = {
|
||||
{ .compatible = "lltc,ltm2987" },
|
||||
{ .compatible = "lltc,ltm4675" },
|
||||
{ .compatible = "lltc,ltm4676" },
|
||||
{ .compatible = "lltc,ltm4686" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2978_of_match);
|
||||
|
@ -118,6 +118,8 @@ static int pmbus_identify(struct i2c_client *client,
|
||||
} else {
|
||||
info->pages = 1;
|
||||
}
|
||||
|
||||
pmbus_clear_faults(client);
|
||||
}
|
||||
|
||||
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,
|
||||
if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
|
||||
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) {
|
||||
ret = (*info->identify)(client, info);
|
||||
|
@ -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);
|
||||
if (IS_ERR(ctx->pwm)) {
|
||||
dev_err(&pdev->dev, "Could not get PWM\n");
|
||||
return PTR_ERR(ctx->pwm);
|
||||
ret = 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);
|
||||
@ -290,9 +294,19 @@ static int pwm_fan_remove(struct platform_device *pdev)
|
||||
static int pwm_fan_suspend(struct device *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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
|
||||
const struct scmi_sensors *scmi_sensors = drvdata;
|
||||
|
||||
sensor = *(scmi_sensors->info[type] + channel);
|
||||
if (sensor && sensor->name)
|
||||
if (sensor)
|
||||
return S_IRUGO;
|
||||
|
||||
return 0;
|
||||
|
@ -286,10 +286,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
|
||||
* any thermal zones or if the thermal subsystem is
|
||||
* not configured.
|
||||
*/
|
||||
if (IS_ERR(z)) {
|
||||
if (IS_ERR(z))
|
||||
devm_kfree(dev, zone);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* sht15.c - support for the SHT15 Temperature and Humidity Sensor
|
||||
*
|
||||
@ -9,10 +10,6 @@
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -226,8 +226,10 @@ static int tmp421_detect(struct i2c_client *client,
|
||||
{
|
||||
enum chips kind;
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
const char * const names[] = { "TMP421", "TMP422", "TMP423",
|
||||
"TMP441", "TMP442" };
|
||||
static const char * const names[] = {
|
||||
"TMP421", "TMP422", "TMP423",
|
||||
"TMP441", "TMP442"
|
||||
};
|
||||
int addr = client->addr;
|
||||
u8 reg;
|
||||
|
||||
|
@ -118,6 +118,7 @@ enum hwmon_in_attributes {
|
||||
hwmon_in_max_alarm,
|
||||
hwmon_in_lcrit_alarm,
|
||||
hwmon_in_crit_alarm,
|
||||
hwmon_in_enable,
|
||||
};
|
||||
|
||||
#define HWMON_I_INPUT BIT(hwmon_in_input)
|
||||
@ -135,6 +136,7 @@ enum hwmon_in_attributes {
|
||||
#define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm)
|
||||
#define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm)
|
||||
#define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm)
|
||||
#define HWMON_I_ENABLE BIT(hwmon_in_enable)
|
||||
|
||||
enum hwmon_curr_attributes {
|
||||
hwmon_curr_input,
|
||||
|
71
include/trace/events/hwmon.h
Normal file
71
include/trace/events/hwmon.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* 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>
|
Loading…
Reference in New Issue
Block a user