From fcb575bfac80d6deb4940d2ebf506d6701761f38 Mon Sep 17 00:00:00 2001 From: Lars Povlsen Date: Thu, 3 Sep 2020 15:47:04 +0200 Subject: [PATCH 01/64] hwmon: (sparx5) Fix initial reading of temperature If the temperature is read before the internal calibration is completed, the driver returns -EIO. Instead it should return -EAGAIN to encourage repeating the operation. Note (groeck): Returning -EAGAIN to userspace may result in hard loops; some userspace code interprets -EAGAIN as request to retry immediately. I would prefer -ENODATA, but it turns out that the thermal subsystem only handles -EAGAIN silently, so we'll have to stick with that. Signed-off-by: Lars Povlsen Link: https://lore.kernel.org/r/20200903134704.8949-1-lars.povlsen@microchip.com Signed-off-by: Guenter Roeck --- drivers/hwmon/sparx5-temp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index 1a2b1026b026..98be48e3a22a 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -56,7 +56,7 @@ static int s5_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp_input: stat = readl_relaxed(hwmon->base + TEMP_STAT); if (!(stat & TEMP_STAT_VALID)) - return -EIO; + return -EAGAIN; value = stat & TEMP_STAT_TEMP; /* * From register documentation: From 6c094b31ea2ad773824362ba0fccb88d36f8d32d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Sep 2020 14:39:29 -0700 Subject: [PATCH 02/64] hwmon: (pmbus/max34440) Fix status register reads for MAX344{51,60,61} Starting with MAX34451, the chips of this series support STATUS_IOUT and STATUS_TEMPERATURE commands, and no longer report over-current and over-temperature status with STATUS_MFR_SPECIFIC. Fixes: 7a001dbab4ade ("hwmon: (pmbus/max34440) Add support for MAX34451.") Fixes: 50115ac9b6f35 ("hwmon: (pmbus/max34440) Add support for MAX34460 and MAX34461") Reported-by: Steve Foreman Cc: Steve Foreman Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max34440.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 18b4e071067f..de04dff28945 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -388,7 +388,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -419,7 +418,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -455,7 +453,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, From 18360b33a071e5883250fd1e04bfdeff8c3887a3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 21 Sep 2020 15:52:12 +0300 Subject: [PATCH 03/64] hwmon: (w83627ehf) Fix a resource leak in probe Smatch has a new check for resource leaks which found a bug in probe: drivers/hwmon/w83627ehf.c:2417 w83627ehf_probe() warn: 'res->start' not released on lines: 2412. We need to clean up if devm_hwmon_device_register_with_info() fails. Fixes: 266cd5835947 ("hwmon: (w83627ehf) convert to with_info interface") Signed-off-by: Dan Carpenter Reviewed-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20200921125212.GA1128194@mwanda Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 5a5120121e50..3964ceab2817 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1951,8 +1951,12 @@ static int w83627ehf_probe(struct platform_device *pdev) data, &w83627ehf_chip_info, w83627ehf_groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto exit_release; + } - return PTR_ERR_OR_ZERO(hwmon_dev); + return 0; exit_release: release_region(res->start, IOREGION_LENGTH); From e8e612350f178674ba738ae8ae8fd31467868a05 Mon Sep 17 00:00:00 2001 From: Zbigniew Lukwinski Date: Fri, 31 Jul 2020 21:37:15 +0200 Subject: [PATCH 04/64] docs: hwmon: Add attributes to report rated values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New attributes (rated_min/rated_max) are being added the hwmon ABI. They are needed to cover rated values documented by PMBus specification: PMBus Power System Mgt Protocol Specification - Part II – Revision 1.3.1, chapters: 22.3.1 - 22.3.10, 22.3.15 Signed-off-by: Zbigniew Lukwinski Link: https://lore.kernel.org/r/1596224237-32280-2-git-send-email-zbigniew.lukwinski@linux.intel.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/sysfs-interface.rst | 70 +++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Documentation/hwmon/sysfs-interface.rst b/Documentation/hwmon/sysfs-interface.rst index fd590633bb14..678c9c60b5a3 100644 --- a/Documentation/hwmon/sysfs-interface.rst +++ b/Documentation/hwmon/sysfs-interface.rst @@ -241,6 +241,20 @@ Voltages Affects the way the driver calculates the CPU core reference voltage from the vid pins. +`in[0-*]_rated_min` + Minimum rated voltage. + + Unit: millivolt + + RO + +`in[0-*]_rated_max` + Maximum rated voltage. + + Unit: millivolt + + RO + Also see the Alarms section for status flags associated with voltages. @@ -574,6 +588,20 @@ Temperatures RW +`temp[1-*]_rated_min` + Minimum rated temperature. + + Unit: millidegree Celsius + + RO + +`temp[1-*]_rated_max` + Maximum rated temperature. + + Unit: millidegree Celsius + + RO + Some chips measure temperature using external thermistors and an ADC, and report the temperature measurement as a voltage. Converting this voltage back to a temperature (or the other way around for limits) requires @@ -664,6 +692,20 @@ Currents RW +`curr[1-*]_rated_min` + Minimum rated current. + + Unit: milliampere + + RO + +`curr[1-*]_rated_max` + Maximum rated current. + + Unit: milliampere + + RO + Also see the Alarms section for status flags associated with currents. ***** @@ -830,6 +872,20 @@ Power RW +`power[1-*]_rated_min` + Minimum rated power. + + Unit: microWatt + + RO + +`power[1-*]_rated_max` + Maximum rated power. + + Unit: microWatt + + RO + Also see the Alarms section for status flags associated with power readings. ****** @@ -877,6 +933,20 @@ Humidity RW +`humidity[1-*]_rated_min` + Minimum rated humidity. + + Unit: milli-percent (per cent mille, pcm) + + RO + +`humidity[1-*]_rated_max` + Maximum rated humidity. + + Unit: milli-percent (per cent mille, pcm) + + RO + ****** Alarms ****** From 1967f712677429f52ac3e8896b5ecfecc2372d95 Mon Sep 17 00:00:00 2001 From: Zbigniew Lukwinski Date: Fri, 31 Jul 2020 21:37:16 +0200 Subject: [PATCH 05/64] hwmon: (core) Add support for rated attributes Adding implementation for new attributes (rated_min/rated_max) for currentX, inX, powerX, tempX and humidityX. Tested with OpenBMC stack and simple hwmon driver using rated_min/rated_max for the following types of sensors: hwmon_temp, hwmon_in, hwmon_curr, hwmon_power, hwmon_humidity. For each sensor rated attributes were available and returned expected values. Signed-off-by: Zbigniew Lukwinski Link: https://lore.kernel.org/r/1596224237-32280-3-git-send-email-zbigniew.lukwinski@linux.intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 10 ++++++++++ include/linux/hwmon.h | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 3f596a5328da..6c684058bfdf 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -431,6 +431,8 @@ static const char * const hwmon_temp_attr_templates[] = { [hwmon_temp_lowest] = "temp%d_lowest", [hwmon_temp_highest] = "temp%d_highest", [hwmon_temp_reset_history] = "temp%d_reset_history", + [hwmon_temp_rated_min] = "temp%d_rated_min", + [hwmon_temp_rated_max] = "temp%d_rated_max", }; static const char * const hwmon_in_attr_templates[] = { @@ -450,6 +452,8 @@ 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_rated_min] = "in%d_rated_min", + [hwmon_in_rated_max] = "in%d_rated_max", }; static const char * const hwmon_curr_attr_templates[] = { @@ -469,6 +473,8 @@ static const char * const hwmon_curr_attr_templates[] = { [hwmon_curr_max_alarm] = "curr%d_max_alarm", [hwmon_curr_lcrit_alarm] = "curr%d_lcrit_alarm", [hwmon_curr_crit_alarm] = "curr%d_crit_alarm", + [hwmon_curr_rated_min] = "curr%d_rated_min", + [hwmon_curr_rated_max] = "curr%d_rated_max", }; static const char * const hwmon_power_attr_templates[] = { @@ -501,6 +507,8 @@ static const char * const hwmon_power_attr_templates[] = { [hwmon_power_max_alarm] = "power%d_max_alarm", [hwmon_power_lcrit_alarm] = "power%d_lcrit_alarm", [hwmon_power_crit_alarm] = "power%d_crit_alarm", + [hwmon_power_rated_min] = "power%d_rated_min", + [hwmon_power_rated_max] = "power%d_rated_max", }; static const char * const hwmon_energy_attr_templates[] = { @@ -519,6 +527,8 @@ static const char * const hwmon_humidity_attr_templates[] = { [hwmon_humidity_max_hyst] = "humidity%d_max_hyst", [hwmon_humidity_alarm] = "humidity%d_alarm", [hwmon_humidity_fault] = "humidity%d_fault", + [hwmon_humidity_rated_min] = "humidity%d_rated_min", + [hwmon_humidity_rated_max] = "humidity%d_rated_max", }; static const char * const hwmon_fan_attr_templates[] = { diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 363d4a814aa1..1e8d6ea8992e 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -85,6 +85,8 @@ enum hwmon_temp_attributes { hwmon_temp_lowest, hwmon_temp_highest, hwmon_temp_reset_history, + hwmon_temp_rated_min, + hwmon_temp_rated_max, }; #define HWMON_T_ENABLE BIT(hwmon_temp_enable) @@ -112,6 +114,8 @@ enum hwmon_temp_attributes { #define HWMON_T_LOWEST BIT(hwmon_temp_lowest) #define HWMON_T_HIGHEST BIT(hwmon_temp_highest) #define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history) +#define HWMON_T_RATED_MIN BIT(hwmon_temp_rated_min) +#define HWMON_T_RATED_MAX BIT(hwmon_temp_rated_max) enum hwmon_in_attributes { hwmon_in_enable, @@ -130,6 +134,8 @@ enum hwmon_in_attributes { hwmon_in_max_alarm, hwmon_in_lcrit_alarm, hwmon_in_crit_alarm, + hwmon_in_rated_min, + hwmon_in_rated_max, }; #define HWMON_I_ENABLE BIT(hwmon_in_enable) @@ -148,6 +154,8 @@ 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_RATED_MIN BIT(hwmon_in_rated_min) +#define HWMON_I_RATED_MAX BIT(hwmon_in_rated_max) enum hwmon_curr_attributes { hwmon_curr_enable, @@ -166,6 +174,8 @@ enum hwmon_curr_attributes { hwmon_curr_max_alarm, hwmon_curr_lcrit_alarm, hwmon_curr_crit_alarm, + hwmon_curr_rated_min, + hwmon_curr_rated_max, }; #define HWMON_C_ENABLE BIT(hwmon_curr_enable) @@ -184,6 +194,8 @@ enum hwmon_curr_attributes { #define HWMON_C_MAX_ALARM BIT(hwmon_curr_max_alarm) #define HWMON_C_LCRIT_ALARM BIT(hwmon_curr_lcrit_alarm) #define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm) +#define HWMON_C_RATED_MIN BIT(hwmon_curr_rated_min) +#define HWMON_C_RATED_MAX BIT(hwmon_curr_rated_max) enum hwmon_power_attributes { hwmon_power_enable, @@ -215,6 +227,8 @@ enum hwmon_power_attributes { hwmon_power_max_alarm, hwmon_power_lcrit_alarm, hwmon_power_crit_alarm, + hwmon_power_rated_min, + hwmon_power_rated_max, }; #define HWMON_P_ENABLE BIT(hwmon_power_enable) @@ -246,6 +260,8 @@ enum hwmon_power_attributes { #define HWMON_P_MAX_ALARM BIT(hwmon_power_max_alarm) #define HWMON_P_LCRIT_ALARM BIT(hwmon_power_lcrit_alarm) #define HWMON_P_CRIT_ALARM BIT(hwmon_power_crit_alarm) +#define HWMON_P_RATED_MIN BIT(hwmon_power_rated_min) +#define HWMON_P_RATED_MAX BIT(hwmon_power_rated_max) enum hwmon_energy_attributes { hwmon_energy_enable, @@ -267,6 +283,8 @@ enum hwmon_humidity_attributes { hwmon_humidity_max_hyst, hwmon_humidity_alarm, hwmon_humidity_fault, + hwmon_humidity_rated_min, + hwmon_humidity_rated_max, }; #define HWMON_H_ENABLE BIT(hwmon_humidity_enable) @@ -278,6 +296,8 @@ enum hwmon_humidity_attributes { #define HWMON_H_MAX_HYST BIT(hwmon_humidity_max_hyst) #define HWMON_H_ALARM BIT(hwmon_humidity_alarm) #define HWMON_H_FAULT BIT(hwmon_humidity_fault) +#define HWMON_H_RATED_MIN BIT(hwmon_humidity_rated_min) +#define HWMON_H_RATED_MAX BIT(hwmon_humidity_rated_max) enum hwmon_fan_attributes { hwmon_fan_enable, From 787c095edaa9de28d39671282eba7bddd479c038 Mon Sep 17 00:00:00 2001 From: Zbigniew Lukwinski Date: Fri, 31 Jul 2020 21:37:17 +0200 Subject: [PATCH 06/64] hwmon: (pmbus/core) Add support for rated attributes Adding implementation for new attributes (rated_min/rated_max) to cover PMBus specification about rated values reporting: MFR_VIN_MIN, MFR_VIN_MAX, MFR_IIN_MAX, MFR_PIN_MAX, MFR_VOUT_MIN, MFR_VOUT_MAX, MFR_IOUT_MAX, MFR_POUT_MAX, MFR_MAX_TEMP_1/2/3. Tested with OpenBMC stack. All rated attributes were available and reported correct values. Signed-off-by: Zbigniew Lukwinski Link: https://lore.kernel.org/r/1596224237-32280-4-git-send-email-zbigniew.lukwinski@linux.intel.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus.rst | 15 +++++++++- drivers/hwmon/pmbus/pmbus.h | 13 +++++++++ drivers/hwmon/pmbus/pmbus_core.c | 49 ++++++++++++++++++++++++++------ 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/pmbus.rst b/Documentation/hwmon/pmbus.rst index 66b3e894612f..67284bd5f4cd 100644 --- a/Documentation/hwmon/pmbus.rst +++ b/Documentation/hwmon/pmbus.rst @@ -211,6 +211,10 @@ inX_lcrit_alarm Voltage critical low alarm. inX_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. inX_label "vin", "vcap", or "voutY" +inX_rated_min Minimum rated voltage. + From MFR_VIN_MIN or MFR_VOUT_MIN register. +inX_rated_max Maximum rated voltage. + From MFR_VIN_MAX or MFR_VOUT_MAX register. currX_input Measured current. From READ_IIN or READ_IOUT register. currX_max Maximum current. @@ -230,6 +234,8 @@ currX_crit_alarm Current critical high alarm. currX_label "iin", "iinY", "iinY.Z", "ioutY", or "ioutY.Z", where Y reflects the page number and Z reflects the phase. +currX_rated_max Maximum rated current. + From MFR_IIN_MAX or MFR_IOUT_MAX register. powerX_input Measured power. From READ_PIN or READ_POUT register. powerX_cap Output power cap. From POUT_MAX register. @@ -244,10 +250,12 @@ powerX_crit_alarm Output power critical high alarm. powerX_label "pin", "pinY", "pinY.Z", "poutY", or "poutY.Z", where Y reflects the page number and Z reflects the phase. +powerX_rated_max Maximum rated power. + From MFR_PIN_MAX or MFR_POUT_MAX register. tempX_input Measured temperature. From READ_TEMPERATURE_X register. -tempX_min Mimimum temperature. From UT_WARN_LIMIT register. +tempX_min Minimum temperature. From UT_WARN_LIMIT register. tempX_max Maximum temperature. From OT_WARN_LIMIT register. tempX_lcrit Critical low temperature. From UT_FAULT_LIMIT register. @@ -265,4 +273,9 @@ tempX_lcrit_alarm Chip temperature critical low alarm. Set by comparing tempX_crit_alarm Chip temperature critical high alarm. Set by comparing READ_TEMPERATURE_X with OT_FAULT_LIMIT if TEMP_OT_FAULT status is set. +tempX_rated_min Minimum rated temperature. + From MFR_TAMBIENT_MIN register. +tempX_rated_max Maximum rated temperature. + From MFR_TAMBIENT_MAX, MFR_MAX_TEMP_1, MFR_MAX_TEMP_2 or + MFR_MAX_TEMP_3 register. ======================= ======================================================== diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 18e06fc6c53f..6d9f2cf70bff 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -119,9 +119,22 @@ enum pmbus_regs { PMBUS_MFR_DATE = 0x9D, PMBUS_MFR_SERIAL = 0x9E, + PMBUS_MFR_VIN_MIN = 0xA0, + PMBUS_MFR_VIN_MAX = 0xA1, + PMBUS_MFR_IIN_MAX = 0xA2, + PMBUS_MFR_PIN_MAX = 0xA3, + PMBUS_MFR_VOUT_MIN = 0xA4, + PMBUS_MFR_VOUT_MAX = 0xA5, + PMBUS_MFR_IOUT_MAX = 0xA6, + PMBUS_MFR_POUT_MAX = 0xA7, + PMBUS_IC_DEVICE_ID = 0xAD, PMBUS_IC_DEVICE_REV = 0xAE, + PMBUS_MFR_MAX_TEMP_1 = 0xC0, + PMBUS_MFR_MAX_TEMP_2 = 0xC1, + PMBUS_MFR_MAX_TEMP_3 = 0xC2, + /* * Virtual registers. * Useful to support attributes which are not supported by standard PMBus diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 44535add3a4a..89ea7da1403f 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1404,6 +1404,12 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VIN_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VIN_MAX, + .attr = "rated_max", }, }; @@ -1467,7 +1473,13 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_VOUT_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr voltage_attributes[] = { @@ -1537,7 +1549,10 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr iout_limit_attrs[] = { @@ -1571,7 +1586,10 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr current_attributes[] = { @@ -1622,7 +1640,10 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_PIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr pout_limit_attrs[] = { @@ -1656,7 +1677,10 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_POUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr power_attributes[] = { @@ -1720,7 +1744,10 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_1, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs2[] = { @@ -1758,7 +1785,10 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_2, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs3[] = { @@ -1784,7 +1814,10 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = { .attr = "crit", .alarm = "crit_alarm", .sbit = PB_TEMP_OT_FAULT, - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_3, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr temp_attributes[] = { From e40358390928f9ab9d8d7dde5c60c08981dc1d81 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 8 Aug 2020 18:07:10 -0700 Subject: [PATCH 07/64] hwmon: (drivetemp) Add usage not describing impact on drive spin-down On some drives, reading the drive temperature resets the drive's spin-down timer. If the drive temperature is read too often, affected drives will never spin down. Add this information as usage note to the driver documentation. Reported-by: Peter Sulyok Cc: Peter Sulyok Signed-off-by: Guenter Roeck --- Documentation/hwmon/drivetemp.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/hwmon/drivetemp.rst b/Documentation/hwmon/drivetemp.rst index 2d37d049247f..0b1cf2f912c5 100644 --- a/Documentation/hwmon/drivetemp.rst +++ b/Documentation/hwmon/drivetemp.rst @@ -30,6 +30,24 @@ Transport is not supported, the driver uses SMART attributes to read the drive temperature. +Usage Note +---------- + +Reading the drive temperature may reset the spin down timer on some drives. +This has been observed with WD120EFAX drives, but may be seen with other +drives as well. The same behavior is observed if the 'hdtemp' or 'smartd' +tools are used to access the drive. +With the WD120EFAX drive, reading the drive temperature using the drivetemp +driver is still possible _after_ it transitioned to standby mode, and +reading the drive temperature in this mode will not cause the drive to +change its mode (meaning the drive will not spin up). It is unknown if other +drives experience similar behavior. + +A known workaround for WD120EFAX drives is to read the drive temperature at +intervals larger than twice the spin-down time. Otherwise affected drives +will never spin down. + + Sysfs entries ------------- From dd43193976b9a7b2affe8fb71780bb96d16a8449 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Sat, 8 Aug 2020 23:00:04 +0200 Subject: [PATCH 08/64] hwmon (pmbus) use simple i2c probe function pmbus_do_probe doesn't use the id information provided in its second argument, so this can be removed, which then allows using the single-parameter i2c probe function ("probe_new") for probes. This avoids scanning the identifier tables during probes. Drivers which didn't use the id are converted as-is; drivers which did are modified as follows: * if the information in i2c_client is sufficient, that's used instead (client->name); * configured v. probed comparisons are performed by comparing the configured name to the detected name, instead of the ids; this involves strcmp but is still cheaper than comparing all the device names when scanning the tables; * anything else is handled by calling i2c_match_id() with the same level of error-handling (if any) as before. Additionally, the mismatch message in the ltc2978 driver is adjusted so that it no longer assumes that the driver_data is an index into ltc2978_id. Signed-off-by: Stephen Kitt Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/20200808210004.30880-1-steve@sk2.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus-core.rst | 3 +-- Documentation/hwmon/pmbus.rst | 7 +++---- drivers/hwmon/pmbus/adm1275.c | 11 +++++------ drivers/hwmon/pmbus/bel-pfe.c | 11 ++++++----- drivers/hwmon/pmbus/ibm-cffps.c | 19 ++++++++++++------- drivers/hwmon/pmbus/inspur-ipsps.c | 7 +++---- drivers/hwmon/pmbus/ir35221.c | 7 +++---- drivers/hwmon/pmbus/ir38064.c | 7 +++---- drivers/hwmon/pmbus/irps5401.c | 7 +++---- drivers/hwmon/pmbus/isl68137.c | 11 ++++++----- drivers/hwmon/pmbus/lm25066.c | 11 ++++++----- drivers/hwmon/pmbus/ltc2978.c | 14 ++++++++------ drivers/hwmon/pmbus/ltc3815.c | 7 +++---- drivers/hwmon/pmbus/max16064.c | 7 +++---- drivers/hwmon/pmbus/max16601.c | 7 +++---- drivers/hwmon/pmbus/max20730.c | 11 ++++++----- drivers/hwmon/pmbus/max20751.c | 7 +++---- drivers/hwmon/pmbus/max31785.c | 9 ++++----- drivers/hwmon/pmbus/max34440.c | 13 +++++++------ drivers/hwmon/pmbus/max8688.c | 7 +++---- drivers/hwmon/pmbus/pmbus.c | 11 ++++++----- drivers/hwmon/pmbus/pmbus.h | 3 +-- drivers/hwmon/pmbus/pmbus_core.c | 3 +-- drivers/hwmon/pmbus/pxe1610.c | 7 +++---- drivers/hwmon/pmbus/tps40422.c | 7 +++---- drivers/hwmon/pmbus/tps53679.c | 11 ++++++----- drivers/hwmon/pmbus/ucd9000.c | 13 ++++++------- drivers/hwmon/pmbus/ucd9200.c | 13 ++++++------- drivers/hwmon/pmbus/xdpe12284.c | 7 +++---- drivers/hwmon/pmbus/zl6100.c | 11 +++++------ 30 files changed, 131 insertions(+), 138 deletions(-) diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 501b37b0610d..e22c4f6808bc 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -270,8 +270,7 @@ obtain the chip status. Therefore, it must _not_ be called from that function. :: - int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info); + int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); Execute probe function. Similar to standard probe function for other drivers, with the pointer to struct pmbus_driver_info as additional argument. Calls diff --git a/Documentation/hwmon/pmbus.rst b/Documentation/hwmon/pmbus.rst index 67284bd5f4cd..fb3ad67dedc1 100644 --- a/Documentation/hwmon/pmbus.rst +++ b/Documentation/hwmon/pmbus.rst @@ -143,10 +143,9 @@ Emerson DS1200 power modules might look as follows:: | PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, }; - static int ds1200_probe(struct i2c_client *client, - const struct i2c_device_id *id) + static int ds1200_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &ds1200_info); + return pmbus_do_probe(client, &ds1200_info); } static int ds1200_remove(struct i2c_client *client) @@ -166,7 +165,7 @@ Emerson DS1200 power modules might look as follows:: .driver = { .name = "ds1200", }, - .probe = ds1200_probe, + .probe_new = ds1200_probe, .remove = ds1200_remove, .id_table = ds1200_id, }; diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 651846650a9c..e7997f37b266 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -462,8 +462,7 @@ static const struct i2c_device_id adm1275_id[] = { }; MODULE_DEVICE_TABLE(i2c, adm1275_id); -static int adm1275_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1275_probe(struct i2c_client *client) { s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; @@ -506,10 +505,10 @@ static int adm1275_probe(struct i2c_client *client, return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || mid->driver_data == adm1293 || mid->driver_data == adm1294) @@ -790,14 +789,14 @@ static int adm1275_probe(struct i2c_client *client, info->R[PSC_TEMPERATURE] = coefficients[tindex].R; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static struct i2c_driver adm1275_driver = { .driver = { .name = "adm1275", }, - .probe = adm1275_probe, + .probe_new = adm1275_probe, .remove = pmbus_do_remove, .id_table = adm1275_id, }; diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index f236e18f45a5..2c5b853d6c7f 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -87,12 +87,13 @@ static struct pmbus_driver_info pfe_driver_info[] = { }, }; -static int pfe_pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id pfe_device_id[]; + +static int pfe_pmbus_probe(struct i2c_client *client) { int model; - model = (int)id->driver_data; + model = (int)i2c_match_id(pfe_device_id, client)->driver_data; /* * PFE3000-12-069RA devices may not stay in page 0 during device @@ -104,7 +105,7 @@ static int pfe_pmbus_probe(struct i2c_client *client, i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); } - return pmbus_do_probe(client, id, &pfe_driver_info[model]); + return pmbus_do_probe(client, &pfe_driver_info[model]); } static const struct i2c_device_id pfe_device_id[] = { @@ -119,7 +120,7 @@ static struct i2c_driver pfe_pmbus_driver = { .driver = { .name = "bel-pfe", }, - .probe = pfe_pmbus_probe, + .probe_new = pfe_pmbus_probe, .remove = pmbus_do_remove, .id_table = pfe_device_id, }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 7d300f2f338d..2fb7540ee952 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -91,6 +91,8 @@ struct ibm_cffps { struct led_classdev led; }; +static const struct i2c_device_id ibm_cffps_id[]; + #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, @@ -473,8 +475,7 @@ static struct pmbus_platform_data ibm_cffps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ibm_cffps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ibm_cffps_probe(struct i2c_client *client) { int i, rc; enum versions vs = cffps_unknown; @@ -482,11 +483,15 @@ static int ibm_cffps_probe(struct i2c_client *client, struct dentry *ibm_cffps_dir; struct ibm_cffps *psu; const void *md = of_device_get_match_data(&client->dev); + const struct i2c_device_id *id; - if (md) + if (md) { vs = (enum versions)md; - else if (id) - vs = (enum versions)id->driver_data; + } else { + id = i2c_match_id(ibm_cffps_id, client); + if (id) + vs = (enum versions)id->driver_data; + } if (vs == cffps_unknown) { u16 ccin_revision = 0; @@ -519,7 +524,7 @@ static int ibm_cffps_probe(struct i2c_client *client, } client->dev.platform_data = &ibm_cffps_pdata; - rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]); + rc = pmbus_do_probe(client, &ibm_cffps_info[vs]); if (rc) return rc; @@ -611,7 +616,7 @@ static struct i2c_driver ibm_cffps_driver = { .name = "ibm-cffps", .of_match_table = ibm_cffps_of_match, }, - .probe = ibm_cffps_probe, + .probe_new = ibm_cffps_probe, .remove = pmbus_do_remove, .id_table = ibm_cffps_id, }; diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 42e01549184a..be493182174d 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -190,11 +190,10 @@ static struct pmbus_platform_data ipsps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ipsps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ipsps_probe(struct i2c_client *client) { client->dev.platform_data = &ipsps_pdata; - return pmbus_do_probe(client, id, &ipsps_info); + return pmbus_do_probe(client, &ipsps_info); } static const struct i2c_device_id ipsps_id[] = { @@ -216,7 +215,7 @@ static struct i2c_driver ipsps_driver = { .name = "inspur-ipsps", .of_match_table = of_match_ptr(ipsps_of_match), }, - .probe = ipsps_probe, + .probe_new = ipsps_probe, .remove = pmbus_do_remove, .id_table = ipsps_id, }; diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 3eea3e006a96..5fadb1def49f 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -67,8 +67,7 @@ static int ir35221_read_word_data(struct i2c_client *client, int page, return ret; } -static int ir35221_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir35221_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -123,7 +122,7 @@ static int ir35221_probe(struct i2c_client *client, | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP; info->func[1] = info->func[0]; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id ir35221_id[] = { @@ -137,7 +136,7 @@ static struct i2c_driver ir35221_driver = { .driver = { .name = "ir35221", }, - .probe = ir35221_probe, + .probe_new = ir35221_probe, .remove = pmbus_do_remove, .id_table = ir35221_id, }; diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 1820f5077f66..9ac563ce7dd8 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -35,10 +35,9 @@ static struct pmbus_driver_info ir38064_info = { | PMBUS_HAVE_POUT, }; -static int ir38064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir38064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &ir38064_info); + return pmbus_do_probe(client, &ir38064_info); } static const struct i2c_device_id ir38064_id[] = { @@ -53,7 +52,7 @@ static struct i2c_driver ir38064_driver = { .driver = { .name = "ir38064", }, - .probe = ir38064_probe, + .probe_new = ir38064_probe, .remove = pmbus_do_remove, .id_table = ir38064_id, }; diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index d37daa001fb3..44aeafcbd56c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -38,10 +38,9 @@ static struct pmbus_driver_info irps5401_info = { .func[4] = IRPS5401_LDO_FUNC, }; -static int irps5401_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int irps5401_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &irps5401_info); + return pmbus_do_probe(client, &irps5401_info); } static const struct i2c_device_id irps5401_id[] = { @@ -55,7 +54,7 @@ static struct i2c_driver irps5401_driver = { .driver = { .name = "irps5401", }, - .probe = irps5401_probe, + .probe_new = irps5401_probe, .remove = pmbus_do_remove, .id_table = irps5401_id, }; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 58aa95a3c010..7cad76e07f70 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -72,6 +72,8 @@ enum variants { raa_dmpvr2_hv, }; +static const struct i2c_device_id raa_dmpvr_id[]; + static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, int page, char *buf) @@ -218,8 +220,7 @@ static struct pmbus_driver_info raa_dmpvr_info = { | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; -static int isl68137_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int isl68137_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -228,7 +229,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENOMEM; memcpy(info, &raa_dmpvr_info, sizeof(*info)); - switch (id->driver_data) { + switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { case raa_dmpvr1_2rail: info->pages = 2; info->R[PSC_VOLTAGE_IN] = 3; @@ -267,7 +268,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id raa_dmpvr_id[] = { @@ -322,7 +323,7 @@ static struct i2c_driver isl68137_driver = { .driver = { .name = "isl68137", }, - .probe = isl68137_probe, + .probe_new = isl68137_probe, .remove = pmbus_do_remove, .id_table = raa_dmpvr_id, }; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 9e4cf0800186..429172a42902 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -211,6 +211,8 @@ struct lm25066_data { #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) +static const struct i2c_device_id lm25066_id[]; + static int lm25066_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -416,8 +418,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, return ret; } -static int lm25066_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm25066_probe(struct i2c_client *client) { int config; struct lm25066_data *data; @@ -437,7 +438,7 @@ static int lm25066_probe(struct i2c_client *client, if (config < 0) return config; - data->id = id->driver_data; + data->id = i2c_match_id(lm25066_id, client)->driver_data; info = &data->info; info->pages = 1; @@ -487,7 +488,7 @@ static int lm25066_probe(struct i2c_client *client, info->b[PSC_POWER] = coeff[PSC_POWER].b; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id lm25066_id[] = { @@ -506,7 +507,7 @@ static struct i2c_driver lm25066_driver = { .driver = { .name = "lm25066", }, - .probe = lm25066_probe, + .probe_new = lm25066_probe, .remove = pmbus_do_remove, .id_table = lm25066_id, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7b0e6b37e247..9a024cf70145 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -649,12 +649,12 @@ static int ltc2978_get_id(struct i2c_client *client) return -ENODEV; } -static int ltc2978_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc2978_probe(struct i2c_client *client) { int i, chip_id; struct ltc2978_data *data; struct pmbus_driver_info *info; + const struct i2c_device_id *id; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) @@ -670,11 +670,13 @@ static int ltc2978_probe(struct i2c_client *client, return chip_id; data->id = chip_id; + id = i2c_match_id(ltc2978_id, client); if (data->id != id->driver_data) dev_warn(&client->dev, - "Device mismatch: Configured %s, detected %s\n", + "Device mismatch: Configured %s (%d), detected %d\n", id->name, - ltc2978_id[data->id].name); + (int) id->driver_data, + chip_id); info = &data->info; info->write_word_data = ltc2978_write_word_data; @@ -832,7 +834,7 @@ static int ltc2978_probe(struct i2c_client *client, } #endif - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } @@ -872,7 +874,7 @@ static struct i2c_driver ltc2978_driver = { .name = "ltc2978", .of_match_table = of_match_ptr(ltc2978_of_match), }, - .probe = ltc2978_probe, + .probe_new = ltc2978_probe, .remove = pmbus_do_remove, .id_table = ltc2978_id, }; diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index 3036263e0a66..8328fb367ad6 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -178,8 +178,7 @@ static struct pmbus_driver_info ltc3815_info = { .write_word_data = ltc3815_write_word_data, }; -static int ltc3815_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc3815_probe(struct i2c_client *client) { int chip_id; @@ -193,14 +192,14 @@ static int ltc3815_probe(struct i2c_client *client, if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID) return -ENODEV; - return pmbus_do_probe(client, id, <c3815_info); + return pmbus_do_probe(client, <c3815_info); } static struct i2c_driver ltc3815_driver = { .driver = { .name = "ltc3815", }, - .probe = ltc3815_probe, + .probe_new = ltc3815_probe, .remove = pmbus_do_remove, .id_table = ltc3815_id, }; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 288e93f74c28..26e7f5ef9d7f 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -85,10 +85,9 @@ static struct pmbus_driver_info max16064_info = { .write_word_data = max16064_write_word_data, }; -static int max16064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max16064_info); + return pmbus_do_probe(client, &max16064_info); } static const struct i2c_device_id max16064_id[] = { @@ -103,7 +102,7 @@ static struct i2c_driver max16064_driver = { .driver = { .name = "max16064", }, - .probe = max16064_probe, + .probe_new = max16064_probe, .remove = pmbus_do_remove, .id_table = max16064_id, }; diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 51cdfaf9023c..71bb74e27a5c 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -239,8 +239,7 @@ static void max16601_remove(void *_data) i2c_unregister_device(data->vsa); } -static int max16601_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16601_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -288,7 +287,7 @@ static int max16601_probe(struct i2c_client *client, data->info = max16601_info; - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max16601_id[] = { @@ -302,7 +301,7 @@ static struct i2c_driver max16601_driver = { .driver = { .name = "max16601", }, - .probe = max16601_probe, + .probe_new = max16601_probe, .remove = pmbus_do_remove, .id_table = max16601_id, }; diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index a151a2b588a5..9475261ddacb 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -37,6 +37,8 @@ struct max20730_data { #define MAX20730_MFR_DEVSET1 0xd2 +static const struct i2c_device_id max20730_id[]; + /* * Convert discreet value to direct data format. Strictly speaking, all passed * values are constants, so we could do that calculation manually. On the @@ -295,8 +297,7 @@ static const struct pmbus_driver_info max20730_info[] = { }, }; -static int max20730_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20730_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -356,7 +357,7 @@ static int max20730_probe(struct i2c_client *client, if (client->dev.of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(max20730_id, client)->driver_data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -370,7 +371,7 @@ static int max20730_probe(struct i2c_client *client, return ret; data->mfr_devset1 = ret; - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max20730_id[] = { @@ -398,7 +399,7 @@ static struct i2c_driver max20730_driver = { .name = "max20730", .of_match_table = max20730_of_match, }, - .probe = max20730_probe, + .probe_new = max20730_probe, .remove = pmbus_do_remove, .id_table = max20730_id, }; diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index da3c38cb9a5c..921e92d82aec 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -26,10 +26,9 @@ static struct pmbus_driver_info max20751_info = { PMBUS_HAVE_POUT, }; -static int max20751_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20751_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max20751_info); + return pmbus_do_probe(client, &max20751_info); } static const struct i2c_device_id max20751_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver max20751_driver = { .driver = { .name = "max20751", }, - .probe = max20751_probe, + .probe_new = max20751_probe, .remove = pmbus_do_remove, .id_table = max20751_id, }; diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index d9aa5c873d21..839b957bc03e 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -324,8 +324,7 @@ static int max31785_configure_dual_tach(struct i2c_client *client, return 0; } -static int max31785_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max31785_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -354,7 +353,7 @@ static int max31785_probe(struct i2c_client *client, if (ret == MAX31785A) { dual_tach = true; } else if (ret == MAX31785) { - if (!strcmp("max31785a", id->name)) + if (!strcmp("max31785a", client->name)) dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n"); } else { return -ENODEV; @@ -366,7 +365,7 @@ static int max31785_probe(struct i2c_client *client, return ret; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id max31785_id[] = { @@ -390,7 +389,7 @@ static struct i2c_driver max31785_driver = { .name = "max31785", .of_match_table = max31785_of_match, }, - .probe = max31785_probe, + .probe_new = max31785_probe, .remove = pmbus_do_remove, .id_table = max31785_id, }; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index de04dff28945..8ea31b59f8e8 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -41,6 +41,8 @@ struct max34440_data { #define to_max34440_data(x) container_of(x, struct max34440_data, info) +static const struct i2c_device_id max34440_id[]; + static int max34440_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -458,8 +460,7 @@ static struct pmbus_driver_info max34440_info[] = { }, }; -static int max34440_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max34440_probe(struct i2c_client *client) { struct max34440_data *data; int rv; @@ -468,8 +469,8 @@ static int max34440_probe(struct i2c_client *client, GFP_KERNEL); if (!data) return -ENOMEM; - data->id = id->driver_data; - data->info = max34440_info[id->driver_data]; + data->id = i2c_match_id(max34440_id, client)->driver_data; + data->info = max34440_info[data->id]; if (data->id == max34451) { rv = max34451_set_supported_funcs(client, data); @@ -477,7 +478,7 @@ static int max34440_probe(struct i2c_client *client, return rv; } - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max34440_id[] = { @@ -496,7 +497,7 @@ static struct i2c_driver max34440_driver = { .driver = { .name = "max34440", }, - .probe = max34440_probe, + .probe_new = max34440_probe, .remove = pmbus_do_remove, .id_table = max34440_id, }; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 643ccfc05106..4b2239a6afd3 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -165,10 +165,9 @@ static struct pmbus_driver_info max8688_info = { .write_word_data = max8688_write_word_data, }; -static int max8688_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max8688_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max8688_info); + return pmbus_do_probe(client, &max8688_info); } static const struct i2c_device_id max8688_id[] = { @@ -183,7 +182,7 @@ static struct i2c_driver max8688_driver = { .driver = { .name = "max8688", }, - .probe = max8688_probe, + .probe_new = max8688_probe, .remove = pmbus_do_remove, .id_table = max8688_id, }; diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 6d384e8ee1db..20f1af9165c2 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -20,6 +20,8 @@ struct pmbus_device_info { u32 flags; }; +static const struct i2c_device_id pmbus_id[]; + /* * Find sensor groups and status registers on each page. */ @@ -159,8 +161,7 @@ abort: return ret; } -static int pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pmbus_probe(struct i2c_client *client) { struct pmbus_driver_info *info; struct pmbus_platform_data *pdata = NULL; @@ -171,7 +172,7 @@ static int pmbus_probe(struct i2c_client *client, if (!info) return -ENOMEM; - device_info = (struct pmbus_device_info *)id->driver_data; + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), GFP_KERNEL); @@ -185,7 +186,7 @@ static int pmbus_probe(struct i2c_client *client, info->identify = pmbus_identify; dev->platform_data = pdata; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct pmbus_device_info pmbus_info_one = { @@ -236,7 +237,7 @@ static struct i2c_driver pmbus_driver = { .driver = { .name = "pmbus", }, - .probe = pmbus_probe, + .probe_new = pmbus_probe, .remove = pmbus_do_remove, .id_table = pmbus_id, }; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 6d9f2cf70bff..88a5df2633fb 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -489,8 +489,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, void pmbus_clear_faults(struct i2c_client *client); bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info); +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); int pmbus_do_remove(struct i2c_client *client); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 89ea7da1403f..987de6d857bc 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2521,8 +2521,7 @@ static int pmbus_init_debugfs(struct i2c_client *client, } #endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info) +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) { struct device *dev = &client->dev; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 517584cff3de..fa5c5dd29b7a 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -78,8 +78,7 @@ static struct pmbus_driver_info pxe1610_info = { .identify = pxe1610_identify, }; -static int pxe1610_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pxe1610_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -115,7 +114,7 @@ static int pxe1610_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id pxe1610_id[] = { @@ -131,7 +130,7 @@ static struct i2c_driver pxe1610_driver = { .driver = { .name = "pxe1610", }, - .probe = pxe1610_probe, + .probe_new = pxe1610_probe, .remove = pmbus_do_remove, .id_table = pxe1610_id, }; diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 2b83dcda964a..edbdfa809d51 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -25,10 +25,9 @@ static struct pmbus_driver_info tps40422_info = { | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, }; -static int tps40422_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps40422_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &tps40422_info); + return pmbus_do_probe(client, &tps40422_info); } static const struct i2c_device_id tps40422_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver tps40422_driver = { .driver = { .name = "tps40422", }, - .probe = tps40422_probe, + .probe_new = tps40422_probe, .remove = pmbus_do_remove, .id_table = tps40422_id, }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 157c99ffb52b..db2bdf2a1f02 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -34,6 +34,8 @@ enum chips { #define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ +static const struct i2c_device_id tps53679_id[]; + static int tps53679_identify_mode(struct i2c_client *client, struct pmbus_driver_info *info) { @@ -183,8 +185,7 @@ static struct pmbus_driver_info tps53679_info = { .pfunc[5] = PMBUS_HAVE_IOUT, }; -static int tps53679_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps53679_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -193,7 +194,7 @@ static int tps53679_probe(struct i2c_client *client, if (dev->of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(tps53679_id, client)->driver_data; info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); if (!info) @@ -220,7 +221,7 @@ static int tps53679_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id tps53679_id[] = { @@ -249,7 +250,7 @@ static struct i2c_driver tps53679_driver = { .name = "tps53679", .of_match_table = of_match_ptr(tps53679_of_match), }, - .probe = tps53679_probe, + .probe_new = tps53679_probe, .remove = pmbus_do_remove, .id_table = tps53679_id, }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 81f4c4f166cd..f8017993e2b4 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -487,8 +487,7 @@ static int ucd9000_init_debugfs(struct i2c_client *client, } #endif /* CONFIG_DEBUG_FS */ -static int ucd9000_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9000_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct ucd9000_data *data; @@ -523,12 +522,12 @@ static int ucd9000_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9000 && chip != mid->driver_data) + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), GFP_KERNEL); @@ -603,7 +602,7 @@ static int ucd9000_probe(struct i2c_client *client, ucd9000_probe_gpio(client, mid, data); - ret = pmbus_do_probe(client, mid, info); + ret = pmbus_do_probe(client, info); if (ret) return ret; @@ -621,7 +620,7 @@ static struct i2c_driver ucd9000_driver = { .name = "ucd9000", .of_match_table = of_match_ptr(ucd9000_of_match), }, - .probe = ucd9000_probe, + .probe_new = ucd9000_probe, .remove = pmbus_do_remove, .id_table = ucd9000_id, }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 7c04745a9709..e111e25e1619 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -71,8 +71,7 @@ static const struct of_device_id __maybe_unused ucd9200_of_match[] = { }; MODULE_DEVICE_TABLE(of, ucd9200_of_match); -static int ucd9200_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9200_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct pmbus_driver_info *info; @@ -106,12 +105,12 @@ static int ucd9200_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9200 && chip != mid->driver_data) + if (chip != ucd9200 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); @@ -192,7 +191,7 @@ static int ucd9200_probe(struct i2c_client *client, if (mid->driver_data == ucd9240) info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } /* This is the driver that will be inserted */ @@ -201,7 +200,7 @@ static struct i2c_driver ucd9200_driver = { .name = "ucd9200", .of_match_table = of_match_ptr(ucd9200_of_match), }, - .probe = ucd9200_probe, + .probe_new = ucd9200_probe, .remove = pmbus_do_remove, .id_table = ucd9200_id, }; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index d5103fc9e269..c95ac934fde4 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -127,8 +127,7 @@ static struct pmbus_driver_info xdpe122_info = { .read_word_data = xdpe122_read_word_data, }; -static int xdpe122_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int xdpe122_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -137,7 +136,7 @@ static int xdpe122_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id xdpe122_id[] = { @@ -160,7 +159,7 @@ static struct i2c_driver xdpe122_driver = { .name = "xdpe12284", .of_match_table = of_match_ptr(xdpe122_of_match), }, - .probe = xdpe122_probe, + .probe_new = xdpe122_probe, .remove = pmbus_do_remove, .id_table = xdpe122_id, }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 3a827d0a881d..e8bda340482b 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -301,8 +301,7 @@ static const struct i2c_device_id zl6100_id[] = { }; MODULE_DEVICE_TABLE(i2c, zl6100_id); -static int zl6100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int zl6100_probe(struct i2c_client *client) { int ret; struct zl6100_data *data; @@ -333,10 +332,10 @@ static int zl6100_probe(struct i2c_client *client, dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data), GFP_KERNEL); @@ -389,14 +388,14 @@ static int zl6100_probe(struct i2c_client *client, info->write_word_data = zl6100_write_word_data; info->write_byte = zl6100_write_byte; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } static struct i2c_driver zl6100_driver = { .driver = { .name = "zl6100", }, - .probe = zl6100_probe, + .probe_new = zl6100_probe, .remove = pmbus_do_remove, .id_table = zl6100_id, }; From 6748703856d461f8cd62b72ebca51040e06cb310 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:02:22 +0200 Subject: [PATCH 09/64] hwmon: use simple i2c probe function Many hwmon drivers don't use the id information provided by the old i2c probe function, and the remainder can easily be adapted to the new form ("probe_new") by calling i2c_match_id explicitly. This avoids scanning the identifier tables during probes. Drivers which didn't use the id are converted as-is; drivers which did are modified as follows: * if the information in i2c_client is sufficient, that's used instead (client->name); * anything else is handled by calling i2c_match_id() with the same level of error-handling (if any) as before. A few drivers aren't included in this patch because they have a different set of maintainers. They will be covered by other patches. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813160222.1503401-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/ad7414.c | 5 ++--- drivers/hwmon/ad7418.c | 9 +++++---- drivers/hwmon/adm1021.c | 9 +++++---- drivers/hwmon/adm1025.c | 5 ++--- drivers/hwmon/adm1026.c | 5 ++--- drivers/hwmon/adm1031.c | 9 +++++---- drivers/hwmon/adm9240.c | 5 ++--- drivers/hwmon/adt7410.c | 5 ++--- drivers/hwmon/adt7411.c | 5 ++--- drivers/hwmon/adt7462.c | 5 ++--- drivers/hwmon/adt7470.c | 5 ++--- drivers/hwmon/adt7475.c | 6 +++--- drivers/hwmon/amc6821.c | 5 ++--- drivers/hwmon/asb100.c | 8 +++----- drivers/hwmon/atxp1.c | 5 ++--- drivers/hwmon/ds1621.c | 9 +++++---- drivers/hwmon/ds620.c | 5 ++--- drivers/hwmon/emc1403.c | 8 +++++--- drivers/hwmon/emc6w201.c | 5 ++--- drivers/hwmon/fschmd.c | 10 ++++------ drivers/hwmon/ftsteutates.c | 4 ++-- drivers/hwmon/g760a.c | 5 ++--- drivers/hwmon/g762.c | 4 ++-- drivers/hwmon/gl518sm.c | 5 ++--- drivers/hwmon/gl520sm.c | 5 ++--- drivers/hwmon/hih6130.c | 5 ++--- drivers/hwmon/ina209.c | 5 ++--- drivers/hwmon/ina2xx.c | 9 +++++---- drivers/hwmon/ina3221.c | 5 ++--- drivers/hwmon/jc42.c | 4 ++-- drivers/hwmon/lineage-pem.c | 5 ++--- drivers/hwmon/lm63.c | 9 +++++---- drivers/hwmon/lm75.c | 9 +++++---- drivers/hwmon/lm77.c | 4 ++-- drivers/hwmon/lm78.c | 9 +++++---- drivers/hwmon/lm80.c | 5 ++--- drivers/hwmon/lm83.c | 9 +++++---- drivers/hwmon/lm85.c | 8 +++++--- drivers/hwmon/lm90.c | 7 +++---- drivers/hwmon/lm92.c | 5 ++--- drivers/hwmon/lm93.c | 5 ++--- drivers/hwmon/lm95234.c | 9 +++++---- drivers/hwmon/lm95241.c | 5 ++--- drivers/hwmon/lm95245.c | 5 ++--- drivers/hwmon/ltc2945.c | 5 ++--- drivers/hwmon/ltc2990.c | 5 ++--- drivers/hwmon/ltc4151.c | 5 ++--- drivers/hwmon/ltc4215.c | 5 ++--- drivers/hwmon/ltc4222.c | 5 ++--- drivers/hwmon/ltc4245.c | 5 ++--- drivers/hwmon/ltc4260.c | 5 ++--- drivers/hwmon/ltc4261.c | 5 ++--- drivers/hwmon/max16065.c | 8 +++++--- drivers/hwmon/max1619.c | 5 ++--- drivers/hwmon/max1668.c | 9 +++++---- drivers/hwmon/max31730.c | 4 ++-- drivers/hwmon/max31790.c | 5 ++--- drivers/hwmon/max6621.c | 5 ++--- drivers/hwmon/max6639.c | 5 ++--- drivers/hwmon/max6642.c | 5 ++--- drivers/hwmon/max6650.c | 10 ++++++---- drivers/hwmon/max6697.c | 9 +++++---- drivers/hwmon/mcp3021.c | 9 +++++---- drivers/hwmon/nct7802.c | 5 ++--- drivers/hwmon/nct7904.c | 5 ++--- drivers/hwmon/occ/p8_i2c.c | 5 ++--- drivers/hwmon/pcf8591.c | 5 ++--- drivers/hwmon/powr1220.c | 5 ++--- drivers/hwmon/sht21.c | 5 ++--- drivers/hwmon/sht3x.c | 9 +++++---- drivers/hwmon/shtc1.c | 9 +++++---- drivers/hwmon/smm665.c | 9 +++++---- drivers/hwmon/smsc47m192.c | 5 ++--- drivers/hwmon/stts751.c | 5 ++--- drivers/hwmon/tc654.c | 5 ++--- drivers/hwmon/tc74.c | 5 ++--- drivers/hwmon/thmc50.c | 9 +++++---- drivers/hwmon/tmp102.c | 5 ++--- drivers/hwmon/tmp103.c | 5 ++--- drivers/hwmon/tmp108.c | 5 ++--- drivers/hwmon/tmp401.c | 7 +++---- drivers/hwmon/tmp421.c | 7 +++---- drivers/hwmon/w83773g.c | 5 ++--- drivers/hwmon/w83781d.c | 9 +++++---- drivers/hwmon/w83792d.c | 7 +++---- drivers/hwmon/w83l785ts.c | 8 +++----- drivers/hwmon/w83l786ng.c | 4 ++-- 87 files changed, 250 insertions(+), 285 deletions(-) diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index a529f2efc790..6a765755d061 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -169,8 +169,7 @@ static struct attribute *ad7414_attrs[] = { ATTRIBUTE_GROUPS(ad7414); -static int ad7414_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int ad7414_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ad7414_data *data; @@ -222,7 +221,7 @@ static struct i2c_driver ad7414_driver = { .name = "ad7414", .of_match_table = of_match_ptr(ad7414_of_match), }, - .probe = ad7414_probe, + .probe_new = ad7414_probe, .id_table = ad7414_id, }; diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index 74542b8ad8ef..d618f6b2f382 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -230,8 +230,9 @@ static void ad7418_init_client(struct i2c_client *client) } } -static int ad7418_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ad7418_id[]; + +static int ad7418_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; @@ -254,7 +255,7 @@ static int ad7418_probe(struct i2c_client *client, if (dev->of_node) data->type = (enum chips)of_device_get_match_data(dev); else - data->type = id->driver_data; + data->type = i2c_match_id(ad7418_id, client)->driver_data; switch (data->type) { case ad7416: @@ -305,7 +306,7 @@ static struct i2c_driver ad7418_driver = { .name = "ad7418", .of_match_table = ad7418_dt_ids, }, - .probe = ad7418_probe, + .probe_new = ad7418_probe, .id_table = ad7418_id, }; diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index c45046241a1c..71deb2cd20f5 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -425,8 +425,9 @@ static void adm1021_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04); } -static int adm1021_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adm1021_id[]; + +static int adm1021_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adm1021_data *data; @@ -437,7 +438,7 @@ static int adm1021_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(adm1021_id, client)->driver_data; mutex_init(&data->update_lock); /* Initialize the ADM1021 chip */ @@ -472,7 +473,7 @@ static struct i2c_driver adm1021_driver = { .driver = { .name = "adm1021", }, - .probe = adm1021_probe, + .probe_new = adm1021_probe, .id_table = adm1021_id, .detect = adm1021_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index ed15185fa60f..de51e01c061b 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -517,8 +517,7 @@ static void adm1025_init_client(struct i2c_client *client) (reg&0x7E)|0x01); } -static int adm1025_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1025_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -560,7 +559,7 @@ static struct i2c_driver adm1025_driver = { .driver = { .name = "adm1025", }, - .probe = adm1025_probe, + .probe_new = adm1025_probe, .id_table = adm1025_id, .detect = adm1025_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index af77096724fd..49cefbadb156 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1816,8 +1816,7 @@ static void adm1026_init_client(struct i2c_client *client) } } -static int adm1026_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1026_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1860,7 +1859,7 @@ static struct i2c_driver adm1026_driver = { .driver = { .name = "adm1026", }, - .probe = adm1026_probe, + .probe_new = adm1026_probe, .id_table = adm1026_id, .detect = adm1026_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 7723a338446d..b538ace2d292 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -1022,8 +1022,9 @@ static void adm1031_init_client(struct i2c_client *client) data->update_interval = update_intervals[i]; } -static int adm1031_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adm1031_id[]; + +static int adm1031_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1035,7 +1036,7 @@ static int adm1031_probe(struct i2c_client *client, i2c_set_clientdata(client, data); data->client = client; - data->chip_type = id->driver_data; + data->chip_type = i2c_match_id(adm1031_id, client)->driver_data; mutex_init(&data->update_lock); if (data->chip_type == adm1030) @@ -1068,7 +1069,7 @@ static struct i2c_driver adm1031_driver = { .driver = { .name = "adm1031", }, - .probe = adm1031_probe, + .probe_new = adm1031_probe, .id_table = adm1031_id, .detect = adm1031_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 496d47490e10..16364dee1794 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -704,8 +704,7 @@ static void adm9240_init_client(struct i2c_client *client) } } -static int adm9240_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int adm9240_probe(struct i2c_client *new_client) { struct device *dev = &new_client->dev; struct device *hwmon_dev; @@ -741,7 +740,7 @@ static struct i2c_driver adm9240_driver = { .driver = { .name = "adm9240", }, - .probe = adm9240_probe, + .probe_new = adm9240_probe, .id_table = adm9240_id, .detect = adm9240_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 80f8a4673315..9d80895d0266 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -39,8 +39,7 @@ static const struct adt7x10_ops adt7410_i2c_ops = { .write_byte = adt7410_i2c_write_byte, }; -static int adt7410_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7410_i2c_probe(struct i2c_client *client) { if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -67,7 +66,7 @@ static struct i2c_driver adt7410_driver = { .name = "adt7410", .pm = ADT7X10_DEV_PM_OPS, }, - .probe = adt7410_i2c_probe, + .probe_new = adt7410_i2c_probe, .remove = adt7410_i2c_remove, .id_table = adt7410_ids, .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b), diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 5a839cc2ed1c..fad74aa62b64 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -666,8 +666,7 @@ static const struct hwmon_chip_info adt7411_chip_info = { .info = adt7411_info, }; -static int adt7411_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7411_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7411_data *data; @@ -707,7 +706,7 @@ static struct i2c_driver adt7411_driver = { .driver = { .name = "adt7411", }, - .probe = adt7411_probe, + .probe_new = adt7411_probe, .id_table = adt7411_id, .detect = adt7411_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 208813158bb4..e75bbd87ad09 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -1787,8 +1787,7 @@ static int adt7462_detect(struct i2c_client *client, return 0; } -static int adt7462_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7462_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7462_data *data; @@ -1820,7 +1819,7 @@ static struct i2c_driver adt7462_driver = { .driver = { .name = "adt7462", }, - .probe = adt7462_probe, + .probe_new = adt7462_probe, .id_table = adt7462_id, .detect = adt7462_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index a30f34cf512c..740f39a54ab0 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -1217,8 +1217,7 @@ static void adt7470_init_client(struct i2c_client *client) } } -static int adt7470_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7470_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7470_data *data; @@ -1276,7 +1275,7 @@ static struct i2c_driver adt7470_driver = { .driver = { .name = "adt7470", }, - .probe = adt7470_probe, + .probe_new = adt7470_probe, .remove = adt7470_remove, .id_table = adt7470_id, .detect = adt7470_detect, diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 054080443b47..9d5b019651f2 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1539,8 +1539,7 @@ static int adt7475_set_pwm_polarity(struct i2c_client *client) return 0; } -static int adt7475_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7475_probe(struct i2c_client *client) { enum chips chip; static const char * const names[] = { @@ -1554,6 +1553,7 @@ static int adt7475_probe(struct i2c_client *client, struct device *hwmon_dev; int i, ret = 0, revision, group_num = 0; u8 config3; + const struct i2c_device_id *id = i2c_match_id(adt7475_id, client); data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) @@ -1728,7 +1728,7 @@ static struct i2c_driver adt7475_driver = { .name = "adt7475", .of_match_table = of_match_ptr(adt7475_of_match), }, - .probe = adt7475_probe, + .probe_new = adt7475_probe, .id_table = adt7475_id, .detect = adt7475_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 013fb056b1d0..6b1ce2242c61 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -900,8 +900,7 @@ static int amc6821_init_client(struct i2c_client *client) return 0; } -static int amc6821_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int amc6821_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct amc6821_data *data; @@ -940,7 +939,7 @@ static struct i2c_driver amc6821_driver = { .driver = { .name = "amc6821", }, - .probe = amc6821_probe, + .probe_new = amc6821_probe, .id_table = amc6821_id, .detect = amc6821_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 4c609e23a4ef..ba9fcf6f9264 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -205,8 +205,7 @@ struct asb100_data { static int asb100_read_value(struct i2c_client *client, u16 reg); static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); -static int asb100_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int asb100_probe(struct i2c_client *client); static int asb100_detect(struct i2c_client *client, struct i2c_board_info *info); static int asb100_remove(struct i2c_client *client); @@ -224,7 +223,7 @@ static struct i2c_driver asb100_driver = { .driver = { .name = "asb100", }, - .probe = asb100_probe, + .probe_new = asb100_probe, .remove = asb100_remove, .id_table = asb100_id, .detect = asb100_detect, @@ -775,8 +774,7 @@ static int asb100_detect(struct i2c_client *client, return 0; } -static int asb100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int asb100_probe(struct i2c_client *client) { int err; struct asb100_data *data; diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 79b8df258371..1e08a5431f12 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -244,8 +244,7 @@ static struct attribute *atxp1_attrs[] = { }; ATTRIBUTE_GROUPS(atxp1); -static int atxp1_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int atxp1_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct atxp1_data *data; @@ -288,7 +287,7 @@ static struct i2c_driver atxp1_driver = { .driver = { .name = "atxp1", }, - .probe = atxp1_probe, + .probe_new = atxp1_probe, .id_table = atxp1_id, }; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 541bed8732b7..e1d742bfc74c 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -342,8 +342,9 @@ static const struct attribute_group ds1621_group = { }; __ATTRIBUTE_GROUPS(ds1621); -static int ds1621_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ds1621_id[]; + +static int ds1621_probe(struct i2c_client *client) { struct ds1621_data *data; struct device *hwmon_dev; @@ -355,7 +356,7 @@ static int ds1621_probe(struct i2c_client *client, mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(ds1621_id, client)->driver_data; data->client = client; /* Initialize the DS1621 chip */ @@ -383,7 +384,7 @@ static struct i2c_driver ds1621_driver = { .driver = { .name = "ds1621", }, - .probe = ds1621_probe, + .probe_new = ds1621_probe, .id_table = ds1621_id, }; diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 8f1fc83ac37b..9ec722798c4a 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -211,8 +211,7 @@ static struct attribute *ds620_attrs[] = { ATTRIBUTE_GROUPS(ds620); -static int ds620_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds620_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -246,7 +245,7 @@ static struct i2c_driver ds620_driver = { .driver = { .name = "ds620", }, - .probe = ds620_probe, + .probe_new = ds620_probe, .id_table = ds620_id, }; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index e9c0bbc2caa9..314838272049 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -386,11 +386,13 @@ static const struct regmap_config emc1403_regmap_config = { .volatile_reg = emc1403_regmap_is_volatile, }; -static int emc1403_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id emc1403_idtable[]; + +static int emc1403_probe(struct i2c_client *client) { struct thermal_data *data; struct device *hwmon_dev; + const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client); data = devm_kzalloc(&client->dev, sizeof(struct thermal_data), GFP_KERNEL); @@ -452,7 +454,7 @@ static struct i2c_driver sensor_emc1403 = { .name = "emc1403", }, .detect = emc1403_detect, - .probe = emc1403_probe, + .probe_new = emc1403_probe, .id_table = emc1403_idtable, .address_list = emc1403_address_list, }; diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index df0f7292e214..ec5c98702bf5 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -444,8 +444,7 @@ static int emc6w201_detect(struct i2c_client *client, return 0; } -static int emc6w201_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int emc6w201_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct emc6w201_data *data; @@ -475,7 +474,7 @@ static struct i2c_driver emc6w201_driver = { .driver = { .name = "emc6w201", }, - .probe = emc6w201_probe, + .probe_new = emc6w201_probe, .id_table = emc6w201_id, .detect = emc6w201_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 4136643d8e0c..5191cd85a8d1 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -214,8 +214,7 @@ static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; * Functions declarations */ -static int fschmd_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int fschmd_probe(struct i2c_client *client); static int fschmd_detect(struct i2c_client *client, struct i2c_board_info *info); static int fschmd_remove(struct i2c_client *client); @@ -242,7 +241,7 @@ static struct i2c_driver fschmd_driver = { .driver = { .name = "fschmd", }, - .probe = fschmd_probe, + .probe_new = fschmd_probe, .remove = fschmd_remove, .id_table = fschmd_id, .detect = fschmd_detect, @@ -1081,15 +1080,14 @@ static int fschmd_detect(struct i2c_client *client, return 0; } -static int fschmd_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int fschmd_probe(struct i2c_client *client) { struct fschmd_data *data; const char * const names[7] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall", "Hades", "Syleus" }; const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; int i, err; - enum chips kind = id->driver_data; + enum chips kind = i2c_match_id(fschmd_id, client)->driver_data; data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL); if (!data) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 371ce7745f5e..ef88a156efc2 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -752,7 +752,7 @@ static int fts_remove(struct i2c_client *client) return 0; } -static int fts_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int fts_probe(struct i2c_client *client) { u8 revision; struct fts_data *data; @@ -819,7 +819,7 @@ static struct i2c_driver fts_driver = { .name = "ftsteutates", }, .id_table = fts_id, - .probe = fts_probe, + .probe_new = fts_probe, .remove = fts_remove, .detect = fts_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 31beedcb420f..a692f7b2f6f7 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -170,8 +170,7 @@ ATTRIBUTE_GROUPS(g760a); * new-style driver model code */ -static int g760a_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int g760a_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct g760a_data *data; @@ -207,7 +206,7 @@ static struct i2c_driver g760a_driver = { .driver = { .name = "g760a", }, - .probe = g760a_probe, + .probe_new = g760a_probe, .id_table = g760a_id, }; diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 5f0f34631580..64a0599b2da5 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -1033,7 +1033,7 @@ static inline int g762_fan_init(struct device *dev) data->fan_cmd1); } -static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int g762_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1079,7 +1079,7 @@ static struct i2c_driver g762_driver = { .name = DRVNAME, .of_match_table = of_match_ptr(g762_dt_match), }, - .probe = g762_probe, + .probe_new = g762_probe, .id_table = g762_id, }; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 4964beeea542..7aaee5a48243 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -611,8 +611,7 @@ static void gl518_init_client(struct i2c_client *client) gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); } -static int gl518_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gl518_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -653,7 +652,7 @@ static struct i2c_driver gl518_driver = { .driver = { .name = "gl518sm", }, - .probe = gl518_probe, + .probe_new = gl518_probe, .id_table = gl518_id, .detect = gl518_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 4689e01cb56d..4ae1295cc3ea 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -854,8 +854,7 @@ static void gl520_init_client(struct i2c_client *client) gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); } -static int gl520_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gl520_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -896,7 +895,7 @@ static struct i2c_driver gl520_driver = { .driver = { .name = "gl520sm", }, - .probe = gl520_probe, + .probe_new = gl520_probe, .id_table = gl520_id, .detect = gl520_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 018df6074f7b..d9394e19fea8 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -204,8 +204,7 @@ static struct attribute *hih6130_attrs[] = { ATTRIBUTE_GROUPS(hih6130); -static int hih6130_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int hih6130_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct hih6130 *hih6130; @@ -250,7 +249,7 @@ static struct i2c_driver hih6130_driver = { .name = "hih6130", .of_match_table = of_match_ptr(hih6130_of_match), }, - .probe = hih6130_probe, + .probe_new = hih6130_probe, .id_table = hih6130_id, }; diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index 08ee3a64a026..f4c7b5f76359 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -531,8 +531,7 @@ static int ina209_init_client(struct i2c_client *client, return 0; } -static int ina209_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ina209_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct ina209_data *data; @@ -597,7 +596,7 @@ static struct i2c_driver ina209_driver = { .name = "ina209", .of_match_table = of_match_ptr(ina209_of_match), }, - .probe = ina209_probe, + .probe_new = ina209_probe, .remove = ina209_remove, .id_table = ina209_id, }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 0fc6d5857993..ca97f9e931bc 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -614,8 +614,9 @@ static const struct attribute_group ina226_group = { .attrs = ina226_attrs, }; -static int ina2xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ina2xx_id[]; + +static int ina2xx_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ina2xx_data *data; @@ -627,7 +628,7 @@ static int ina2xx_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = i2c_match_id(ina2xx_id, client)->driver_data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -717,7 +718,7 @@ static struct i2c_driver ina2xx_driver = { .name = "ina2xx", .of_match_table = of_match_ptr(ina2xx_of_match), }, - .probe = ina2xx_probe, + .probe_new = ina2xx_probe, .id_table = ina2xx_id, }; diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 81e155692aba..41fb17e0d641 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -822,8 +822,7 @@ static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) return 0; } -static int ina3221_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ina3221_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ina3221_data *ina; @@ -1016,7 +1015,7 @@ static const struct i2c_device_id ina3221_ids[] = { MODULE_DEVICE_TABLE(i2c, ina3221_ids); static struct i2c_driver ina3221_i2c_driver = { - .probe = ina3221_probe, + .probe_new = ina3221_probe, .remove = ina3221_remove, .driver = { .name = INA3221_DRIVER_NAME, diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index e3f1ebee7130..4a03d010ec5a 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -458,7 +458,7 @@ static const struct hwmon_chip_info jc42_chip_info = { .info = jc42_info, }; -static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int jc42_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -581,7 +581,7 @@ static struct i2c_driver jc42_driver = { .pm = JC42_DEV_PM_OPS, .of_match_table = of_match_ptr(jc42_of_ids), }, - .probe = jc42_probe, + .probe_new = jc42_probe, .remove = jc42_remove, .id_table = jc42_id, .detect = jc42_detect, diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index ce5b0598524c..c83eb2fd80eb 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -417,8 +417,7 @@ static const struct attribute_group pem_fan_group = { .attrs = pem_fan_attributes, }; -static int pem_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pem_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -512,7 +511,7 @@ static struct i2c_driver pem_driver = { .driver = { .name = "lineage_pem", }, - .probe = pem_probe, + .probe_new = pem_probe, .id_table = pem_id, }; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 60a817f58db9..50f67265c71d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -1087,8 +1087,9 @@ static void lm63_init_client(struct lm63_data *data) (data->config_fan & 0x20) ? "manual" : "auto"); } -static int lm63_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm63_id[]; + +static int lm63_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1106,7 +1107,7 @@ static int lm63_probe(struct i2c_client *client, if (client->dev.of_node) data->kind = (enum chips)of_device_get_match_data(&client->dev); else - data->kind = id->driver_data; + data->kind = i2c_match_id(lm63_id, client)->driver_data; if (data->kind == lm64) data->temp2_offset = 16000; @@ -1163,7 +1164,7 @@ static struct i2c_driver lm63_driver = { .name = "lm63", .of_match_table = of_match_ptr(lm63_of_match), }, - .probe = lm63_probe, + .probe_new = lm63_probe, .id_table = lm63_id, .detect = lm63_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index ba0be48aeadd..e22f977942b4 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -542,8 +542,9 @@ static void lm75_remove(void *data) i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); } -static int -lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id lm75_ids[]; + +static int lm75_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -554,7 +555,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.of_node) kind = (enum lm75_type)of_device_get_match_data(&client->dev); else - kind = id->driver_data; + kind = i2c_match_id(lm75_ids, client)->driver_data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -893,7 +894,7 @@ static struct i2c_driver lm75_driver = { .of_match_table = of_match_ptr(lm75_of_match), .pm = LM75_DEV_PM_OPS, }, - .probe = lm75_probe, + .probe_new = lm75_probe, .id_table = lm75_ids, .detect = lm75_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 671a962fde29..7570c9d50ddc 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -315,7 +315,7 @@ static void lm77_init_client(struct i2c_client *client) lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); } -static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int lm77_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -348,7 +348,7 @@ static struct i2c_driver lm77_driver = { .driver = { .name = "lm77", }, - .probe = lm77_probe, + .probe_new = lm77_probe, .id_table = lm77_id, .detect = lm77_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 2119461ec43a..1aa35ca0c6fe 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -627,8 +627,9 @@ static int lm78_i2c_detect(struct i2c_client *client, return -ENODEV; } -static int lm78_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm78_i2c_id[]; + +static int lm78_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -639,7 +640,7 @@ static int lm78_i2c_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(lm78_i2c_id, client)->driver_data; /* Initialize the LM78 chip */ lm78_init_device(data); @@ -661,7 +662,7 @@ static struct i2c_driver lm78_driver = { .driver = { .name = "lm78", }, - .probe = lm78_i2c_probe, + .probe_new = lm78_i2c_probe, .id_table = lm78_i2c_id, .detect = lm78_i2c_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 80520cef7617..ac4adb44b224 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -591,8 +591,7 @@ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm80_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm80_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -641,7 +640,7 @@ static struct i2c_driver lm80_driver = { .driver = { .name = "lm80", }, - .probe = lm80_probe, + .probe_new = lm80_probe, .id_table = lm80_id, .detect = lm80_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 8fefca9bbbb7..2ff5ecce608e 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -317,8 +317,9 @@ static int lm83_detect(struct i2c_client *new_client, return 0; } -static int lm83_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm83_id[]; + +static int lm83_probe(struct i2c_client *new_client) { struct device *hwmon_dev; struct lm83_data *data; @@ -338,7 +339,7 @@ static int lm83_probe(struct i2c_client *new_client, * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ data->groups[0] = &lm83_group; - if (id->driver_data == lm83) + if (i2c_match_id(lm83_id, new_client)->driver_data == lm83) data->groups[1] = &lm83_group_opt; hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, @@ -363,7 +364,7 @@ static struct i2c_driver lm83_driver = { .driver = { .name = "lm83", }, - .probe = lm83_probe, + .probe_new = lm83_probe, .id_table = lm83_id, .detect = lm83_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index cff0aa505a78..c7bf5de7b70f 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1544,7 +1544,9 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id lm85_id[]; + +static int lm85_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1559,7 +1561,7 @@ static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.of_node) data->type = (enum chips)of_device_get_match_data(&client->dev); else - data->type = id->driver_data; + data->type = i2c_match_id(lm85_id, client)->driver_data; mutex_init(&data->update_lock); /* Fill in the chip specific driver values */ @@ -1696,7 +1698,7 @@ static struct i2c_driver lm85_driver = { .name = "lm85", .of_match_table = of_match_ptr(lm85_of_match), }, - .probe = lm85_probe, + .probe_new = lm85_probe, .id_table = lm85_id, .detect = lm85_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 7bdc664af55b..ebbfd5f352c0 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1779,8 +1779,7 @@ static const struct hwmon_ops lm90_ops = { .write = lm90_write, }; -static int lm90_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm90_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; @@ -1816,7 +1815,7 @@ static int lm90_probe(struct i2c_client *client, if (client->dev.of_node) data->kind = (enum chips)of_device_get_match_data(&client->dev); else - data->kind = id->driver_data; + data->kind = i2c_match_id(lm90_id, client)->driver_data; if (data->kind == adm1032) { if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) client->flags &= ~I2C_CLIENT_PEC; @@ -1952,7 +1951,7 @@ static struct i2c_driver lm90_driver = { .name = "lm90", .of_match_table = of_match_ptr(lm90_of_match), }, - .probe = lm90_probe, + .probe_new = lm90_probe, .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 84347db5edf3..9bf278cf0bd0 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -292,8 +292,7 @@ static int lm92_detect(struct i2c_client *new_client, return 0; } -static int lm92_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int lm92_probe(struct i2c_client *new_client) { struct device *hwmon_dev; struct lm92_data *data; @@ -331,7 +330,7 @@ static struct i2c_driver lm92_driver = { .driver = { .name = "lm92", }, - .probe = lm92_probe, + .probe_new = lm92_probe, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index cea8ea323271..78d6dfaf145b 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2583,8 +2583,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm93_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm93_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm93_data *data; @@ -2636,7 +2635,7 @@ static struct i2c_driver lm93_driver = { .driver = { .name = "lm93", }, - .probe = lm93_probe, + .probe_new = lm93_probe, .id_table = lm93_id, .detect = lm93_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 8a2a2a490496..ac169a994ae0 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -677,8 +677,9 @@ static int lm95234_init_client(struct i2c_client *client) return 0; } -static int lm95234_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm95234_id[]; + +static int lm95234_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95234_data *data; @@ -698,7 +699,7 @@ static int lm95234_probe(struct i2c_client *client, return err; data->groups[0] = &lm95234_common_group; - if (id->driver_data == lm95234) + if (i2c_match_id(lm95234_id, client)->driver_data == lm95234) data->groups[1] = &lm95234_group; hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, @@ -719,7 +720,7 @@ static struct i2c_driver lm95234_driver = { .driver = { .name = DRVNAME, }, - .probe = lm95234_probe, + .probe_new = lm95234_probe, .id_table = lm95234_id, .detect = lm95234_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 8d66d6e3c0fc..00dbc170c8c6 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -432,8 +432,7 @@ static const struct hwmon_chip_info lm95241_chip_info = { .info = lm95241_info, }; -static int lm95241_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm95241_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95241_data *data; @@ -469,7 +468,7 @@ static struct i2c_driver lm95241_driver = { .driver = { .name = DEVNAME, }, - .probe = lm95241_probe, + .probe_new = lm95241_probe, .id_table = lm95241_id, .detect = lm95241_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 057614e664e1..29388fcf5f74 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -547,8 +547,7 @@ static const struct hwmon_chip_info lm95245_chip_info = { .info = lm95245_info, }; -static int lm95245_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm95245_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95245_data *data; @@ -598,7 +597,7 @@ static struct i2c_driver lm95245_driver = { .name = "lm95245", .of_match_table = of_match_ptr(lm95245_of_match), }, - .probe = lm95245_probe, + .probe_new = lm95245_probe, .id_table = lm95245_id, .detect = lm95245_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 2818276ed3d6..ba9c868a8641 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -445,8 +445,7 @@ static const struct regmap_config ltc2945_regmap_config = { .max_register = LTC2945_MIN_ADIN_THRES_L, }; -static int ltc2945_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc2945_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -478,7 +477,7 @@ static struct i2c_driver ltc2945_driver = { .driver = { .name = "ltc2945", }, - .probe = ltc2945_probe, + .probe_new = ltc2945_probe, .id_table = ltc2945_id, }; diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 53ff5051774c..78b191b26bb2 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -200,8 +200,7 @@ static const struct attribute_group ltc2990_group = { }; __ATTRIBUTE_GROUPS(ltc2990); -static int ltc2990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ltc2990_i2c_probe(struct i2c_client *i2c) { int ret; struct device *hwmon_dev; @@ -269,7 +268,7 @@ static struct i2c_driver ltc2990_i2c_driver = { .driver = { .name = "ltc2990", }, - .probe = ltc2990_i2c_probe, + .probe_new = ltc2990_i2c_probe, .id_table = ltc2990_i2c_id, }; diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index 67a529b7ba18..321f54e237bd 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -154,8 +154,7 @@ static struct attribute *ltc4151_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4151); -static int ltc4151_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4151_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -206,7 +205,7 @@ static struct i2c_driver ltc4151_driver = { .name = "ltc4151", .of_match_table = of_match_ptr(ltc4151_match), }, - .probe = ltc4151_probe, + .probe_new = ltc4151_probe, .id_table = ltc4151_id, }; diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index f783ac19675e..7cef3cb2962b 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -218,8 +218,7 @@ static struct attribute *ltc4215_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4215); -static int ltc4215_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4215_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -256,7 +255,7 @@ static struct i2c_driver ltc4215_driver = { .driver = { .name = "ltc4215", }, - .probe = ltc4215_probe, + .probe_new = ltc4215_probe, .id_table = ltc4215_id, }; diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c index d15485e93fb8..3efce6d1cb88 100644 --- a/drivers/hwmon/ltc4222.c +++ b/drivers/hwmon/ltc4222.c @@ -177,8 +177,7 @@ static const struct regmap_config ltc4222_regmap_config = { .max_register = LTC4222_ADC_CONTROL, }; -static int ltc4222_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4222_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -211,7 +210,7 @@ static struct i2c_driver ltc4222_driver = { .driver = { .name = "ltc4222", }, - .probe = ltc4222_probe, + .probe_new = ltc4222_probe, .id_table = ltc4222_id, }; diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 244a83d675cd..5088d28b3a7c 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -440,8 +440,7 @@ static bool ltc4245_use_extra_gpios(struct i2c_client *client) return false; } -static int ltc4245_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4245_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct ltc4245_data *data; @@ -480,7 +479,7 @@ static struct i2c_driver ltc4245_driver = { .driver = { .name = "ltc4245", }, - .probe = ltc4245_probe, + .probe_new = ltc4245_probe, .id_table = ltc4245_id, }; diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c index 8b8fd4a313ee..d0beb43abf3f 100644 --- a/drivers/hwmon/ltc4260.c +++ b/drivers/hwmon/ltc4260.c @@ -141,8 +141,7 @@ static const struct regmap_config ltc4260_regmap_config = { .max_register = LTC4260_ADIN, }; -static int ltc4260_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4260_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -174,7 +173,7 @@ static struct i2c_driver ltc4260_driver = { .driver = { .name = "ltc4260", }, - .probe = ltc4260_probe, + .probe_new = ltc4260_probe, .id_table = ltc4260_id, }; diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index c415829ffbf5..1dab84b52df5 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -190,8 +190,7 @@ static struct attribute *ltc4261_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4261); -static int ltc4261_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4261_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -234,7 +233,7 @@ static struct i2c_driver ltc4261_driver = { .driver = { .name = "ltc4261", }, - .probe = ltc4261_probe, + .probe_new = ltc4261_probe, .id_table = ltc4261_id, }; diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index 49b7e0b6d1bb..a26226e7bc37 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -493,8 +493,9 @@ static const struct attribute_group max16065_max_group = { .is_visible = max16065_secondary_is_visible, }; -static int max16065_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max16065_id[]; + +static int max16065_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct max16065_data *data; @@ -504,6 +505,7 @@ static int max16065_probe(struct i2c_client *client, bool have_secondary; /* true if chip has secondary limits */ bool secondary_is_max = false; /* secondary limits reflect max */ int groups = 0; + const struct i2c_device_id *id = i2c_match_id(max16065_id, client); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_READ_WORD_DATA)) @@ -598,7 +600,7 @@ static struct i2c_driver max16065_driver = { .driver = { .name = "max16065", }, - .probe = max16065_probe, + .probe_new = max16065_probe, .id_table = max16065_id, }; diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 87c6665bab3a..8bd941cae4d1 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -261,8 +261,7 @@ static void max1619_init_client(struct i2c_client *client) config & 0xBF); /* run */ } -static int max1619_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int max1619_probe(struct i2c_client *new_client) { struct max1619_data *data; struct device *hwmon_dev; @@ -306,7 +305,7 @@ static struct i2c_driver max1619_driver = { .name = "max1619", .of_match_table = of_match_ptr(max1619_of_match), }, - .probe = max1619_probe, + .probe_new = max1619_probe, .id_table = max1619_id, .detect = max1619_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index fb6d17287365..5c41c78f0458 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -391,8 +391,9 @@ static int max1668_detect(struct i2c_client *client, return 0; } -static int max1668_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max1668_id[]; + +static int max1668_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -407,7 +408,7 @@ static int max1668_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(max1668_id, client)->driver_data; mutex_init(&data->update_lock); /* sysfs hooks */ @@ -434,7 +435,7 @@ static struct i2c_driver max1668_driver = { .driver = { .name = "max1668", }, - .probe = max1668_probe, + .probe_new = max1668_probe, .id_table = max1668_id, .detect = max1668_detect, .address_list = max1668_addr_list, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index eb22a34dc36b..23598b8b8793 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -292,7 +292,7 @@ static void max31730_remove(void *data) } static int -max31730_probe(struct i2c_client *client, const struct i2c_device_id *id) +max31730_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -427,7 +427,7 @@ static struct i2c_driver max31730_driver = { .of_match_table = of_match_ptr(max31730_of_match), .pm = &max31730_pm_ops, }, - .probe = max31730_probe, + .probe_new = max31730_probe, .id_table = max31730_ids, .detect = max31730_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 117fb79ef294..86e6c71db685 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -448,8 +448,7 @@ static int max31790_init_client(struct i2c_client *client, return 0; } -static int max31790_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max31790_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -491,7 +490,7 @@ MODULE_DEVICE_TABLE(i2c, max31790_id); static struct i2c_driver max31790_driver = { .class = I2C_CLASS_HWMON, - .probe = max31790_probe, + .probe_new = max31790_probe, .driver = { .name = "max31790", }, diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c index a8bb5de14230..367855d5edae 100644 --- a/drivers/hwmon/max6621.c +++ b/drivers/hwmon/max6621.c @@ -477,8 +477,7 @@ static const struct hwmon_chip_info max6621_chip_info = { .info = max6621_info, }; -static int max6621_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6621_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6621_data *data; @@ -555,7 +554,7 @@ static struct i2c_driver max6621_driver = { .name = MAX6621_DRV_NAME, .of_match_table = of_match_ptr(max6621_of_match), }, - .probe = max6621_probe, + .probe_new = max6621_probe, .id_table = max6621_id, }; diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 2d56e97aa5fa..b71899c641fa 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -516,8 +516,7 @@ static int max6639_detect(struct i2c_client *client, return 0; } -static int max6639_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6639_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6639_data *data; @@ -581,7 +580,7 @@ static struct i2c_driver max6639_driver = { .name = "max6639", .pm = &max6639_pm_ops, }, - .probe = max6639_probe, + .probe_new = max6639_probe, .id_table = max6639_id, .detect = max6639_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 5ab6fdb53b96..23d93142b0b3 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -264,8 +264,7 @@ static struct attribute *max6642_attrs[] = { }; ATTRIBUTE_GROUPS(max6642); -static int max6642_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6642_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6642_data *data; @@ -302,7 +301,7 @@ static struct i2c_driver max6642_driver = { .driver = { .name = "max6642", }, - .probe = max6642_probe, + .probe_new = max6642_probe, .id_table = max6642_id, .detect = max6642_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 3d9d371c35b5..cc7f2980fe83 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -757,8 +757,9 @@ static const struct hwmon_chip_info max6650_chip_info = { .info = max6650_info, }; -static int max6650_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max6650_id[]; + +static int max6650_probe(struct i2c_client *client) { struct thermal_cooling_device *cooling_dev; struct device *dev = &client->dev; @@ -775,7 +776,8 @@ static int max6650_probe(struct i2c_client *client, data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : id->driver_data; + data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : + i2c_match_id(max6650_id, client)->driver_data; /* * Initialize the max6650 chip @@ -817,7 +819,7 @@ static struct i2c_driver max6650_driver = { .name = "max6650", .of_match_table = of_match_ptr(max6650_dt_match), }, - .probe = max6650_probe, + .probe_new = max6650_probe, .id_table = max6650_id, }; diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 58781d999caa..fc3241101178 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -685,8 +685,9 @@ done: return 0; } -static int max6697_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max6697_id[]; + +static int max6697_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -704,7 +705,7 @@ static int max6697_probe(struct i2c_client *client, if (client->dev.of_node) data->type = (enum chips)of_device_get_match_data(&client->dev); else - data->type = id->driver_data; + data->type = i2c_match_id(max6697_id, client)->driver_data; data->chip = &max6697_chip_data[data->type]; data->client = client; mutex_init(&data->update_lock); @@ -785,7 +786,7 @@ static struct i2c_driver max6697_driver = { .name = "max6697", .of_match_table = of_match_ptr(max6697_of_match), }, - .probe = max6697_probe, + .probe_new = max6697_probe, .id_table = max6697_id, }; diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index 4e8f995dc773..ce2780768074 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -100,8 +100,9 @@ static ssize_t in0_input_show(struct device *dev, static DEVICE_ATTR_RO(in0_input); -static int mcp3021_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id mcp3021_id[]; + +static int mcp3021_probe(struct i2c_client *client) { int err; struct mcp3021_data *data = NULL; @@ -132,7 +133,7 @@ static int mcp3021_probe(struct i2c_client *client, data->vdd = MCP3021_VDD_REF_DEFAULT; } - switch (id->driver_data) { + switch (i2c_match_id(mcp3021_id, client)->driver_data) { case mcp3021: data->sar_shift = MCP3021_SAR_SHIFT; data->sar_mask = MCP3021_SAR_MASK; @@ -197,7 +198,7 @@ static struct i2c_driver mcp3021_driver = { .name = "mcp3021", .of_match_table = of_match_ptr(of_mcp3021_match), }, - .probe = mcp3021_probe, + .probe_new = mcp3021_probe, .remove = mcp3021_remove, .id_table = mcp3021_id, }; diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 570df8eb5272..604af2f6103a 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -1056,8 +1056,7 @@ static int nct7802_init_chip(struct nct7802_data *data) return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03); } -static int nct7802_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int nct7802_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct nct7802_data *data; @@ -1101,7 +1100,7 @@ static struct i2c_driver nct7802_driver = { .name = DRVNAME, }, .detect = nct7802_detect, - .probe = nct7802_probe, + .probe_new = nct7802_probe, .id_table = nct7802_idtable, .address_list = nct7802_address_list, }; diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 242ff8bee78d..b1c837fc407a 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -1009,8 +1009,7 @@ static const struct watchdog_ops nct7904_wdt_ops = { .get_timeleft = nct7904_wdt_get_timeleft, }; -static int nct7904_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int nct7904_probe(struct i2c_client *client) { struct nct7904_data *data; struct device *hwmon_dev; @@ -1172,7 +1171,7 @@ static struct i2c_driver nct7904_driver = { .driver = { .name = "nct7904", }, - .probe = nct7904_probe, + .probe_new = nct7904_probe, .id_table = nct7904_id, .detect = nct7904_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c index 76fb7870c7d3..0cf8588be35a 100644 --- a/drivers/hwmon/occ/p8_i2c.c +++ b/drivers/hwmon/occ/p8_i2c.c @@ -203,8 +203,7 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd) return 0; } -static int p8_i2c_occ_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int p8_i2c_occ_probe(struct i2c_client *client) { struct occ *occ; struct p8_i2c_occ *ctx = devm_kzalloc(&client->dev, sizeof(*ctx), @@ -245,7 +244,7 @@ static struct i2c_driver p8_i2c_occ_driver = { .name = "occ-hwmon", .of_match_table = p8_i2c_occ_of_match, }, - .probe = p8_i2c_occ_probe, + .probe_new = p8_i2c_occ_probe, .remove = p8_i2c_occ_remove, }; diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index b7a3a292123d..a97a51005c61 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -179,8 +179,7 @@ static const struct attribute_group pcf8591_attr_group_opt = { * Real code */ -static int pcf8591_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcf8591_probe(struct i2c_client *client) { struct pcf8591_data *data; int err; @@ -295,7 +294,7 @@ static struct i2c_driver pcf8591_driver = { .driver = { .name = "pcf8591", }, - .probe = pcf8591_probe, + .probe_new = pcf8591_probe, .remove = pcf8591_remove, .id_table = pcf8591_id, }; diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index a5d1a890d0be..9e086338dcba 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -297,8 +297,7 @@ static struct attribute *powr1220_attrs[] = { ATTRIBUTE_GROUPS(powr1220); -static int powr1220_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int powr1220_probe(struct i2c_client *client) { struct powr1220_data *data; struct device *hwmon_dev; @@ -331,7 +330,7 @@ static struct i2c_driver powr1220_driver = { .driver = { .name = "powr1220", }, - .probe = powr1220_probe, + .probe_new = powr1220_probe, .id_table = powr1220_ids, }; diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 8ea5534455f2..7d18ce5d3839 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -250,8 +250,7 @@ static struct attribute *sht21_attrs[] = { ATTRIBUTE_GROUPS(sht21); -static int sht21_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sht21_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -286,7 +285,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id); static struct i2c_driver sht21_driver = { .driver.name = "sht21", - .probe = sht21_probe, + .probe_new = sht21_probe, .id_table = sht21_id, }; diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 7364764baaeb..3f279aa1cee5 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -662,8 +662,9 @@ static struct attribute *sts3x_attrs[] = { ATTRIBUTE_GROUPS(sht3x); ATTRIBUTE_GROUPS(sts3x); -static int sht3x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id sht3x_ids[]; + +static int sht3x_probe(struct i2c_client *client) { int ret; struct sht3x_data *data; @@ -715,7 +716,7 @@ static int sht3x_probe(struct i2c_client *client, if (ret) return ret; - if (id->driver_data == sts3x) + if (i2c_match_id(sht3x_ids, client)->driver_data == sts3x) attribute_groups = sts3x_groups; else attribute_groups = sht3x_groups; @@ -742,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, sht3x_ids); static struct i2c_driver sht3x_i2c_driver = { .driver.name = "sht3x", - .probe = sht3x_probe, + .probe_new = sht3x_probe, .id_table = sht3x_ids, }; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index a0078ccede03..288fd0b4c4d3 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -185,15 +185,16 @@ static void shtc1_select_command(struct shtc1_data *data) } } -static int shtc1_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id shtc1_id[]; + +static int shtc1_probe(struct i2c_client *client) { int ret; u16 id_reg; char id_reg_buf[2]; struct shtc1_data *data; struct device *hwmon_dev; - enum shtcx_chips chip = id->driver_data; + enum shtcx_chips chip = i2c_match_id(shtc1_id, client)->driver_data; struct i2c_adapter *adap = client->adapter; struct device *dev = &client->dev; @@ -259,7 +260,7 @@ MODULE_DEVICE_TABLE(i2c, shtc1_id); static struct i2c_driver shtc1_i2c_driver = { .driver.name = "shtc1", - .probe = shtc1_probe, + .probe_new = shtc1_probe, .id_table = shtc1_id, }; diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index af01f763f7d1..b6cbe9810a1b 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -562,8 +562,9 @@ static struct attribute *smm665_attrs[] = { ATTRIBUTE_GROUPS(smm665); -static int smm665_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id smm665_id[]; + +static int smm665_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct smm665_data *data; @@ -585,7 +586,7 @@ static int smm665_probe(struct i2c_client *client, mutex_init(&data->update_lock); data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(smm665_id, client)->driver_data; data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK) | SMM665_CMDREG_BASE); if (IS_ERR(data->cmdreg)) @@ -694,7 +695,7 @@ static struct i2c_driver smm665_driver = { .driver = { .name = "smm665", }, - .probe = smm665_probe, + .probe_new = smm665_probe, .remove = smm665_remove, .id_table = smm665_id, }; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 6cbb119e3d0e..03a87aa2017a 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -587,8 +587,7 @@ static int smsc47m192_detect(struct i2c_client *client, return 0; } -static int smsc47m192_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int smsc47m192_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -629,7 +628,7 @@ static struct i2c_driver smsc47m192_driver = { .driver = { .name = "smsc47m192", }, - .probe = smsc47m192_probe, + .probe_new = smsc47m192_probe, .id_table = smsc47m192_id, .detect = smsc47m192_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 35b353c2b0a1..6928be6dbe4e 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -762,8 +762,7 @@ static struct attribute *stts751_attrs[] = { }; ATTRIBUTE_GROUPS(stts751); -static int stts751_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int stts751_probe(struct i2c_client *client) { struct stts751_priv *priv; int ret; @@ -822,7 +821,7 @@ static struct i2c_driver stts751_driver = { .name = DEVNAME, .of_match_table = of_match_ptr(stts751_of_match), }, - .probe = stts751_probe, + .probe_new = stts751_probe, .id_table = stts751_id, .detect = stts751_detect, .alert = stts751_alert, diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c index 3e3b8c61bd76..a52ca72af120 100644 --- a/drivers/hwmon/tc654.c +++ b/drivers/hwmon/tc654.c @@ -446,8 +446,7 @@ ATTRIBUTE_GROUPS(tc654); * device probe and removal */ -static int tc654_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc654_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc654_data *data; @@ -488,7 +487,7 @@ static struct i2c_driver tc654_driver = { .driver = { .name = "tc654", }, - .probe = tc654_probe, + .probe_new = tc654_probe, .id_table = tc654_id, }; diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c index fcf638ed16a9..ace55da97fc2 100644 --- a/drivers/hwmon/tc74.c +++ b/drivers/hwmon/tc74.c @@ -103,8 +103,7 @@ static struct attribute *tc74_attrs[] = { ATTRIBUTE_GROUPS(tc74); -static int tc74_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int tc74_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc74_data *data; @@ -161,7 +160,7 @@ static struct i2c_driver tc74_driver = { .driver = { .name = "tc74", }, - .probe = tc74_probe, + .probe_new = tc74_probe, .id_table = tc74_id, }; diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 3f5a983d9289..fde5e2d0825a 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -377,8 +377,9 @@ static void thmc50_init_client(struct thmc50_data *data) i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); } -static int thmc50_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id thmc50_id[]; + +static int thmc50_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct thmc50_data *data; @@ -390,7 +391,7 @@ static int thmc50_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(thmc50_id, client)->driver_data; mutex_init(&data->update_lock); thmc50_init_client(data); @@ -419,7 +420,7 @@ static struct i2c_driver thmc50_driver = { .driver = { .name = "thmc50", }, - .probe = thmc50_probe, + .probe_new = thmc50_probe, .id_table = thmc50_id, .detect = thmc50_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5fe35e5b2f73..e867a0c2e539 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -189,8 +189,7 @@ static const struct regmap_config tmp102_regmap_config = { .use_single_write = true, }; -static int tmp102_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp102_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -304,7 +303,7 @@ static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.of_match_table = of_match_ptr(tmp102_of_match), .driver.pm = &tmp102_dev_pm_ops, - .probe = tmp102_probe, + .probe_new = tmp102_probe, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index 49851533935e..a7e202cc8323 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -109,8 +109,7 @@ static const struct regmap_config tmp103_regmap_config = { .volatile_reg = tmp103_regmap_is_volatile, }; -static int tmp103_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp103_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -172,7 +171,7 @@ static struct i2c_driver tmp103_driver = { .of_match_table = of_match_ptr(tmp103_of_match), .pm = &tmp103_dev_pm_ops, }, - .probe = tmp103_probe, + .probe_new = tmp103_probe, .id_table = tmp103_id, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index fe587d4f9b2d..5435664c3f6e 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -323,8 +323,7 @@ static const struct regmap_config tmp108_regmap_config = { .use_single_write = true, }; -static int tmp108_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp108_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -433,7 +432,7 @@ static struct i2c_driver tmp108_driver = { .pm = &tmp108_dev_pm_ops, .of_match_table = of_match_ptr(tmp108_of_ids), }, - .probe = tmp108_probe, + .probe_new = tmp108_probe, .id_table = tmp108_i2c_ids, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index fa361d9949db..9dc210b55e69 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -683,8 +683,7 @@ static int tmp401_detect(struct i2c_client *client, return 0; } -static int tmp401_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp401_probe(struct i2c_client *client) { static const char * const names[] = { "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" @@ -700,7 +699,7 @@ static int tmp401_probe(struct i2c_client *client, data->client = client; mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(tmp401_id, client)->driver_data; /* Initialize the TMP401 chip */ status = tmp401_init_client(data, client); @@ -736,7 +735,7 @@ static struct i2c_driver tmp401_driver = { .driver = { .name = "tmp401", }, - .probe = tmp401_probe, + .probe_new = tmp401_probe, .id_table = tmp401_id, .detect = tmp401_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 83a4fab151d2..ede66ea6a730 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -279,8 +279,7 @@ static const struct hwmon_ops tmp421_ops = { .read = tmp421_read, }; -static int tmp421_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp421_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -296,7 +295,7 @@ static int tmp421_probe(struct i2c_client *client, data->channels = (unsigned long) of_device_get_match_data(&client->dev); else - data->channels = id->driver_data; + data->channels = i2c_match_id(tmp421_id, client)->driver_data; data->client = client; err = tmp421_init_client(client); @@ -327,7 +326,7 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", .of_match_table = of_match_ptr(tmp421_of_match), }, - .probe = tmp421_probe, + .probe_new = tmp421_probe, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c index 96b695b32572..88d11dc5feb9 100644 --- a/drivers/hwmon/w83773g.c +++ b/drivers/hwmon/w83773g.c @@ -259,8 +259,7 @@ static const struct regmap_config w83773_regmap_config = { .val_bits = 8, }; -static int w83773_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83773_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -296,7 +295,7 @@ static struct i2c_driver w83773_driver = { .name = "w83773g", .of_match_table = of_match_ptr(w83773_of_match), }, - .probe = w83773_probe, + .probe_new = w83773_probe, .id_table = w83773_id, }; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index d833a4f16c47..e84aa5604e64 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1192,8 +1192,9 @@ static void w83781d_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &w83781d_group_other); } -static int -w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id w83781d_ids[]; + +static int w83781d_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct w83781d_data *data; @@ -1207,7 +1208,7 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_init(&data->lock); mutex_init(&data->update_lock); - data->type = id->driver_data; + data->type = i2c_match_id(w83781d_ids, client)->driver_data; data->client = client; /* attach secondary i2c lm75-like clients */ @@ -1575,7 +1576,7 @@ static struct i2c_driver w83781d_driver = { .driver = { .name = "w83781d", }, - .probe = w83781d_probe, + .probe_new = w83781d_probe, .remove = w83781d_remove, .id_table = w83781d_ids, .detect = w83781d_detect, diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 7fc8a1160c8f..abd5c3a722b9 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -286,8 +286,7 @@ struct w83792d_data { u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */ }; -static int w83792d_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83792d_probe(struct i2c_client *client); static int w83792d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83792d_remove(struct i2c_client *client); @@ -310,7 +309,7 @@ static struct i2c_driver w83792d_driver = { .driver = { .name = "w83792d", }, - .probe = w83792d_probe, + .probe_new = w83792d_probe, .remove = w83792d_remove, .id_table = w83792d_id, .detect = w83792d_detect, @@ -1359,7 +1358,7 @@ w83792d_detect(struct i2c_client *client, struct i2c_board_info *info) } static int -w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) +w83792d_probe(struct i2c_client *client) { struct w83792d_data *data; struct device *dev = &client->dev; diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 6f6d925cf017..656a77102ca6 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -62,8 +62,7 @@ static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; * Functions declaration */ -static int w83l785ts_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83l785ts_probe(struct i2c_client *client); static int w83l785ts_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83l785ts_remove(struct i2c_client *client); @@ -85,7 +84,7 @@ static struct i2c_driver w83l785ts_driver = { .driver = { .name = "w83l785ts", }, - .probe = w83l785ts_probe, + .probe_new = w83l785ts_probe, .remove = w83l785ts_remove, .id_table = w83l785ts_id, .detect = w83l785ts_detect, @@ -163,8 +162,7 @@ static int w83l785ts_detect(struct i2c_client *client, return 0; } -static int w83l785ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83l785ts_probe(struct i2c_client *client) { struct w83l785ts_data *data; struct device *dev = &client->dev; diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index ce98ec8794e2..542afff1423b 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -706,7 +706,7 @@ static void w83l786ng_init_client(struct i2c_client *client) } static int -w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id) +w83l786ng_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct w83l786ng_data *data; @@ -752,7 +752,7 @@ static struct i2c_driver w83l786ng_driver = { .driver = { .name = "w83l786ng", }, - .probe = w83l786ng_probe, + .probe_new = w83l786ng_probe, .id_table = w83l786ng_id, .detect = w83l786ng_detect, .address_list = normal_i2c, From a391adfae11f3cfb08115dc0ff3ca63fb883d70e Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:09:58 +0200 Subject: [PATCH 10/64] hwmon: (adm1177) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813160958.1506536-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1177.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index d314223a404a..6e8bb661894b 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -196,8 +196,7 @@ static void adm1177_remove(void *data) regulator_disable(st->reg); } -static int adm1177_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1177_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -277,7 +276,7 @@ static struct i2c_driver adm1177_driver = { .name = "adm1177", .of_match_table = adm1177_dt_ids, }, - .probe = adm1177_probe, + .probe_new = adm1177_probe, .id_table = adm1177_id, }; module_i2c_driver(adm1177_driver); From 7d6ed4ba4fdc0f3029e32e4fd46d83bcc0255c30 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:11:29 +0200 Subject: [PATCH 11/64] hwmon: (adm1029) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Acked-by: Corentin LABBE Tested-by: Corentin Labbe Link: https://lore.kernel.org/r/20200813161129.1507599-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1029.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index f7752a5bef31..50b1df7b008c 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -352,8 +352,7 @@ static int adm1029_init_client(struct i2c_client *client) return 1; } -static int adm1029_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1029_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adm1029_data *data; @@ -390,7 +389,7 @@ static struct i2c_driver adm1029_driver = { .driver = { .name = "adm1029", }, - .probe = adm1029_probe, + .probe_new = adm1029_probe, .id_table = adm1029_id, .detect = adm1029_detect, .address_list = normal_i2c, From 16b237f5e50624a99387245a821021194576c9d7 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:18:45 +0200 Subject: [PATCH 12/64] hwmon: (w83793) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813161845.1511261-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/w83793.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 3f59f2a1a5e3..e7d0484eabe4 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -283,8 +283,7 @@ static void w83793_release_resources(struct kref *ref) static u8 w83793_read_value(struct i2c_client *client, u16 reg); static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value); -static int w83793_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83793_probe(struct i2c_client *client); static int w83793_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83793_remove(struct i2c_client *client); @@ -303,7 +302,7 @@ static struct i2c_driver w83793_driver = { .driver = { .name = "w83793", }, - .probe = w83793_probe, + .probe_new = w83793_probe, .remove = w83793_remove, .id_table = w83793_id, .detect = w83793_detect, @@ -1646,8 +1645,7 @@ static int w83793_detect(struct i2c_client *client, return 0; } -static int w83793_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83793_probe(struct i2c_client *client) { struct device *dev = &client->dev; static const int watchdog_minors[] = { From 77b5b8a8021fa0258ed70d38b396654ae1dce7a4 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:20:26 +0200 Subject: [PATCH 13/64] hwmon: (w83791d) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813162026.1512242-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/w83791d.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index aad8d4da5802..37b25a1474c4 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -315,8 +315,7 @@ struct w83791d_data { u8 vrm; /* hwmon-vid */ }; -static int w83791d_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83791d_probe(struct i2c_client *client); static int w83791d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83791d_remove(struct i2c_client *client); @@ -342,7 +341,7 @@ static struct i2c_driver w83791d_driver = { .driver = { .name = "w83791d", }, - .probe = w83791d_probe, + .probe_new = w83791d_probe, .remove = w83791d_remove, .id_table = w83791d_id, .detect = w83791d_detect, @@ -1346,8 +1345,7 @@ static int w83791d_detect(struct i2c_client *client, return 0; } -static int w83791d_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83791d_probe(struct i2c_client *client) { struct w83791d_data *data; struct device *dev = &client->dev; From 91ed7c40f339511a33c42fcf4e7f9a358293d9b5 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:23:00 +0200 Subject: [PATCH 14/64] hwmon: (lm73) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813162300.1514695-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/lm73.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 733c48bf6c98..beb0d61bcd82 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -190,7 +190,7 @@ ATTRIBUTE_GROUPS(lm73); /* device probe and removal */ static int -lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) +lm73_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -277,7 +277,7 @@ static struct i2c_driver lm73_driver = { .name = "lm73", .of_match_table = lm73_of_match, }, - .probe = lm73_probe, + .probe_new = lm73_probe, .id_table = lm73_ids, .detect = lm73_detect, .address_list = normal_i2c, From 7dedb79d295b4b61144be72dfa4f48b0d3bf80f0 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:25:44 +0200 Subject: [PATCH 15/64] hwmon: (asc7621) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813162544.1516647-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/asc7621.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 9e14e2829ee9..600ffc7e1900 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1087,7 +1087,7 @@ static void asc7621_init_client(struct i2c_client *client) } static int -asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id) +asc7621_probe(struct i2c_client *client) { struct asc7621_data *data; int i, err; @@ -1193,7 +1193,7 @@ static struct i2c_driver asc7621_driver = { .driver = { .name = "asc7621", }, - .probe = asc7621_probe, + .probe_new = asc7621_probe, .remove = asc7621_remove, .id_table = asc7621_id, .detect = asc7621_detect, From 9bf5dd8b26282778412e60c79b8db60687e3dfc4 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:27:04 +0200 Subject: [PATCH 16/64] hwmon: (emc2103) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813162704.1517951-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2103.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 924c02c1631d..e4c95ca9e19f 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -551,7 +551,7 @@ static const struct attribute_group emc2103_temp4_group = { }; static int -emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id) +emc2103_probe(struct i2c_client *client) { struct emc2103_data *data; struct device *hwmon_dev; @@ -653,7 +653,7 @@ static struct i2c_driver emc2103_driver = { .driver = { .name = "emc2103", }, - .probe = emc2103_probe, + .probe_new = emc2103_probe, .id_table = emc2103_ids, .detect = emc2103_detect, .address_list = normal_i2c, From c1e60c0d571b6c0264ae18f5e2cfdb34569da762 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 13 Aug 2020 18:28:51 +0200 Subject: [PATCH 17/64] hwmon: (ltc2947) use simple i2c probe This driver doesn't use the id information provided by the old i2c probe function, so it can trivially be converted to the simple ("probe_new") form. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200813162851.1519546-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2947-i2c.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/ltc2947-i2c.c b/drivers/hwmon/ltc2947-i2c.c index cf6074b110ae..ad0dfd3efbf8 100644 --- a/drivers/hwmon/ltc2947-i2c.c +++ b/drivers/hwmon/ltc2947-i2c.c @@ -15,8 +15,7 @@ static const struct regmap_config ltc2947_regmap_config = { .val_bits = 8, }; -static int ltc2947_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ltc2947_probe(struct i2c_client *i2c) { struct regmap *map; @@ -39,7 +38,7 @@ static struct i2c_driver ltc2947_driver = { .of_match_table = ltc2947_of_match, .pm = <c2947_pm_ops, }, - .probe = ltc2947_probe, + .probe_new = ltc2947_probe, .id_table = ltc2947_id, }; module_i2c_driver(ltc2947_driver); From 673afe466166cda94053d2d2400e669fe19f8050 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Fri, 21 Aug 2020 18:03:54 +0200 Subject: [PATCH 18/64] hwmon: use simple i2c probe function (take 2) Many hwmon drivers don't use the id information provided by the old i2c probe function, and the remainder can easily be adapted to the new form ("probe_new") by calling i2c_match_id explicitly. This avoids scanning the identifier tables during probes. Drivers which didn't use the id are converted as-is; drivers which did are modified to call i2c_match_id() with the same level of error-handling (if any) as before. This patch wraps up the transition for hwmon, with four stragglers not included in the previous large patch. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200821160354.594715-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/adc128d818.c | 5 ++--- drivers/hwmon/ads7828.c | 9 +++++---- drivers/hwmon/lm87.c | 4 ++-- drivers/hwmon/w83795.c | 9 +++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 571d5454c6b2..6c9a906631b8 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -427,8 +427,7 @@ static int adc128_init_client(struct adc128_data *data) return 0; } -static int adc128_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adc128_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct regulator *regulator; @@ -524,7 +523,7 @@ static struct i2c_driver adc128_driver = { .name = "adc128d818", .of_match_table = of_match_ptr(adc128_of_match), }, - .probe = adc128_probe, + .probe_new = adc128_probe, .remove = adc128_remove, .id_table = adc128_id, .detect = adc128_detect, diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index d895b73fde6f..7246198f0901 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -99,8 +99,9 @@ static const struct regmap_config ads2830_regmap_config = { .val_bits = 8, }; -static int ads7828_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ads7828_device_ids[]; + +static int ads7828_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ads7828_platform_data *pdata = dev_get_platdata(dev); @@ -141,7 +142,7 @@ static int ads7828_probe(struct i2c_client *client, chip = (enum ads7828_chips) of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = i2c_match_id(ads7828_device_ids, client)->driver_data; /* Bound Vref with min/max values */ vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN, @@ -207,7 +208,7 @@ static struct i2c_driver ads7828_driver = { }, .id_table = ads7828_device_ids, - .probe = ads7828_probe, + .probe_new = ads7828_probe, }; module_i2c_driver(ads7828_driver); diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index c96c4d807e38..b2d820125bb6 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -912,7 +912,7 @@ static int lm87_init_client(struct i2c_client *client) return 0; } -static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int lm87_probe(struct i2c_client *client) { struct lm87_data *data; struct device *hwmon_dev; @@ -994,7 +994,7 @@ static struct i2c_driver lm87_driver = { .name = "lm87", .of_match_table = lm87_of_match, }, - .probe = lm87_probe, + .probe_new = lm87_probe, .id_table = lm87_id, .detect = lm87_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 6d52b530b429..621b05afa837 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -2134,8 +2134,9 @@ static void w83795_apply_temp_config(struct w83795_data *data, u8 config, } } -static int w83795_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id w83795_id[]; + +static int w83795_probe(struct i2c_client *client) { int i; u8 tmp; @@ -2148,7 +2149,7 @@ static int w83795_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); - data->chip_type = id->driver_data; + data->chip_type = i2c_match_id(w83795_id, client)->driver_data; data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); mutex_init(&data->update_lock); @@ -2256,7 +2257,7 @@ static struct i2c_driver w83795_driver = { .driver = { .name = "w83795", }, - .probe = w83795_probe, + .probe_new = w83795_probe, .remove = w83795_remove, .id_table = w83795_id, From e3b9f691252840f8cee89179a2307872eff751f1 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Fri, 21 Aug 2020 18:02:31 +0200 Subject: [PATCH 19/64] hwmon: (tmp513) use simple i2c probe As part of the ongoing i2c transition to the simple probe ("probe_new"), this patch uses i2c_match_id to retrieve the driver_data for the probed device. The id parameter is thus no longer necessary and the simple probe can be used instead. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200821160231.592571-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp513.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 23908dc5611b..9187dac06ffd 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -709,8 +709,7 @@ static int tmp51x_configure(struct device *dev, struct tmp51x_data *data) return 0; } -static int tmp51x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp51x_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tmp51x_data *data; @@ -724,7 +723,7 @@ static int tmp51x_probe(struct i2c_client *client, if (client->dev.of_node) data->id = (enum tmp51x_ids)device_get_match_data(&client->dev); else - data->id = id->driver_data; + data->id = i2c_match_id(tmp51x_id, client)->driver_data; ret = tmp51x_configure(dev, data); if (ret < 0) { @@ -751,7 +750,7 @@ static int tmp51x_probe(struct i2c_client *client, if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); - dev_dbg(dev, "power monitor %s\n", id->name); + dev_dbg(dev, "power monitor %s\n", client->name); return 0; } @@ -761,7 +760,7 @@ static struct i2c_driver tmp51x_driver = { .name = "tmp51x", .of_match_table = of_match_ptr(tmp51x_of_match), }, - .probe = tmp51x_probe, + .probe_new = tmp51x_probe, .id_table = tmp51x_id, }; From f7bd7b5452978fb41879ca6a98af8c5643ad61e8 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Fri, 21 Aug 2020 18:01:59 +0200 Subject: [PATCH 20/64] hwmon: (f75375s) use simple i2c probe As part of the ongoing i2c transition to the simple probe ("probe_new"), this patch uses i2c_match_id to retrieve the driver_data for the probed device. The id parameter is thus no longer necessary and the simple probe can be used instead. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200821160159.591293-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/f75375s.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index eb847a7d6b83..3e567be60fb1 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -113,8 +113,7 @@ struct f75375_data { static int f75375_detect(struct i2c_client *client, struct i2c_board_info *info); -static int f75375_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int f75375_probe(struct i2c_client *client); static int f75375_remove(struct i2c_client *client); static const struct i2c_device_id f75375_id[] = { @@ -130,7 +129,7 @@ static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, - .probe = f75375_probe, + .probe_new = f75375_probe, .remove = f75375_remove, .id_table = f75375_id, .detect = f75375_detect, @@ -814,8 +813,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, } -static int f75375_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int f75375_probe(struct i2c_client *client) { struct f75375_data *data; struct f75375s_platform_data *f75375s_pdata = @@ -832,7 +830,7 @@ static int f75375_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(f75375_id, client)->driver_data; err = sysfs_create_group(&client->dev.kobj, &f75375_group); if (err) From 4e1b4d22279188e63546838144399a6dde44a5aa Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Fri, 21 Aug 2020 18:00:35 +0200 Subject: [PATCH 21/64] hwmon: (dme1737) use simple i2c probe As part of the ongoing i2c transition to the simple probe ("probe_new"), this patch uses i2c_match_id to retrieve the driver_data for the probed device. The id parameter is thus no longer necessary and the simple probe can be used instead. Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20200821160035.590142-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/dme1737.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index c3472b73fa79..c1e4cfb40c3d 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2461,8 +2461,9 @@ static int dme1737_i2c_detect(struct i2c_client *client, return 0; } -static int dme1737_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id dme1737_id[]; + +static int dme1737_i2c_probe(struct i2c_client *client) { struct dme1737_data *data; struct device *dev = &client->dev; @@ -2473,7 +2474,7 @@ static int dme1737_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); - data->type = id->driver_data; + data->type = i2c_match_id(dme1737_id, client)->driver_data; data->client = client; data->name = client->name; mutex_init(&data->update_lock); @@ -2529,7 +2530,7 @@ static struct i2c_driver dme1737_i2c_driver = { .driver = { .name = "dme1737", }, - .probe = dme1737_i2c_probe, + .probe_new = dme1737_i2c_probe, .remove = dme1737_i2c_remove, .id_table = dme1737_id, .detect = dme1737_i2c_detect, From 65b2aad0699b3915cc3a5afee0a382eda0fc93b5 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 17 Aug 2020 15:34:33 +0800 Subject: [PATCH 22/64] hwmon: (pwm-fan) Use dev_err_probe() to simplify error handling dev_err_probe() can reduce code size, uniform error handling and record the defer probe reason etc., use it to simplify the code. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1597649673-22329-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 17bb64299bfd..bdba2143021a 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -293,14 +293,8 @@ static int pwm_fan_probe(struct platform_device *pdev) mutex_init(&ctx->lock); ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL); - if (IS_ERR(ctx->pwm)) { - ret = PTR_ERR(ctx->pwm); - - if (ret != -EPROBE_DEFER) - dev_err(dev, "Could not get PWM: %d\n", ret); - - return ret; - } + if (IS_ERR(ctx->pwm)) + return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); platform_set_drvdata(pdev, ctx); From be7373b60df5020c00dfac4db185a6b4e9f98395 Mon Sep 17 00:00:00 2001 From: Chris Ruehl Date: Sat, 15 Aug 2020 09:22:26 +0800 Subject: [PATCH 23/64] hwmon: shtc1: add support for device tree bindings Add support for DTS bindings for the sensirion shtc1,shtw1 and shtc3. Signed-off-by: Chris Ruehl Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200815012227.32538-2-chris.ruehl@gtsys.com.hk [groeck: Resolved conflicts] Signed-off-by: Guenter Roeck --- drivers/hwmon/shtc1.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index 288fd0b4c4d3..18546ebc8e9f 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -14,6 +14,7 @@ #include #include #include +#include /* commands (high precision mode) */ static const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 }; @@ -197,6 +198,7 @@ static int shtc1_probe(struct i2c_client *client) enum shtcx_chips chip = i2c_match_id(shtc1_id, client)->driver_data; struct i2c_adapter *adap = client->adapter; struct device *dev = &client->dev; + struct device_node *np = dev->of_node; if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) { dev_err(dev, "plain i2c transactions not supported\n"); @@ -234,8 +236,14 @@ static int shtc1_probe(struct i2c_client *client) data->client = client; data->chip = chip; - if (client->dev.platform_data) - data->setup = *(struct shtc1_platform_data *)dev->platform_data; + if (np) { + data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io"); + data->setup.high_precision = !of_property_read_bool(np, "sensicon,low-precision"); + } else { + if (client->dev.platform_data) + data->setup = *(struct shtc1_platform_data *)dev->platform_data; + } + shtc1_select_command(data); mutex_init(&data->update_lock); @@ -258,8 +266,19 @@ static const struct i2c_device_id shtc1_id[] = { }; MODULE_DEVICE_TABLE(i2c, shtc1_id); +static const struct of_device_id shtc1_of_match[] = { + { .compatible = "sensirion,shtc1" }, + { .compatible = "sensirion,shtw1" }, + { .compatible = "sensirion,shtc3" }, + { } +}; +MODULE_DEVICE_TABLE(of, shtc1_of_match); + static struct i2c_driver shtc1_i2c_driver = { - .driver.name = "shtc1", + .driver = { + .name = "shtc1", + .of_match_table = shtc1_of_match, + }, .probe_new = shtc1_probe, .id_table = shtc1_id, }; From d2e08eba09a5e1a46e09f93ce46f06414ab90e8a Mon Sep 17 00:00:00 2001 From: Chris Ruehl Date: Sat, 15 Aug 2020 09:22:27 +0800 Subject: [PATCH 24/64] devicetree: hwmon: shtc1: add sensirion,shtc1.yaml Add documentation for the newly added DTS support in the shtc1 driver. To align with the drivers logic to have high precision by default a boolean sensirion,low-precision is used to switch to low precision. Signed-off-by: Chris Ruehl Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200815012227.32538-3-chris.ruehl@gtsys.com.hk Signed-off-by: Guenter Roeck --- .../bindings/hwmon/sensirion,shtc1.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml diff --git a/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml new file mode 100644 index 000000000000..c523a1beb2b7 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/sensirion,shtc1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sensirion SHTC1 Humidity and Temperature Sensor IC + +maintainers: + - Christopher Ruehl chris.ruehl@gtsys.com.hk + +description: | + The SHTC1, SHTW1 and SHTC3 are digital humidity and temperature sensor + designed especially for battery-driven high-volume consumer electronics + applications. + For further information refere to Documentation/hwmon/shtc1.rst + + This binding document describes the binding for the hardware monitor + portion of the driver. + +properties: + compatible: + enum: + - sensirion,shtc1 + - sensirion,shtw1 + - sensirion,shtc3 + + reg: + const: 0x70 + + sensirion,blocking-io: + $ref: /schemas/types.yaml#definitions/flag + description: + If set, the driver hold the i2c bus until measurement is finished. + + sensirion,low-precision: + $ref: /schemas/types.yaml#definitions/flag + description: + If set, the sensor aquire data with low precision (not recommended). + The driver aquire data with high precision by default. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + + shtc3@70 { + compatible = "sensirion,shtc3"; + reg = <0x70>; + sensirion,blocking-io; + }; + }; +... From 9514a22866ba1300c7e3f6aab2e558bb30679743 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:50 +0300 Subject: [PATCH 25/64] hwmon: (pmbus) Add support for ADM1266 Add pmbus probing driver for the adm1266 Cascadable Super Sequencer with Margin Control and Fault Recording. Driver is using the pmbus_core, creating sysfs files under hwmon for inputs: vh1->vh4 and vp1->vp13. Signed-off-by: Alexandru Tachici Link: https://lore.kernel.org/r/20200812142055.9213-2-alexandru.tachici@analog.com [groeck: Use .probe_new function, adjust for changed pmbus_do_probe API] Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1266.rst | 37 +++++++++++++++++++ Documentation/hwmon/index.rst | 1 + drivers/hwmon/pmbus/Kconfig | 9 +++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/adm1266.c | 65 +++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+) create mode 100644 Documentation/hwmon/adm1266.rst create mode 100644 drivers/hwmon/pmbus/adm1266.c diff --git a/Documentation/hwmon/adm1266.rst b/Documentation/hwmon/adm1266.rst new file mode 100644 index 000000000000..9257f8a48650 --- /dev/null +++ b/Documentation/hwmon/adm1266.rst @@ -0,0 +1,37 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver adm1266 +===================== + +Supported chips: + * Analog Devices ADM1266 + Prefix: 'adm1266' + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf + +Author: Alexandru Tachici + + +Description +----------- + +This driver supports hardware monitoring for Analog Devices ADM1266 sequencer. + +ADM1266 is a sequencer that features voltage readback from 17 channels via an +integrated 12 bit SAR ADC, accessed using a PMBus interface. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write, history reset +attributes are write-only, all other attributes are read-only. + +inX_label "voutx" +inX_input Measured voltage. +inX_min Minimum Voltage. +inX_max Maximum voltage. +inX_min_alarm Voltage low alarm. +inX_max_alarm Voltage high alarm. diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 750d3a975d82..af064a9ad42f 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -30,6 +30,7 @@ Hardware Monitoring Kernel Drivers adm1026 adm1031 adm1177 + adm1266 adm1275 adm9240 ads7828 diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index e35db489b76f..890f08be7244 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -26,6 +26,15 @@ config SENSORS_PMBUS This driver can also be built as a module. If so, the module will be called pmbus. +config SENSORS_ADM1266 + tristate "Analog Devices ADM1266 Sequencer" + help + If you say yes here you get hardware monitoring support for Analog + Devices ADM1266 Cascadable Super Sequencer. + + This driver can also be built as a module. If so, the module will + be called adm1266. + config SENSORS_ADM1275 tristate "Analog Devices ADM1275 and compatibles" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index c4b15db996ad..da41d22be1c9 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o +obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c new file mode 100644 index 000000000000..9c75958c2969 --- /dev/null +++ b/drivers/hwmon/pmbus/adm1266.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADM1266 - Cascadable Super Sequencer with Margin + * Control and Fault Recording + * + * Copyright 2020 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include "pmbus.h" +#include + +struct adm1266_data { + struct pmbus_driver_info info; + struct i2c_client *client; +}; + +static int adm1266_probe(struct i2c_client *client) +{ + struct adm1266_data *data; + int i; + + data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->info.pages = 17; + data->info.format[PSC_VOLTAGE_OUT] = linear; + for (i = 0; i < data->info.pages; i++) + data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + return pmbus_do_probe(client, &data->info); +} + +static const struct of_device_id adm1266_of_match[] = { + { .compatible = "adi,adm1266" }, + { } +}; +MODULE_DEVICE_TABLE(of, adm1266_of_match); + +static const struct i2c_device_id adm1266_id[] = { + { "adm1266", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adm1266_id); + +static struct i2c_driver adm1266_driver = { + .driver = { + .name = "adm1266", + .of_match_table = adm1266_of_match, + }, + .probe_new = adm1266_probe, + .remove = pmbus_do_remove, + .id_table = adm1266_id, +}; + +module_i2c_driver(adm1266_driver); + +MODULE_AUTHOR("Alexandru Tachici "); +MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266"); +MODULE_LICENSE("GPL v2"); From 407dc802a9c0809ca6a48de4b4c63305eb84ef56 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:51 +0300 Subject: [PATCH 26/64] hwmon: (pmbus/adm1266) Add Block process call PmBus devices support Block Write-Block Read Process Call described in SMBus specification v 2.0 with the exception that Block writes and reads are permitted to have up 255 data bytes instead of max 32 bytes (SMBus). This patch adds Block WR process call support for ADM1266. Signed-off-by: Alexandru Tachici Link: https://lore.kernel.org/r/20200812142055.9213-3-alexandru.tachici@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 1 + drivers/hwmon/pmbus/adm1266.c | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 890f08be7244..7902a9a72681 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -28,6 +28,7 @@ config SENSORS_PMBUS config SENSORS_ADM1266 tristate "Analog Devices ADM1266 Sequencer" + select CRC8 help If you say yes here you get hardware monitoring support for Analog Devices ADM1266 Cascadable Super Sequencer. diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 9c75958c2969..d85835091a40 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -6,6 +6,7 @@ * Copyright 2020 Analog Devices Inc. */ +#include #include #include #include @@ -13,11 +14,85 @@ #include "pmbus.h" #include +#define ADM1266_PMBUS_BLOCK_MAX 255 + struct adm1266_data { struct pmbus_driver_info info; struct i2c_client *client; + struct mutex buf_mutex; + u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; }; +DECLARE_CRC8_TABLE(pmbus_crc_table); + +/* + * Different from Block Read as it sends data and waits for the slave to + * return a value dependent on that data. The protocol is simply a Write Block + * followed by a Read Block without the Read-Block command field and the + * Write-Block STOP bit. + */ +static int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, u8 *data_w, + u8 *data_r) +{ + struct i2c_client *client = data->client; + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = I2C_M_DMA_SAFE, + .buf = data->write_buf, + .len = w_len + 2, + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_DMA_SAFE, + .buf = data->read_buf, + .len = ADM1266_PMBUS_BLOCK_MAX + 2, + } + }; + u8 addr; + u8 crc; + int ret; + + mutex_lock(&data->buf_mutex); + + msgs[0].buf[0] = cmd; + msgs[0].buf[1] = w_len; + memcpy(&msgs[0].buf[2], data_w, w_len); + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret != 2) { + if (ret >= 0) + ret = -EPROTO; + + mutex_unlock(&data->buf_mutex); + + return ret; + } + + if (client->flags & I2C_CLIENT_PEC) { + addr = i2c_8bit_addr_from_msg(&msgs[0]); + crc = crc8(pmbus_crc_table, &addr, 1, 0); + crc = crc8(pmbus_crc_table, msgs[0].buf, msgs[0].len, crc); + + addr = i2c_8bit_addr_from_msg(&msgs[1]); + crc = crc8(pmbus_crc_table, &addr, 1, crc); + crc = crc8(pmbus_crc_table, msgs[1].buf, msgs[1].buf[0] + 1, crc); + + if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) { + mutex_unlock(&data->buf_mutex); + return -EBADMSG; + } + } + + memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]); + + ret = msgs[1].buf[0]; + mutex_unlock(&data->buf_mutex); + + return ret; +} + static int adm1266_probe(struct i2c_client *client) { struct adm1266_data *data; @@ -33,6 +108,9 @@ static int adm1266_probe(struct i2c_client *client) for (i = 0; i < data->info.pages; i++) data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + crc8_populate_msb(pmbus_crc_table, 0x7); + mutex_init(&data->buf_mutex); + return pmbus_do_probe(client, &data->info); } From d98dfad35c38c037b37c4adc99df01da571031a5 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:52 +0300 Subject: [PATCH 27/64] hwmon: (pmbus/adm1266) Add support for GPIOs Adm1266 exposes 9 GPIOs and 16 PDIOs which are currently read-only. They are controlled by the internal sequencing engine. This patch makes adm1266 driver expose GPIOs and PDIOs to user-space using GPIO provider kernel api. Signed-off-by: Alexandru Tachici Link: https://lore.kernel.org/r/20200812142055.9213-4-alexandru.tachici@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 1 + drivers/hwmon/pmbus/adm1266.c | 204 ++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 7902a9a72681..db90e0018948 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -29,6 +29,7 @@ config SENSORS_PMBUS config SENSORS_ADM1266 tristate "Analog Devices ADM1266 Sequencer" select CRC8 + depends on GPIOLIB help If you say yes here you get hardware monitoring support for Analog Devices ADM1266 Cascadable Super Sequencer. diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index d85835091a40..bcc8a78c2725 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -6,18 +6,42 @@ * Copyright 2020 Analog Devices Inc. */ +#include #include +#include +#include #include +#include #include #include #include #include "pmbus.h" #include +#define ADM1266_PDIO_CONFIG 0xD4 +#define ADM1266_GPIO_CONFIG 0xE1 +#define ADM1266_PDIO_STATUS 0xE9 +#define ADM1266_GPIO_STATUS 0xEA + +/* ADM1266 GPIO defines */ +#define ADM1266_GPIO_NR 9 +#define ADM1266_GPIO_FUNCTIONS(x) FIELD_GET(BIT(0), x) +#define ADM1266_GPIO_INPUT_EN(x) FIELD_GET(BIT(2), x) +#define ADM1266_GPIO_OUTPUT_EN(x) FIELD_GET(BIT(3), x) +#define ADM1266_GPIO_OPEN_DRAIN(x) FIELD_GET(BIT(4), x) + +/* ADM1266 PDIO defines */ +#define ADM1266_PDIO_NR 16 +#define ADM1266_PDIO_PIN_CFG(x) FIELD_GET(GENMASK(15, 13), x) +#define ADM1266_PDIO_GLITCH_FILT(x) FIELD_GET(GENMASK(12, 9), x) +#define ADM1266_PDIO_OUT_CFG(x) FIELD_GET(GENMASK(2, 0), x) + #define ADM1266_PMBUS_BLOCK_MAX 255 struct adm1266_data { struct pmbus_driver_info info; + struct gpio_chip gc; + const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR]; struct i2c_client *client; struct mutex buf_mutex; u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; @@ -93,9 +117,185 @@ static int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, return ret; } +static const unsigned int adm1266_gpio_mapping[ADM1266_GPIO_NR][2] = { + {1, 0}, + {2, 1}, + {3, 2}, + {4, 8}, + {5, 9}, + {6, 10}, + {7, 11}, + {8, 6}, + {9, 7}, +}; + +static const char *adm1266_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR] = { + "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8", + "GPIO9", "PDIO1", "PDIO2", "PDIO3", "PDIO4", "PDIO5", "PDIO6", + "PDIO7", "PDIO8", "PDIO9", "PDIO10", "PDIO11", "PDIO12", "PDIO13", + "PDIO14", "PDIO15", "PDIO16", +}; + +static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1]; + unsigned long pins_status; + unsigned int pmbus_cmd; + int ret; + + if (offset < ADM1266_GPIO_NR) + pmbus_cmd = ADM1266_GPIO_STATUS; + else + pmbus_cmd = ADM1266_PDIO_STATUS; + + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); + if (ret < 0) + return ret; + + pins_status = read_buf[0] + (read_buf[1] << 8); + if (offset < ADM1266_GPIO_NR) + return test_bit(adm1266_gpio_mapping[offset][1], &pins_status); + + return test_bit(offset - ADM1266_GPIO_NR, &pins_status); +} + +static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long status; + unsigned int gpio_nr; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) { + if (test_bit(adm1266_gpio_mapping[gpio_nr][1], &status)) + set_bit(gpio_nr, bits); + } + + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) { + if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status)) + set_bit(gpio_nr, bits); + } + + return 0; +} + +static void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long gpio_config; + unsigned long pdio_config; + unsigned long pin_cfg; + u8 write_cmd; + int ret; + int i; + + for (i = 0; i < ADM1266_GPIO_NR; i++) { + write_cmd = adm1266_gpio_mapping[i][1]; + ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 2) + return; + + gpio_config = read_buf[0]; + seq_puts(s, adm1266_names[i]); + + seq_puts(s, " ( "); + if (!ADM1266_GPIO_FUNCTIONS(gpio_config)) { + seq_puts(s, "high-Z )\n"); + continue; + } + if (ADM1266_GPIO_INPUT_EN(gpio_config)) + seq_puts(s, "input "); + if (ADM1266_GPIO_OUTPUT_EN(gpio_config)) + seq_puts(s, "output "); + if (ADM1266_GPIO_OPEN_DRAIN(gpio_config)) + seq_puts(s, "open-drain )\n"); + else + seq_puts(s, "push-pull )\n"); + } + + write_cmd = 0xFF; + ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 32) + return; + + for (i = 0; i < ADM1266_PDIO_NR; i++) { + seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]); + + pdio_config = read_buf[2 * i]; + pdio_config += (read_buf[2 * i + 1] << 8); + pin_cfg = ADM1266_PDIO_PIN_CFG(pdio_config); + + seq_puts(s, " ( "); + if (!pin_cfg || pin_cfg > 5) { + seq_puts(s, "high-Z )\n"); + continue; + } + + if (pin_cfg & BIT(0)) + seq_puts(s, "output "); + + if (pin_cfg & BIT(1)) + seq_puts(s, "input "); + + seq_puts(s, ")\n"); + } +} + +static int adm1266_config_gpio(struct adm1266_data *data) +{ + const char *name = dev_name(&data->client->dev); + char *gpio_name; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) { + gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s", + data->client->addr, adm1266_names[i]); + if (!gpio_name) + return -ENOMEM; + + data->gpio_names[i] = gpio_name; + } + + data->gc.label = name; + data->gc.parent = &data->client->dev; + data->gc.owner = THIS_MODULE; + data->gc.base = -1; + data->gc.names = data->gpio_names; + data->gc.ngpio = ARRAY_SIZE(data->gpio_names); + data->gc.get = adm1266_gpio_get; + data->gc.get_multiple = adm1266_gpio_get_multiple; + data->gc.dbg_show = adm1266_gpio_dbg_show; + + ret = devm_gpiochip_add_data(&data->client->dev, &data->gc, data); + if (ret) + dev_err(&data->client->dev, "GPIO registering failed (%d)\n", ret); + + return ret; +} + static int adm1266_probe(struct i2c_client *client) { struct adm1266_data *data; + int ret; int i; data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL); @@ -111,6 +311,10 @@ static int adm1266_probe(struct i2c_client *client) crc8_populate_msb(pmbus_crc_table, 0x7); mutex_init(&data->buf_mutex); + ret = adm1266_config_gpio(data); + if (ret < 0) + return ret; + return pmbus_do_probe(client, &data->info); } From ed1ff457e1870425ea8d3c8643d9aeb7fa54300f Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:53 +0300 Subject: [PATCH 28/64] hwmon: (pmbus/adm1266) add debugfs for states Add a debugfs entry which prints the current state of the adm1266 sequencer. Signed-off-by: Alexandru Tachici Link: https://lore.kernel.org/r/20200812142055.9213-5-alexandru.tachici@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1266.c | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index bcc8a78c2725..e129a88e58f5 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -19,6 +19,7 @@ #include #define ADM1266_PDIO_CONFIG 0xD4 +#define ADM1266_READ_STATE 0xD9 #define ADM1266_GPIO_CONFIG 0xE1 #define ADM1266_PDIO_STATUS 0xE9 #define ADM1266_GPIO_STATUS 0xEA @@ -43,6 +44,7 @@ struct adm1266_data { struct gpio_chip gc; const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR]; struct i2c_client *client; + struct dentry *debugfs_dir; struct mutex buf_mutex; u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; @@ -292,6 +294,37 @@ static int adm1266_config_gpio(struct adm1266_data *data) return ret; } +static int adm1266_state_read(struct seq_file *s, void *pdata) +{ + struct device *dev = s->private; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE); + if (ret < 0) + return ret; + + seq_printf(s, "%d\n", ret); + + return 0; +} + +static void adm1266_init_debugfs(struct adm1266_data *data) +{ + struct dentry *root; + + root = pmbus_get_debugfs_dir(data->client); + if (!root) + return; + + data->debugfs_dir = debugfs_create_dir(data->client->name, root); + if (!data->debugfs_dir) + return; + + debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir, + adm1266_state_read); +} + static int adm1266_probe(struct i2c_client *client) { struct adm1266_data *data; @@ -315,7 +348,13 @@ static int adm1266_probe(struct i2c_client *client) if (ret < 0) return ret; - return pmbus_do_probe(client, &data->info); + ret = pmbus_do_probe(client, &data->info); + if (ret) + return ret; + + adm1266_init_debugfs(data); + + return 0; } static const struct of_device_id adm1266_of_match[] = { From 15609d1893020436e1e8ccfd9ded774a96dd17a2 Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:54 +0300 Subject: [PATCH 29/64] hwmon: (pmbus/adm1266) read blackbox Use the nvmem kernel api to expose the black box chip functionality to userspace. Using this feature, the device is capable of recording to nonvolatile flash memory the vital data about the system status that caused the system to perform a black box write. A blackbox is 64 bytes of data containing all the status registers, last two states of the sequencer, timestamp and counters. The mapping of this data is described in the adm1266 datasheet. On power-up the driver sets the unix time to the adm1266 using the SET_RTC command. This value is incremented by an internal clock and it is used as timestamp for the black box feature. Signed-off-by: Alexandru Tachici Link: https://lore.kernel.org/r/20200812142055.9213-6-alexandru.tachici@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1266.c | 127 ++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index e129a88e58f5..c7b373ba92f2 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -15,12 +15,19 @@ #include #include #include +#include +#include #include "pmbus.h" #include +#include +#define ADM1266_BLACKBOX_CONFIG 0xD3 #define ADM1266_PDIO_CONFIG 0xD4 #define ADM1266_READ_STATE 0xD9 +#define ADM1266_READ_BLACKBOX 0xDE +#define ADM1266_SET_RTC 0xDF #define ADM1266_GPIO_CONFIG 0xE1 +#define ADM1266_BLACKBOX_INFO 0xE6 #define ADM1266_PDIO_STATUS 0xE9 #define ADM1266_GPIO_STATUS 0xEA @@ -37,6 +44,9 @@ #define ADM1266_PDIO_GLITCH_FILT(x) FIELD_GET(GENMASK(12, 9), x) #define ADM1266_PDIO_OUT_CFG(x) FIELD_GET(GENMASK(2, 0), x) +#define ADM1266_BLACKBOX_OFFSET 0 +#define ADM1266_BLACKBOX_SIZE 64 + #define ADM1266_PMBUS_BLOCK_MAX 255 struct adm1266_data { @@ -45,11 +55,22 @@ struct adm1266_data { const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR]; struct i2c_client *client; struct dentry *debugfs_dir; + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + u8 *dev_mem; struct mutex buf_mutex; u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; }; +static const struct nvmem_cell_info adm1266_nvmem_cells[] = { + { + .name = "blackbox", + .offset = ADM1266_BLACKBOX_OFFSET, + .bytes = 2048, + }, +}; + DECLARE_CRC8_TABLE(pmbus_crc_table); /* @@ -325,6 +346,104 @@ static void adm1266_init_debugfs(struct adm1266_data *data) adm1266_state_read); } +static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff) +{ + int record_count; + char index; + u8 buf[5]; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); + if (ret < 0) + return ret; + + if (ret != 4) + return -EIO; + + record_count = buf[3]; + + for (index = 0; index < record_count; index++) { + ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff); + if (ret < 0) + return ret; + + if (ret != ADM1266_BLACKBOX_SIZE) + return -EIO; + + read_buff += ADM1266_BLACKBOX_SIZE; + } + + return 0; +} + +static int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct adm1266_data *data = priv; + int ret; + + if (offset + bytes > data->nvmem_config.size) + return -EINVAL; + + if (offset == 0) { + memset(data->dev_mem, 0, data->nvmem_config.size); + + ret = adm1266_nvmem_read_blackbox(data, data->dev_mem); + if (ret) { + dev_err(&data->client->dev, "Could not read blackbox!"); + return ret; + } + } + + memcpy(val, data->dev_mem + offset, bytes); + + return 0; +} + +static int adm1266_config_nvmem(struct adm1266_data *data) +{ + data->nvmem_config.name = dev_name(&data->client->dev); + data->nvmem_config.dev = &data->client->dev; + data->nvmem_config.root_only = true; + data->nvmem_config.read_only = true; + data->nvmem_config.owner = THIS_MODULE; + data->nvmem_config.reg_read = adm1266_nvmem_read; + data->nvmem_config.cells = adm1266_nvmem_cells; + data->nvmem_config.ncells = ARRAY_SIZE(adm1266_nvmem_cells); + data->nvmem_config.priv = data; + data->nvmem_config.stride = 1; + data->nvmem_config.word_size = 1; + data->nvmem_config.size = adm1266_nvmem_cells[0].bytes; + + data->dev_mem = devm_kzalloc(&data->client->dev, data->nvmem_config.size, GFP_KERNEL); + if (!data->dev_mem) + return -ENOMEM; + + data->nvmem = devm_nvmem_register(&data->client->dev, &data->nvmem_config); + if (IS_ERR(data->nvmem)) { + dev_err(&data->client->dev, "Could not register nvmem!"); + return PTR_ERR(data->nvmem); + } + + return 0; +} + +static int adm1266_set_rtc(struct adm1266_data *data) +{ + time64_t kt; + char write_buf[6]; + int i; + + kt = ktime_get_seconds(); + + memset(write_buf, 0, sizeof(write_buf)); + + for (i = 0; i < 4; i++) + write_buf[2 + i] = (kt >> (i * 8)) & 0xFF; + + return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf), + write_buf); +} + static int adm1266_probe(struct i2c_client *client) { struct adm1266_data *data; @@ -348,6 +467,14 @@ static int adm1266_probe(struct i2c_client *client) if (ret < 0) return ret; + ret = adm1266_set_rtc(data); + if (ret < 0) + return ret; + + ret = adm1266_config_nvmem(data); + if (ret < 0) + return ret; + ret = pmbus_do_probe(client, &data->info); if (ret) return ret; From 0c92ddcc7e76fce82b1d348e1dd6f0347ae7aebd Mon Sep 17 00:00:00 2001 From: Alexandru Tachici Date: Wed, 12 Aug 2020 17:20:55 +0300 Subject: [PATCH 30/64] dt-bindings: hwmon: Add bindings for ADM1266 Add bindings for the Analog Devices ADM1266 sequencer. Signed-off-by: Alexandru Tachici Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200812142055.9213-7-alexandru.tachici@analog.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,adm1266.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml new file mode 100644 index 000000000000..43b4f4f57b49 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,adm1266.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADM1266 Cascadable Super Sequencer with Margin + Control and Fault Recording + +maintainers: + - Alexandru Tachici + +description: | + Analog Devices ADM1266 Cascadable Super Sequencer with Margin + Control and Fault Recording. + https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf + +properties: + compatible: + enum: + - adi,adm1266 + + reg: + description: | + I2C address of slave device. + items: + minimum: 0x40 + maximum: 0x4F + + avcc-supply: + description: | + Phandle to the Avcc power supply. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + adm1266@40 { + compatible = "adi,adm1266"; + reg = <0x40>; + }; + }; +... From 0ef0f755b36e369d2195150fc7bf5634d4e55a2f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2020 21:56:08 -0700 Subject: [PATCH 31/64] hwmon: (scmi-hwmon) Avoid comma separated statements Use semicolons and braces. Signed-off-by: Joe Perches Link: https://lore.kernel.org/r/5e1ca60df261e3bfd0e6510e388581a1d1f52c77.1598331149.git.joe@perches.com Signed-off-by: Guenter Roeck --- drivers/hwmon/scmi-hwmon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index d421e691318b..09ce30cba54b 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -202,8 +202,10 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) } } - if (nr_count[hwmon_temp]) - nr_count[hwmon_chip]++, nr_types++; + if (nr_count[hwmon_temp]) { + nr_count[hwmon_chip]++; + nr_types++; + } scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), GFP_KERNEL); From 1782241704239fb7215871bd670e0ae6eefe36b0 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Thu, 27 Aug 2020 00:42:41 -0500 Subject: [PATCH 32/64] hwmon: (k10temp) Create common functions and macros for Zen CPU families Many SMN thermal registers in Zen CPU families are common across different generations. For long-term code maintenance, it is better to rename these macro and function names to Zen. Signed-off-by: Wei Huang Link: https://lore.kernel.org/r/20200827054242.2347-1-wei.huang2@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/k10temp.c | 56 +++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 8f12995ec133..f3addb97b021 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -73,22 +73,24 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 -/* F17h M01h Access througn SMN */ -#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800 +/* Common for Zen CPU families (Family 17h and 18h) */ +#define ZEN_REPORTED_TEMP_CTRL_OFFSET 0x00059800 -#define F17H_M70H_CCD_TEMP(x) (0x00059954 + ((x) * 4)) -#define F17H_M70H_CCD_TEMP_VALID BIT(11) -#define F17H_M70H_CCD_TEMP_MASK GENMASK(10, 0) +#define ZEN_CCD_TEMP(x) (0x00059954 + ((x) * 4)) +#define ZEN_CCD_TEMP_VALID BIT(11) +#define ZEN_CCD_TEMP_MASK GENMASK(10, 0) -#define F17H_M01H_SVI 0x0005A000 -#define F17H_M01H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0xc) -#define F17H_M01H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10) +#define ZEN_CUR_TEMP_SHIFT 21 +#define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19) -#define CUR_TEMP_SHIFT 21 -#define CUR_TEMP_RANGE_SEL_MASK BIT(19) +#define ZEN_SVI_BASE 0x0005A000 -#define CFACTOR_ICORE 1000000 /* 1A / LSB */ -#define CFACTOR_ISOC 250000 /* 0.25A / LSB */ +/* F17h thermal registers through SMN */ +#define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) +#define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +#define F17H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F17H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ struct k10temp_data { struct pci_dev *pdev; @@ -168,10 +170,10 @@ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval) F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval); } -static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) +static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval) { amd_smn_read(amd_pci_dev_to_node_id(pdev), - F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); + ZEN_REPORTED_TEMP_CTRL_OFFSET, regval); } static long get_raw_temp(struct k10temp_data *data) @@ -180,7 +182,7 @@ static long get_raw_temp(struct k10temp_data *data) long temp; data->read_tempreg(data->pdev, ®val); - temp = (regval >> CUR_TEMP_SHIFT) * 125; + temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125; if (regval & data->temp_adjust_mask) temp -= 49000; return temp; @@ -288,8 +290,8 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel, break; case 2 ... 9: /* Tccd{1-8} */ amd_smn_read(amd_pci_dev_to_node_id(data->pdev), - F17H_M70H_CCD_TEMP(channel - 2), ®val); - *val = (regval & F17H_M70H_CCD_TEMP_MASK) * 125 - 49000; + ZEN_CCD_TEMP(channel - 2), ®val); + *val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000; break; default: return -EOPNOTSUPP; @@ -438,7 +440,7 @@ static int svi_show(struct seq_file *s, void *unused) { struct k10temp_data *data = s->private; - k10temp_smn_regs_show(s, data->pdev, F17H_M01H_SVI, 32); + k10temp_smn_regs_show(s, data->pdev, ZEN_SVI_BASE, 32); return 0; } DEFINE_SHOW_ATTRIBUTE(svi); @@ -448,7 +450,7 @@ static int thm_show(struct seq_file *s, void *unused) struct k10temp_data *data = s->private; k10temp_smn_regs_show(s, data->pdev, - F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, 256); + ZEN_REPORTED_TEMP_CTRL_OFFSET, 256); return 0; } DEFINE_SHOW_ATTRIBUTE(thm); @@ -528,8 +530,8 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev, for (i = 0; i < limit; i++) { amd_smn_read(amd_pci_dev_to_node_id(pdev), - F17H_M70H_CCD_TEMP(i), ®val); - if (regval & F17H_M70H_CCD_TEMP_VALID) + ZEN_CCD_TEMP(i), ®val); + if (regval & ZEN_CCD_TEMP_VALID) data->show_temp |= BIT(TCCD_BIT(i)); } } @@ -565,8 +567,8 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) data->read_htcreg = read_htcreg_nb_f15; data->read_tempreg = read_tempreg_nb_f15; } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) { - data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK; - data->read_tempreg = read_tempreg_nb_f17; + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; + data->read_tempreg = read_tempreg_nb_zen; data->show_temp |= BIT(TDIE_BIT); /* show Tdie */ data->is_zen = true; @@ -578,15 +580,15 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) data->show_current = !is_threadripper() && !is_epyc(); data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0; data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1; - data->cfactor[0] = CFACTOR_ICORE; - data->cfactor[1] = CFACTOR_ISOC; + data->cfactor[0] = F17H_CFACTOR_ICORE; + data->cfactor[1] = F17H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 4); break; case 0x31: /* Zen2 Threadripper */ case 0x71: /* Zen2 */ data->show_current = !is_threadripper() && !is_epyc(); - data->cfactor[0] = CFACTOR_ICORE; - data->cfactor[1] = CFACTOR_ISOC; + data->cfactor[0] = F17H_CFACTOR_ICORE; + data->cfactor[1] = F17H_CFACTOR_ISOC; data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE1; data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE0; k10temp_get_ccd_support(pdev, data, 8); From d6144a40041a70ecce410a07d3a2b6906f6e7da9 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Thu, 27 Aug 2020 00:42:42 -0500 Subject: [PATCH 33/64] hwmon: (k10temp) Define SVI telemetry and current factors for Zen2 CPUs The voltage telemetry registers for Zen2 are different from Zen1. Also the factors of CPU current values are changed on Zen2. Add new definitions for these register. Signed-off-by: Wei Huang Link: https://lore.kernel.org/r/20200827054242.2347-2-wei.huang2@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/k10temp.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index f3addb97b021..de9f68570a4f 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -88,9 +88,13 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); /* F17h thermal registers through SMN */ #define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) #define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) +#define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) +#define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) -#define F17H_CFACTOR_ICORE 1000000 /* 1A / LSB */ -#define F17H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ +#define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ +#define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ struct k10temp_data { struct pci_dev *pdev; @@ -580,17 +584,17 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) data->show_current = !is_threadripper() && !is_epyc(); data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0; data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1; - data->cfactor[0] = F17H_CFACTOR_ICORE; - data->cfactor[1] = F17H_CFACTOR_ISOC; + data->cfactor[0] = F17H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M01H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 4); break; case 0x31: /* Zen2 Threadripper */ case 0x71: /* Zen2 */ data->show_current = !is_threadripper() && !is_epyc(); - data->cfactor[0] = F17H_CFACTOR_ICORE; - data->cfactor[1] = F17H_CFACTOR_ISOC; - data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE1; - data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE0; + data->cfactor[0] = F17H_M31H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M31H_CFACTOR_ISOC; + data->svi_addr[0] = F17H_M31H_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_M31H_SVI_TEL_PLANE1; k10temp_get_ccd_support(pdev, data, 8); break; } From 7497d4a66c596fc8312cafe1b8d1e76ad2bc34c3 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 27 Aug 2020 13:04:54 -0700 Subject: [PATCH 34/64] hwmon: (gsc-hwmon) add fan sensor Add a fan sensor to report RPM's from a fan tach input. Signed-off-by: Tim Harvey Signed-off-by: Guenter Roeck --- drivers/hwmon/gsc-hwmon.c | 32 ++++++++++++++++++++++--- include/linux/platform_data/gsc_hwmon.h | 1 + 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index c6d4567f3952..1fe37418ff46 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -17,6 +17,7 @@ #define GSC_HWMON_MAX_TEMP_CH 16 #define GSC_HWMON_MAX_IN_CH 16 +#define GSC_HWMON_MAX_FAN_CH 16 #define GSC_HWMON_RESOLUTION 12 #define GSC_HWMON_VREF 2500 @@ -27,11 +28,14 @@ struct gsc_hwmon_data { struct regmap *regmap; const struct gsc_hwmon_channel *temp_ch[GSC_HWMON_MAX_TEMP_CH]; const struct gsc_hwmon_channel *in_ch[GSC_HWMON_MAX_IN_CH]; + const struct gsc_hwmon_channel *fan_ch[GSC_HWMON_MAX_FAN_CH]; u32 temp_config[GSC_HWMON_MAX_TEMP_CH + 1]; u32 in_config[GSC_HWMON_MAX_IN_CH + 1]; + u32 fan_config[GSC_HWMON_MAX_FAN_CH + 1]; struct hwmon_channel_info temp_info; struct hwmon_channel_info in_info; - const struct hwmon_channel_info *info[3]; + struct hwmon_channel_info fan_info; + const struct hwmon_channel_info *info[4]; struct hwmon_chip_info chip; }; @@ -155,6 +159,9 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_temp: ch = hwmon->temp_ch[channel]; break; + case hwmon_fan: + ch = hwmon->fan_ch[channel]; + break; default: return -EOPNOTSUPP; } @@ -187,6 +194,9 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, /* adjust by uV offset */ tmp += ch->mvoffset; break; + case mode_fan: + tmp *= 30; /* convert to revolutions per minute */ + break; case mode_voltage_24bit: case mode_voltage_16bit: /* no adjustment needed */ @@ -211,6 +221,9 @@ gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp: *buf = hwmon->temp_ch[channel]->name; break; + case hwmon_fan: + *buf = hwmon->fan_ch[channel]->name; + break; default: return -ENOTSUPP; } @@ -304,7 +317,7 @@ static int gsc_hwmon_probe(struct platform_device *pdev) struct gsc_hwmon_platform_data *pdata = dev_get_platdata(dev); struct gsc_hwmon_data *hwmon; const struct attribute_group **groups; - int i, i_in, i_temp; + int i, i_in, i_temp, i_fan; if (!pdata) { pdata = gsc_hwmon_get_devtree_pdata(dev); @@ -324,7 +337,7 @@ static int gsc_hwmon_probe(struct platform_device *pdev) if (IS_ERR(hwmon->regmap)) return PTR_ERR(hwmon->regmap); - for (i = 0, i_in = 0, i_temp = 0; i < hwmon->pdata->nchannels; i++) { + for (i = 0, i_in = 0, i_temp = 0, i_fan = 0; i < hwmon->pdata->nchannels; i++) { const struct gsc_hwmon_channel *ch = &pdata->channels[i]; switch (ch->mode) { @@ -338,6 +351,16 @@ static int gsc_hwmon_probe(struct platform_device *pdev) HWMON_T_LABEL; i_temp++; break; + case mode_fan: + if (i_fan == GSC_HWMON_MAX_FAN_CH) { + dev_err(gsc->dev, "too many fan channels\n"); + return -EINVAL; + } + hwmon->fan_ch[i_fan] = ch; + hwmon->fan_config[i_fan] = HWMON_F_INPUT | + HWMON_F_LABEL; + i_fan++; + break; case mode_voltage_24bit: case mode_voltage_16bit: case mode_voltage_raw: @@ -361,10 +384,13 @@ static int gsc_hwmon_probe(struct platform_device *pdev) hwmon->chip.info = hwmon->info; hwmon->info[0] = &hwmon->temp_info; hwmon->info[1] = &hwmon->in_info; + hwmon->info[2] = &hwmon->fan_info; hwmon->temp_info.type = hwmon_temp; hwmon->temp_info.config = hwmon->temp_config; hwmon->in_info.type = hwmon_in; hwmon->in_info.config = hwmon->in_config; + hwmon->fan_info.type = hwmon_fan; + hwmon->fan_info.config = hwmon->fan_config; groups = pdata->fan_base ? gsc_hwmon_groups : NULL; hwmon_dev = devm_hwmon_device_register_with_info(dev, diff --git a/include/linux/platform_data/gsc_hwmon.h b/include/linux/platform_data/gsc_hwmon.h index 37a8f554da00..281f499eda97 100644 --- a/include/linux/platform_data/gsc_hwmon.h +++ b/include/linux/platform_data/gsc_hwmon.h @@ -7,6 +7,7 @@ enum gsc_hwmon_mode { mode_voltage_24bit, mode_voltage_raw, mode_voltage_16bit, + mode_fan, mode_max, }; From 8999eabf332acf13455f33006ea8678398b8c95e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 8 Sep 2020 10:13:45 -0700 Subject: [PATCH 35/64] hwmon: (k10temp) Take out debugfs code The debugfs code was intended to aid figuring out functionality of undocumented registers. Turns out that wasn't very helpful, since register locations change too much between AMD chip revisions, and the data isn't really valuable for chips where it isn't already supported. On top of that, its existence has been used as argument for providing pseudo-API debugfs functions in other drivers. So let's just take it out. Signed-off-by: Guenter Roeck --- drivers/hwmon/k10temp.c | 78 +---------------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index de9f68570a4f..49e8ebf8da32 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -422,76 +421,6 @@ static bool has_erratum_319(struct pci_dev *pdev) (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); } -#ifdef CONFIG_DEBUG_FS - -static void k10temp_smn_regs_show(struct seq_file *s, struct pci_dev *pdev, - u32 addr, int count) -{ - u32 reg; - int i; - - for (i = 0; i < count; i++) { - if (!(i & 3)) - seq_printf(s, "0x%06x: ", addr + i * 4); - amd_smn_read(amd_pci_dev_to_node_id(pdev), addr + i * 4, ®); - seq_printf(s, "%08x ", reg); - if ((i & 3) == 3) - seq_puts(s, "\n"); - } -} - -static int svi_show(struct seq_file *s, void *unused) -{ - struct k10temp_data *data = s->private; - - k10temp_smn_regs_show(s, data->pdev, ZEN_SVI_BASE, 32); - return 0; -} -DEFINE_SHOW_ATTRIBUTE(svi); - -static int thm_show(struct seq_file *s, void *unused) -{ - struct k10temp_data *data = s->private; - - k10temp_smn_regs_show(s, data->pdev, - ZEN_REPORTED_TEMP_CTRL_OFFSET, 256); - return 0; -} -DEFINE_SHOW_ATTRIBUTE(thm); - -static void k10temp_debugfs_cleanup(void *ddir) -{ - debugfs_remove_recursive(ddir); -} - -static void k10temp_init_debugfs(struct k10temp_data *data) -{ - struct dentry *debugfs; - char name[32]; - - /* Only show debugfs data for Family 17h/18h CPUs */ - if (!data->is_zen) - return; - - scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev)); - - debugfs = debugfs_create_dir(name, NULL); - if (debugfs) { - debugfs_create_file("svi", 0444, debugfs, data, &svi_fops); - debugfs_create_file("thm", 0444, debugfs, data, &thm_fops); - devm_add_action_or_reset(&data->pdev->dev, - k10temp_debugfs_cleanup, debugfs); - } -} - -#else - -static void k10temp_init_debugfs(struct k10temp_data *data) -{ -} - -#endif - static const struct hwmon_channel_info *k10temp_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | @@ -616,12 +545,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data, &k10temp_chip_info, NULL); - if (IS_ERR(hwmon_dev)) - return PTR_ERR(hwmon_dev); - - k10temp_init_debugfs(data); - - return 0; + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct pci_device_id k10temp_id_table[] = { From a919ba06979a7858dab65492eb580121ccbd524f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 4 Sep 2020 09:33:14 -0700 Subject: [PATCH 36/64] hwmon: (pmbus) Stop caching register values Caching register values can be very expensive for PMBus chips. Some modern chips may have 10 or more pages, with several sensors supported per page. For example, MAX16601 creates more than 90 sysfs attributes. Register caching for such chips is time consuming, especially if only a few attributes are read on a regular basis. For MAX16601, it was observed that it can take up to two seconds to read all attributes on a slow I2C bus. In this situation, register caching results in the opposite of its intention: It increases the number of I2C operations, in some cases substantially, and it results in large latency when trying to access individual sensor data. Drop all register caching to solve the problem. Since it is no longer necessary, drop status register mapping as part of the change, and specify status registers directly. Cc: Alex Qiu Signed-off-by: Guenter Roeck Reviewed-by: Alex Qiu Tested-by: Alex Qiu Link: https://lore.kernel.org/r/20200904163314.259087-1-linux@roeck-us.net Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 206 +++++++++++++------------------ 1 file changed, 89 insertions(+), 117 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 987de6d857bc..1f43bf0f23b2 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -27,21 +26,6 @@ * with each call to krealloc */ #define PMBUS_ATTR_ALLOC_SIZE 32 - -/* - * Index into status register array, per status register group - */ -#define PB_STATUS_BASE 0 -#define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) -#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) -#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) -#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES) -#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1) - -#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1) - #define PMBUS_NAME_SIZE 24 struct pmbus_sensor { @@ -77,6 +61,21 @@ struct pmbus_label { #define to_pmbus_label(_attr) \ container_of(_attr, struct pmbus_label, attribute) +/* Macros for converting between sensor index and register/page/status mask */ + +#define PB_STATUS_MASK 0xffff +#define PB_REG_SHIFT 16 +#define PB_REG_MASK 0x3ff +#define PB_PAGE_SHIFT 26 +#define PB_PAGE_MASK 0x3f + +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ + ((reg) << PB_REG_SHIFT) | (mask)) + +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) + struct pmbus_data { struct device *dev; struct device *hwmon_dev; @@ -97,14 +96,6 @@ struct pmbus_data { struct pmbus_sensor *sensors; struct mutex update_lock; - bool valid; - unsigned long last_updated; /* in jiffies */ - - /* - * A single status register covers multiple attributes, - * so we keep them all together. - */ - u16 status[PB_NUM_STATUS_REG]; bool has_status_word; /* device uses STATUS_WORD register */ int (*read_status)(struct i2c_client *client, int page); @@ -143,8 +134,10 @@ static const int pmbus_fan_command_registers[] = { void pmbus_clear_cache(struct i2c_client *client) { struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; - data->valid = false; + for (sensor = data->sensors; sensor; sensor = sensor->next) + sensor->data = -ENODATA; } EXPORT_SYMBOL_GPL(pmbus_clear_cache); @@ -560,68 +553,29 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_get_driver_info); -static struct _pmbus_status { - u32 func; - u16 base; - u16 reg; -} pmbus_status[] = { - { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT }, - { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT }, - { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE, - PMBUS_STATUS_TEMPERATURE }, - { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 }, - { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 }, -}; - -static struct pmbus_data *pmbus_update_device(struct device *dev) +static int pmbus_get_status(struct i2c_client *client, int page, int reg) { - struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); - const struct pmbus_driver_info *info = data->info; - struct pmbus_sensor *sensor; + int status; - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - for (i = 0; i < info->pages; i++) { - data->status[PB_STATUS_BASE + i] - = data->read_status(client, i); - for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { - struct _pmbus_status *s = &pmbus_status[j]; - - if (!(info->func[i] & s->func)) - continue; - data->status[s->base + i] - = _pmbus_read_byte_data(client, i, - s->reg); - } - } - - if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) - data->status[PB_STATUS_INPUT_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_STATUS_INPUT); - - if (info->func[0] & PMBUS_HAVE_STATUS_VMON) - data->status[PB_STATUS_VMON_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_VIRT_STATUS_VMON); - - for (sensor = data->sensors; sensor; sensor = sensor->next) { - if (!data->valid || sensor->update) - sensor->data - = _pmbus_read_word_data(client, - sensor->page, - sensor->phase, - sensor->reg); - } - pmbus_clear_faults(client); - data->last_updated = jiffies; - data->valid = 1; + switch (reg) { + case PMBUS_STATUS_WORD: + status = data->read_status(client, page); + break; + default: + status = _pmbus_read_byte_data(client, page, reg); + break; } - mutex_unlock(&data->update_lock); - return data; + if (status < 0) + pmbus_clear_faults(client); + return status; +} + +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) +{ + if (sensor->data < 0 || sensor->update) + sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); } /* @@ -919,38 +873,53 @@ static u16 pmbus_data2reg(struct pmbus_data *data, * If a negative value is stored in any of the referenced registers, this value * reflects an error code which will be returned. */ -static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, int index) { + struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_sensor *s1 = b->s1; struct pmbus_sensor *s2 = b->s2; - u16 reg = (index >> 16) & 0xffff; - u16 mask = index & 0xffff; + u16 mask = pb_index_to_mask(index); + u8 page = pb_index_to_page(index); + u16 reg = pb_index_to_reg(index); int ret, status; u16 regval; - status = data->status[reg]; - if (status < 0) - return status; + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, reg); + if (status < 0) { + ret = status; + goto unlock; + } + + if (s1) + pmbus_update_sensor_data(client, s1); + if (s2) + pmbus_update_sensor_data(client, s2); regval = status & mask; if (!s1 && !s2) { ret = !!regval; } else if (!s1 || !s2) { WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); - return 0; } else { s64 v1, v2; - if (s1->data < 0) - return s1->data; - if (s2->data < 0) - return s2->data; + if (s1->data < 0) { + ret = s1->data; + goto unlock; + } + if (s2->data < 0) { + ret = s2->data; + goto unlock; + } v1 = pmbus_reg2data(data, s1); v2 = pmbus_reg2data(data, s2); ret = !!(regval && v1 >= v2); } +unlock: + mutex_unlock(&data->update_lock); return ret; } @@ -959,10 +928,10 @@ static ssize_t pmbus_show_boolean(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct pmbus_boolean *boolean = to_pmbus_boolean(attr); - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); int val; - val = pmbus_get_boolean(data, boolean, attr->index); + val = pmbus_get_boolean(client, boolean, attr->index); if (val < 0) return val; return snprintf(buf, PAGE_SIZE, "%d\n", val); @@ -971,9 +940,11 @@ static ssize_t pmbus_show_boolean(struct device *dev, static ssize_t pmbus_show_sensor(struct device *dev, struct device_attribute *devattr, char *buf) { - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + pmbus_update_sensor_data(client, sensor); if (sensor->data < 0) return sensor->data; @@ -1068,7 +1039,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, const char *name, const char *type, int seq, struct pmbus_sensor *s1, struct pmbus_sensor *s2, - u16 reg, u16 mask) + u8 page, u16 reg, u16 mask) { struct pmbus_boolean *boolean; struct sensor_device_attribute *a; @@ -1084,7 +1055,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, boolean->s1 = s1; boolean->s2 = s2; pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, - (reg << 16) | mask); + pb_reg_to_index(page, reg, mask)); return pmbus_add_attribute(data, &a->dev_attr.attr); } @@ -1121,6 +1092,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->class = class; sensor->update = update; sensor->convert = convert; + sensor->data = -ENODATA; pmbus_dev_attr_init(a, sensor->name, readonly ? 0444 : 0644, pmbus_show_sensor, pmbus_set_sensor); @@ -1201,7 +1173,7 @@ struct pmbus_sensor_attr { bool compare; /* true if compare function needed */ u32 func; /* sensor mask */ u32 sfunc; /* sensor status mask */ - int sbase; /* status base register */ + int sreg; /* status register */ const struct pmbus_limit_attr *limit;/* limit registers */ }; @@ -1239,7 +1211,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, : NULL, attr->compare ? l->low ? base : curr : NULL, - attr->sbase + page, l->sbit); + page, attr->sreg, l->sbit); if (ret) return ret; have_alarm = 1; @@ -1289,7 +1261,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, pmbus_check_status_register(client, page)) { ret = pmbus_add_boolean(data, name, "alarm", index, NULL, NULL, - PB_STATUS_BASE + page, + page, PMBUS_STATUS_WORD, attr->gbit); if (ret) return ret; @@ -1489,7 +1461,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vin", .func = PMBUS_HAVE_VIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_VIN_UV, .limit = vin_limit_attrs, .nlimit = ARRAY_SIZE(vin_limit_attrs), @@ -1499,7 +1471,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vmon", .func = PMBUS_HAVE_VMON, .sfunc = PMBUS_HAVE_STATUS_VMON, - .sbase = PB_STATUS_VMON_BASE, + .sreg = PMBUS_VIRT_STATUS_VMON, .limit = vmon_limit_attrs, .nlimit = ARRAY_SIZE(vmon_limit_attrs), }, { @@ -1514,7 +1486,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .paged = true, .func = PMBUS_HAVE_VOUT, .sfunc = PMBUS_HAVE_STATUS_VOUT, - .sbase = PB_STATUS_VOUT_BASE, + .sreg = PMBUS_STATUS_VOUT, .gbit = PB_STATUS_VOUT_OV, .limit = vout_limit_attrs, .nlimit = ARRAY_SIZE(vout_limit_attrs), @@ -1599,7 +1571,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .label = "iin", .func = PMBUS_HAVE_IIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = iin_limit_attrs, .nlimit = ARRAY_SIZE(iin_limit_attrs), @@ -1610,7 +1582,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .paged = true, .func = PMBUS_HAVE_IOUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .gbit = PB_STATUS_IOUT_OC, .limit = iout_limit_attrs, .nlimit = ARRAY_SIZE(iout_limit_attrs), @@ -1690,7 +1662,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .label = "pin", .func = PMBUS_HAVE_PIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = pin_limit_attrs, .nlimit = ARRAY_SIZE(pin_limit_attrs), @@ -1701,7 +1673,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .paged = true, .func = PMBUS_HAVE_POUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .limit = pout_limit_attrs, .nlimit = ARRAY_SIZE(pout_limit_attrs), } @@ -1829,7 +1801,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs, .nlimit = ARRAY_SIZE(temp_limit_attrs), @@ -1841,7 +1813,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP2, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs2, .nlimit = ARRAY_SIZE(temp_limit_attrs2), @@ -1853,7 +1825,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP3, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs3, .nlimit = ARRAY_SIZE(temp_limit_attrs3), @@ -1978,19 +1950,19 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, if ((info->func[page] & pmbus_fan_status_flags[f]) && pmbus_check_byte_register(client, page, pmbus_fan_status_registers[f])) { - int base; + int reg; if (f > 1) /* fan 3, 4 */ - base = PB_STATUS_FAN34_BASE + page; + reg = PMBUS_STATUS_FAN_34; else - base = PB_STATUS_FAN_BASE + page; + reg = PMBUS_STATUS_FAN_12; ret = pmbus_add_boolean(data, "fan", - "alarm", index, NULL, NULL, base, + "alarm", index, NULL, NULL, page, reg, PB_FAN_FAN1_WARNING >> (f & 1)); if (ret) return ret; ret = pmbus_add_boolean(data, "fan", - "fault", index, NULL, NULL, base, + "fault", index, NULL, NULL, page, reg, PB_FAN_FAN1_FAULT >> (f & 1)); if (ret) return ret; From 2cd8529cfb28eb9bc392a8a36c66dd318aafd49d Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Thu, 10 Sep 2020 11:41:06 +0930 Subject: [PATCH 37/64] hwmon: (pmbus) Expose PEC debugfs attribute Enable runtime debug control of whether the PEC byte is exchanged with the PMBus device. Some manufacturers have asked for the PEC to be disabled as part of debugging driver communication issues with devices. Signed-off-by: Andrew Jeffery Link: https://lore.kernel.org/r/20200910021106.2958382-1-andrew@aj.id.au [groeck: Replace %1llu with %llu] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 1f43bf0f23b2..138f83538c8b 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2351,6 +2351,42 @@ static int pmbus_debugfs_get_status(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, NULL, "0x%04llx\n"); +static int pmbus_debugfs_get_pec(void *data, u64 *val) +{ + struct i2c_client *client = data; + + *val = !!(client->flags & I2C_CLIENT_PEC); + + return 0; +} + +static int pmbus_debugfs_set_pec(void *data, u64 val) +{ + int rc; + struct i2c_client *client = data; + + if (!val) { + client->flags &= ~I2C_CLIENT_PEC; + return 0; + } + + if (val != 1) + return -EINVAL; + + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (rc < 0) + return rc; + + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) + return -EOPNOTSUPP; + + client->flags |= I2C_CLIENT_PEC; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, + pmbus_debugfs_set_pec, "%llu\n"); + static int pmbus_init_debugfs(struct i2c_client *client, struct pmbus_data *data) { @@ -2379,6 +2415,9 @@ static int pmbus_init_debugfs(struct i2c_client *client, if (!entries) return -ENOMEM; + debugfs_create_file("pec", 0664, data->debugfs, client, + &pmbus_debugfs_ops_pec); + for (i = 0; i < data->info->pages; ++i) { /* Check accessibility of status register if it's not page 0 */ if (!i || pmbus_check_status_register(client, i)) { From 04e216d19e4044148f16ca4eb3fade2a90a0b02e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 10 Sep 2020 03:09:49 -0700 Subject: [PATCH 38/64] hwmon: (pmbus) Move boolean error condition check to generating code 0-day rightfully complains about a sometimes uninitialized variable in pmbus_get_boolean(). drivers/hwmon/pmbus/pmbus_core.c:903:13: warning: variable 'ret' is used uninitialized whenever 'if' condition is true } else if (!s1 || !s2) { While that is technically true, it won't be hit in the field since the condition indicates a programming error. Move the check of that condition into the code generating the attribute entry, and refuse generating the attribute if the condition is true. Swap the condition check in pmbus_get_boolean() to ensure that static analyzers don't get a hiccup (because we check if s1 and s2 are NULL, static analyzers may believe that they can be NULL independently of each other). Reported-by: kernel test robot Cc: Alex Qiu Reviewed-by: Alex Qiu Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 138f83538c8b..a0842d5ae950 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -898,11 +898,7 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, pmbus_update_sensor_data(client, s2); regval = status & mask; - if (!s1 && !s2) { - ret = !!regval; - } else if (!s1 || !s2) { - WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); - } else { + if (s1 && s2) { s64 v1, v2; if (s1->data < 0) { @@ -917,6 +913,8 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, v1 = pmbus_reg2data(data, s1); v2 = pmbus_reg2data(data, s2); ret = !!(regval && v1 >= v2); + } else { + ret = !!regval; } unlock: mutex_unlock(&data->update_lock); @@ -1044,6 +1042,9 @@ static int pmbus_add_boolean(struct pmbus_data *data, struct pmbus_boolean *boolean; struct sensor_device_attribute *a; + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) + return -EINVAL; + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); if (!boolean) return -ENOMEM; From 55163a1c00fcb526e2aa9f7f952fb38d3543da5e Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Mon, 14 Sep 2020 15:07:15 -0500 Subject: [PATCH 39/64] hwmon: (k10temp) Add support for Zen3 CPUs Zen3 thermal info is supported via a new PCI device ID. Also the voltage telemetry registers and the current factors need to be defined. k10temp driver then searches for CPU family 0x19 and configures k10temp_data accordingly. Signed-off-by: Wei Huang Link: https://lore.kernel.org/r/20200914200715.1997757-1-wei.huang2@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/k10temp.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 49e8ebf8da32..a250481b5a97 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -95,6 +95,13 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ #define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ +/* F19h thermal registers through SMN */ +#define F19H_M01_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) +#define F19H_M01_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +#define F19H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F19H_M01H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ + struct k10temp_data { struct pci_dev *pdev; void (*read_htcreg)(struct pci_dev *pdev, u32 *regval); @@ -527,6 +534,22 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) k10temp_get_ccd_support(pdev, data, 8); break; } + } else if (boot_cpu_data.x86 == 0x19) { + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; + data->read_tempreg = read_tempreg_nb_zen; + data->show_temp |= BIT(TDIE_BIT); + data->is_zen = true; + + switch (boot_cpu_data.x86_model) { + case 0x0 ... 0x1: /* Zen3 */ + data->show_current = true; + data->svi_addr[0] = F19H_M01_SVI_TEL_PLANE0; + data->svi_addr[1] = F19H_M01_SVI_TEL_PLANE1; + data->cfactor[0] = F19H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F19H_M01H_CFACTOR_ISOC; + k10temp_get_ccd_support(pdev, data, 8); + break; + } } else { data->read_htcreg = read_htcreg_pci; data->read_tempreg = read_tempreg_pci; @@ -564,6 +587,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, {} }; From 10d097737dfe27bb0bf3f825b5ff28d26053a8c6 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 24 Sep 2020 20:51:00 +1200 Subject: [PATCH 40/64] hwmon: (adm9240) Use loops to avoid duplicated code Use loops for reading temp_max and initialising FAN_MIN/TEMP_MAX rather than duplicating code. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20200924085102.15219-2-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck --- drivers/hwmon/adm9240.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 16364dee1794..a34a8c9235b8 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -223,10 +223,10 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) data->fan_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN_MIN(i)); } - data->temp_max[0] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(0)); - data->temp_max[1] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(1)); + for (i = 0; i < 2; i++) { + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(i)); + } /* read fan divs and 5-bit VID */ i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); @@ -687,14 +687,14 @@ static void adm9240_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(i), 255); } - i2c_smbus_write_byte_data(client, - ADM9240_REG_FAN_MIN(0), 255); - i2c_smbus_write_byte_data(client, - ADM9240_REG_FAN_MIN(1), 255); - i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_MAX(0), 127); - i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_MAX(1), 127); + for (i = 0; i < 2; i++) { + i2c_smbus_write_byte_data(client, + ADM9240_REG_FAN_MIN(i), 255); + } + for (i = 0; i < 2; i++) { + i2c_smbus_write_byte_data(client, + ADM9240_REG_TEMP_MAX(i), 127); + } /* start measurement cycle */ i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); From 6a8cdd146459a4f48d2932908b608cf44f18970e Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 24 Sep 2020 20:51:01 +1200 Subject: [PATCH 41/64] hwmon: (adm9240) Create functions for updating measure and config Split the body of adm9240_update_device() into two helper functions adm9240_update_measure() and adm9240_update_config(). Although neither of the new helpers returns an error yet lay the groundwork for propagating failures through to the sysfs readers. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20200924085102.15219-3-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck --- drivers/hwmon/adm9240.c | 202 +++++++++++++++++++++++++++------------- 1 file changed, 138 insertions(+), 64 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index a34a8c9235b8..94b03eab832e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -158,53 +158,100 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, nr + 1, 1 << old, 1 << fan_div); } +static int adm9240_update_measure(struct adm9240_data *data) +{ + struct i2c_client *client = data->client; + int i; + + for (i = 0; i < 6; i++) { /* read voltages */ + data->in[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_IN(i)); + } + data->alarms = i2c_smbus_read_byte_data(client, + ADM9240_REG_INT(0)) | + i2c_smbus_read_byte_data(client, + ADM9240_REG_INT(1)) << 8; + + /* + * read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant + */ + data->temp = (i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP) << 8) | + i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_CONF); + + for (i = 0; i < 2; i++) { /* read fans */ + data->fan[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_FAN(i)); + + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + adm9240_write_fan_div(client, i, + ++data->fan_div[i]); + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + + return 0; +} + +static int adm9240_update_config(struct adm9240_data *data) +{ + struct i2c_client *client = data->client; + int i; + + for (i = 0; i < 6; i++) { + data->in_min[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_IN_MIN(i)); + data->in_max[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) { + data->fan_min[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_FAN_MIN(i)); + } + for (i = 0; i < 2; i++) { + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(i)); + } + + /* read fan divs and 5-bit VID */ + i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 3; + data->fan_div[1] = (i >> 6) & 3; + data->vid = i & 0x0f; + data->vid |= (i2c_smbus_read_byte_data(client, + ADM9240_REG_VID4) & 1) << 4; + /* read analog out */ + data->aout = i2c_smbus_read_byte_data(client, + ADM9240_REG_ANALOG_OUT); + + return 0; +} + static struct adm9240_data *adm9240_update_device(struct device *dev) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int i; + int err; mutex_lock(&data->update_lock); /* minimum measurement cycle: 1.75 seconds */ if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) || !data->valid) { - - for (i = 0; i < 6; i++) { /* read voltages */ - data->in[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN(i)); - } - data->alarms = i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(0)) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(1)) << 8; - - /* - * read temperature: assume temperature changes less than - * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant - */ - data->temp = (i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP) << 8) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_CONF); - - for (i = 0; i < 2; i++) { /* read fans */ - data->fan[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN(i)); - - /* adjust fan clock divider on overflow */ - if (data->valid && data->fan[i] == 255 && - data->fan_div[i] < 3) { - - adm9240_write_fan_div(client, i, - ++data->fan_div[i]); - - /* adjust fan_min if active, but not to 0 */ - if (data->fan_min[i] < 255 && - data->fan_min[i] >= 2) - data->fan_min[i] /= 2; - } + err = adm9240_update_measure(data); + if (err < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return ERR_PTR(err); } data->last_updated_measure = jiffies; } @@ -212,33 +259,12 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) /* minimum config reading cycle: 300 seconds */ if (time_after(jiffies, data->last_updated_config + (HZ * 300)) || !data->valid) { - - for (i = 0; i < 6; i++) { - data->in_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MAX(i)); + err = adm9240_update_config(data); + if (err < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return ERR_PTR(err); } - for (i = 0; i < 2; i++) { - data->fan_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN_MIN(i)); - } - for (i = 0; i < 2; i++) { - data->temp_max[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(i)); - } - - /* read fan divs and 5-bit VID */ - i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 3; - data->fan_div[1] = (i >> 6) & 3; - data->vid = i & 0x0f; - data->vid |= (i2c_smbus_read_byte_data(client, - ADM9240_REG_VID4) & 1) << 4; - /* read analog out */ - data->aout = i2c_smbus_read_byte_data(client, - ADM9240_REG_ANALOG_OUT); - data->last_updated_config = jiffies; data->valid = 1; } @@ -253,6 +279,10 @@ static ssize_t temp1_input_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */ } @@ -261,6 +291,10 @@ static ssize_t max_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000); } @@ -295,6 +329,10 @@ static ssize_t in_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index], attr->index)); } @@ -304,6 +342,10 @@ static ssize_t in_min_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index], attr->index)); } @@ -313,6 +355,10 @@ static ssize_t in_max_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index], attr->index)); } @@ -386,6 +432,10 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], 1 << data->fan_div[attr->index])); } @@ -395,6 +445,10 @@ static ssize_t fan_min_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index], 1 << data->fan_div[attr->index])); } @@ -404,6 +458,10 @@ static ssize_t fan_div_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]); } @@ -490,6 +548,10 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR_RO(alarms); @@ -499,6 +561,10 @@ static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); @@ -516,6 +582,10 @@ static ssize_t cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR_RO(cpu0_vid); @@ -525,6 +595,10 @@ static ssize_t aout_output_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } From df885d912f678f45a867c4eb3f3a5b0ea17796f4 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 24 Sep 2020 20:51:02 +1200 Subject: [PATCH 42/64] hwmon: (adm9240) Convert to regmap Convert the adm9240 driver to using regmap and add error handling. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20200924085102.15219-4-chris.packham@alliedtelesis.co.nz [groeck: Fixed context conflict against 'hwmon: use simple i2c probe function'] Signed-off-by: Guenter Roeck --- drivers/hwmon/adm9240.c | 215 +++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 79 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 94b03eab832e..cc3e0184e720 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -38,6 +38,7 @@ #include #include #include +#include /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, @@ -123,6 +124,7 @@ static inline unsigned int AOUT_FROM_REG(u8 reg) /* per client data */ struct adm9240_data { struct i2c_client *client; + struct regmap *regmap; struct mutex update_lock; char valid; unsigned long last_updated_measure; @@ -143,55 +145,72 @@ struct adm9240_data { }; /* write new fan div, callers must hold data->update_lock */ -static void adm9240_write_fan_div(struct i2c_client *client, int nr, +static int adm9240_write_fan_div(struct adm9240_data *data, int nr, u8 fan_div) { - u8 reg, old, shift = (nr + 2) * 2; + unsigned int reg, old, shift = (nr + 2) * 2; + int err; - reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, ®); + if (err < 0) + return err; old = (reg >> shift) & 3; reg &= ~(3 << shift); reg |= (fan_div << shift); - i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg); - dev_dbg(&client->dev, + err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg); + if (err < 0) + return err; + dev_dbg(&data->client->dev, "fan%d clock divider changed from %u to %u\n", nr + 1, 1 << old, 1 << fan_div); + + return 0; } static int adm9240_update_measure(struct adm9240_data *data) { - struct i2c_client *client = data->client; + unsigned int val; + u8 regs[2]; + int err; int i; - for (i = 0; i < 6; i++) { /* read voltages */ - data->in[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN(i)); - } - data->alarms = i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(0)) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(1)) << 8; + err = regmap_bulk_read(data->regmap, ADM9240_REG_IN(0), &data->in[0], 6); + if (err < 0) + return err; + err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), ®s, 2); + if (err < 0) + return err; + + data->alarms = regs[0] | regs[1] << 8; /* * read temperature: assume temperature changes less than * 0.5'C per two measurement cycles thus ignore possible * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = (i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP) << 8) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_CONF); + err = regmap_read(data->regmap, ADM9240_REG_TEMP, &val); + if (err < 0) + return err; + data->temp = val << 8; + err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &val); + if (err < 0) + return err; + data->temp |= val; + + err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN(0), + &data->fan[0], 2); + if (err < 0) + return err; for (i = 0; i < 2; i++) { /* read fans */ - data->fan[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN(i)); - /* adjust fan clock divider on overflow */ if (data->valid && data->fan[i] == 255 && data->fan_div[i] < 3) { - adm9240_write_fan_div(client, i, + err = adm9240_write_fan_div(data, i, ++data->fan_div[i]); + if (err < 0) + return err; /* adjust fan_min if active, but not to 0 */ if (data->fan_min[i] < 255 && @@ -205,36 +224,45 @@ static int adm9240_update_measure(struct adm9240_data *data) static int adm9240_update_config(struct adm9240_data *data) { - struct i2c_client *client = data->client; + unsigned int val; int i; + int err; for (i = 0; i < 6; i++) { - data->in_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) { - data->fan_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN_MIN(i)); - } - for (i = 0; i < 2; i++) { - data->temp_max[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(i)); + err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MIN(i), + &data->in_min[i], 1); + if (err < 0) + return err; + err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MAX(i), + &data->in_max[i], 1); + if (err < 0) + return err; } + err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN_MIN(0), + &data->fan_min[0], 2); + if (err < 0) + return err; + err = regmap_bulk_read(data->regmap, ADM9240_REG_TEMP_MAX(0), + &data->temp_max[0], 2); + if (err < 0) + return err; /* read fan divs and 5-bit VID */ - i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 3; - data->fan_div[1] = (i >> 6) & 3; - data->vid = i & 0x0f; - data->vid |= (i2c_smbus_read_byte_data(client, - ADM9240_REG_VID4) & 1) << 4; + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &val); + if (err < 0) + return err; + data->fan_div[0] = (val >> 4) & 3; + data->fan_div[1] = (val >> 6) & 3; + data->vid = val & 0x0f; + err = regmap_read(data->regmap, ADM9240_REG_VID4, &val); + if (err < 0) + return err; + data->vid |= (val & 1) << 4; /* read analog out */ - data->aout = i2c_smbus_read_byte_data(client, - ADM9240_REG_ANALOG_OUT); + err = regmap_raw_read(data->regmap, ADM9240_REG_ANALOG_OUT, + &data->aout, 1); - return 0; + return err; } static struct adm9240_data *adm9240_update_device(struct device *dev) @@ -303,7 +331,6 @@ static ssize_t max_store(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; long val; int err; @@ -313,10 +340,10 @@ static ssize_t max_store(struct device *dev, struct device_attribute *devattr, mutex_lock(&data->update_lock); data->temp_max[attr->index] = TEMP_TO_REG(val); - i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index), - data->temp_max[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(attr->index), + data->temp_max[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static DEVICE_ATTR_RO(temp1_input); @@ -369,7 +396,6 @@ static ssize_t in_min_store(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int err; @@ -379,10 +405,10 @@ static ssize_t in_min_store(struct device *dev, mutex_lock(&data->update_lock); data->in_min[attr->index] = IN_TO_REG(val, attr->index); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index), - data->in_min[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_IN_MIN(attr->index), + data->in_min[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static ssize_t in_max_store(struct device *dev, @@ -391,7 +417,6 @@ static ssize_t in_max_store(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int err; @@ -401,10 +426,10 @@ static ssize_t in_max_store(struct device *dev, mutex_lock(&data->update_lock); data->in_max[attr->index] = IN_TO_REG(val, attr->index); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index), - data->in_max[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_IN_MAX(attr->index), + data->in_max[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); @@ -527,13 +552,13 @@ static ssize_t fan_min_store(struct device *dev, if (new_div != data->fan_div[nr]) { data->fan_div[nr] = new_div; - adm9240_write_fan_div(client, nr, new_div); + adm9240_write_fan_div(data, nr, new_div); } - i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr), - data->fan_min[nr]); + err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); @@ -607,7 +632,6 @@ static ssize_t aout_output_store(struct device *dev, const char *buf, size_t count) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; long val; int err; @@ -617,9 +641,9 @@ static ssize_t aout_output_store(struct device *dev, mutex_lock(&data->update_lock); data->aout = AOUT_TO_REG(val); - i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout); + err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, data->aout); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static DEVICE_ATTR_RW(aout_output); @@ -627,17 +651,19 @@ static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; + int err; if (kstrtoul(buf, 10, &val) || val != 0) return -EINVAL; mutex_lock(&data->update_lock); - i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80); data->valid = 0; /* Force cache refresh */ mutex_unlock(&data->update_lock); - dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + if (err < 0) + return err; + dev_dbg(&data->client->dev, "chassis intrusion latch cleared\n"); return count; } @@ -736,11 +762,18 @@ static int adm9240_detect(struct i2c_client *new_client, return 0; } -static void adm9240_init_client(struct i2c_client *client) +static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *data) { - struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = i2c_smbus_read_byte_data(client, ADM9240_REG_CONFIG); - u8 mode = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF) & 3; + u8 conf, mode; + int err; + + err = regmap_raw_read(data->regmap, ADM9240_REG_CONFIG, &conf, 1); + if (err < 0) + return err; + err = regmap_raw_read(data->regmap, ADM9240_REG_TEMP_CONF, &mode, 1); + if (err < 0) + return err; + mode &= 3; data->vrm = vid_which_vrm(); /* need this to report vid as mV */ @@ -756,43 +789,67 @@ static void adm9240_init_client(struct i2c_client *client) int i; for (i = 0; i < 6; i++) { - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MIN(i), 0); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MAX(i), 255); + err = regmap_write(data->regmap, + ADM9240_REG_IN_MIN(i), 0); + if (err < 0) + return err; + err = regmap_write(data->regmap, + ADM9240_REG_IN_MAX(i), 255); + if (err < 0) + return err; } for (i = 0; i < 2; i++) { - i2c_smbus_write_byte_data(client, + err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(i), 255); + if (err < 0) + return err; } for (i = 0; i < 2; i++) { - i2c_smbus_write_byte_data(client, + err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(i), 127); + if (err < 0) + return err; } /* start measurement cycle */ - i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); + err = regmap_write(data->regmap, ADM9240_REG_CONFIG, 1); + if (err < 0) + return err; dev_info(&client->dev, "cold start: config was 0x%02x mode %u\n", conf, mode); } + + return 0; } +static const struct regmap_config adm9240_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, +}; + static int adm9240_probe(struct i2c_client *new_client) { struct device *dev = &new_client->dev; struct device *hwmon_dev; struct adm9240_data *data; + int err; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); data->client = new_client; mutex_init(&data->update_lock); + data->regmap = devm_regmap_init_i2c(new_client, &adm9240_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); - adm9240_init_client(new_client); + err = adm9240_init_client(new_client, data); + if (err < 0) + return err; hwmon_dev = devm_hwmon_device_register_with_groups(dev, new_client->name, From 6b0c0c83dc55dc2484b1d5cbf32631262ae86284 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Tue, 29 Sep 2020 16:23:19 +0530 Subject: [PATCH 43/64] hwmon: (amd_energy) Move label out of accumulation structure At present, core & socket labels are defined in struct sensor_accumulator This patch moves it to the amd_energy_data structure, which will help in calling memset on struct sensor_accumulator to optimize the code. Signed-off-by: Akshay Gupta Link: https://lore.kernel.org/r/20200929105322.8919-2-nchatrad@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/amd_energy.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c index 29603742c858..9580a16185b8 100644 --- a/drivers/hwmon/amd_energy.c +++ b/drivers/hwmon/amd_energy.c @@ -35,7 +35,6 @@ struct sensor_accumulator { u64 energy_ctr; u64 prev_value; - char label[10]; }; struct amd_energy_data { @@ -52,6 +51,7 @@ struct amd_energy_data { int nr_cpus; int nr_socks; int core_id; + char (*label)[10]; }; static int amd_energy_read_labels(struct device *dev, @@ -61,7 +61,7 @@ static int amd_energy_read_labels(struct device *dev, { struct amd_energy_data *data = dev_get_drvdata(dev); - *str = data->accums[channel].label; + *str = data->label[channel]; return 0; } @@ -253,6 +253,7 @@ static int amd_create_sensor(struct device *dev, struct sensor_accumulator *accums; int i, num_siblings, cpus, sockets; u32 *s_config; + char (*label_l)[10]; /* Identify the number of siblings per core */ num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1; @@ -276,21 +277,25 @@ static int amd_create_sensor(struct device *dev, if (!accums) return -ENOMEM; + label_l = devm_kcalloc(dev, cpus + sockets, + sizeof(*label_l), GFP_KERNEL); + if (!label_l) + return -ENOMEM; + info->type = type; info->config = s_config; data->nr_cpus = cpus; data->nr_socks = sockets; data->accums = accums; + data->label = label_l; for (i = 0; i < cpus + sockets; i++) { s_config[i] = config; if (i < cpus) - scnprintf(accums[i].label, 10, - "Ecore%03u", i); + scnprintf(label_l[i], 10, "Ecore%03u", i); else - scnprintf(accums[i].label, 10, - "Esocket%u", (i - cpus)); + scnprintf(label_l[i], 10, "Esocket%u", (i - cpus)); } return 0; From 514db2b445df79e0a2f040842969cf58088a3886 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Tue, 29 Sep 2020 16:23:20 +0530 Subject: [PATCH 44/64] hwmon: (amd_energy) optimize accumulation interval On a system with course grain resolution of energy unit (milli J) the accumulation thread can be executed less frequently than on the system with fine grain resolution(micro J). This patch sets the accumulation thread interval to an optimum value calculated based on the (energy unit) resolution supported by the hardware (assuming a peak wattage of 240W). Signed-off-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20200929105322.8919-3-nchatrad@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/amd_energy.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c index 9580a16185b8..c413adfc6a73 100644 --- a/drivers/hwmon/amd_energy.c +++ b/drivers/hwmon/amd_energy.c @@ -46,8 +46,9 @@ struct amd_energy_data { struct mutex lock; /* An accumulator for each core and socket */ struct sensor_accumulator *accums; + unsigned int timeout_ms; /* Energy Status Units */ - u64 energy_units; + int energy_units; int nr_cpus; int nr_socks; int core_id; @@ -215,6 +216,7 @@ static umode_t amd_energy_is_visible(const void *_data, static int energy_accumulator(void *p) { struct amd_energy_data *data = (struct amd_energy_data *)p; + unsigned int timeout = data->timeout_ms; while (!kthread_should_stop()) { /* @@ -227,14 +229,7 @@ static int energy_accumulator(void *p) if (kthread_should_stop()) break; - /* - * On a 240W system, with default resolution the - * Socket Energy status register may wrap around in - * 2^32*15.3 e-6/240 = 273.8041 secs (~4.5 mins) - * - * let us accumulate for every 100secs - */ - schedule_timeout(msecs_to_jiffies(100000)); + schedule_timeout(msecs_to_jiffies(timeout)); } return 0; } @@ -331,6 +326,13 @@ static int amd_energy_probe(struct platform_device *pdev) if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); + /* + * On a system with peak wattage of 250W + * timeout = 2 ^ 32 / 2 ^ energy_units / 250 secs + */ + data->timeout_ms = 1000 * + BIT(min(28, 31 - data->energy_units)) / 250; + data->wrap_accumulate = kthread_run(energy_accumulator, data, "%s", dev_name(hwmon_dev)); if (IS_ERR(data->wrap_accumulate)) From b75394c19d0127ee8aab03c5eff7efb253de4199 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Tue, 29 Sep 2020 16:23:21 +0530 Subject: [PATCH 45/64] hwmon: (amd_energy) Improve the accumulation logic Factor out the common code in the accumulation functions for core and socket accumulation. While at it, handle the return value of the amd_create_sensor() function. Signed-off-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20200929105322.8919-4-nchatrad@amd.com Signed-off-by: Guenter Roeck --- drivers/hwmon/amd_energy.c | 129 +++++++++++++------------------------ 1 file changed, 45 insertions(+), 84 deletions(-) diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c index c413adfc6a73..d06597303d5a 100644 --- a/drivers/hwmon/amd_energy.c +++ b/drivers/hwmon/amd_energy.c @@ -74,108 +74,67 @@ static void get_energy_units(struct amd_energy_data *data) data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8; } -static void accumulate_socket_delta(struct amd_energy_data *data, - int sock, int cpu) +static void accumulate_delta(struct amd_energy_data *data, + int channel, int cpu, u32 reg) { - struct sensor_accumulator *s_accum; + struct sensor_accumulator *accum; u64 input; mutex_lock(&data->lock); - rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input); + rdmsrl_safe_on_cpu(cpu, reg, &input); input &= AMD_ENERGY_MASK; - s_accum = &data->accums[data->nr_cpus + sock]; - if (input >= s_accum->prev_value) - s_accum->energy_ctr += - input - s_accum->prev_value; + accum = &data->accums[channel]; + if (input >= accum->prev_value) + accum->energy_ctr += + input - accum->prev_value; else - s_accum->energy_ctr += UINT_MAX - - s_accum->prev_value + input; + accum->energy_ctr += UINT_MAX - + accum->prev_value + input; - s_accum->prev_value = input; - mutex_unlock(&data->lock); -} - -static void accumulate_core_delta(struct amd_energy_data *data) -{ - struct sensor_accumulator *c_accum; - u64 input; - int cpu; - - mutex_lock(&data->lock); - if (data->core_id >= data->nr_cpus) - data->core_id = 0; - - cpu = data->core_id; - - if (!cpu_online(cpu)) - goto out; - - rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input); - input &= AMD_ENERGY_MASK; - - c_accum = &data->accums[cpu]; - - if (input >= c_accum->prev_value) - c_accum->energy_ctr += - input - c_accum->prev_value; - else - c_accum->energy_ctr += UINT_MAX - - c_accum->prev_value + input; - - c_accum->prev_value = input; - -out: - data->core_id++; + accum->prev_value = input; mutex_unlock(&data->lock); } static void read_accumulate(struct amd_energy_data *data) { - int sock; + int sock, scpu, cpu; for (sock = 0; sock < data->nr_socks; sock++) { - int cpu; + scpu = cpumask_first_and(cpu_online_mask, + cpumask_of_node(sock)); - cpu = cpumask_first_and(cpu_online_mask, - cpumask_of_node(sock)); - - accumulate_socket_delta(data, sock, cpu); + accumulate_delta(data, data->nr_cpus + sock, + scpu, ENERGY_PKG_MSR); } - accumulate_core_delta(data); + if (data->core_id >= data->nr_cpus) + data->core_id = 0; + + cpu = data->core_id; + if (cpu_online(cpu)) + accumulate_delta(data, cpu, cpu, ENERGY_CORE_MSR); + + data->core_id++; } static void amd_add_delta(struct amd_energy_data *data, int ch, - int cpu, long *val, bool is_core) + int cpu, long *val, u32 reg) { - struct sensor_accumulator *s_accum, *c_accum; + struct sensor_accumulator *accum; u64 input; mutex_lock(&data->lock); - if (!is_core) { - rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input); - input &= AMD_ENERGY_MASK; + rdmsrl_safe_on_cpu(cpu, reg, &input); + input &= AMD_ENERGY_MASK; - s_accum = &data->accums[ch]; - if (input >= s_accum->prev_value) - input += s_accum->energy_ctr - - s_accum->prev_value; - else - input += UINT_MAX - s_accum->prev_value + - s_accum->energy_ctr; - } else { - rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input); - input &= AMD_ENERGY_MASK; - - c_accum = &data->accums[ch]; - if (input >= c_accum->prev_value) - input += c_accum->energy_ctr - - c_accum->prev_value; - else - input += UINT_MAX - c_accum->prev_value + - c_accum->energy_ctr; - } + accum = &data->accums[ch]; + if (input >= accum->prev_value) + input += accum->energy_ctr - + accum->prev_value; + else + input += UINT_MAX - accum->prev_value + + accum->energy_ctr; /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */ *val = div64_ul(input * 1000000UL, BIT(data->energy_units)); @@ -188,20 +147,22 @@ static int amd_energy_read(struct device *dev, u32 attr, int channel, long *val) { struct amd_energy_data *data = dev_get_drvdata(dev); + u32 reg; int cpu; if (channel >= data->nr_cpus) { cpu = cpumask_first_and(cpu_online_mask, cpumask_of_node (channel - data->nr_cpus)); - amd_add_delta(data, channel, cpu, val, false); + reg = ENERGY_PKG_MSR; } else { cpu = channel; if (!cpu_online(cpu)) return -ENODEV; - amd_add_delta(data, channel, cpu, val, true); + reg = ENERGY_CORE_MSR; } + amd_add_delta(data, channel, cpu, val, reg); return 0; } @@ -242,7 +203,7 @@ static const struct hwmon_ops amd_energy_ops = { static int amd_create_sensor(struct device *dev, struct amd_energy_data *data, - u8 type, u32 config) + enum hwmon_sensor_types type, u32 config) { struct hwmon_channel_info *info = &data->energy_info; struct sensor_accumulator *accums; @@ -301,6 +262,7 @@ static int amd_energy_probe(struct platform_device *pdev) struct device *hwmon_dev; struct amd_energy_data *data; struct device *dev = &pdev->dev; + int ret; data = devm_kzalloc(dev, sizeof(struct amd_energy_data), GFP_KERNEL); @@ -313,8 +275,10 @@ static int amd_energy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); /* Populate per-core energy reporting */ data->info[0] = &data->energy_info; - amd_create_sensor(dev, data, hwmon_energy, - HWMON_E_INPUT | HWMON_E_LABEL); + ret = amd_create_sensor(dev, data, hwmon_energy, + HWMON_E_INPUT | HWMON_E_LABEL); + if (ret) + return ret; mutex_init(&data->lock); get_energy_units(data); @@ -335,9 +299,6 @@ static int amd_energy_probe(struct platform_device *pdev) data->wrap_accumulate = kthread_run(energy_accumulator, data, "%s", dev_name(hwmon_dev)); - if (IS_ERR(data->wrap_accumulate)) - return PTR_ERR(data->wrap_accumulate); - return PTR_ERR_OR_ZERO(data->wrap_accumulate); } From 045ad73397e68e6afefe7df0af804df5fc783fcb Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Tue, 29 Sep 2020 16:23:22 +0530 Subject: [PATCH 46/64] hwmon: (amd_energy) Update driver documentation Update the documentation with the newly added features * Set the accumulation interval based on resolution Signed-off-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20200929105322.8919-5-nchatrad@amd.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/amd_energy.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/hwmon/amd_energy.rst b/Documentation/hwmon/amd_energy.rst index f8288edff664..86e4ebc5cbc2 100644 --- a/Documentation/hwmon/amd_energy.rst +++ b/Documentation/hwmon/amd_energy.rst @@ -84,6 +84,11 @@ per run to a respective 64-bit counter. The kernel thread starts running during probe, wakes up every 100secs and stops running when driver is removed. +Frequency of the accumulator thread is set during the probe +based on the chosen energy unit resolution. For example +A. fine grain (1.625 micro J) +B. course grain (0.125 milli J) + A socket and core energy read would return the current register value added to the respective energy accumulator. From c073292b166a9a0d4d2df605fcbca1ed887aa307 Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Sat, 26 Sep 2020 10:08:33 +0800 Subject: [PATCH 47/64] hwmon: (tmp513) fix spelling typo in comments Modify the comment typo: "compliment" -> "complement". Signed-off-by: Wang Qing Link: https://lore.kernel.org/r/1601086116-32218-1-git-send-email-wangqing@vivo.com Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp513.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 9187dac06ffd..47bbe47e062f 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -192,7 +192,7 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, /* * The valus is read in voltage in the chip but reported as * current to the user. - * 2's compliment number shifted by one to four depending + * 2's complement number shifted by one to four depending * on the pga gain setting. 1lsb = 10uV */ *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data)); From 2c6fcbb211494f1ff6ef384776944b9e04f4c14c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 26 Sep 2020 23:49:56 +0300 Subject: [PATCH 48/64] hwmon: (pmbus) Add support for MPS Multi-phase mp2975 controller Add support for mp295 device from Monolithic Power Systems, Inc. (MPS) vendor. This is a dual-loop, digital, multi-phase controller. This device: - Supports two power rail. - Provides 8 pulse-width modulations (PWMs), and can be configured up to 8-phase operation for rail 1 and up to 4-phase operation for rail 2. - Supports two pages 0 and 1 for telemetry and also pages 2 and 3 for configuration. - Can configured VOUT readout in direct or VID format and allows setting of different formats on rails 1 and 2. For VID the following protocols are available: VR13 mode with 5-mV DAC; VR13 mode with 10-mV DAC, IMVP9 mode with 5-mV DAC. Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20200926204957.10268-2-vadimp@nvidia.com [groeck: Cleaned up a couple of error returns; fixed up API changes] Signed-off-by: Guenter Roeck --- Documentation/hwmon/mp2975.rst | 116 +++++ drivers/hwmon/pmbus/Kconfig | 9 + drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/mp2975.c | 769 +++++++++++++++++++++++++++++++++ 4 files changed, 895 insertions(+) create mode 100644 Documentation/hwmon/mp2975.rst create mode 100644 drivers/hwmon/pmbus/mp2975.c diff --git a/Documentation/hwmon/mp2975.rst b/Documentation/hwmon/mp2975.rst new file mode 100644 index 000000000000..5b0609c62f48 --- /dev/null +++ b/Documentation/hwmon/mp2975.rst @@ -0,0 +1,116 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp2975 +==================== + +Supported chips: + + * MPS MP12254 + + Prefix: 'mp2975' + +Author: + + Vadim Pasternak + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +vendor dual-loop, digital, multi-phase controller MP2975. + +This device: +- Supports up to two power rail. +- Provides 8 pulse-width modulations (PWMs), and can be configured up + to 8-phase operation for rail 1 and up to 4-phase operation for rail + 2. +- Supports two pages 0 and 1 for telemetry and also pages 2 and 3 for + configuration. +- Can configured VOUT readout in direct or VID format and allows + setting of different formats on rails 1 and 2. For VID the following + protocols are available: VR13 mode with 5-mV DAC; VR13 mode with + 10-mV DAC, IMVP9 mode with 5-mV DAC. + +Device supports: +- SVID interface. +- AVSBus interface. + +Device complaint with: +- PMBus rev 1.3 interface. + +Device supports direct format for reading output current, output voltage, +input and output power and temperature. +Device supports linear format for reading input voltage and input power. +Device supports VID and direct formats for reading output voltage. +The below VID modes are supported: VR12, VR13, IMVP9. + +The driver provides the next attributes for the current: +- for current in: input, maximum alarm; +- for current out input, maximum alarm and highest values; +- for phase current: input and label. +attributes. +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- 'k' is number of configured phases (from 1 to 8); +- indexes 1, 1*n for "iin"; +- indexes n+1, n+2 for "iout"; +- indexes 2*n+1 ... 2*n + k for phases. + +**curr[1-{2n}]_alarm** + +**curr[{n+1}-{n+2}]_highest** + +**curr[1-{2n+k}]_input** + +**curr[1-{2n+k}]_label** + +The driver provides the next attributes for the voltage: +- for voltage in: input, high critical threshold, high critical alarm, all only + from page 0; +- for voltage out: input, low and high critical thresholds, low and high + critical alarms, from pages 0 and 1; +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- indexes 1 for "iin"; +- indexes n+1, n+2 for "vout"; + +**in[1-{2n+1}]_crit** + +**in[1-{2n+1}]_crit_alarm** + +**in[1-{2n+1}]_input** + +**in[1-{2n+1}]_label** + +**in[2-{n+1}]_lcrit** + +**in[2-{n+1}1_lcrit_alarm** + +The driver provides the next attributes for the power: +- for power in alarm and input. +- for power out: highest and input. +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- indexes 1 for "pin"; +- indexes n+1, n+2 for "pout"; + +**power1_alarm** + +**power[2-{n+1}]_highest** + +**power[1-{2n+1}]_input** + +**power[1-{2n+1}]_label** + +The driver provides the next attributes for the temperature (only from page 0): + + +**temp1_crit** + +**temp1_crit_alarm** + +**temp1_input** + +**temp1_max** + +**temp1_max_alarm** diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index db90e0018948..a25faf69fce3 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -211,6 +211,15 @@ config SENSORS_MAX8688 This driver can also be built as a module. If so, the module will be called max8688. +config SENSORS_MP2975 + tristate "MPS MP2975" + help + If you say yes here you get hardware monitoring support for MPS + MP2975 Dual Loop Digital Multi-Phase Controller. + + This driver can also be built as a module. If so, the module will + be called mp2975. + config SENSORS_PXE1610 tristate "Infineon PXE1610" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index da41d22be1c9..4c97ad0bd791 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX31785) += max31785.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o +obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c new file mode 100644 index 000000000000..1c3e2a9453b1 --- /dev/null +++ b/drivers/hwmon/pmbus/mp2975.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers + * + * Copyright (C) 2020 Nvidia Technologies Ltd. + */ + +#include +#include +#include +#include +#include +#include "pmbus.h" + +/* Vendor specific registers. */ +#define MP2975_MFR_APS_HYS_R2 0x0d +#define MP2975_MFR_SLOPE_TRIM3 0x1d +#define MP2975_MFR_VR_MULTI_CONFIG_R1 0x0d +#define MP2975_MFR_VR_MULTI_CONFIG_R2 0x1d +#define MP2975_MFR_APS_DECAY_ADV 0x56 +#define MP2975_MFR_DC_LOOP_CTRL 0x59 +#define MP2975_MFR_OCP_UCP_PHASE_SET 0x65 +#define MP2975_MFR_VR_CONFIG1 0x68 +#define MP2975_MFR_READ_CS1_2 0x82 +#define MP2975_MFR_READ_CS3_4 0x83 +#define MP2975_MFR_READ_CS5_6 0x84 +#define MP2975_MFR_READ_CS7_8 0x85 +#define MP2975_MFR_READ_CS9_10 0x86 +#define MP2975_MFR_READ_CS11_12 0x87 +#define MP2975_MFR_READ_IOUT_PK 0x90 +#define MP2975_MFR_READ_POUT_PK 0x91 +#define MP2975_MFR_READ_VREF_R1 0xa1 +#define MP2975_MFR_READ_VREF_R2 0xa3 +#define MP2975_MFR_OVP_TH_SET 0xe5 +#define MP2975_MFR_UVP_SET 0xe6 + +#define MP2975_VOUT_FORMAT BIT(15) +#define MP2975_VID_STEP_SEL_R1 BIT(4) +#define MP2975_IMVP9_EN_R1 BIT(13) +#define MP2975_VID_STEP_SEL_R2 BIT(3) +#define MP2975_IMVP9_EN_R2 BIT(12) +#define MP2975_PRT_THRES_DIV_OV_EN BIT(14) +#define MP2975_DRMOS_KCS GENMASK(13, 12) +#define MP2975_PROT_DEV_OV_OFF 10 +#define MP2975_PROT_DEV_OV_ON 5 +#define MP2975_SENSE_AMPL BIT(11) +#define MP2975_SENSE_AMPL_UNIT 1 +#define MP2975_SENSE_AMPL_HALF 2 +#define MP2975_VIN_UV_LIMIT_UNIT 8 + +#define MP2975_MAX_PHASE_RAIL1 8 +#define MP2975_MAX_PHASE_RAIL2 4 +#define MP2975_PAGE_NUM 2 + +#define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_PHASE_VIRTUAL) + +struct mp2975_data { + struct pmbus_driver_info info; + int vout_scale; + int vid_step[MP2975_PAGE_NUM]; + int vref[MP2975_PAGE_NUM]; + int vref_off[MP2975_PAGE_NUM]; + int vout_max[MP2975_PAGE_NUM]; + int vout_ov_fixed[MP2975_PAGE_NUM]; + int vout_format[MP2975_PAGE_NUM]; + int curr_sense_gain[MP2975_PAGE_NUM]; +}; + +#define to_mp2975_data(x) container_of(x, struct mp2975_data, info) + +static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg) +{ + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * Enforce VOUT direct format, since device allows to set the + * different formats for the different rails. Conversion from + * VID to direct provided by driver internally, in case it is + * necessary. + */ + return PB_VOUT_MODE_DIRECT; + default: + return -ENODATA; + } +} + +static int +mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg, + u16 mask) +{ + int ret = pmbus_read_word_data(client, page, phase, reg); + + return (ret > 0) ? ret & mask : ret; +} + +static int +mp2975_vid2direct(int vrf, int val) +{ + switch (vrf) { + case vr12: + if (val >= 0x01) + return 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + return 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + return 200 + (val - 1) * 10; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data, + int page, int phase, u8 reg) +{ + int ph_curr, ret; + + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + if (!((phase + 1) % MP2975_PAGE_NUM)) + ret >>= 8; + ret &= 0xff; + + /* + * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) + * where: + * - Kcs is the DrMOS current sense gain of power stage, which is + * obtained from the register MP2975_MFR_VR_CONFIG1, bits 13-12 with + * the following selection of DrMOS (data->curr_sense_gain[page]): + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. + * - Rcs is the internal phase current sense resistor which is constant + * value 1kΩ. + */ + ph_curr = ret * 100 - 9800; + + /* + * Current phase sensing, providing by the device is not accurate + * for the light load. This because sampling of current occurrence of + * bit weight has a big deviation for light load. For handling such + * case phase current is represented as the maximum between the value + * calculated above and total rail current divided by number phases. + */ + ret = pmbus_read_word_data(client, page, phase, PMBUS_READ_IOUT); + if (ret < 0) + return ret; + + return max_t(int, DIV_ROUND_CLOSEST(ret, data->info.phases[page]), + DIV_ROUND_CLOSEST(ph_curr, data->curr_sense_gain[page])); +} + +static int +mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data, + int page, int phase) +{ + int ret; + + if (page) { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } else { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS1_2); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS3_4); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS5_6); + break; + case 6 ... 7: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 8 ... 9: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 10 ... 11: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } + return ret; +} + +static int mp2975_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2975_data *data = to_mp2975_data(info); + int ret; + + switch (reg) { + case PMBUS_OT_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + break; + case PMBUS_VIN_OV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + /* + * Register provides two values for over-voltage protection + * threshold for fixed (ovp2) and tracking (ovp1) modes. The + * minimum of these two values is provided as over-voltage + * fault alarm. + */ + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_OVP_TH_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = min_t(int, data->vout_max[page] + 50 * (ret + 1), + data->vout_ov_fixed[page]); + break; + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_UVP_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 * + (ret + 1) * data->vout_scale, 10); + break; + case PMBUS_READ_VOUT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(11, 0)); + if (ret < 0) + return ret; + + /* + * READ_VOUT can be provided in VID or direct format. The + * format type is specified by bit 15 of the register + * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct + * format, since device allows to set the different formats for + * the different rails and also all VOUT limits registers are + * provided in a direct format. In case format is VID - convert + * to direct. + */ + if (data->vout_format[page] == vid) + ret = mp2975_vid2direct(info->vrm_version[page], ret); + break; + case PMBUS_VIRT_READ_POUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_POUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_VIRT_READ_IOUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_IOUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_READ_IOUT: + ret = mp2975_read_phases(client, data, page, phase); + if (ret < 0) + return ret; + + break; + case PMBUS_UT_WARN_LIMIT: + case PMBUS_UT_FAULT_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_VOUT_OV_WARN_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_IIN_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_LV_FAULT_LIMIT: + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_UC_FAULT_LIMIT: + case PMBUS_POUT_OP_FAULT_LIMIT: + case PMBUS_POUT_OP_WARN_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + return -ENXIO; + default: + return -ENODATA; + } + + return ret; +} + +static int mp2975_identify_multiphase_rail2(struct i2c_client *client) +{ + int ret; + + /* + * Identify multiphase for rail 2 - could be from 0 to 4. + * In case phase number is zero – only page zero is supported + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 2 - could be from 0 to 4. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2); + if (ret < 0) + return ret; + + ret &= GENMASK(2, 0); + return (ret >= 4) ? 4 : ret; +} + +static void mp2975_set_phase_rail1(struct pmbus_driver_info *info) +{ + int i; + + for (i = 0 ; i < info->phases[0]; i++) + info->pfunc[i] = PMBUS_HAVE_IOUT; +} + +static void +mp2975_set_phase_rail2(struct pmbus_driver_info *info, int num_phases) +{ + int i; + + /* Set phases for rail 2 from upper to lower. */ + for (i = 1; i <= num_phases; i++) + info->pfunc[MP2975_MAX_PHASE_RAIL1 - i] = PMBUS_HAVE_IOUT; +} + +static int +mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int num_phases2, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 1 - could be from 1 to 8. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1); + if (ret <= 0) + return ret; + + info->phases[0] = ret & GENMASK(3, 0); + + /* + * The device provides a total of 8 PWM pins, and can be configured + * to different phase count applications for rail 1 and rail 2. + * Rail 1 can be set to 8 phases, while rail 2 can only be set to 4 + * phases at most. When rail 1’s phase count is configured as 0, rail + * 1 operates with 1-phase DCM. When rail 2 phase count is configured + * as 0, rail 2 is disabled. + */ + if (info->phases[0] > MP2975_MAX_PHASE_RAIL1) + return -EINVAL; + + mp2975_set_phase_rail1(info); + num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0], + MP2975_MAX_PHASE_RAIL2); + if (info->phases[1] && info->phases[1] <= num_phases2) + mp2975_set_phase_rail2(info, num_phases2); + + return 0; +} + +static int +mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, u32 reg, int page, + u32 imvp_bit, u32 vr_bit) +{ + int ret; + + /* Identify VID mode and step selection. */ + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + if (ret & imvp_bit) { + info->vrm_version[page] = imvp9; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } else if (ret & vr_bit) { + info->vrm_version[page] = vr12; + data->vid_step[page] = MP2975_PROT_DEV_OV_ON; + } else { + info->vrm_version[page] = vr13; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } + + return 0; +} + +static int +mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 1. */ + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R1, 0, + MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 2, if connected. */ + if (info->phases[1]) + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R2, 1, + MP2975_IMVP9_EN_R2, + MP2975_VID_STEP_SEL_R2); + return ret; +} + +static int +mp2975_current_sense_gain_get(struct i2c_client *client, + struct mp2975_data *data) +{ + int i, ret; + + /* + * Obtain DrMOS current sense gain of power stage from the register + * MP2975_MFR_VR_CONFIG1, bits 13-12. The value is selected as below: + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other + * values are invalid. + */ + for (i = 0 ; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + ret = i2c_smbus_read_word_data(client, + MP2975_MFR_VR_CONFIG1); + if (ret < 0) + return ret; + + switch ((ret & MP2975_DRMOS_KCS) >> 12) { + case 0: + data->curr_sense_gain[i] = 50; + break; + case 1: + data->curr_sense_gain[i] = 85; + break; + case 2: + data->curr_sense_gain[i] = 97; + break; + default: + data->curr_sense_gain[i] = 100; + break; + } + } + + return 0; +} + +static int +mp2975_vref_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); + if (ret < 0) + return ret; + + /* Get voltage reference value for rail 1. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R1); + if (ret < 0) + return ret; + + data->vref[0] = ret * data->vid_step[0]; + + /* Get voltage reference value for rail 2, if connected. */ + if (data->info.pages == MP2975_PAGE_NUM) { + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R2); + if (ret < 0) + return ret; + + data->vref[1] = ret * data->vid_step[1]; + } + return 0; +} + +static int +mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data, + int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_OVP_TH_SET); + if (ret < 0) + return ret; + + switch ((ret & GENMASK(5, 3)) >> 3) { + case 1: + data->vref_off[page] = 140; + break; + case 2: + data->vref_off[page] = 220; + break; + case 4: + data->vref_off[page] = 400; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, int page) +{ + int ret; + + /* Get maximum reference voltage of VID-DAC in VID format. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + data->vout_max[page] = mp2975_vid2direct(info->vrm_version[page], ret & + GENMASK(8, 0)); + return 0; +} + +static int +mp2975_identify_vout_format(struct i2c_client *client, + struct mp2975_data *data, int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL); + if (ret < 0) + return ret; + + if (ret & MP2975_VOUT_FORMAT) + data->vout_format[page] = vid; + else + data->vout_format[page] = direct; + return 0; +} + +static int +mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int thres_dev, sense_ampl, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + /* + * Get divider for over- and under-voltage protection thresholds + * configuration from the Advanced Options of Auto Phase Shedding and + * decay register. + */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_APS_DECAY_ADV); + if (ret < 0) + return ret; + thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON : + MP2975_PROT_DEV_OV_OFF; + + /* Select the gain of remote sense amplifier. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP); + if (ret < 0) + return ret; + sense_ampl = ret & MP2975_SENSE_AMPL ? MP2975_SENSE_AMPL_HALF : + MP2975_SENSE_AMPL_UNIT; + + data->vout_scale = sense_ampl * thres_dev; + + return 0; +} + +static int +mp2975_vout_per_rail_config_get(struct i2c_client *client, + struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int i, ret; + + for (i = 0; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + + /* Obtain voltage reference offsets. */ + ret = mp2975_vref_offset_get(client, data, i); + if (ret < 0) + return ret; + + /* Obtain maximum voltage values. */ + ret = mp2975_vout_max_get(client, data, info, i); + if (ret < 0) + return ret; + + /* + * Get VOUT format for READ_VOUT command : VID or direct. + * Pages on same device can be configured with different + * formats. + */ + ret = mp2975_identify_vout_format(client, data, i); + if (ret < 0) + return ret; + + /* + * Set over-voltage fixed value. Thresholds are provided as + * fixed value, and tracking value. The minimum of them are + * exposed as over-voltage critical threshold. + */ + data->vout_ov_fixed[i] = data->vref[i] + + DIV_ROUND_CLOSEST(data->vref_off[i] * + data->vout_scale, + 10); + } + + return 0; +} + +static struct pmbus_driver_info mp2975_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_TEMPERATURE] = 1, + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL, + .read_byte_data = mp2975_read_byte_data, + .read_word_data = mp2975_read_word_data, +}; + +static int mp2975_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct mp2975_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2975_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2975_info, sizeof(*info)); + info = &data->info; + + /* Identify multiphase configuration for rail 2. */ + ret = mp2975_identify_multiphase_rail2(client); + if (ret < 0) + return ret; + + if (ret) { + /* Two rails are connected. */ + data->info.pages = MP2975_PAGE_NUM; + data->info.phases[1] = ret; + data->info.func[1] = MP2975_RAIL2_FUNC; + } + + /* Identify multiphase configuration. */ + ret = mp2975_identify_multiphase(client, data, info); + if (ret) + return ret; + + /* Identify VID setting per rail. */ + ret = mp2975_identify_rails_vid(client, data, info); + if (ret < 0) + return ret; + + /* Obtain current sense gain of power stage. */ + ret = mp2975_current_sense_gain_get(client, data); + if (ret) + return ret; + + /* Obtain voltage reference values. */ + ret = mp2975_vref_get(client, data, info); + if (ret) + return ret; + + /* Obtain vout over-voltage scales. */ + ret = mp2975_vout_ov_scale_get(client, data, info); + if (ret < 0) + return ret; + + /* Obtain offsets, maximum and format for vout. */ + ret = mp2975_vout_per_rail_config_get(client, data, info); + if (ret) + return ret; + + return pmbus_do_probe(client, info); +} + +static const struct i2c_device_id mp2975_id[] = { + {"mp2975", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mp2975_id); + +static const struct of_device_id __maybe_unused mp2975_of_match[] = { + {.compatible = "mps,mp2975"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2975_of_match); + +static struct i2c_driver mp2975_driver = { + .driver = { + .name = "mp2975", + .of_match_table = of_match_ptr(mp2975_of_match), + }, + .probe_new = mp2975_probe, + .remove = pmbus_do_remove, + .id_table = mp2975_id, +}; + +module_i2c_driver(mp2975_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); +MODULE_LICENSE("GPL"); From 5f977a0630db300e3517e4383db3d74f0c39d6cf Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 26 Sep 2020 23:49:57 +0300 Subject: [PATCH 49/64] dt-bindings: Add MP2975 voltage regulator device Monolithic Power Systems, Inc. (MPS) dual-loop, digital, multi-phase controller. Signed-off-by: Vadim Pasternak Acked-by: Rob Herring Link: https://lore.kernel.org/r/20200926204957.10268-3-vadimp@nvidia.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 4ace8039840a..b2e994bc00af 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -80,6 +80,8 @@ properties: - fsl,mpl3115 # MPR121: Proximity Capacitive Touch Sensor Controller - fsl,mpr121 + # Monolithic Power Systems Inc. multi-phase controller mp2975 + - mps,mp2975 # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface - gmt,g751 # Infineon IR38064 Voltage Regulator From 865e4fc013ba58cc3245fc1180033ee52e9c426e Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Mon, 21 Sep 2020 14:17:51 +0800 Subject: [PATCH 50/64] hwmon: Add hwmon driver for Intel MAX 10 BMC This patch adds hwmon functionality for Intel MAX 10 BMC chip. This BMC chip connects to a set of sensor chips to monitor current, voltage, thermal and power of different components on board. The BMC firmware is responsible for sensor data sampling and recording in shared registers. Host driver reads the sensor data from these shared registers and exposes them to users as hwmon interfaces. Signed-off-by: Xu Yilun Signed-off-by: Wu Hao Signed-off-by: Matthew Gerlach Signed-off-by: Tom Rix Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1600669071-26235-3-git-send-email-yilun.xu@intel.com [groeck: Adjusted subject] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/intel-m10-bmc-hwmon.rst | 78 +++++ drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/intel-m10-bmc-hwmon.c | 334 ++++++++++++++++++++ 5 files changed, 425 insertions(+) create mode 100644 Documentation/hwmon/intel-m10-bmc-hwmon.rst create mode 100644 drivers/hwmon/intel-m10-bmc-hwmon.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index af064a9ad42f..0a3383f6a2d4 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -74,6 +74,7 @@ Hardware Monitoring Kernel Drivers ina209 ina2xx ina3221 + intel-m10-bmc-hwmon ir35221 ir38064 isl68137 diff --git a/Documentation/hwmon/intel-m10-bmc-hwmon.rst b/Documentation/hwmon/intel-m10-bmc-hwmon.rst new file mode 100644 index 000000000000..3d148c6e3256 --- /dev/null +++ b/Documentation/hwmon/intel-m10-bmc-hwmon.rst @@ -0,0 +1,78 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver intel-m10-bmc-hwmon +================================= + +Supported chips: + + * Intel MAX 10 BMC for Intel PAC N3000 + + Prefix: 'n3000bmc-hwmon' + +Author: Xu Yilun + + +Description +----------- + +This driver adds the temperature, voltage, current and power reading +support for the Intel MAX 10 Board Management Controller (BMC) chip. +The BMC chip is integrated in some Intel Programmable Acceleration +Cards (PAC). It connects to a set of sensor chips to monitor the +sensor data of different components on the board. The BMC firmware is +responsible for sensor data sampling and recording in shared +registers. The host driver reads the sensor data from these shared +registers and exposes them to users as hwmon interfaces. + +The BMC chip is implemented using the Intel MAX 10 CPLD. It could be +reprogramed to some variants in order to support different Intel +PACs. The driver is designed to be able to distinguish between the +variants, but now it only supports the BMC for Intel PAC N3000. + + +Sysfs attributes +---------------- + +The following attributes are supported: + +- Intel MAX 10 BMC for Intel PAC N3000: + +======================= ======================================================= +tempX_input Temperature of the component (specified by tempX_label) +tempX_max Temperature maximum setpoint of the component +tempX_crit Temperature critical setpoint of the component +tempX_max_hyst Hysteresis for temperature maximum of the component +tempX_crit_hyst Hysteresis for temperature critical of the component +temp1_label "Board Temperature" +temp2_label "FPGA Die Temperature" +temp3_label "QSFP0 Temperature" +temp4_label "QSFP1 Temperature" +temp5_label "Retimer A Temperature" +temp6_label "Retimer A SerDes Temperature" +temp7_label "Retimer B Temperature" +temp8_label "Retimer B SerDes Temperature" + +inX_input Measured voltage of the component (specified by + inX_label) +in0_label "QSFP0 Supply Voltage" +in1_label "QSFP1 Supply Voltage" +in2_label "FPGA Core Voltage" +in3_label "12V Backplane Voltage" +in4_label "1.2V Voltage" +in5_label "12V AUX Voltage" +in6_label "1.8V Voltage" +in7_label "3.3V Voltage" + +currX_input Measured current of the component (specified by + currX_label) +curr1_label "FPGA Core Current" +curr2_label "12V Backplane Current" +curr3_label "12V AUX Current" + +powerX_input Measured power of the component (specified by + powerX_label) +power1_label "Board Power" + +======================= ======================================================= + +All the attributes are read-only. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 8dc28b26916e..53af15c439dd 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2064,6 +2064,17 @@ config SENSORS_XGENE If you say yes here you get support for the temperature and power sensors for APM X-Gene SoC. +config SENSORS_INTEL_M10_BMC_HWMON + tristate "Intel MAX10 BMC Hardware Monitoring" + depends on MFD_INTEL_M10_BMC + help + This driver provides support for the hardware monitoring functionality + on Intel MAX10 BMC chip. + + This BMC Chip is used on Intel FPGA PCIe Acceleration Cards (PAC). Its + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + if ACPI comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index a8f4b35b136b..ba5a25a560e7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o +obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c new file mode 100644 index 000000000000..17d5e6b91c8a --- /dev/null +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel MAX 10 BMC HWMON Driver + * + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + */ +#include +#include +#include +#include +#include +#include + +struct m10bmc_sdata { + unsigned int reg_input; + unsigned int reg_max; + unsigned int reg_crit; + unsigned int reg_hyst; + unsigned int reg_min; + unsigned int multiplier; + const char *label; +}; + +struct m10bmc_hwmon_board_data { + const struct m10bmc_sdata *tables[hwmon_max]; + const struct hwmon_channel_info **hinfo; +}; + +struct m10bmc_hwmon { + struct device *dev; + struct hwmon_chip_info chip; + char *hw_name; + struct intel_m10bmc *m10bmc; + const struct m10bmc_hwmon_board_data *bdata; +}; + +static const struct m10bmc_sdata n3000bmc_temp_tbl[] = { + { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Temperature" }, + { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Die Temperature" }, + { 0x11c, 0x124, 0x120, 0x0, 0x0, 500, "QSFP0 Temperature" }, + { 0x12c, 0x134, 0x130, 0x0, 0x0, 500, "QSFP1 Temperature" }, + { 0x168, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A Temperature" }, + { 0x16c, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A SerDes Temperature" }, + { 0x170, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B Temperature" }, + { 0x174, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B SerDes Temperature" }, +}; + +static const struct m10bmc_sdata n3000bmc_in_tbl[] = { + { 0x128, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" }, + { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" }, + { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" }, + { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Voltage" }, + { 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "1.2V Voltage" }, + { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" }, + { 0x158, 0x0, 0x0, 0x0, 0x0, 1, "1.8V Voltage" }, + { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "3.3V Voltage" }, +}; + +static const struct m10bmc_sdata n3000bmc_curr_tbl[] = { + { 0x140, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" }, + { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Current" }, + { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" }, +}; + +static const struct m10bmc_sdata n3000bmc_power_tbl[] = { + { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, +}; + +static const struct hwmon_channel_info *n3000bmc_hinfo[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL), + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_LABEL), + NULL +}; + +static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = { + .tables = { + [hwmon_temp] = n3000bmc_temp_tbl, + [hwmon_in] = n3000bmc_in_tbl, + [hwmon_curr] = n3000bmc_curr_tbl, + [hwmon_power] = n3000bmc_power_tbl, + }, + + .hinfo = n3000bmc_hinfo, +}; + +static umode_t +m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static const struct m10bmc_sdata * +find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type, + int channel) +{ + const struct m10bmc_sdata *tbl; + + tbl = hw->bdata->tables[type]; + if (!tbl) + return ERR_PTR(-EOPNOTSUPP); + + return &tbl[channel]; +} + +static int do_sensor_read(struct m10bmc_hwmon *hw, + const struct m10bmc_sdata *data, + unsigned int regoff, long *val) +{ + unsigned int regval; + int ret; + + ret = m10bmc_sys_read(hw->m10bmc, regoff, ®val); + if (ret) + return ret; + + /* + * BMC Firmware will return 0xdeadbeef if the sensor value is invalid + * at that time. This usually happens on sensor channels which connect + * to external pluggable modules, e.g. QSFP temperature and voltage. + * When the QSFP is unplugged from cage, driver will get 0xdeadbeef + * from their registers. + */ + if (regval == 0xdeadbeef) + return -ENODATA; + + *val = regval * data->multiplier; + + return 0; +} + +static int m10bmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct m10bmc_hwmon *hw = dev_get_drvdata(dev); + unsigned int reg = 0, reg_hyst = 0; + const struct m10bmc_sdata *data; + long hyst, value; + int ret; + + data = find_sensor_data(hw, type, channel); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + reg = data->reg_input; + break; + case hwmon_temp_max_hyst: + reg_hyst = data->reg_hyst; + fallthrough; + case hwmon_temp_max: + reg = data->reg_max; + break; + case hwmon_temp_crit_hyst: + reg_hyst = data->reg_hyst; + fallthrough; + case hwmon_temp_crit: + reg = data->reg_crit; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + reg = data->reg_input; + break; + case hwmon_in_max: + reg = data->reg_max; + break; + case hwmon_in_crit: + reg = data->reg_crit; + break; + case hwmon_in_min: + reg = data->reg_min; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + reg = data->reg_input; + break; + case hwmon_curr_max: + reg = data->reg_max; + break; + case hwmon_curr_crit: + reg = data->reg_crit; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_power: + switch (attr) { + case hwmon_power_input: + reg = data->reg_input; + break; + default: + return -EOPNOTSUPP; + } + break; + default: + return -EOPNOTSUPP; + } + + if (!reg) + return -EOPNOTSUPP; + + ret = do_sensor_read(hw, data, reg, &value); + if (ret) + return ret; + + if (reg_hyst) { + ret = do_sensor_read(hw, data, reg_hyst, &hyst); + if (ret) + return ret; + + value -= hyst; + } + + *val = value; + + return 0; +} + +static int m10bmc_hwmon_read_string(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct m10bmc_hwmon *hw = dev_get_drvdata(dev); + const struct m10bmc_sdata *data; + + data = find_sensor_data(hw, type, channel); + if (IS_ERR(data)) + return PTR_ERR(data); + + *str = data->label; + + return 0; +} + +static const struct hwmon_ops m10bmc_hwmon_ops = { + .is_visible = m10bmc_hwmon_is_visible, + .read = m10bmc_hwmon_read, + .read_string = m10bmc_hwmon_read_string, +}; + +static int m10bmc_hwmon_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + struct intel_m10bmc *m10bmc = dev_get_drvdata(pdev->dev.parent); + struct device *hwmon_dev, *dev = &pdev->dev; + struct m10bmc_hwmon *hw; + int i; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + hw->dev = dev; + hw->m10bmc = m10bmc; + hw->bdata = (const struct m10bmc_hwmon_board_data *)id->driver_data; + + hw->chip.info = hw->bdata->hinfo; + hw->chip.ops = &m10bmc_hwmon_ops; + + hw->hw_name = devm_kstrdup(dev, id->name, GFP_KERNEL); + if (!hw->hw_name) + return -ENOMEM; + + for (i = 0; hw->hw_name[i]; i++) + if (hwmon_is_bad_char(hw->hw_name[i])) + hw->hw_name[i] = '_'; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hw->hw_name, + hw, &hw->chip, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { + { + .name = "n3000bmc-hwmon", + .driver_data = (unsigned long)&n3000bmc_hwmon_bdata, + }, + { } +}; + +static struct platform_driver intel_m10bmc_hwmon_driver = { + .probe = m10bmc_hwmon_probe, + .driver = { + .name = "intel-m10-bmc-hwmon", + }, + .id_table = intel_m10bmc_hwmon_ids, +}; +module_platform_driver(intel_m10bmc_hwmon_driver); + +MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor"); +MODULE_LICENSE("GPL"); From 707d151bd1ac4062796b95f9f6c32309ce69888c Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 1 Oct 2020 16:57:38 +0200 Subject: [PATCH 51/64] hwmon: (lm75) Add regulator support Add regulator support for boards where the sensor first need to be powered up before it can be used. Signed-off-by: Alban Bedel Link: https://lore.kernel.org/r/20201001145738.17326-4-alban.bedel@aerq.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index e22f977942b4..e447febd121a 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "lm75.h" /* @@ -101,6 +102,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, struct lm75_data { struct i2c_client *client; struct regmap *regmap; + struct regulator *vs; u8 orig_conf; u8 current_conf; u8 resolution; /* In bits, 9 to 16 */ @@ -534,6 +536,13 @@ static const struct regmap_config lm75_regmap_config = { .use_single_write = true, }; +static void lm75_disable_regulator(void *data) +{ + struct lm75_data *lm75 = data; + + regulator_disable(lm75->vs); +} + static void lm75_remove(void *data) { struct lm75_data *lm75 = data; @@ -568,6 +577,10 @@ static int lm75_probe(struct i2c_client *client) data->client = client; data->kind = kind; + data->vs = devm_regulator_get(dev, "vs"); + if (IS_ERR(data->vs)) + return PTR_ERR(data->vs); + data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); @@ -582,6 +595,17 @@ static int lm75_probe(struct i2c_client *client) data->sample_time = data->params->default_sample_time; data->resolution = data->params->default_resolution; + /* Enable the power */ + err = regulator_enable(data->vs); + if (err) { + dev_err(dev, "failed to enable regulator: %d\n", err); + return err; + } + + err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); + if (err) + return err; + /* Cache original configuration */ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { From a6db1561291fc0f2f9aa23bf38f381adc63e7b14 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Sun, 20 Sep 2020 14:09:21 +0300 Subject: [PATCH 52/64] hwmon: (bt1-pvt) Test sensor power supply on probe Baikal-T1 PVT sensor has got a dedicated power supply domain (feed up by the external GPVT/VPVT_18 pins). In case if it isn't powered up, the registers will be accessible, but the sensor conversion just won't happen. Due to that an attempt to read data from any PVT sensor will cause the task hanging up. For instance that will happen if XP11 jumper isn't installed on the Baikal-T1-based BFK3.1 board. Let's at least test whether the conversion work on the device probe procedure. By doing so will make sure that the PVT sensor is powered up at least at boot time. Fixes: 87976ce2825d ("hwmon: Add Baikal-T1 PVT sensor driver") Signed-off-by: Serge Semin Link: https://lore.kernel.org/r/20200920110924.19741-2-Sergey.Semin@baikalelectronics.ru Signed-off-by: Guenter Roeck --- drivers/hwmon/bt1-pvt.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c index 94698cae0497..f4b7353c078a 100644 --- a/drivers/hwmon/bt1-pvt.c +++ b/drivers/hwmon/bt1-pvt.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -982,6 +983,41 @@ static int pvt_request_clks(struct pvt_hwmon *pvt) return 0; } +static int pvt_check_pwr(struct pvt_hwmon *pvt) +{ + unsigned long tout; + int ret = 0; + u32 data; + + /* + * Test out the sensor conversion functionality. If it is not done on + * time then the domain must have been unpowered and we won't be able + * to use the device later in this driver. + * Note If the power source is lost during the normal driver work the + * data read procedure will either return -ETIMEDOUT (for the + * alarm-less driver configuration) or just stop the repeated + * conversion. In the later case alas we won't be able to detect the + * problem. + */ + pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL); + pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); + pvt_set_tout(pvt, 0); + readl(pvt->regs + PVT_DATA); + + tout = PVT_TOUT_MIN / NSEC_PER_USEC; + usleep_range(tout, 2 * tout); + + data = readl(pvt->regs + PVT_DATA); + if (!(data & PVT_DATA_VALID)) { + ret = -ENODEV; + dev_err(pvt->dev, "Sensor is powered down\n"); + } + + pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); + + return ret; +} + static void pvt_init_iface(struct pvt_hwmon *pvt) { u32 trim, temp; @@ -1109,6 +1145,10 @@ static int pvt_probe(struct platform_device *pdev) if (ret) return ret; + ret = pvt_check_pwr(pvt); + if (ret) + return ret; + pvt_init_iface(pvt); ret = pvt_request_irq(pvt); From 0015503e5f6357f286bef34d039e43359fa4efd4 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Sun, 20 Sep 2020 14:09:22 +0300 Subject: [PATCH 53/64] hwmon: (bt1-pvt) Cache current update timeout Instead of converting the update timeout data to the milliseconds each time on the read procedure let's preserve the currently set timeout in the dedicated driver private data cache. The cached value will be then used in the timeout read method and in the alarm-less data conversion to prevent the caller task hanging up in case if the PVT sensor is suddenly powered down. Fixes: 87976ce2825d ("hwmon: Add Baikal-T1 PVT sensor driver") Signed-off-by: Serge Semin Link: https://lore.kernel.org/r/20200920110924.19741-3-Sergey.Semin@baikalelectronics.ru Signed-off-by: Guenter Roeck --- drivers/hwmon/bt1-pvt.c | 85 ++++++++++++++++++++++------------------- drivers/hwmon/bt1-pvt.h | 3 ++ 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c index f4b7353c078a..2600426a3b21 100644 --- a/drivers/hwmon/bt1-pvt.c +++ b/drivers/hwmon/bt1-pvt.c @@ -655,44 +655,16 @@ static int pvt_write_trim(struct pvt_hwmon *pvt, long val) static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val) { - unsigned long rate; - ktime_t kt; - u32 data; + int ret; - rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); - if (!rate) - return -ENODEV; - - /* - * Don't bother with mutex here, since we just read data from MMIO. - * We also have to scale the ticks timeout up to compensate the - * ms-ns-data translations. - */ - data = readl(pvt->regs + PVT_TTIMEOUT) + 1; - - /* - * Calculate ref-clock based delay (Ttotal) between two consecutive - * data samples of the same sensor. So we first must calculate the - * delay introduced by the internal ref-clock timer (Tref * Fclk). - * Then add the constant timeout cuased by each conversion latency - * (Tmin). The basic formulae for each conversion is following: - * Ttotal = Tref * Fclk + Tmin - * Note if alarms are enabled the sensors are polled one after - * another, so in order to have the delay being applicable for each - * sensor the requested value must be equally redistirbuted. - */ -#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) - kt = ktime_set(PVT_SENSORS_NUM * (u64)data, 0); - kt = ktime_divns(kt, rate); - kt = ktime_add_ns(kt, PVT_SENSORS_NUM * PVT_TOUT_MIN); -#else - kt = ktime_set(data, 0); - kt = ktime_divns(kt, rate); - kt = ktime_add_ns(kt, PVT_TOUT_MIN); -#endif + ret = mutex_lock_interruptible(&pvt->iface_mtx); + if (ret) + return ret; /* Return the result in msec as hwmon sysfs interface requires. */ - *val = ktime_to_ms(kt); + *val = ktime_to_ms(pvt->timeout); + + mutex_unlock(&pvt->iface_mtx); return 0; } @@ -700,7 +672,7 @@ static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val) static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) { unsigned long rate; - ktime_t kt; + ktime_t kt, cache; u32 data; int ret; @@ -713,7 +685,7 @@ static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) * between all available sensors to have the requested delay * applicable to each individual sensor. */ - kt = ms_to_ktime(val); + cache = kt = ms_to_ktime(val); #if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) kt = ktime_divns(kt, PVT_SENSORS_NUM); #endif @@ -742,6 +714,7 @@ static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) return ret; pvt_set_tout(pvt, data); + pvt->timeout = cache; mutex_unlock(&pvt->iface_mtx); @@ -1018,10 +991,17 @@ static int pvt_check_pwr(struct pvt_hwmon *pvt) return ret; } -static void pvt_init_iface(struct pvt_hwmon *pvt) +static int pvt_init_iface(struct pvt_hwmon *pvt) { + unsigned long rate; u32 trim, temp; + rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); + if (!rate) { + dev_err(pvt->dev, "Invalid reference clock rate\n"); + return -ENODEV; + } + /* * Make sure all interrupts and controller are disabled so not to * accidentally have ISR executed before the driver data is fully @@ -1036,12 +1016,37 @@ static void pvt_init_iface(struct pvt_hwmon *pvt) pvt_set_mode(pvt, pvt_info[pvt->sensor].mode); pvt_set_tout(pvt, PVT_TOUT_DEF); + /* + * Preserve the current ref-clock based delay (Ttotal) between the + * sensors data samples in the driver data so not to recalculate it + * each time on the data requests and timeout reads. It consists of the + * delay introduced by the internal ref-clock timer (N / Fclk) and the + * constant timeout caused by each conversion latency (Tmin): + * Ttotal = N / Fclk + Tmin + * If alarms are enabled the sensors are polled one after another and + * in order to get the next measurement of a particular sensor the + * caller will have to wait for at most until all the others are + * polled. In that case the formulae will look a bit different: + * Ttotal = 5 * (N / Fclk + Tmin) + */ +#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) + pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0); + pvt->timeout = ktime_divns(pvt->timeout, rate); + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN); +#else + pvt->timeout = ktime_set(PVT_TOUT_DEF, 0); + pvt->timeout = ktime_divns(pvt->timeout, rate); + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN); +#endif + trim = PVT_TRIM_DEF; if (!of_property_read_u32(pvt->dev->of_node, "baikal,pvt-temp-offset-millicelsius", &temp)) trim = pvt_calc_trim(temp); pvt_set_trim(pvt, trim); + + return 0; } static int pvt_request_irq(struct pvt_hwmon *pvt) @@ -1149,7 +1154,9 @@ static int pvt_probe(struct platform_device *pdev) if (ret) return ret; - pvt_init_iface(pvt); + ret = pvt_init_iface(pvt); + if (ret) + return ret; ret = pvt_request_irq(pvt); if (ret) diff --git a/drivers/hwmon/bt1-pvt.h b/drivers/hwmon/bt1-pvt.h index 5eac73e94885..93b8dd5e7c94 100644 --- a/drivers/hwmon/bt1-pvt.h +++ b/drivers/hwmon/bt1-pvt.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,7 @@ struct pvt_cache { * if alarms are disabled). * @sensor: current PVT sensor the data conversion is being performed for. * @cache: data cache descriptor. + * @timeout: conversion timeout cache. */ struct pvt_hwmon { struct device *dev; @@ -214,6 +216,7 @@ struct pvt_hwmon { struct mutex iface_mtx; enum pvt_sensor_type sensor; struct pvt_cache cache[PVT_SENSORS_NUM]; + ktime_t timeout; }; /* From 0ffd21d5985506d164ada9e8fff6daae8ef469a1 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Sun, 20 Sep 2020 14:09:23 +0300 Subject: [PATCH 54/64] hwmon: (bt1-pvt) Wait for the completion with timeout If the PVT sensor is suddenly powered down while a caller is waiting for the conversion completion, the request won't be finished and the task will hang up on this procedure until the power is back up again. Let's call the wait_for_completion_timeout() method instead to prevent that. The cached timeout is exactly what we need to predict for how long conversion could normally last. Fixes: 87976ce2825d ("hwmon: Add Baikal-T1 PVT sensor driver") Signed-off-by: Serge Semin Link: https://lore.kernel.org/r/20200920110924.19741-4-Sergey.Semin@baikalelectronics.ru Signed-off-by: Guenter Roeck --- drivers/hwmon/bt1-pvt.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c index 2600426a3b21..3e1d56585b91 100644 --- a/drivers/hwmon/bt1-pvt.c +++ b/drivers/hwmon/bt1-pvt.c @@ -477,6 +477,7 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, long *val) { struct pvt_cache *cache = &pvt->cache[type]; + unsigned long timeout; u32 data; int ret; @@ -500,7 +501,14 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0); pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); - wait_for_completion(&cache->conversion); + /* + * Wait with timeout since in case if the sensor is suddenly powered + * down the request won't be completed and the caller will hang up on + * this procedure until the power is back up again. Multiply the + * timeout by the factor of two to prevent a false timeout. + */ + timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout)); + ret = wait_for_completion_timeout(&cache->conversion, timeout); pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, @@ -510,6 +518,9 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, mutex_unlock(&pvt->iface_mtx); + if (!ret) + return -ETIMEDOUT; + if (type == PVT_TEMP) *val = pvt_calc_poly(&poly_N_to_temp, data); else From 2b52278150c49559a472f2d6dd66f6f3b405378e Mon Sep 17 00:00:00 2001 From: Steve Foreman Date: Fri, 2 Oct 2020 16:35:38 +0000 Subject: [PATCH 55/64] hwmon: (pmbus/max34440) Fix OC fault limits The max34* family have the IOUT_OC_WARN_LIMIT and IOUT_OC_CRIT_LIMIT registers swapped. Cc: stable@vger.kernel.org Signed-off-by: Steve Foreman [groeck: Updated subject, use C comment style, tab after defines] [groeck: Added missing break; statements (by alexandru.ardelean@analog.com)] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max34440.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 8ea31b59f8e8..f4cb196aaaf3 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -31,6 +31,13 @@ enum chips { max34440, max34441, max34446, max34451, max34460, max34461 }; #define MAX34440_STATUS_OT_FAULT BIT(5) #define MAX34440_STATUS_OT_WARN BIT(6) +/* + * The whole max344* family have IOUT_OC_WARN_LIMIT and IOUT_OC_FAULT_LIMIT + * swapped from the standard pmbus spec addresses. + */ +#define MAX34440_IOUT_OC_WARN_LIMIT 0x46 +#define MAX34440_IOUT_OC_FAULT_LIMIT 0x4A + #define MAX34451_MFR_CHANNEL_CONFIG 0xe4 #define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f @@ -51,6 +58,14 @@ static int max34440_read_word_data(struct i2c_client *client, int page, const struct max34440_data *data = to_max34440_data(info); switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_FAULT_LIMIT); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_WARN_LIMIT); + break; case PMBUS_VIRT_READ_VOUT_MIN: ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_VOUT_MIN); @@ -117,6 +132,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page, int ret; switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_FAULT_LIMIT, + word); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_WARN_LIMIT, + word); + break; case PMBUS_VIRT_RESET_POUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34446_MFR_POUT_PEAK, 0); From 8910c0bd533dc0aa13f2bc53bf8ac5373a79f7a9 Mon Sep 17 00:00:00 2001 From: Ugur Usug Date: Tue, 22 Sep 2020 19:15:38 +0000 Subject: [PATCH 56/64] hwmon: (pmbus/max20730) add device monitoring via debugfs Add debugfs interface support for accessing device specific registers (MFR_VOUT_MIN, MFR_DEVSET1 and MFR_DEVSET2) and others including OPERATION, ON_OFF_CONFIG, SMB_ALERT_MASK, VOUT_MODE, VOUT_COMMAND and VOUT_MAX. Signed-off-by: Ugur Usug Link: https://lore.kernel.org/r/MWHPR11MB1965C01083AD013C630646B2FD3B0@MWHPR11MB1965.namprd11.prod.outlook.com [groeck: Resolved conflics seen due to PMBus driver API changes] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max20730.c | 363 ++++++++++++++++++++++++++++++++- 1 file changed, 362 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index 9475261ddacb..59907bf6e47d 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -26,16 +27,367 @@ enum chips { max20743 }; +enum { + MAX20730_DEBUGFS_VOUT_MIN = 0, + MAX20730_DEBUGFS_FREQUENCY, + MAX20730_DEBUGFS_PG_DELAY, + MAX20730_DEBUGFS_INTERNAL_GAIN, + MAX20730_DEBUGFS_BOOT_VOLTAGE, + MAX20730_DEBUGFS_OUT_V_RAMP_RATE, + MAX20730_DEBUGFS_OC_PROTECT_MODE, + MAX20730_DEBUGFS_SS_TIMING, + MAX20730_DEBUGFS_IMAX, + MAX20730_DEBUGFS_OPERATION, + MAX20730_DEBUGFS_ON_OFF_CONFIG, + MAX20730_DEBUGFS_SMBALERT_MASK, + MAX20730_DEBUGFS_VOUT_MODE, + MAX20730_DEBUGFS_VOUT_COMMAND, + MAX20730_DEBUGFS_VOUT_MAX, + MAX20730_DEBUGFS_NUM_ENTRIES +}; + struct max20730_data { enum chips id; struct pmbus_driver_info info; struct mutex lock; /* Used to protect against parallel writes */ u16 mfr_devset1; + u16 mfr_devset2; + u16 mfr_voutmin; }; #define to_max20730_data(x) container_of(x, struct max20730_data, info) +#define VOLT_FROM_REG(val) DIV_ROUND_CLOSEST((val), 1 << 9) + +#define PMBUS_SMB_ALERT_MASK 0x1B + +#define MAX20730_MFR_VOUT_MIN 0xd1 #define MAX20730_MFR_DEVSET1 0xd2 +#define MAX20730_MFR_DEVSET2 0xd3 + +#define MAX20730_MFR_VOUT_MIN_MASK GENMASK(9, 0) +#define MAX20730_MFR_VOUT_MIN_BIT_POS 0 + +#define MAX20730_MFR_DEVSET1_RGAIN_MASK (BIT(13) | BIT(14)) +#define MAX20730_MFR_DEVSET1_OTP_MASK (BIT(11) | BIT(12)) +#define MAX20730_MFR_DEVSET1_VBOOT_MASK (BIT(8) | BIT(9)) +#define MAX20730_MFR_DEVSET1_OCP_MASK (BIT(5) | BIT(6)) +#define MAX20730_MFR_DEVSET1_FSW_MASK GENMASK(4, 2) +#define MAX20730_MFR_DEVSET1_TSTAT_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET1_RGAIN_BIT_POS 13 +#define MAX20730_MFR_DEVSET1_OTP_BIT_POS 11 +#define MAX20730_MFR_DEVSET1_VBOOT_BIT_POS 8 +#define MAX20730_MFR_DEVSET1_OCP_BIT_POS 5 +#define MAX20730_MFR_DEVSET1_FSW_BIT_POS 2 +#define MAX20730_MFR_DEVSET1_TSTAT_BIT_POS 0 + +#define MAX20730_MFR_DEVSET2_IMAX_MASK GENMASK(10, 8) +#define MAX20730_MFR_DEVSET2_VRATE (BIT(6) | BIT(7)) +#define MAX20730_MFR_DEVSET2_OCPM_MASK BIT(5) +#define MAX20730_MFR_DEVSET2_SS_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET2_IMAX_BIT_POS 8 +#define MAX20730_MFR_DEVSET2_VRATE_BIT_POS 6 +#define MAX20730_MFR_DEVSET2_OCPM_BIT_POS 5 +#define MAX20730_MFR_DEVSET2_SS_BIT_POS 0 + +#define DEBUG_FS_DATA_MAX 16 + +struct max20730_debugfs_data { + struct i2c_client *client; + int debugfs_entries[MAX20730_DEBUGFS_NUM_ENTRIES]; +}; + +#define to_psu(x, y) container_of((x), \ + struct max20730_debugfs_data, debugfs_entries[(y)]) + +#ifdef CONFIG_DEBUG_FS +static ssize_t max20730_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret, len; + int *idxp = file->private_data; + int idx = *idxp; + struct max20730_debugfs_data *psu = to_psu(idxp, idx); + const struct pmbus_driver_info *info; + const struct max20730_data *data; + char tbuf[DEBUG_FS_DATA_MAX] = { 0 }; + u16 val; + + info = pmbus_get_driver_info(psu->client); + data = to_max20730_data(info); + + switch (idx) { + case MAX20730_DEBUGFS_VOUT_MIN: + ret = VOLT_FROM_REG(data->mfr_voutmin * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d.%d\n", + ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_FREQUENCY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_FSW_MASK) + >> MAX20730_MFR_DEVSET1_FSW_BIT_POS; + + if (val == 0) + ret = 400; + else if (val == 1) + ret = 500; + else if (val == 2 || val == 3) + ret = 600; + else if (val == 4) + ret = 700; + else if (val == 5) + ret = 800; + else + ret = 900; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_PG_DELAY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_TSTAT_MASK) + >> MAX20730_MFR_DEVSET1_TSTAT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "2000\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "125\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "62.5\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "32\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_INTERNAL_GAIN: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_RGAIN_MASK) + >> MAX20730_MFR_DEVSET1_RGAIN_BIT_POS; + + if (data->id == max20734) { + /* AN6209 */ + if (val == 0) + len = strlcpy(tbuf, "0.8\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.6\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6.4\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20730 || data->id == max20710) { + /* AN6042 or AN6140 */ + if (val == 0) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "7.2\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20743) { + /* AN6042 */ + if (val == 0) + len = strlcpy(tbuf, "0.45\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + } else { + len = strlcpy(tbuf, "Not supported\n", DEBUG_FS_DATA_MAX); + } + break; + case MAX20730_DEBUGFS_BOOT_VOLTAGE: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_VBOOT_MASK) + >> MAX20730_MFR_DEVSET1_VBOOT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.6484\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "0.8984\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.0\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OUT_V_RAMP_RATE: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_VRATE) + >> MAX20730_MFR_DEVSET2_VRATE_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "4\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OC_PROTECT_MODE: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_OCPM_MASK) + >> MAX20730_MFR_DEVSET2_OCPM_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SS_TIMING: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_SS_MASK) + >> MAX20730_MFR_DEVSET2_SS_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.75\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.5\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "3\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_IMAX: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_IMAX_MASK) + >> MAX20730_MFR_DEVSET2_IMAX_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_OPERATION: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_OPERATION); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_ON_OFF_CONFIG: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SMBALERT_MASK: + ret = i2c_smbus_read_word_data(psu->client, + PMBUS_SMB_ALERT_MASK); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_MODE: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_COMMAND: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_COMMAND); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_VOUT_MAX: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + default: + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + } + + return simple_read_from_buffer(buf, count, ppos, tbuf, len); +} + +static const struct file_operations max20730_fops = { + .llseek = noop_llseek, + .read = max20730_debugfs_read, + .write = NULL, + .open = simple_open, +}; + +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + int ret, i; + struct dentry *debugfs; + struct dentry *max20730_dir; + struct max20730_debugfs_data *psu; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET2); + if (ret < 0) + return ret; + data->mfr_devset2 = ret; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_VOUT_MIN); + if (ret < 0) + return ret; + data->mfr_voutmin = ret; + + psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL); + if (!psu) + return -ENOMEM; + psu->client = client; + + debugfs = pmbus_get_debugfs_dir(client); + if (!debugfs) + return -ENOENT; + + max20730_dir = debugfs_create_dir(client->name, debugfs); + if (!max20730_dir) + return -ENOENT; + + for (i = 0; i < MAX20730_DEBUGFS_NUM_ENTRIES; ++i) + psu->debugfs_entries[i] = i; + + debugfs_create_file("vout_min", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MIN], + &max20730_fops); + debugfs_create_file("frequency", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_FREQUENCY], + &max20730_fops); + debugfs_create_file("power_good_delay", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_PG_DELAY], + &max20730_fops); + debugfs_create_file("internal_gain", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_INTERNAL_GAIN], + &max20730_fops); + debugfs_create_file("boot_voltage", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_BOOT_VOLTAGE], + &max20730_fops); + debugfs_create_file("out_voltage_ramp_rate", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OUT_V_RAMP_RATE], + &max20730_fops); + debugfs_create_file("oc_protection_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OC_PROTECT_MODE], + &max20730_fops); + debugfs_create_file("soft_start_timing", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SS_TIMING], + &max20730_fops); + debugfs_create_file("imax", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_IMAX], + &max20730_fops); + debugfs_create_file("operation", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OPERATION], + &max20730_fops); + debugfs_create_file("on_off_config", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_ON_OFF_CONFIG], + &max20730_fops); + debugfs_create_file("smbalert_mask", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SMBALERT_MASK], + &max20730_fops); + debugfs_create_file("vout_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MODE], + &max20730_fops); + debugfs_create_file("vout_command", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_COMMAND], + &max20730_fops); + debugfs_create_file("vout_max", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MAX], + &max20730_fops); + + return 0; +} +#else +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ static const struct i2c_device_id max20730_id[]; @@ -371,7 +723,16 @@ static int max20730_probe(struct i2c_client *client) return ret; data->mfr_devset1 = ret; - return pmbus_do_probe(client, &data->info); + ret = pmbus_do_probe(client, &data->info); + if (ret < 0) + return ret; + + ret = max20730_init_debugfs(client, data); + if (ret) + dev_warn(dev, "Failed to register debugfs: %d\n", + ret); + + return 0; } static const struct i2c_device_id max20730_id[] = { From 712d1b3749aff7ffb59412d1a4ac23a91575095e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 5 Oct 2020 14:48:43 +0200 Subject: [PATCH 57/64] hwmon: (mlxreg-fan) Fix double "Mellanox" Remove the duplicate "Mellanox" in the help text for the Mellanox FAN driver configuration option. Fixes: 65afb4c8e7e4e7e7 ("hwmon: (mlxreg-fan) Add support for Mellanox FAN driver") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20201005124843.26688-1-geert+renesas@glider.be Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 53af15c439dd..88866c55e7fc 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1080,7 +1080,7 @@ config SENSORS_MCP3021 will be called mcp3021. config SENSORS_MLXREG_FAN - tristate "Mellanox Mellanox FAN driver" + tristate "Mellanox FAN driver" depends on MELLANOX_PLATFORM imply THERMAL select REGMAP From f6a496a5ce8d23eee5ed6ba65d94ca95005f3e91 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 5 Oct 2020 16:12:26 +0300 Subject: [PATCH 58/64] docs: hwmon: (ltc2945) update datasheet link Old one isn't working anymore. Update to the latest datasheet link. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201005131226.1774081-1-alexandru.ardelean@analog.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/ltc2945.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/ltc2945.rst b/Documentation/hwmon/ltc2945.rst index 20c884985367..8d65c141ce2b 100644 --- a/Documentation/hwmon/ltc2945.rst +++ b/Documentation/hwmon/ltc2945.rst @@ -11,7 +11,7 @@ Supported chips: Datasheet: - http://cds.linear.com/docs/en/datasheet/2945fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/2945fb.pdf Author: Guenter Roeck From 3e37c9d48f7a71b682e98e915eff21ab8624af03 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 1 Oct 2020 16:57:36 +0200 Subject: [PATCH 59/64] dt-bindings: hwmon: Convert lm75 bindings to yaml In order to automate the verification of DT nodes convert lm75.txt to lm75.yaml. Signed-off-by: Alban Bedel Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201001145738.17326-2-alban.bedel@aerq.com Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/lm75.txt | 39 ------------ .../devicetree/bindings/hwmon/lm75.yaml | 62 +++++++++++++++++++ 2 files changed, 62 insertions(+), 39 deletions(-) delete mode 100644 Documentation/devicetree/bindings/hwmon/lm75.txt create mode 100644 Documentation/devicetree/bindings/hwmon/lm75.yaml diff --git a/Documentation/devicetree/bindings/hwmon/lm75.txt b/Documentation/devicetree/bindings/hwmon/lm75.txt deleted file mode 100644 index 273616702c51..000000000000 --- a/Documentation/devicetree/bindings/hwmon/lm75.txt +++ /dev/null @@ -1,39 +0,0 @@ -*LM75 hwmon sensor. - -Required properties: -- compatible: manufacturer and chip name, one of - "adi,adt75", - "dallas,ds1775", - "dallas,ds75", - "dallas,ds7505", - "gmt,g751", - "national,lm75", - "national,lm75a", - "national,lm75b", - "maxim,max6625", - "maxim,max6626", - "maxim,max31725", - "maxim,max31726", - "maxim,mcp980x", - "nxp,pct2075", - "st,stds75", - "st,stlm75", - "microchip,tcn75", - "ti,tmp100", - "ti,tmp101", - "ti,tmp105", - "ti,tmp112", - "ti,tmp175", - "ti,tmp275", - "ti,tmp75", - "ti,tmp75b", - "ti,tmp75c", - -- reg: I2C bus address of the device - -Example: - -sensor@48 { - compatible = "st,stlm75"; - reg = <0x48>; -}; diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml new file mode 100644 index 000000000000..c9a001627945 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/lm75.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LM75 hwmon sensor + +maintainers: + - Jean Delvare + - Guenter Roeck + +properties: + compatible: + enum: + - adi,adt75 + - dallas,ds1775 + - dallas,ds75 + - dallas,ds7505 + - gmt,g751 + - national,lm75 + - national,lm75a + - national,lm75b + - maxim,max6625 + - maxim,max6626 + - maxim,max31725 + - maxim,max31726 + - maxim,mcp980x + - nxp,pct2075 + - st,stds75 + - st,stlm75 + - microchip,tcn75 + - ti,tmp100 + - ti,tmp101 + - ti,tmp105 + - ti,tmp112 + - ti,tmp175 + - ti,tmp275 + - ti,tmp75 + - ti,tmp75b + - ti,tmp75c + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@48 { + compatible = "st,stlm75"; + reg = <0x48>; + }; + }; From efc2360b2873abbff0d6b46b6ad610daa8e5d197 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 1 Oct 2020 16:57:37 +0200 Subject: [PATCH 60/64] dt-bindings: hwmon: Add the +vs supply to the lm75 bindings Some boards might have a regulator that control the +VS supply, add it to the bindings. Signed-off-by: Alban Bedel Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201001145738.17326-3-alban.bedel@aerq.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm75.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml index c9a001627945..96eed5cc7841 100644 --- a/Documentation/devicetree/bindings/hwmon/lm75.yaml +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -43,6 +43,9 @@ properties: reg: maxItems: 1 + vs-supply: + description: phandle to the regulator that provides the +VS supply + required: - compatible - reg @@ -58,5 +61,6 @@ examples: sensor@48 { compatible = "st,stlm75"; reg = <0x48>; + vs-supply = <&vs>; }; }; From 748022ef093f73d424115ee40bf205dbbe8fb198 Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Mon, 5 Oct 2020 17:27:45 +0800 Subject: [PATCH 61/64] hwmon: Add DT bindings schema for PVT controller PVT controller (MR75203) is used to configure & control Moortec embedded analog IP which contains temprature sensor(TS), voltage monitor(VM) & process detector(PD) modules. Add DT bindings schema for PVT controller. Signed-off-by: Rahul Tanwar Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/b540b49ca47d75c5f716f8a4e4eed0664a1116bf.1601889876.git.rahul.tanwar@linux.intel.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/moortec,mr75203.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml diff --git a/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml new file mode 100644 index 000000000000..6f3e3c01f717 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/moortec,mr75203.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Moortec Semiconductor MR75203 PVT Controller bindings + +maintainers: + - Rahul Tanwar + +properties: + compatible: + const: moortec,mr75203 + + reg: + items: + - description: PVT common registers + - description: PVT temprature sensor registers + - description: PVT process detector registers + - description: PVT voltage monitor registers + + reg-names: + items: + - const: common + - const: ts + - const: pd + - const: vm + + intel,vm-map: + description: + PVT controller has 5 VM (voltage monitor) sensors. + vm-map defines CPU core to VM instance mapping. A + value of 0xff means that VM sensor is unused. + $ref: /schemas/types.yaml#definitions/uint8-array + maxItems: 5 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + +required: + - compatible + - reg + - reg-names + - intel,vm-map + - clocks + - resets + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + pvt: pvt@e0680000 { + compatible = "moortec,mr75203"; + reg = <0xe0680000 0x80>, + <0xe0680080 0x180>, + <0xe0680200 0x200>, + <0xe0680400 0xc00>; + reg-names = "common", "ts", "pd", "vm"; + intel,vm-map = [03 01 04 ff ff]; + clocks = <&osc0>; + resets = <&rcu0 0x40 7>; + #thermal-sensor-cells = <1>; + }; From 9d823351a337484ad0ed436c626dd4967b5602dd Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Mon, 5 Oct 2020 17:27:46 +0800 Subject: [PATCH 62/64] hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller PVT controller (MR75203) is used to configure & control Moortec embedded analog IP which contains temprature sensor(TS), voltage monitor(VM) & process detector(PD) modules. Add hardware monitoring driver to support MR75203 PVT controller. Signed-off-by: Rahul Tanwar Reviewed-by: Guenter Roeck Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/05b59cd860d2a1aa0a68ab300829efe709645184.1601889876.git.rahul.tanwar@linux.intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/mr75203.c | 656 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 667 insertions(+) create mode 100644 drivers/hwmon/mr75203.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 88866c55e7fc..676ad6ee7f8d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1112,6 +1112,16 @@ config SENSORS_MENF21BMC_HWMON This driver can also be built as a module. If so the module will be called menf21bmc_hwmon. +config SENSORS_MR75203 + tristate "Moortec Semiconductor MR75203 PVT Controller" + select REGMAP_MMIO + help + If you say yes here you get support for Moortec MR75203 + PVT controller. + + This driver can also be built as a module. If so, the module + will be called mr75203. + config SENSORS_ADCXX tristate "National Semiconductor ADCxxxSxxx" depends on SPI_MASTER diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index ba5a25a560e7..8193340a7238 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_TC654) += tc654.o obj-$(CONFIG_SENSORS_MLXREG_FAN) += mlxreg-fan.o obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o +obj-$(CONFIG_SENSORS_MR75203) += mr75203.o obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c new file mode 100644 index 000000000000..18da5a25e89a --- /dev/null +++ b/drivers/hwmon/mr75203.c @@ -0,0 +1,656 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MaxLinear, Inc. + * + * This driver is a hardware monitoring driver for PVT controller + * (MR75203) which is used to configure & control Moortec embedded + * analog IP to enable multiple embedded temperature sensor(TS), + * voltage monitor(VM) & process detector(PD) modules. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PVT Common register */ +#define PVT_IP_CONFIG 0x04 +#define TS_NUM_MSK GENMASK(4, 0) +#define TS_NUM_SFT 0 +#define PD_NUM_MSK GENMASK(12, 8) +#define PD_NUM_SFT 8 +#define VM_NUM_MSK GENMASK(20, 16) +#define VM_NUM_SFT 16 +#define CH_NUM_MSK GENMASK(31, 24) +#define CH_NUM_SFT 24 + +/* Macro Common Register */ +#define CLK_SYNTH 0x00 +#define CLK_SYNTH_LO_SFT 0 +#define CLK_SYNTH_HI_SFT 8 +#define CLK_SYNTH_HOLD_SFT 16 +#define CLK_SYNTH_EN BIT(24) +#define CLK_SYS_CYCLES_MAX 514 +#define CLK_SYS_CYCLES_MIN 2 +#define HZ_PER_MHZ 1000000L + +#define SDIF_DISABLE 0x04 + +#define SDIF_STAT 0x08 +#define SDIF_BUSY BIT(0) +#define SDIF_LOCK BIT(1) + +#define SDIF_W 0x0c +#define SDIF_PROG BIT(31) +#define SDIF_WRN_W BIT(27) +#define SDIF_WRN_R 0x00 +#define SDIF_ADDR_SFT 24 + +#define SDIF_HALT 0x10 +#define SDIF_CTRL 0x14 +#define SDIF_SMPL_CTRL 0x20 + +/* TS & PD Individual Macro Register */ +#define COM_REG_SIZE 0x40 + +#define SDIF_DONE(n) (COM_REG_SIZE + 0x14 + 0x40 * (n)) +#define SDIF_SMPL_DONE BIT(0) + +#define SDIF_DATA(n) (COM_REG_SIZE + 0x18 + 0x40 * (n)) +#define SAMPLE_DATA_MSK GENMASK(15, 0) + +#define HILO_RESET(n) (COM_REG_SIZE + 0x2c + 0x40 * (n)) + +/* VM Individual Macro Register */ +#define VM_COM_REG_SIZE 0x200 +#define VM_SDIF_DONE(n) (VM_COM_REG_SIZE + 0x34 + 0x200 * (n)) +#define VM_SDIF_DATA(n) (VM_COM_REG_SIZE + 0x40 + 0x200 * (n)) + +/* SDA Slave Register */ +#define IP_CTRL 0x00 +#define IP_RST_REL BIT(1) +#define IP_RUN_CONT BIT(3) +#define IP_AUTO BIT(8) +#define IP_VM_MODE BIT(10) + +#define IP_CFG 0x01 +#define CFG0_MODE_2 BIT(0) +#define CFG0_PARALLEL_OUT 0 +#define CFG0_12_BIT 0 +#define CFG1_VOL_MEAS_MODE 0 +#define CFG1_PARALLEL_OUT 0 +#define CFG1_14_BIT 0 + +#define IP_DATA 0x03 + +#define IP_POLL 0x04 +#define VM_CH_INIT BIT(20) +#define VM_CH_REQ BIT(21) + +#define IP_TMR 0x05 +#define POWER_DELAY_CYCLE_256 0x80 +#define POWER_DELAY_CYCLE_64 0x40 + +#define PVT_POLL_DELAY_US 20 +#define PVT_POLL_TIMEOUT_US 20000 +#define PVT_H_CONST 100000 +#define PVT_CAL5_CONST 2047 +#define PVT_G_CONST 40000 +#define PVT_CONV_BITS 10 +#define PVT_N_CONST 90 +#define PVT_R_CONST 245805 + +struct pvt_device { + struct regmap *c_map; + struct regmap *t_map; + struct regmap *p_map; + struct regmap *v_map; + struct clk *clk; + struct reset_control *rst; + u32 t_num; + u32 p_num; + u32 v_num; + u32 ip_freq; + u8 *vm_idx; +}; + +static umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + if (attr == hwmon_temp_input) + return 0444; + break; + case hwmon_in: + if (attr == hwmon_in_input) + return 0444; + break; + default: + break; + } + return 0; +} + +static int pvt_read_temp(struct device *dev, u32 attr, int channel, long *val) +{ + struct pvt_device *pvt = dev_get_drvdata(dev); + struct regmap *t_map = pvt->t_map; + u32 stat, nbs; + int ret; + u64 tmp; + + switch (attr) { + case hwmon_temp_input: + ret = regmap_read_poll_timeout(t_map, SDIF_DONE(channel), + stat, stat & SDIF_SMPL_DONE, + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + ret = regmap_read(t_map, SDIF_DATA(channel), &nbs); + if(ret < 0) + return ret; + + nbs &= SAMPLE_DATA_MSK; + + /* + * Convert the register value to + * degrees centigrade temperature + */ + tmp = nbs * PVT_H_CONST; + do_div(tmp, PVT_CAL5_CONST); + *val = tmp - PVT_G_CONST - pvt->ip_freq; + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct pvt_device *pvt = dev_get_drvdata(dev); + struct regmap *v_map = pvt->v_map; + u32 n, stat; + u8 vm_idx; + int ret; + + if (channel >= pvt->v_num) + return -EINVAL; + + vm_idx = pvt->vm_idx[channel]; + + switch (attr) { + case hwmon_in_input: + ret = regmap_read_poll_timeout(v_map, VM_SDIF_DONE(vm_idx), + stat, stat & SDIF_SMPL_DONE, + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx), &n); + if(ret < 0) + return ret; + + n &= SAMPLE_DATA_MSK; + /* Convert the N bitstream count into voltage */ + *val = (PVT_N_CONST * n - PVT_R_CONST) >> PVT_CONV_BITS; + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int pvt_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_temp: + return pvt_read_temp(dev, attr, channel, val); + case hwmon_in: + return pvt_read_in(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static const u32 pvt_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0 +}; + +static const struct hwmon_channel_info pvt_chip = { + .type = hwmon_chip, + .config = pvt_chip_config, +}; + +static struct hwmon_channel_info pvt_temp = { + .type = hwmon_temp, +}; + +static struct hwmon_channel_info pvt_in = { + .type = hwmon_in, +}; + +static const struct hwmon_ops pvt_hwmon_ops = { + .is_visible = pvt_is_visible, + .read = pvt_read, +}; + +static struct hwmon_chip_info pvt_chip_info = { + .ops = &pvt_hwmon_ops, +}; + +static int pvt_init(struct pvt_device *pvt) +{ + u16 sys_freq, key, middle, low = 4, high = 8; + struct regmap *t_map = pvt->t_map; + struct regmap *p_map = pvt->p_map; + struct regmap *v_map = pvt->v_map; + u32 t_num = pvt->t_num; + u32 p_num = pvt->p_num; + u32 v_num = pvt->v_num; + u32 clk_synth, val; + int ret; + + sys_freq = clk_get_rate(pvt->clk) / HZ_PER_MHZ; + while (high >= low) { + middle = (low + high + 1) / 2; + key = DIV_ROUND_CLOSEST(sys_freq, middle); + if (key > CLK_SYS_CYCLES_MAX) { + low = middle + 1; + continue; + } else if (key < CLK_SYS_CYCLES_MIN) { + high = middle - 1; + continue; + } else { + break; + } + } + + /* + * The system supports 'clk_sys' to 'clk_ip' frequency ratios + * from 2:1 to 512:1 + */ + key = clamp_val(key, CLK_SYS_CYCLES_MIN, CLK_SYS_CYCLES_MAX) - 2; + + clk_synth = ((key + 1) >> 1) << CLK_SYNTH_LO_SFT | + (key >> 1) << CLK_SYNTH_HI_SFT | + (key >> 1) << CLK_SYNTH_HOLD_SFT | CLK_SYNTH_EN; + + pvt->ip_freq = sys_freq * 100 / (key + 2); + + if (t_num) { + ret = regmap_write(t_map, SDIF_SMPL_CTRL, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, SDIF_DISABLE, 0x0); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = CFG0_MODE_2 | CFG0_PARALLEL_OUT | CFG0_12_BIT | + IP_CFG << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(t_map, SDIF_W, val); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = POWER_DELAY_CYCLE_256 | IP_TMR << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(t_map, SDIF_W, val); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | + IP_CTRL << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(t_map, SDIF_W, val); + if(ret < 0) + return ret; + } + + if (p_num) { + ret = regmap_write(p_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(p_map, SDIF_DISABLE, BIT(p_num) - 1); + if(ret < 0) + return ret; + + ret = regmap_write(p_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + } + + if (v_num) { + ret = regmap_write(v_map, SDIF_SMPL_CTRL, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, SDIF_DISABLE, 0x0); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = CFG1_VOL_MEAS_MODE | CFG1_PARALLEL_OUT | + CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = POWER_DELAY_CYCLE_64 | IP_TMR << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | IP_VM_MODE | + IP_CTRL << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if(ret < 0) + return ret; + } + + return 0; +} + +static struct regmap_config pvt_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static int pvt_get_regmap(struct platform_device *pdev, char *reg_name, + struct pvt_device *pvt) +{ + struct device *dev = &pdev->dev; + struct regmap **reg_map; + void __iomem *io_base; + + if (!strcmp(reg_name, "common")) + reg_map = &pvt->c_map; + else if (!strcmp(reg_name, "ts")) + reg_map = &pvt->t_map; + else if (!strcmp(reg_name, "pd")) + reg_map = &pvt->p_map; + else if (!strcmp(reg_name, "vm")) + reg_map = &pvt->v_map; + else + return -EINVAL; + + io_base = devm_platform_ioremap_resource_byname(pdev, reg_name); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + pvt_regmap_config.name = reg_name; + *reg_map = devm_regmap_init_mmio(dev, io_base, &pvt_regmap_config); + if (IS_ERR(*reg_map)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(*reg_map); + } + + return 0; +} + +static void pvt_clk_disable(void *data) +{ + struct pvt_device *pvt = data; + + clk_disable_unprepare(pvt->clk); +} + +static int pvt_clk_enable(struct device *dev, struct pvt_device *pvt) +{ + int ret; + + ret = clk_prepare_enable(pvt->clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, pvt_clk_disable, pvt); +} + +static void pvt_reset_control_assert(void *data) +{ + struct pvt_device *pvt = data; + + reset_control_assert(pvt->rst); +} + +static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt) +{ + int ret; + + ret = reset_control_deassert(pvt->rst); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, pvt_reset_control_assert, pvt); +} + +static int mr75203_probe(struct platform_device *pdev) +{ + const struct hwmon_channel_info **pvt_info; + u32 ts_num, vm_num, pd_num, val, index, i; + struct device *dev = &pdev->dev; + u32 *temp_config, *in_config; + struct device *hwmon_dev; + struct pvt_device *pvt; + int ret; + + pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL); + if (!pvt) + return -ENOMEM; + + ret = pvt_get_regmap(pdev, "common", pvt); + if (ret) + return ret; + + pvt->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pvt->clk)) + return dev_err_probe(dev, PTR_ERR(pvt->clk), "failed to get clock\n"); + + ret = pvt_clk_enable(dev, pvt); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + pvt->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(pvt->rst)) + return dev_err_probe(dev, PTR_ERR(pvt->rst), + "failed to get reset control\n"); + + ret = pvt_reset_control_deassert(dev, pvt); + if (ret) + return dev_err_probe(dev, ret, "cannot deassert reset control\n"); + + ret = regmap_read(pvt->c_map, PVT_IP_CONFIG, &val); + if(ret < 0) + return ret; + + ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT; + pd_num = (val & PD_NUM_MSK) >> PD_NUM_SFT; + vm_num = (val & VM_NUM_MSK) >> VM_NUM_SFT; + pvt->t_num = ts_num; + pvt->p_num = pd_num; + pvt->v_num = vm_num; + val = 0; + if (ts_num) + val++; + if (vm_num) + val++; + if (!val) + return -ENODEV; + + pvt_info = devm_kcalloc(dev, val + 2, sizeof(*pvt_info), GFP_KERNEL); + if (!pvt_info) + return -ENOMEM; + pvt_info[0] = &pvt_chip; + index = 1; + + if (ts_num) { + ret = pvt_get_regmap(pdev, "ts", pvt); + if (ret) + return ret; + + temp_config = devm_kcalloc(dev, ts_num + 1, + sizeof(*temp_config), GFP_KERNEL); + if (!temp_config) + return -ENOMEM; + + memset32(temp_config, HWMON_T_INPUT, ts_num); + pvt_temp.config = temp_config; + pvt_info[index++] = &pvt_temp; + } + + if (pd_num) { + ret = pvt_get_regmap(pdev, "pd", pvt); + if (ret) + return ret; + } + + if (vm_num) { + u32 num = vm_num; + + ret = pvt_get_regmap(pdev, "vm", pvt); + if (ret) + return ret; + + pvt->vm_idx = devm_kcalloc(dev, vm_num, sizeof(*pvt->vm_idx), + GFP_KERNEL); + if (!pvt->vm_idx) + return -ENOMEM; + + ret = device_property_read_u8_array(dev, "intel,vm-map", + pvt->vm_idx, vm_num); + if (ret) { + num = 0; + } else { + for (i = 0; i < vm_num; i++) + if (pvt->vm_idx[i] >= vm_num || + pvt->vm_idx[i] == 0xff) { + num = i; + break; + } + } + + /* + * Incase intel,vm-map property is not defined, we assume + * incremental channel numbers. + */ + for (i = num; i < vm_num; i++) + pvt->vm_idx[i] = i; + + in_config = devm_kcalloc(dev, num + 1, + sizeof(*in_config), GFP_KERNEL); + if (!in_config) + return -ENOMEM; + + memset32(in_config, HWMON_I_INPUT, num); + in_config[num] = 0; + pvt_in.config = in_config; + + pvt_info[index++] = &pvt_in; + } + + ret = pvt_init(pvt); + if (ret) { + dev_err(dev, "failed to init pvt: %d\n", ret); + return ret; + } + + pvt_chip_info.info = pvt_info; + hwmon_dev = devm_hwmon_device_register_with_info(dev, "pvt", + pvt, + &pvt_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id moortec_pvt_of_match[] = { + { .compatible = "moortec,mr75203" }, + { } +}; +MODULE_DEVICE_TABLE(of, moortec_pvt_of_match); + +static struct platform_driver moortec_pvt_driver = { + .driver = { + .name = "moortec-pvt", + .of_match_table = moortec_pvt_of_match, + }, + .probe = mr75203_probe, +}; +module_platform_driver(moortec_pvt_driver); + +MODULE_LICENSE("GPL v2"); From b9a9a375438e24ac36a82c56259aeccfc7b88346 Mon Sep 17 00:00:00 2001 From: Chu Lin Date: Sun, 4 Oct 2020 03:14:44 +0000 Subject: [PATCH 63/64] dt-bindings: hwmon: max20730: adding device tree doc for max20730 max20730 Integrated, Step-Down Switching Regulator with PMBus Signed-off-by: Chu Lin Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201004031445.2321090-2-linchuyuan@google.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/maxim,max20730.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml new file mode 100644 index 000000000000..93e86e3b4602 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/maxim,max20730.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim max20730 + +maintainers: + - Jean Delvare + - Guenter Roeck + +description: | + The MAX20730 is a fully integrated, highly efficient switching regulator + with PMBus for applications operating from 4.5V to 16V and requiring + up to 25A (max) load. This single-chip regulator provides extremely + compact, high efficiency power-delivery solutions with high-precision + output voltages and excellent transient response. + + Datasheets: + https://datasheets.maximintegrated.com/en/ds/MAX20730.pdf + https://datasheets.maximintegrated.com/en/ds/MAX20734.pdf + https://datasheets.maximintegrated.com/en/ds/MAX20743.pdf + +properties: + compatible: + enum: + - maxim,max20730 + - maxim,max20734 + - maxim,max20743 + + reg: + maxItems: 1 + + vout-voltage-divider: + description: | + If voltage divider present at vout, the voltage at voltage sensor pin + will be scaled. The properties will convert the raw reading to a more + meaningful number if voltage divider present. It has two numbers, + the first number is the output resistor, the second number is the total + resistance. Therefore, the adjusted vout is equal to + Vout = Vout * output_resistance / total resistance. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + max20730@10 { + compatible = "maxim,max20730"; + reg = <0x10>; + vout-voltage-divider = <1000 2000>; // vout would be scaled to 0.5 + }; + }; From 9b20aec24b8ab2860ea41182ba554dfcc444c0c8 Mon Sep 17 00:00:00 2001 From: Chu Lin Date: Sun, 4 Oct 2020 03:14:45 +0000 Subject: [PATCH 64/64] hwmon: (pmbus/max20730) adjust the vout reading given voltage divider Problem: We use voltage dividers so that the voltage presented at the voltage sense pins is confusing. We might need to convert these readings to more meaningful readings given the voltage divider. Solution: Read the voltage divider resistance from dts and convert the voltage reading to a more meaningful reading. Testing: max20730 with voltage divider Signed-off-by: Chu Lin Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20201004031445.2321090-3-linchuyuan@google.com [groeck: Return -EINVAL instead of -ENODEV on bad deevicetree data] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max20730.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index 59907bf6e47d..57923d72490c 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -53,6 +53,7 @@ struct max20730_data { u16 mfr_devset1; u16 mfr_devset2; u16 mfr_voutmin; + u32 vout_voltage_divider[2]; }; #define to_max20730_data(x) container_of(x, struct max20730_data, info) @@ -468,6 +469,14 @@ static int max20730_read_word_data(struct i2c_client *client, int page, max_c = max_current[data->id][(data->mfr_devset1 >> 5) & 0x3]; ret = val_to_direct(max_c, PSC_CURRENT_OUT, info); break; + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret > 0 && data->vout_voltage_divider[0] && data->vout_voltage_divider[1]) { + u64 temp = DIV_ROUND_CLOSEST_ULL((u64)ret * data->vout_voltage_divider[1], + data->vout_voltage_divider[0]); + ret = clamp_val(temp, 0, 0xffff); + } + break; default: ret = -ENODATA; break; @@ -717,6 +726,15 @@ static int max20730_probe(struct i2c_client *client) data->id = chip_id; mutex_init(&data->lock); memcpy(&data->info, &max20730_info[chip_id], sizeof(data->info)); + if (of_property_read_u32_array(client->dev.of_node, "vout-voltage-divider", + data->vout_voltage_divider, + ARRAY_SIZE(data->vout_voltage_divider)) != 0) + memset(data->vout_voltage_divider, 0, sizeof(data->vout_voltage_divider)); + if (data->vout_voltage_divider[1] < data->vout_voltage_divider[0]) { + dev_err(dev, + "The total resistance of voltage divider is less than output resistance\n"); + return -EINVAL; + } ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET1); if (ret < 0)