2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

hwmon updates for v6.17

* Updated chip support in existing drivers
 
   - ina238: Support for INA228
 
   - pmbus/tps53679: Support for TPS53685
 
   - pmbus/adp1050: Support for adp1051, adp1055 and ltp8800
 
   - corsair-psu: Support for HX1200i Series 2025
 
   - pmbus/isl68137: Support for RAA229621
 
   - asus-ec-sensors: Support for ProArt X870E-CREATOR WIFI and
 
 * Other notable changes
 
   - adt7475: Support for #pwm-cells = <3>
 
   - amc6821: Cooling device support
 
   - emc2305: Support for PWM frequency, polarity and output
 
   - Add missing compatible entries to various devicetree bindings
 
 * Various other minor fixes and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmiLiv4ACgkQyx8mb86f
 mYHCpxAAjHqk1OraRteQoUp0xT8YqSxDCvW8BSCvHSotGKdk5t2Ad9C0rqTqtKzT
 s0jo1h/dIqVfe1c7siOnAZEoqEVmbUfWJhxMSpMsDCSysJ8lEfP/ofWn4L2GxAyt
 v60cv9hNZbyeFxCXEe9XFFG2I39kKY1isj8gPiS7HHzDp5PAdSZTjhyV03NgWJJ0
 L+aJ9sw5TKMWG6hs4OgkbeAllg2G5oXbZ9AOXhBE71DAIub8lxk+UyJHOng6ecBe
 I7eAwFKLscOtEd1xzt0FBlHM/0OHj+A+yGwjHVhwXkKgNIN53t/OLLjADTbuVv51
 1nW9IAOJHtQ4OzD3MTnQEL+BIC37JbDlPX7VnhHTgYGwJhM5Pj5yUtHLqTlURUfH
 rZiLhjyGLWKIMGShVXzbKxcyVscMouLTnfn4ZXDjlDzPXOgz5Ha9+Fs3Gd+QP17D
 Y/w7pIQMA3A0f1FOxlLyRayjcPElb9vmNF2cacxPeqN2EJYRn+8tfYC6290sKBt1
 HrCeAVdXLbGCvPFBdC8w8derjQOvkPi+6a07PtUR7BB+QjO23R6FeuzpOFMBucV+
 c1q/F2d1gOP2gvtYTz5H2OvLhAKe/FnSEWlVB28C3pTrmpBs+3AkvDSBlSvZ3sIn
 vLGCVBrSI3SqxwOCnGPwGw4fxbdSrKO9OwRGOjWXxdgNOPDRWog=
 =6w+m
 -----END PGP SIGNATURE-----

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

Pull hwmon updates from Guenter Roeck:
 "Updated chip support in existing drivers:

   - ina238: Support for INA228

   - pmbus/tps53679: Support for TPS53685

   - pmbus/adp1050: Support for adp1051, adp1055 and ltp8800

   - corsair-psu: Support for HX1200i Series 2025

   - pmbus/isl68137: Support for RAA229621

   - asus-ec-sensors: Support for ProArt X870E-CREATOR WIFI and

  Other notable changes:

   - adt7475: Support for #pwm-cells = <3>

   - amc6821: Cooling device support

   - emc2305: Support for PWM frequency, polarity and output

   - Add missing compatible entries to various devicetree bindings

  And various other minor fixes and improvements"

* tag 'hwmon-for-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (34 commits)
  dt-bindings: hwmon: Replace bouncing Alexandru Tachici emails
  hwmon: (ina238) Add support for INA228
  dt-bindings: Add INA228 to ina2xx devicetree bindings
  hwmon: (ina238) Fix inconsistent whitespace
  dt-bindings: hwmon: adt7475: Allow and recommend #pwm-cells = <3>
  hwmon: (adt7475) Implement support for #pwm-cells = <3>
  hwmon: (pmbus/tps53679) Add support for TPS53685
  dt-bindings: trivial: Add tps53685 support
  hwmon: (pmbus/adp1050) Add regulator support for ltp8800
  hwmon: (pmbus/adp1050) Add support for adp1051, adp1055 and ltp8800
  dt-bindings: hwmon: pmbus/adp1050: Add adp1051, adp1055 and ltp8800
  hwmon: (max31827) use sysfs_emit() in temp1_resolution_show()
  hwmon: (ltc4282) convert from round_rate() to determine_rate()
  hwmon: (corsair-psu) add support for HX1200i Series 2025
  dt-bindings: hwmon: pmbus: ti,ucd90320: Add missing compatibles
  dt-bindings: hwmon: maxim,max20730: Add maxim,max20710 compatible
  dt-bindings: hwmon: lltc,ltc2978: Add lltc,ltc713 compatible
  dt-bindings: hwmon: ti,lm87: Add adi,adm1024 compatible
  dt-bindings: hwmon: national,lm90: Add missing Dallas max6654 and onsemi nct72, nct214, and nct218
  hwmon: (w83627ehf) make the read-only arrays 'bit' static const
  ...
This commit is contained in:
Linus Torvalds 2025-07-31 13:34:06 -07:00
commit be413ec746
33 changed files with 743 additions and 114 deletions

View File

@ -8,7 +8,7 @@ title: Analog Devices ADM1266 Cascadable Super Sequencer with Margin
Control and Fault Recording Control and Fault Recording
maintainers: maintainers:
- Alexandru Tachici <alexandru.tachici@analog.com> - Cedric Encarnacion <cedricjustine.encarnacion@analog.com>
description: | description: |
Analog Devices ADM1266 Cascadable Super Sequencer with Margin Analog Devices ADM1266 Cascadable Super Sequencer with Margin

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology 2992 Power Monitor title: Linear Technology 2992 Power Monitor
maintainers: maintainers:
- Alexandru Tachici <alexandru.tachici@analog.com> - Cedric Encarnacion <cedricjustine.encarnacion@analog.com>
description: | description: |
Linear Technology 2992 Dual Wide Range Power Monitor Linear Technology 2992 Dual Wide Range Power Monitor

View File

@ -53,7 +53,10 @@ properties:
default: 1 default: 1
"#pwm-cells": "#pwm-cells":
const: 4 oneOf:
- const: 3
- const: 4
deprecated: true
description: | description: |
Number of cells in a PWM specifier. Number of cells in a PWM specifier.
- 0: The PWM channel - 0: The PWM channel
@ -68,7 +71,7 @@ properties:
- 11363636 (88 Hz) - 11363636 (88 Hz)
- 44444 (22 kHz) - 44444 (22 kHz)
- 2: PWM flags 0 or PWM_POLARITY_INVERTED - 2: PWM flags 0 or PWM_POLARITY_INVERTED
- 3: The default PWM duty cycle in nanoseconds - 3: The default PWM duty cycle in nanoseconds, defaults to period.
patternProperties: patternProperties:
"^adi,bypass-attenuator-in[0-4]$": "^adi,bypass-attenuator-in[0-4]$":
@ -124,15 +127,15 @@ examples:
adi,bypass-attenuator-in1 = <0>; adi,bypass-attenuator-in1 = <0>;
adi,pin10-function = "smbalert#"; adi,pin10-function = "smbalert#";
adi,pin14-function = "tach4"; adi,pin14-function = "tach4";
#pwm-cells = <4>; #pwm-cells = <3>;
/* PWMs at 22.5 kHz frequency, 50% duty*/ /* PWMs at 22.5 kHz frequency */
fan-0 { fan-0 {
pwms = <&pwm 0 44444 0 22222>; pwms = <&pwm 0 44444 0>;
}; };
fan-1 { fan-1 {
pwms = <&pwm 2 44444 0 22222>; pwms = <&pwm 2 44444 0>;
}; };
}; };
}; };

View File

@ -28,6 +28,7 @@ properties:
- lltc,ltc3886 - lltc,ltc3886
- lltc,ltc3887 - lltc,ltc3887
- lltc,ltc3889 - lltc,ltc3889
- lltc,ltc7132
- lltc,ltc7841 - lltc,ltc7841
- lltc,ltc7880 - lltc,ltc7880
- lltc,ltm2987 - lltc,ltm2987
@ -55,6 +56,7 @@ properties:
* ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7 * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7
* ltc2978 : vout0 - vout7 * ltc2978 : vout0 - vout7
* ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1 * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1
* ltc7132 : vout0 - vout1
* ltc7841 : vout0 * ltc7841 : vout0
* ltc7880 : vout0 - vout1 * ltc7880 : vout0 - vout1
* ltc3883 : vout0 * ltc3883 : vout0

View File

@ -25,6 +25,7 @@ description: |
properties: properties:
compatible: compatible:
enum: enum:
- maxim,max20710
- maxim,max20730 - maxim,max20730
- maxim,max20734 - maxim,max20734
- maxim,max20743 - maxim,max20743

View File

@ -20,6 +20,7 @@ properties:
- dallas,max6646 - dallas,max6646
- dallas,max6647 - dallas,max6647
- dallas,max6649 - dallas,max6649
- dallas,max6654
- dallas,max6657 - dallas,max6657
- dallas,max6658 - dallas,max6658
- dallas,max6659 - dallas,max6659
@ -36,6 +37,9 @@ properties:
- nuvoton,nct7717 - nuvoton,nct7717
- nuvoton,nct7718 - nuvoton,nct7718
- nxp,sa56004 - nxp,sa56004
- onnn,nct72
- onnn,nct214
- onnn,nct218
- onnn,nct1008 - onnn,nct1008
- ti,tmp451 - ti,tmp451
- ti,tmp461 - ti,tmp461
@ -118,6 +122,7 @@ allOf:
- dallas,max6646 - dallas,max6646
- dallas,max6647 - dallas,max6647
- dallas,max6649 - dallas,max6649
- dallas,max6654
- dallas,max6657 - dallas,max6657
- dallas,max6658 - dallas,max6658
- dallas,max6659 - dallas,max6659
@ -139,6 +144,9 @@ allOf:
- adi,adt7461 - adi,adt7461
- adi,adt7461a - adi,adt7461a
- adi,adt7481 - adi,adt7481
- onnn,nct72
- onnn,nct214
- onnn,nct218
- onnn,nct1008 - onnn,nct1008
then: then:
patternProperties: patternProperties:

View File

@ -10,16 +10,27 @@ maintainers:
- Radu Sabau <radu.sabau@analog.com> - Radu Sabau <radu.sabau@analog.com>
description: | description: |
The ADP1050 is used to monitor system voltages, currents and temperatures. The ADP1050 and similar devices are used to monitor system voltages,
currents, power, and temperatures.
Through the PMBus interface, the ADP1050 targets isolated power supplies Through the PMBus interface, the ADP1050 targets isolated power supplies
and has four individual monitors for input/output voltage, input current and has four individual monitors for input/output voltage, input current
and temperature. and temperature.
Datasheet: Datasheet:
https://www.analog.com/en/products/adp1050.html https://www.analog.com/en/products/adp1050.html
https://www.analog.com/en/products/adp1051.html
https://www.analog.com/en/products/adp1055.html
https://www.analog.com/en/products/ltp8800-1a.html
https://www.analog.com/en/products/ltp8800-2.html
https://www.analog.com/en/products/ltp8800-4a.html
properties: properties:
compatible: compatible:
const: adi,adp1050 enum:
- adi,adp1050
- adi,adp1051
- adi,adp1055
- adi,ltp8800
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -56,6 +56,7 @@ properties:
- renesas,raa228228 - renesas,raa228228
- renesas,raa229001 - renesas,raa229001
- renesas,raa229004 - renesas,raa229004
- renesas,raa229621
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -23,7 +23,13 @@ description: |
properties: properties:
compatible: compatible:
enum: enum:
- ti,ucd9000
- ti,ucd9090
- ti,ucd90120
- ti,ucd90124
- ti,ucd90160
- ti,ucd90320 - ti,ucd90320
- ti,ucd90910
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -32,6 +32,12 @@ properties:
$ref: fan-common.yaml# $ref: fan-common.yaml#
unevaluatedProperties: false unevaluatedProperties: false
properties:
cooling-levels:
description: PWM duty cycle values corresponding to thermal cooling states.
items:
maximum: 255
"#pwm-cells": "#pwm-cells":
const: 2 const: 2
description: | description: |

View File

@ -25,6 +25,7 @@ properties:
- ti,ina219 - ti,ina219
- ti,ina220 - ti,ina220
- ti,ina226 - ti,ina226
- ti,ina228
- ti,ina230 - ti,ina230
- ti,ina231 - ti,ina231
- ti,ina233 - ti,ina233
@ -107,6 +108,7 @@ allOf:
- ti,ina219 - ti,ina219
- ti,ina220 - ti,ina220
- ti,ina226 - ti,ina226
- ti,ina228
- ti,ina230 - ti,ina230
- ti,ina231 - ti,ina231
- ti,ina237 - ti,ina237

View File

@ -18,7 +18,9 @@ description: |
properties: properties:
compatible: compatible:
const: ti,lm87 enum:
- adi,adm1024
- ti,lm87
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -450,6 +450,8 @@ properties:
- ti,tps53679 - ti,tps53679
# TI Dual channel DCAP+ multiphase controller TPS53681 # TI Dual channel DCAP+ multiphase controller TPS53681
- ti,tps53681 - ti,tps53681
# TI Dual channel DCAP+ multiphase controller TPS53685 with AMD-SVI3
- ti,tps53685
# TI Dual channel DCAP+ multiphase controller TPS53688 # TI Dual channel DCAP+ multiphase controller TPS53688
- ti,tps53688 - ti,tps53688
# TI DC-DC converters on PMBus # TI DC-DC converters on PMBus

View File

@ -13,6 +13,32 @@ Supported chips:
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1050.pdf Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1050.pdf
* Analog Devices ADP1051
Prefix: 'adp1051'
Addresses scanned: I2C 0x70 - 0x77
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1051.pdf
* Analog Devices ADP1055
Prefix: 'adp1055'
Addresses scanned: I2C 0x4B - 0x77
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1055.pdf
* Analog Devices LTP8800-1A/-2/-4A
Prefix: 'ltp8800'
Addresses scanned: -
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-1A.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-2.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-4A.pdf
Authors: Authors:
- Radu Sabau <radu.sabau@analog.com> - Radu Sabau <radu.sabau@analog.com>
@ -21,14 +47,17 @@ Authors:
Description Description
----------- -----------
This driver supprts hardware monitoring for Analog Devices ADP1050 Digital This driver supports hardware monitoring for Analog Devices ADP1050, ADP1051,
Controller for Isolated Power Supply with PMBus interface. and ADP1055 Digital Controller for Isolated Power Supply with PMBus interface,
and the LTP8800 step-down μModule regulators.
The ADP1050 is an advanced digital controller with a PMBus™ The ADP1050, ADP1051, and ADP1055 are advanced digital controllers with PMBus™
interface targeting high density, high efficiency dc-to-dc power interface targeting high density, high efficiency dc-to-dc power
conversion used to monitor system temperatures, voltages and currents. conversion used to monitor system temperatures, voltages and currents. The
Through the PMBus interface, the device can monitor input/output voltages, LTP8800 is a family of step-down μModule regulators that provides microprocessor
input current and temperature. core voltage from 54V power distribution architecture. Through the PMBus
interface, the device can monitor input/output voltages, input current and
temperature.
Usage Notes Usage Notes
----------- -----------
@ -49,16 +78,46 @@ Sysfs Attributes
in1_label "vin" in1_label "vin"
in1_input Measured input voltage in1_input Measured input voltage
in1_alarm Input voltage alarm in1_alarm Input voltage alarm
in1_crit Critical maximum input voltage
in1_crit_alarm Input voltage high alarm
in1_lcrit Critical minimum input voltage
in1_lcrit_alarm Input voltage critical low alarm
in2_label "vout1" in2_label "vout1"
in2_input Measured output voltage in2_input Measured output voltage
in2_crit Critical maximum output voltage in2_crit Critical maximum output voltage
in2_crit_alarm Output voltage high alarm in2_crit_alarm Output voltage high alarm
in2_lcrit Critical minimum output voltage in2_lcrit Critical minimum output voltage
in2_lcrit_alarm Output voltage critical low alarm in2_lcrit_alarm Output voltage critical low alarm
in2_max Critical maximum output voltage
in2_max_alarm Output voltage critical max alarm
in2_min Critical minimum output voltage
in2_min_alarm Output voltage critical min alarm
curr1_label "iin" curr1_label "iin"
curr1_input Measured input current. curr1_input Measured input current.
curr1_alarm Input current alarm curr1_alarm Input current alarm
curr1_crit Critical maximum input current
curr1_crit_alarm Input current high alarm
curr2_label "iout1"
curr2_input Measured output current
curr2_alarm Output current alarm
curr2_crit Critical maximum output current
curr2_crit_alarm Output current high alarm
curr2_lcrit Critical minimum output current
curr2_lcrit_alarm Output current critical low alarm
curr2_max Critical maximum output current
curr2_max_alarm Output current critical max alarm
power1_label "pout1"
power1_input Measured output power
power1_crit Critical maximum output power
power1_crit_alarm Output power high alarm
temp1_input Measured temperature temp1_input Measured temperature
temp1_crit Critical high temperature temp1_crit Critical high temperature
temp1_crit_alarm Chip temperature critical high alarm temp1_crit_alarm Chip temperature critical high alarm
temp1_max Critical maximum temperature
temp1_max_alarm Temperature critical max alarm
temp2_input Measured temperature
temp2_crit Critical high temperature
temp2_crit_alarm Chip temperature critical high alarm
temp2_max Critical maximum temperature
temp2_max_alarm Temperature critical max alarm
================= ======================================== ================= ========================================

View File

@ -11,6 +11,7 @@ Supported boards:
* Pro WS X570-ACE * Pro WS X570-ACE
* ProArt X570-CREATOR WIFI * ProArt X570-CREATOR WIFI
* ProArt X670E-CREATOR WIFI * ProArt X670E-CREATOR WIFI
* ProArt X870E-CREATOR WIFI
* ProArt B550-CREATOR * ProArt B550-CREATOR
* ROG CROSSHAIR VIII DARK HERO * ROG CROSSHAIR VIII DARK HERO
* ROG CROSSHAIR VIII HERO (WI-FI) * ROG CROSSHAIR VIII HERO (WI-FI)
@ -29,6 +30,7 @@ Supported boards:
* ROG STRIX X570-F GAMING * ROG STRIX X570-F GAMING
* ROG STRIX X570-I GAMING * ROG STRIX X570-I GAMING
* ROG STRIX Z390-F GAMING * ROG STRIX Z390-F GAMING
* ROG STRIX Z490-F GAMING
* ROG STRIX Z690-A GAMING WIFI D4 * ROG STRIX Z690-A GAMING WIFI D4
* ROG ZENITH II EXTREME * ROG ZENITH II EXTREME
* ROG ZENITH II EXTREME ALPHA * ROG ZENITH II EXTREME ALPHA

View File

@ -17,7 +17,7 @@ Supported devices:
Corsair HX1000i (Legacy and Series 2023) Corsair HX1000i (Legacy and Series 2023)
Corsair HX1200i (Legacy and Series 2023) Corsair HX1200i (Legacy, Series 2023 and Series 2025)
Corsair HX1500i (Legacy and Series 2023) Corsair HX1500i (Legacy and Series 2023)

View File

@ -43,6 +43,14 @@ Supported chips:
Datasheet: https://www.ti.com/lit/gpn/TPS53681 Datasheet: https://www.ti.com/lit/gpn/TPS53681
* Texas Instruments TPS53685
Prefix: 'tps53685'
Addresses scanned: -
Datasheet: https://www.ti.com/lit/gpn/TPS53685
* Texas Instruments TPS53688 * Texas Instruments TPS53688
Prefix: 'tps53688' Prefix: 'tps53688'

View File

@ -1704,12 +1704,15 @@ static int adt7475_pwm_properties_parse_reference_args(struct fwnode_handle *fwn
if (ret) if (ret)
return ret; return ret;
if (rargs.nargs != 4) { if (rargs.nargs != 3 && rargs.nargs != 4) {
fwnode_handle_put(rargs.fwnode); fwnode_handle_put(rargs.fwnode);
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < 4; i++) /* Let duty_cycle default to period */
args[3] = rargs.args[1];
for (i = 0; i < rargs.nargs; i++)
args[i] = rargs.args[i]; args[i] = rargs.args[i];
ret = _adt7475_pwm_properties_parse_args(args, cfg); ret = _adt7475_pwm_properties_parse_args(args, cfg);
@ -1724,11 +1727,22 @@ static int adt7475_pwm_properties_parse_args(struct fwnode_handle *fwnode,
{ {
int ret; int ret;
u32 args[4] = {}; u32 args[4] = {};
size_t n_vals = fwnode_property_count_u32(fwnode, "pwms");
ret = fwnode_property_read_u32_array(fwnode, "pwms", args, ARRAY_SIZE(args)); if (n_vals != 3 && n_vals != 4)
return -EOVERFLOW;
ret = fwnode_property_read_u32_array(fwnode, "pwms", args, n_vals);
if (ret) if (ret)
return ret; return ret;
/*
* If there are no item to define the duty_cycle, default it to the
* period.
*/
if (n_vals == 3)
args[3] = args[1];
return _adt7475_pwm_properties_parse_args(args, cfg); return _adt7475_pwm_properties_parse_args(args, cfg);
} }

View File

@ -26,6 +26,7 @@
#include <linux/pwm.h> #include <linux/pwm.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/thermal.h>
#include <dt-bindings/pwm/pwm.h> #include <dt-bindings/pwm/pwm.h>
@ -126,6 +127,10 @@ module_param(init, int, 0444);
struct amc6821_data { struct amc6821_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock; struct mutex update_lock;
unsigned long fan_state;
unsigned long fan_max_state;
unsigned int *fan_cooling_levels;
enum pwm_polarity pwm_polarity;
}; };
/* /*
@ -804,6 +809,65 @@ static const struct hwmon_chip_info amc6821_chip_info = {
.info = amc6821_info, .info = amc6821_info,
}; };
static int amc6821_set_sw_dcy(struct amc6821_data *data, u8 duty_cycle)
{
int ret;
ret = regmap_write(data->regmap, AMC6821_REG_DCY, duty_cycle);
if (ret)
return ret;
return regmap_update_bits(data->regmap, AMC6821_REG_CONF1,
AMC6821_CONF1_FDRC0 | AMC6821_CONF1_FDRC1, 0);
}
static int amc6821_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state)
{
struct amc6821_data *data = cdev->devdata;
if (!data)
return -EINVAL;
*state = data->fan_max_state;
return 0;
}
static int amc6821_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state)
{
struct amc6821_data *data = cdev->devdata;
if (!data)
return -EINVAL;
*state = data->fan_state;
return 0;
}
static int amc6821_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct amc6821_data *data = cdev->devdata;
int ret;
if (!data || state > data->fan_max_state)
return -EINVAL;
ret = amc6821_set_sw_dcy(data, data->fan_cooling_levels[state]);
if (ret)
return ret;
data->fan_state = state;
return 0;
}
static const struct thermal_cooling_device_ops amc6821_cooling_ops = {
.get_max_state = amc6821_get_max_state,
.get_cur_state = amc6821_get_cur_state,
.set_cur_state = amc6821_set_cur_state,
};
/* Return 0 if detection is successful, -ENODEV otherwise */ /* Return 0 if detection is successful, -ENODEV otherwise */
static int amc6821_detect(struct i2c_client *client, struct i2c_board_info *info) static int amc6821_detect(struct i2c_client *client, struct i2c_board_info *info)
{ {
@ -848,11 +912,11 @@ static int amc6821_detect(struct i2c_client *client, struct i2c_board_info *info
return 0; return 0;
} }
static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client) static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client,
struct device_node *fan_np)
{ {
enum pwm_polarity polarity = PWM_POLARITY_NORMAL; enum pwm_polarity polarity = PWM_POLARITY_NORMAL;
struct of_phandle_args args; struct of_phandle_args args;
struct device_node *fan_np;
/* /*
* For backward compatibility, the pwminv module parameter takes * For backward compatibility, the pwminv module parameter takes
@ -863,10 +927,6 @@ static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client)
if (pwminv > 0) if (pwminv > 0)
return PWM_POLARITY_INVERSED; return PWM_POLARITY_INVERSED;
fan_np = of_get_child_by_name(client->dev.of_node, "fan");
if (!fan_np)
return PWM_POLARITY_NORMAL;
if (of_parse_phandle_with_args(fan_np, "pwms", "#pwm-cells", 0, &args)) if (of_parse_phandle_with_args(fan_np, "pwms", "#pwm-cells", 0, &args))
goto out; goto out;
of_node_put(args.np); of_node_put(args.np);
@ -877,10 +937,34 @@ static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client)
if (args.args[1] & PWM_POLARITY_INVERTED) if (args.args[1] & PWM_POLARITY_INVERTED)
polarity = PWM_POLARITY_INVERSED; polarity = PWM_POLARITY_INVERSED;
out: out:
of_node_put(fan_np);
return polarity; return polarity;
} }
static int amc6821_of_fan_read_data(struct i2c_client *client,
struct amc6821_data *data,
struct device_node *fan_np)
{
int num;
data->pwm_polarity = amc6821_pwm_polarity(client, fan_np);
num = of_property_count_u32_elems(fan_np, "cooling-levels");
if (num <= 0)
return 0;
data->fan_max_state = num - 1;
data->fan_cooling_levels = devm_kcalloc(&client->dev, num,
sizeof(u32),
GFP_KERNEL);
if (!data->fan_cooling_levels)
return -ENOMEM;
return of_property_read_u32_array(fan_np, "cooling-levels",
data->fan_cooling_levels, num);
}
static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *data) static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *data)
{ {
struct regmap *regmap = data->regmap; struct regmap *regmap = data->regmap;
@ -902,7 +986,7 @@ static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *d
return err; return err;
regval = AMC6821_CONF1_START; regval = AMC6821_CONF1_START;
if (amc6821_pwm_polarity(client) == PWM_POLARITY_INVERSED) if (data->pwm_polarity == PWM_POLARITY_INVERSED)
regval |= AMC6821_CONF1_PWMINV; regval |= AMC6821_CONF1_PWMINV;
err = regmap_update_bits(regmap, AMC6821_REG_CONF1, err = regmap_update_bits(regmap, AMC6821_REG_CONF1,
@ -911,6 +995,14 @@ static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *d
regval); regval);
if (err) if (err)
return err; return err;
/* Software DCY-control mode with fan enabled when cooling-levels present */
if (data->fan_cooling_levels) {
err = amc6821_set_sw_dcy(data,
data->fan_cooling_levels[data->fan_max_state]);
if (err)
return err;
}
} }
return 0; return 0;
} }
@ -944,6 +1036,7 @@ static int amc6821_probe(struct i2c_client *client)
struct amc6821_data *data; struct amc6821_data *data;
struct device *hwmon_dev; struct device *hwmon_dev;
struct regmap *regmap; struct regmap *regmap;
struct device_node *fan_np __free(device_node) = NULL;
int err; int err;
data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL); data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL);
@ -956,6 +1049,14 @@ static int amc6821_probe(struct i2c_client *client)
"Failed to initialize regmap\n"); "Failed to initialize regmap\n");
data->regmap = regmap; data->regmap = regmap;
fan_np = of_get_child_by_name(dev->of_node, "fan");
if (fan_np) {
err = amc6821_of_fan_read_data(client, data, fan_np);
if (err)
return dev_err_probe(dev, err,
"Failed to read fan device tree data\n");
}
err = amc6821_init_client(client, data); err = amc6821_init_client(client, data);
if (err) if (err)
return err; return err;
@ -970,7 +1071,15 @@ static int amc6821_probe(struct i2c_client *client)
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data, &amc6821_chip_info, data, &amc6821_chip_info,
amc6821_groups); amc6821_groups);
return PTR_ERR_OR_ZERO(hwmon_dev); if (IS_ERR(hwmon_dev))
return dev_err_probe(dev, PTR_ERR(hwmon_dev),
"Failed to initialize hwmon\n");
if (IS_ENABLED(CONFIG_THERMAL) && fan_np && data->fan_cooling_levels)
return PTR_ERR_OR_ZERO(devm_thermal_of_cooling_device_register(dev,
fan_np, client->name, data, &amc6821_cooling_ops));
return 0;
} }
static const struct i2c_device_id amc6821_id[] = { static const struct i2c_device_id amc6821_id[] = {

View File

@ -165,7 +165,9 @@ enum board_family {
family_amd_400_series, family_amd_400_series,
family_amd_500_series, family_amd_500_series,
family_amd_600_series, family_amd_600_series,
family_amd_800_series,
family_intel_300_series, family_intel_300_series,
family_intel_400_series,
family_intel_600_series family_intel_600_series
}; };
@ -259,6 +261,20 @@ static const struct ec_sensor_info sensors_family_amd_600[] = {
EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
}; };
static const struct ec_sensor_info sensors_family_amd_800[] = {
[ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30),
[ec_sensor_temp_cpu_package] =
EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),
[ec_sensor_temp_mb] =
EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32),
[ec_sensor_temp_vrm] =
EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),
[ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36),
[ec_sensor_fan_cpu_opt] =
EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
};
static const struct ec_sensor_info sensors_family_intel_300[] = { static const struct ec_sensor_info sensors_family_intel_300[] = {
[ec_sensor_temp_chipset] = [ec_sensor_temp_chipset] =
EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
@ -279,6 +295,20 @@ static const struct ec_sensor_info sensors_family_intel_300[] = {
EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
}; };
static const struct ec_sensor_info sensors_family_intel_400[] = {
[ec_sensor_temp_chipset] =
EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
[ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
[ec_sensor_temp_mb] =
EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),
[ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
[ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
[ec_sensor_fan_cpu_opt] =
EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
[ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),
};
static const struct ec_sensor_info sensors_family_intel_600[] = { static const struct ec_sensor_info sensors_family_intel_600[] = {
[ec_sensor_temp_t_sensor] = [ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
@ -362,6 +392,14 @@ static const struct ec_board_info board_info_pro_art_x670E_creator_wifi = {
.family = family_amd_600_series, .family = family_amd_600_series,
}; };
static const struct ec_board_info board_info_pro_art_x870E_creator_wifi = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT,
.mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
.family = family_amd_800_series,
};
static const struct ec_board_info board_info_pro_art_b550_creator = { static const struct ec_board_info board_info_pro_art_b550_creator = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_T_SENSOR |
@ -498,6 +536,18 @@ static const struct ec_board_info board_info_strix_z390_f_gaming = {
.family = family_intel_300_series, .family = family_intel_300_series,
}; };
static const struct ec_board_info board_info_strix_z490_f_gaming = {
.sensors = SENSOR_TEMP_CHIPSET |
SENSOR_TEMP_CPU |
SENSOR_TEMP_MB |
SENSOR_TEMP_T_SENSOR |
SENSOR_TEMP_VRM |
SENSOR_FAN_CPU_OPT |
SENSOR_FAN_VRM_HS,
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_intel_400_series,
};
static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = { static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = {
.sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM, .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
@ -548,6 +598,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_pro_art_x570_creator_wifi), &board_info_pro_art_x570_creator_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI",
&board_info_pro_art_x670E_creator_wifi), &board_info_pro_art_x670E_creator_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI",
&board_info_pro_art_x870E_creator_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR",
&board_info_pro_art_b550_creator), &board_info_pro_art_b550_creator),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",
@ -586,6 +638,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_strix_x570_i_gaming), &board_info_strix_x570_i_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",
&board_info_strix_z390_f_gaming), &board_info_strix_z390_f_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING",
&board_info_strix_z490_f_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4",
&board_info_strix_z690_a_gaming_wifi_d4), &board_info_strix_z690_a_gaming_wifi_d4),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
@ -1058,9 +1112,15 @@ static int asus_ec_probe(struct platform_device *pdev)
case family_amd_600_series: case family_amd_600_series:
ec_data->sensors_info = sensors_family_amd_600; ec_data->sensors_info = sensors_family_amd_600;
break; break;
case family_amd_800_series:
ec_data->sensors_info = sensors_family_amd_800;
break;
case family_intel_300_series: case family_intel_300_series:
ec_data->sensors_info = sensors_family_intel_300; ec_data->sensors_info = sensors_family_intel_300;
break; break;
case family_intel_400_series:
ec_data->sensors_info = sensors_family_intel_400;
break;
case family_intel_600_series: case family_intel_600_series:
ec_data->sensors_info = sensors_family_intel_600; ec_data->sensors_info = sensors_family_intel_600;
break; break;

View File

@ -885,6 +885,7 @@ static const struct hid_device_id corsairpsu_idtable[] = {
{ HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */
{ HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy and Series 2023 */ { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy and Series 2023 */
{ HID_USB_DEVICE(0x1b1c, 0x1c23) }, /* Corsair HX1200i Series 2023 */ { HID_USB_DEVICE(0x1b1c, 0x1c23) }, /* Corsair HX1200i Series 2023 */
{ HID_USB_DEVICE(0x1b1c, 0x1c27) }, /* Corsair HX1200i Series 2025 */
{ }, { },
}; };
MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); MODULE_DEVICE_TABLE(hid, corsairpsu_idtable);

View File

@ -11,6 +11,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_data/emc2305.h> #include <linux/platform_data/emc2305.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/pwm.h>
#include <linux/of_device.h>
#include <linux/util_macros.h>
#define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 #define EMC2305_REG_DRIVE_FAIL_STATUS 0x27
#define EMC2305_REG_VENDOR 0xfe #define EMC2305_REG_VENDOR 0xfe
@ -23,6 +26,12 @@
#define EMC2305_TACH_REGS_UNUSE_BITS 3 #define EMC2305_TACH_REGS_UNUSE_BITS 3
#define EMC2305_TACH_CNT_MULTIPLIER 0x02 #define EMC2305_TACH_CNT_MULTIPLIER 0x02
#define EMC2305_TACH_RANGE_MIN 480 #define EMC2305_TACH_RANGE_MIN 480
#define EMC2305_DEFAULT_OUTPUT 0x0
#define EMC2305_DEFAULT_POLARITY 0x0
#define EMC2305_REG_POLARITY 0x2a
#define EMC2305_REG_DRIVE_PWM_OUT 0x2b
#define EMC2305_OPEN_DRAIN 0x0
#define EMC2305_PUSH_PULL 0x1
#define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \ #define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \
DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max)) DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max))
@ -39,6 +48,9 @@
#define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n)) #define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n))
#define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n)) #define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n))
/* Supported base PWM frequencies */
static const unsigned int base_freq_table[] = { 2441, 4882, 19530, 26000 };
enum emc230x_product_id { enum emc230x_product_id {
EMC2305 = 0x34, EMC2305 = 0x34,
EMC2303 = 0x35, EMC2303 = 0x35,
@ -89,8 +101,11 @@ struct emc2305_cdev_data {
* @hwmon_dev: hwmon device * @hwmon_dev: hwmon device
* @max_state: maximum cooling state of the cooling device * @max_state: maximum cooling state of the cooling device
* @pwm_num: number of PWM channels * @pwm_num: number of PWM channels
* @pwm_output_mask: PWM output mask
* @pwm_polarity_mask: PWM polarity mask
* @pwm_separate: separate PWM settings for every channel * @pwm_separate: separate PWM settings for every channel
* @pwm_min: array of minimum PWM per channel * @pwm_min: array of minimum PWM per channel
* @pwm_freq: array of PWM frequency per channel
* @cdev_data: array of cooling devices data * @cdev_data: array of cooling devices data
*/ */
struct emc2305_data { struct emc2305_data {
@ -98,8 +113,11 @@ struct emc2305_data {
struct device *hwmon_dev; struct device *hwmon_dev;
u8 max_state; u8 max_state;
u8 pwm_num; u8 pwm_num;
u8 pwm_output_mask;
u8 pwm_polarity_mask;
bool pwm_separate; bool pwm_separate;
u8 pwm_min[EMC2305_PWM_MAX]; u8 pwm_min[EMC2305_PWM_MAX];
u16 pwm_freq[EMC2305_PWM_MAX];
struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX]; struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX];
}; };
@ -281,7 +299,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel)
return 0; return 0;
} }
static int emc2305_set_single_tz(struct device *dev, int idx) static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_node, int idx)
{ {
struct emc2305_data *data = dev_get_drvdata(dev); struct emc2305_data *data = dev_get_drvdata(dev);
long pwm; long pwm;
@ -291,7 +309,7 @@ static int emc2305_set_single_tz(struct device *dev, int idx)
pwm = data->pwm_min[cdev_idx]; pwm = data->pwm_min[cdev_idx];
data->cdev_data[cdev_idx].cdev = data->cdev_data[cdev_idx].cdev =
devm_thermal_of_cooling_device_register(dev, dev->of_node, devm_thermal_of_cooling_device_register(dev, fan_node,
emc2305_fan_name[idx], data, emc2305_fan_name[idx], data,
&emc2305_cooling_ops); &emc2305_cooling_ops);
@ -299,6 +317,12 @@ static int emc2305_set_single_tz(struct device *dev, int idx)
dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]); dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]);
return PTR_ERR(data->cdev_data[cdev_idx].cdev); return PTR_ERR(data->cdev_data[cdev_idx].cdev);
} }
if (data->cdev_data[cdev_idx].cur_state > 0)
/* Update pwm when temperature is above trips */
pwm = EMC2305_PWM_STATE2DUTY(data->cdev_data[cdev_idx].cur_state,
data->max_state, EMC2305_FAN_MAX);
/* Set minimal PWM speed. */ /* Set minimal PWM speed. */
if (data->pwm_separate) { if (data->pwm_separate) {
ret = emc2305_set_pwm(dev, pwm, cdev_idx); ret = emc2305_set_pwm(dev, pwm, cdev_idx);
@ -312,10 +336,10 @@ static int emc2305_set_single_tz(struct device *dev, int idx)
} }
} }
data->cdev_data[cdev_idx].cur_state = data->cdev_data[cdev_idx].cur_state =
EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, EMC2305_PWM_DUTY2STATE(pwm, data->max_state,
EMC2305_FAN_MAX); EMC2305_FAN_MAX);
data->cdev_data[cdev_idx].last_hwmon_state = data->cdev_data[cdev_idx].last_hwmon_state =
EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, EMC2305_PWM_DUTY2STATE(pwm, data->max_state,
EMC2305_FAN_MAX); EMC2305_FAN_MAX);
return 0; return 0;
} }
@ -326,10 +350,10 @@ static int emc2305_set_tz(struct device *dev)
int i, ret; int i, ret;
if (!data->pwm_separate) if (!data->pwm_separate)
return emc2305_set_single_tz(dev, 0); return emc2305_set_single_tz(dev, dev->of_node, 0);
for (i = 0; i < data->pwm_num; i++) { for (i = 0; i < data->pwm_num; i++) {
ret = emc2305_set_single_tz(dev, i + 1); ret = emc2305_set_single_tz(dev, dev->of_node, i + 1);
if (ret) if (ret)
return ret; return ret;
} }
@ -511,15 +535,85 @@ static int emc2305_identify(struct device *dev)
return 0; return 0;
} }
static int emc2305_of_parse_pwm_child(struct device *dev,
struct device_node *child,
struct emc2305_data *data)
{ u32 ch;
int ret;
struct of_phandle_args args;
ret = of_property_read_u32(child, "reg", &ch);
if (ret) {
dev_err(dev, "missing reg property of %pOFn\n", child);
return ret;
}
ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", 0, &args);
if (ret)
return ret;
if (args.args_count > 0) {
data->pwm_freq[ch] = find_closest(args.args[0], base_freq_table,
ARRAY_SIZE(base_freq_table));
} else {
data->pwm_freq[ch] = base_freq_table[3];
}
if (args.args_count > 1) {
if (args.args[1] == PWM_POLARITY_NORMAL || args.args[1] == PWM_POLARITY_INVERSED)
data->pwm_polarity_mask |= args.args[1] << ch;
else
dev_err(dev, "Wrong PWM polarity config provided: %d\n", args.args[0]);
} else {
data->pwm_polarity_mask |= PWM_POLARITY_NORMAL << ch;
}
if (args.args_count > 2) {
if (args.args[2] == EMC2305_PUSH_PULL || args.args[2] <= EMC2305_OPEN_DRAIN)
data->pwm_output_mask |= args.args[2] << ch;
else
dev_err(dev, "Wrong PWM output config provided: %d\n", args.args[1]);
} else {
data->pwm_output_mask |= EMC2305_OPEN_DRAIN << ch;
}
return 0;
}
static int emc2305_probe_childs_from_dt(struct device *dev)
{
struct emc2305_data *data = dev_get_drvdata(dev);
struct device_node *child;
int ret, count = 0;
data->pwm_output_mask = 0x0;
data->pwm_polarity_mask = 0x0;
for_each_child_of_node(dev->of_node, child) {
if (of_property_present(child, "reg")) {
ret = emc2305_of_parse_pwm_child(dev, child, data);
if (ret) {
of_node_put(child);
continue;
}
count++;
}
}
return count;
}
static int emc2305_probe(struct i2c_client *client) static int emc2305_probe(struct i2c_client *client)
{ {
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct device_node *child;
struct emc2305_data *data; struct emc2305_data *data;
struct emc2305_platform_data *pdata; struct emc2305_platform_data *pdata;
int vendor; int vendor;
int ret; int ret;
int i; int i;
int pwm_childs;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV; return -ENODEV;
@ -539,22 +633,40 @@ static int emc2305_probe(struct i2c_client *client)
if (ret) if (ret)
return ret; return ret;
pwm_childs = emc2305_probe_childs_from_dt(dev);
pdata = dev_get_platdata(&client->dev); pdata = dev_get_platdata(&client->dev);
if (pdata) {
if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE) if (!pwm_childs) {
return -EINVAL; if (pdata) {
data->max_state = pdata->max_state; if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE)
/* return -EINVAL;
* Validate a number of active PWM channels. Note that data->max_state = pdata->max_state;
* configured number can be less than the actual maximum /*
* supported by the device. * Validate a number of active PWM channels. Note that
*/ * configured number can be less than the actual maximum
if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX) * supported by the device.
return -EINVAL; */
data->pwm_num = pdata->pwm_num; if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX)
data->pwm_separate = pdata->pwm_separate; return -EINVAL;
for (i = 0; i < EMC2305_PWM_MAX; i++) data->pwm_num = pdata->pwm_num;
data->pwm_min[i] = pdata->pwm_min[i]; data->pwm_output_mask = pdata->pwm_output_mask;
data->pwm_polarity_mask = pdata->pwm_polarity_mask;
data->pwm_separate = pdata->pwm_separate;
for (i = 0; i < EMC2305_PWM_MAX; i++) {
data->pwm_min[i] = pdata->pwm_min[i];
data->pwm_freq[i] = pdata->pwm_freq[i];
}
} else {
data->max_state = EMC2305_FAN_MAX_STATE;
data->pwm_separate = false;
data->pwm_output_mask = EMC2305_DEFAULT_OUTPUT;
data->pwm_polarity_mask = EMC2305_DEFAULT_POLARITY;
for (i = 0; i < EMC2305_PWM_MAX; i++) {
data->pwm_min[i] = EMC2305_FAN_MIN;
data->pwm_freq[i] = base_freq_table[3];
}
}
} else { } else {
data->max_state = EMC2305_FAN_MAX_STATE; data->max_state = EMC2305_FAN_MAX_STATE;
data->pwm_separate = false; data->pwm_separate = false;
@ -568,11 +680,32 @@ static int emc2305_probe(struct i2c_client *client)
return PTR_ERR(data->hwmon_dev); return PTR_ERR(data->hwmon_dev);
if (IS_REACHABLE(CONFIG_THERMAL)) { if (IS_REACHABLE(CONFIG_THERMAL)) {
ret = emc2305_set_tz(dev); /* Parse and check for the available PWM child nodes */
if (ret != 0) if (pwm_childs > 0) {
return ret; i = 0;
for_each_child_of_node(dev->of_node, child) {
ret = emc2305_set_single_tz(dev, child, i);
if (ret != 0)
return ret;
i++;
}
} else {
ret = emc2305_set_tz(dev);
if (ret != 0)
return ret;
}
} }
ret = i2c_smbus_write_byte_data(client, EMC2305_REG_DRIVE_PWM_OUT,
data->pwm_output_mask);
if (ret < 0)
dev_err(dev, "Failed to configure pwm output, using default\n");
ret = i2c_smbus_write_byte_data(client, EMC2305_REG_POLARITY,
data->pwm_polarity_mask);
if (ret < 0)
dev_err(dev, "Failed to configure pwm polarity, using default\n");
for (i = 0; i < data->pwm_num; i++) { for (i = 0; i < data->pwm_num; i++) {
ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i), ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i),
data->pwm_min[i]); data->pwm_min[i]);

View File

@ -64,7 +64,7 @@ static ssize_t pwm_auto_point_temp_show(struct device *dev,
return ret; return ret;
ret = regs[0] | regs[1] << 8; ret = regs[0] | regs[1] << 8;
return sprintf(buf, "%d\n", ret * 10); return sprintf(buf, "%d\n", ret * 100);
} }
static ssize_t pwm_auto_point_temp_store(struct device *dev, static ssize_t pwm_auto_point_temp_store(struct device *dev,
@ -99,7 +99,7 @@ static ssize_t pwm_auto_point_pwm_show(struct device *dev,
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10))); return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100);
} }
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0); static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0);

View File

@ -349,7 +349,7 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
void *buf, size_t size) void *buf, size_t size)
{ {
int rs_size, res; int rs_size;
struct aem_read_sensor_req rs_req; struct aem_read_sensor_req rs_req;
/* Use preallocated rx buffer */ /* Use preallocated rx buffer */
struct aem_read_sensor_resp *rs_resp = data->rs_resp; struct aem_read_sensor_resp *rs_resp = data->rs_resp;
@ -383,17 +383,12 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
aem_send_message(ipmi); aem_send_message(ipmi);
res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); if (!wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT))
if (!res) { return -ETIMEDOUT;
res = -ETIMEDOUT;
goto out;
}
if (ipmi->rx_result || ipmi->rx_msg_len != rs_size || if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) { memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id)))
res = -ENOENT; return -ENOENT;
goto out;
}
switch (size) { switch (size) {
case 1: { case 1: {
@ -417,10 +412,8 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
break; break;
} }
} }
res = 0;
out: return 0;
return res;
} }
/* Update AEM energy registers */ /* Update AEM energy registers */
@ -491,7 +484,6 @@ static void aem_delete(struct aem_data *data)
/* Retrieve version and module handle for an AEM1 instance */ /* Retrieve version and module handle for an AEM1 instance */
static int aem_find_aem1_count(struct aem_ipmi_data *data) static int aem_find_aem1_count(struct aem_ipmi_data *data)
{ {
int res;
struct aem_find_firmware_req ff_req; struct aem_find_firmware_req ff_req;
struct aem_find_firmware_resp ff_resp; struct aem_find_firmware_resp ff_resp;
@ -508,8 +500,7 @@ static int aem_find_aem1_count(struct aem_ipmi_data *data)
aem_send_message(data); aem_send_message(data);
res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); if (!wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT))
if (!res)
return -ETIMEDOUT; return -ETIMEDOUT;
if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) || if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) ||
@ -632,7 +623,6 @@ static int aem_find_aem2(struct aem_ipmi_data *data,
struct aem_find_instance_resp *fi_resp, struct aem_find_instance_resp *fi_resp,
int instance_num) int instance_num)
{ {
int res;
struct aem_find_instance_req fi_req; struct aem_find_instance_req fi_req;
fi_req.id = system_x_id; fi_req.id = system_x_id;
@ -648,8 +638,7 @@ static int aem_find_aem2(struct aem_ipmi_data *data,
aem_send_message(data); aem_send_message(data);
res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); if (!wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT))
if (!res)
return -ETIMEDOUT; return -ETIMEDOUT;
if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) || if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) ||

View File

@ -6,6 +6,7 @@
* Copyright (C) 2021 Nathan Rossi <nathan.rossi@digi.com> * Copyright (C) 2021 Nathan Rossi <nathan.rossi@digi.com>
*/ */
#include <linux/bitops.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/i2c.h> #include <linux/i2c.h>
@ -41,7 +42,7 @@
#define INA238_CONFIG_ADCRANGE BIT(4) #define INA238_CONFIG_ADCRANGE BIT(4)
#define SQ52206_CONFIG_ADCRANGE_HIGH BIT(4) #define SQ52206_CONFIG_ADCRANGE_HIGH BIT(4)
#define SQ52206_CONFIG_ADCRANGE_LOW BIT(3) #define SQ52206_CONFIG_ADCRANGE_LOW BIT(3)
#define INA238_DIAG_ALERT_TMPOL BIT(7) #define INA238_DIAG_ALERT_TMPOL BIT(7)
#define INA238_DIAG_ALERT_SHNTOL BIT(6) #define INA238_DIAG_ALERT_SHNTOL BIT(6)
@ -104,9 +105,10 @@
#define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */ #define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */
#define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */ #define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */
#define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ #define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */
#define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */ #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */
#define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
#define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
static const struct regmap_config ina238_regmap_config = { static const struct regmap_config ina238_regmap_config = {
.max_register = INA238_REGISTERS, .max_register = INA238_REGISTERS,
@ -114,16 +116,17 @@ static const struct regmap_config ina238_regmap_config = {
.val_bits = 16, .val_bits = 16,
}; };
enum ina238_ids { ina238, ina237, sq52206 }; enum ina238_ids { ina238, ina237, sq52206, ina228 };
struct ina238_config { struct ina238_config {
bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */
bool has_power_highest; /* chip detection power peak */ bool has_power_highest; /* chip detection power peak */
bool has_energy; /* chip detection energy */ bool has_energy; /* chip detection energy */
u8 temp_shift; /* fixed parameters for temp calculate */ u8 temp_shift; /* fixed parameters for temp calculate */
u32 power_calculate_factor; /* fixed parameters for power calculate */ u32 power_calculate_factor; /* fixed parameters for power calculate */
u16 config_default; /* Power-on default state */ u16 config_default; /* Power-on default state */
int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */ int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */
int temp_lsb; /* use for temperature calculate */ int temp_lsb; /* use for temperature calculate */
}; };
struct ina238_data { struct ina238_data {
@ -137,6 +140,7 @@ struct ina238_data {
static const struct ina238_config ina238_config[] = { static const struct ina238_config ina238_config[] = {
[ina238] = { [ina238] = {
.has_20bit_voltage_current = false,
.has_energy = false, .has_energy = false,
.has_power_highest = false, .has_power_highest = false,
.temp_shift = 4, .temp_shift = 4,
@ -146,6 +150,7 @@ static const struct ina238_config ina238_config[] = {
.temp_lsb = INA238_DIE_TEMP_LSB, .temp_lsb = INA238_DIE_TEMP_LSB,
}, },
[ina237] = { [ina237] = {
.has_20bit_voltage_current = false,
.has_energy = false, .has_energy = false,
.has_power_highest = false, .has_power_highest = false,
.temp_shift = 4, .temp_shift = 4,
@ -155,6 +160,7 @@ static const struct ina238_config ina238_config[] = {
.temp_lsb = INA238_DIE_TEMP_LSB, .temp_lsb = INA238_DIE_TEMP_LSB,
}, },
[sq52206] = { [sq52206] = {
.has_20bit_voltage_current = false,
.has_energy = true, .has_energy = true,
.has_power_highest = true, .has_power_highest = true,
.temp_shift = 0, .temp_shift = 0,
@ -163,6 +169,16 @@ static const struct ina238_config ina238_config[] = {
.bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB, .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB,
.temp_lsb = SQ52206_DIE_TEMP_LSB, .temp_lsb = SQ52206_DIE_TEMP_LSB,
}, },
[ina228] = {
.has_20bit_voltage_current = true,
.has_energy = true,
.has_power_highest = false,
.temp_shift = 0,
.power_calculate_factor = 20,
.config_default = INA238_CONFIG_DEFAULT,
.bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
.temp_lsb = INA228_DIE_TEMP_LSB,
},
}; };
static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val) static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
@ -199,6 +215,65 @@ static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val)
return 0; return 0;
} }
static int ina238_read_field_s20(const struct i2c_client *client, u8 reg, s32 *val)
{
u32 regval;
int err;
err = ina238_read_reg24(client, reg, &regval);
if (err)
return err;
/* bits 3-0 Reserved, always zero */
regval >>= 4;
*val = sign_extend32(regval, 19);
return 0;
}
static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel,
long *val)
{
struct ina238_data *data = dev_get_drvdata(dev);
int regval;
int err;
err = ina238_read_field_s20(data->client, INA238_SHUNT_VOLTAGE, &regval);
if (err)
return err;
/*
* gain of 1 -> LSB / 4
* This field has 16 bit on ina238. ina228 adds another 4 bits of
* precision. ina238 conversion factors can still be applied when
* dividing by 16.
*/
*val = (regval * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16;
return 0;
}
static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel,
long *val)
{
struct ina238_data *data = dev_get_drvdata(dev);
int regval;
int err;
err = ina238_read_field_s20(data->client, INA238_BUS_VOLTAGE, &regval);
if (err)
return err;
/*
* gain of 1 -> LSB / 4
* This field has 16 bit on ina238. ina228 adds another 4 bits of
* precision. ina238 conversion factors can still be applied when
* dividing by 16.
*/
*val = (regval * data->config->bus_voltage_lsb) / 1000 / 16;
return 0;
}
static int ina238_read_in(struct device *dev, u32 attr, int channel, static int ina238_read_in(struct device *dev, u32 attr, int channel,
long *val) long *val)
{ {
@ -211,6 +286,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
case 0: case 0:
switch (attr) { switch (attr) {
case hwmon_in_input: case hwmon_in_input:
if (data->config->has_20bit_voltage_current)
return ina228_read_shunt_voltage(dev, attr, channel, val);
reg = INA238_SHUNT_VOLTAGE; reg = INA238_SHUNT_VOLTAGE;
break; break;
case hwmon_in_max: case hwmon_in_max:
@ -234,6 +311,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
case 1: case 1:
switch (attr) { switch (attr) {
case hwmon_in_input: case hwmon_in_input:
if (data->config->has_20bit_voltage_current)
return ina228_read_bus_voltage(dev, attr, channel, val);
reg = INA238_BUS_VOLTAGE; reg = INA238_BUS_VOLTAGE;
break; break;
case hwmon_in_max: case hwmon_in_max:
@ -271,7 +350,7 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
if (channel == 0) if (channel == 0)
/* gain of 1 -> LSB / 4 */ /* gain of 1 -> LSB / 4 */
*val = (regval * INA238_SHUNT_VOLTAGE_LSB) * *val = (regval * INA238_SHUNT_VOLTAGE_LSB) *
data->gain / (1000 * 4); data->gain / (1000 * 4);
else else
*val = (regval * data->config->bus_voltage_lsb) / 1000; *val = (regval * data->config->bus_voltage_lsb) / 1000;
break; break;
@ -341,13 +420,25 @@ static int ina238_read_current(struct device *dev, u32 attr, long *val)
switch (attr) { switch (attr) {
case hwmon_curr_input: case hwmon_curr_input:
err = regmap_read(data->regmap, INA238_CURRENT, &regval); if (data->config->has_20bit_voltage_current) {
if (err < 0) err = ina238_read_field_s20(data->client, INA238_CURRENT, &regval);
return err; if (err)
return err;
} else {
err = regmap_read(data->regmap, INA238_CURRENT, &regval);
if (err < 0)
return err;
/* sign-extend */
regval = (s16)regval;
}
/* Signed register, fixed 1mA current lsb. result in mA */ /* Signed register, fixed 1mA current lsb. result in mA */
*val = div_s64((s16)regval * INA238_FIXED_SHUNT * data->gain, *val = div_s64((s64)regval * INA238_FIXED_SHUNT * data->gain,
data->rshunt * 4); data->rshunt * 4);
/* Account for 4 bit offset */
if (data->config->has_20bit_voltage_current)
*val /= 16;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -370,7 +461,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
return err; return err;
/* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
data->config->power_calculate_factor, 4 * 100 * data->rshunt); data->config->power_calculate_factor, 4 * 100 * data->rshunt);
/* Clamp value to maximum value of long */ /* Clamp value to maximum value of long */
*val = clamp_val(power, 0, LONG_MAX); *val = clamp_val(power, 0, LONG_MAX);
@ -381,7 +472,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
return err; return err;
/* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
data->config->power_calculate_factor, 4 * 100 * data->rshunt); data->config->power_calculate_factor, 4 * 100 * data->rshunt);
/* Clamp value to maximum value of long */ /* Clamp value to maximum value of long */
*val = clamp_val(power, 0, LONG_MAX); *val = clamp_val(power, 0, LONG_MAX);
@ -395,7 +486,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
* Truncated 24-bit compare register, lower 8-bits are * Truncated 24-bit compare register, lower 8-bits are
* truncated. Same conversion to/from uW as POWER register. * truncated. Same conversion to/from uW as POWER register.
*/ */
power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain * power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain *
data->config->power_calculate_factor, 4 * 100 * data->rshunt); data->config->power_calculate_factor, 4 * 100 * data->rshunt);
/* Clamp value to maximum value of long */ /* Clamp value to maximum value of long */
*val = clamp_val(power, 0, LONG_MAX); *val = clamp_val(power, 0, LONG_MAX);
@ -448,7 +539,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val)
return err; return err;
/* Signed, result in mC */ /* Signed, result in mC */
*val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
(s64)data->config->temp_lsb, 10000); (s64)data->config->temp_lsb, 10000);
break; break;
case hwmon_temp_max: case hwmon_temp_max:
err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval); err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval);
@ -456,7 +547,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val)
return err; return err;
/* Signed, result in mC */ /* Signed, result in mC */
*val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
(s64)data->config->temp_lsb, 10000); (s64)data->config->temp_lsb, 10000);
break; break;
case hwmon_temp_max_alarm: case hwmon_temp_max_alarm:
err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval); err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval);
@ -501,8 +592,8 @@ static ssize_t energy1_input_show(struct device *dev,
return ret; return ret;
/* result in uJ */ /* result in uJ */
energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 * energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 *
data->config->power_calculate_factor, 4 * data->rshunt); data->config->power_calculate_factor, 4 * data->rshunt);
return sysfs_emit(buf, "%llu\n", energy); return sysfs_emit(buf, "%llu\n", energy);
} }
@ -750,6 +841,7 @@ static int ina238_probe(struct i2c_client *client)
} }
static const struct i2c_device_id ina238_id[] = { static const struct i2c_device_id ina238_id[] = {
{ "ina228", ina228 },
{ "ina237", ina237 }, { "ina237", ina237 },
{ "ina238", ina238 }, { "ina238", ina238 },
{ "sq52206", sq52206 }, { "sq52206", sq52206 },
@ -758,6 +850,10 @@ static const struct i2c_device_id ina238_id[] = {
MODULE_DEVICE_TABLE(i2c, ina238_id); MODULE_DEVICE_TABLE(i2c, ina238_id);
static const struct of_device_id __maybe_unused ina238_of_match[] = { static const struct of_device_id __maybe_unused ina238_of_match[] = {
{
.compatible = "ti,ina228",
.data = (void *)ina228
},
{ {
.compatible = "ti,ina237", .compatible = "ti,ina237",
.data = (void *)ina237 .data = (void *)ina237

View File

@ -177,13 +177,15 @@ static const unsigned int ltc4282_out_rates[] = {
LTC4282_CLKOUT_CNV, LTC4282_CLKOUT_SYSTEM LTC4282_CLKOUT_CNV, LTC4282_CLKOUT_SYSTEM
}; };
static long ltc4282_round_rate(struct clk_hw *hw, unsigned long rate, static int ltc4282_determine_rate(struct clk_hw *hw,
unsigned long *parent_rate) struct clk_rate_request *req)
{ {
int idx = find_closest(rate, ltc4282_out_rates, int idx = find_closest(req->rate, ltc4282_out_rates,
ARRAY_SIZE(ltc4282_out_rates)); ARRAY_SIZE(ltc4282_out_rates));
return ltc4282_out_rates[idx]; req->rate = ltc4282_out_rates[idx];
return 0;
} }
static unsigned long ltc4282_recalc_rate(struct clk_hw *hw, static unsigned long ltc4282_recalc_rate(struct clk_hw *hw,
@ -1124,7 +1126,7 @@ static ssize_t ltc4282_energy_show(struct device *dev,
static const struct clk_ops ltc4282_ops = { static const struct clk_ops ltc4282_ops = {
.recalc_rate = ltc4282_recalc_rate, .recalc_rate = ltc4282_recalc_rate,
.round_rate = ltc4282_round_rate, .determine_rate = ltc4282_determine_rate,
.set_rate = ltc4282_set_rate, .set_rate = ltc4282_set_rate,
.disable = ltc4282_disable, .disable = ltc4282_disable,
}; };
@ -1596,7 +1598,7 @@ static const struct hwmon_ops ltc4282_hwmon_ops = {
.read_string = ltc4282_read_labels, .read_string = ltc4282_read_labels,
}; };
static const struct hwmon_chip_info ltc2947_chip_info = { static const struct hwmon_chip_info ltc4282_chip_info = {
.ops = &ltc4282_hwmon_ops, .ops = &ltc4282_hwmon_ops,
.info = ltc4282_info, .info = ltc4282_info,
}; };
@ -1717,7 +1719,7 @@ static int ltc4282_probe(struct i2c_client *i2c)
mutex_init(&st->lock); mutex_init(&st->lock);
hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st, hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st,
&ltc2947_chip_info, &ltc4282_chip_info,
ltc4282_groups); ltc4282_groups);
if (IS_ERR(hwmon)) if (IS_ERR(hwmon))
return PTR_ERR(hwmon); return PTR_ERR(hwmon);

View File

@ -445,7 +445,7 @@ static ssize_t temp1_resolution_show(struct device *dev,
val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val); val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val);
return scnprintf(buf, PAGE_SIZE, "%u\n", max31827_resolutions[val]); return sysfs_emit(buf, "%u\n", max31827_resolutions[val]);
} }
static ssize_t temp1_resolution_store(struct device *dev, static ssize_t temp1_resolution_store(struct device *dev,

View File

@ -67,6 +67,15 @@ config SENSORS_ADP1050
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called adp1050. be called adp1050.
config SENSORS_ADP1050_REGULATOR
bool "Regulator support for ADP1050 and compatibles"
depends on SENSORS_ADP1050 && REGULATOR
help
If you say yes here you get regulator support for Analog Devices
LTP8800-1A, LTP8800-4A, and LTP8800-2. LTP8800 is a family of DC/DC
µModule regulators that can provide microprocessor power from 54V
power distribution architecture.
config SENSORS_BEL_PFE config SENSORS_BEL_PFE
tristate "Bel PFE Compatible Power Supplies" tristate "Bel PFE Compatible Power Supplies"
help help

View File

@ -11,6 +11,12 @@
#include "pmbus.h" #include "pmbus.h"
#if IS_ENABLED(CONFIG_SENSORS_ADP1050_REGULATOR)
static const struct regulator_desc adp1050_reg_desc[] = {
PMBUS_REGULATOR_ONE("vout"),
};
#endif /* CONFIG_SENSORS_ADP1050_REGULATOR */
static struct pmbus_driver_info adp1050_info = { static struct pmbus_driver_info adp1050_info = {
.pages = 1, .pages = 1,
.format[PSC_VOLTAGE_IN] = linear, .format[PSC_VOLTAGE_IN] = linear,
@ -23,19 +29,79 @@ static struct pmbus_driver_info adp1050_info = {
| PMBUS_HAVE_STATUS_TEMP, | PMBUS_HAVE_STATUS_TEMP,
}; };
static struct pmbus_driver_info adp1051_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_TEMPERATURE] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT
| PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP,
};
static struct pmbus_driver_info adp1055_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_TEMPERATURE] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3
| PMBUS_HAVE_POUT
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP,
};
static struct pmbus_driver_info ltp8800_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_TEMPERATURE] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT
| PMBUS_HAVE_TEMP
| PMBUS_HAVE_POUT
| PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP,
#if IS_ENABLED(CONFIG_SENSORS_ADP1050_REGULATOR)
.num_regulators = 1,
.reg_desc = adp1050_reg_desc,
#endif
};
static int adp1050_probe(struct i2c_client *client) static int adp1050_probe(struct i2c_client *client)
{ {
return pmbus_do_probe(client, &adp1050_info); struct pmbus_driver_info *info;
info = (struct pmbus_driver_info *)i2c_get_match_data(client);
if (!info)
return -ENODEV;
return pmbus_do_probe(client, info);
} }
static const struct i2c_device_id adp1050_id[] = { static const struct i2c_device_id adp1050_id[] = {
{"adp1050"}, { .name = "adp1050", .driver_data = (kernel_ulong_t)&adp1050_info },
{ .name = "adp1051", .driver_data = (kernel_ulong_t)&adp1051_info },
{ .name = "adp1055", .driver_data = (kernel_ulong_t)&adp1055_info },
{ .name = "ltp8800", .driver_data = (kernel_ulong_t)&ltp8800_info },
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, adp1050_id); MODULE_DEVICE_TABLE(i2c, adp1050_id);
static const struct of_device_id adp1050_of_match[] = { static const struct of_device_id adp1050_of_match[] = {
{ .compatible = "adi,adp1050"}, { .compatible = "adi,adp1050", .data = &adp1050_info },
{ .compatible = "adi,adp1051", .data = &adp1051_info },
{ .compatible = "adi,adp1055", .data = &adp1055_info },
{ .compatible = "adi,ltp8800", .data = &ltp8800_info },
{} {}
}; };
MODULE_DEVICE_TABLE(of, adp1050_of_match); MODULE_DEVICE_TABLE(of, adp1050_of_match);

View File

@ -63,6 +63,7 @@ enum chips {
raa228228, raa228228,
raa229001, raa229001,
raa229004, raa229004,
raa229621,
}; };
enum variants { enum variants {
@ -465,6 +466,7 @@ static const struct i2c_device_id raa_dmpvr_id[] = {
{"raa228228", raa_dmpvr2_2rail_nontc}, {"raa228228", raa_dmpvr2_2rail_nontc},
{"raa229001", raa_dmpvr2_2rail}, {"raa229001", raa_dmpvr2_2rail},
{"raa229004", raa_dmpvr2_2rail}, {"raa229004", raa_dmpvr2_2rail},
{"raa229621", raa_dmpvr2_2rail},
{} {}
}; };
@ -512,6 +514,7 @@ static const struct of_device_id isl68137_of_match[] = {
{ .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc }, { .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc },
{ .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail }, { .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail },
{ .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail }, { .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail },
{ .compatible = "renesas,raa229621", .data = (void *)raa_dmpvr2_2rail },
{ }, { },
}; };

View File

@ -16,7 +16,7 @@
#include "pmbus.h" #include "pmbus.h"
enum chips { enum chips {
tps53647, tps53667, tps53676, tps53679, tps53681, tps53688 tps53647, tps53667, tps53676, tps53679, tps53681, tps53685, tps53688
}; };
#define TPS53647_PAGE_NUM 1 #define TPS53647_PAGE_NUM 1
@ -31,7 +31,8 @@ enum chips {
#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ #define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */
#define TPS53679_PAGE_NUM 2 #define TPS53679_PAGE_NUM 2
#define TPS53681_DEVICE_ID 0x81 #define TPS53681_DEVICE_ID "\x81"
#define TPS53685_DEVICE_ID "TIShP"
#define TPS53681_PMBUS_REVISION 0x33 #define TPS53681_PMBUS_REVISION 0x33
@ -86,10 +87,12 @@ static int tps53679_identify_phases(struct i2c_client *client,
} }
static int tps53679_identify_chip(struct i2c_client *client, static int tps53679_identify_chip(struct i2c_client *client,
u8 revision, u16 id) u8 revision, char *id)
{ {
u8 buf[I2C_SMBUS_BLOCK_MAX]; u8 buf[I2C_SMBUS_BLOCK_MAX];
int ret; int ret;
int buf_len;
int id_len;
ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION); ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION);
if (ret < 0) if (ret < 0)
@ -102,8 +105,14 @@ static int tps53679_identify_chip(struct i2c_client *client,
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret != 1 || buf[0] != id) {
dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); /* Adjust length if null terminator if present */
buf_len = (buf[ret - 1] != '\x00' ? ret : ret - 1);
id_len = strlen(id);
if (buf_len != id_len || strncmp(id, buf, id_len)) {
dev_err(&client->dev, "Unexpected device ID: %*ph\n", ret, buf);
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
@ -117,7 +126,7 @@ static int tps53679_identify_chip(struct i2c_client *client,
*/ */
static int tps53679_identify_multiphase(struct i2c_client *client, static int tps53679_identify_multiphase(struct i2c_client *client,
struct pmbus_driver_info *info, struct pmbus_driver_info *info,
int pmbus_rev, int device_id) int pmbus_rev, char *device_id)
{ {
int ret; int ret;
@ -138,6 +147,16 @@ static int tps53679_identify(struct i2c_client *client,
return tps53679_identify_mode(client, info); return tps53679_identify_mode(client, info);
} }
static int tps53685_identify(struct i2c_client *client,
struct pmbus_driver_info *info)
{
info->func[1] |= PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
PMBUS_HAVE_STATUS_INPUT;
info->format[PSC_VOLTAGE_OUT] = linear;
return tps53679_identify_chip(client, TPS53681_PMBUS_REVISION,
TPS53685_DEVICE_ID);
}
static int tps53681_identify(struct i2c_client *client, static int tps53681_identify(struct i2c_client *client,
struct pmbus_driver_info *info) struct pmbus_driver_info *info)
{ {
@ -263,6 +282,10 @@ static int tps53679_probe(struct i2c_client *client)
info->identify = tps53681_identify; info->identify = tps53681_identify;
info->read_word_data = tps53681_read_word_data; info->read_word_data = tps53681_read_word_data;
break; break;
case tps53685:
info->pages = TPS53679_PAGE_NUM;
info->identify = tps53685_identify;
break;
default: default:
return -ENODEV; return -ENODEV;
} }
@ -277,6 +300,7 @@ static const struct i2c_device_id tps53679_id[] = {
{"tps53676", tps53676}, {"tps53676", tps53676},
{"tps53679", tps53679}, {"tps53679", tps53679},
{"tps53681", tps53681}, {"tps53681", tps53681},
{"tps53685", tps53685},
{"tps53688", tps53688}, {"tps53688", tps53688},
{} {}
}; };
@ -289,6 +313,7 @@ static const struct of_device_id __maybe_unused tps53679_of_match[] = {
{.compatible = "ti,tps53676", .data = (void *)tps53676}, {.compatible = "ti,tps53676", .data = (void *)tps53676},
{.compatible = "ti,tps53679", .data = (void *)tps53679}, {.compatible = "ti,tps53679", .data = (void *)tps53679},
{.compatible = "ti,tps53681", .data = (void *)tps53681}, {.compatible = "ti,tps53681", .data = (void *)tps53681},
{.compatible = "ti,tps53685", .data = (void *)tps53685},
{.compatible = "ti,tps53688", .data = (void *)tps53688}, {.compatible = "ti,tps53688", .data = (void *)tps53688},
{} {}
}; };

View File

@ -1448,7 +1448,8 @@ w83627ehf_do_read_temp(struct w83627ehf_data *data, u32 attr,
return 0; return 0;
case hwmon_temp_alarm: case hwmon_temp_alarm:
if (channel < 3) { if (channel < 3) {
int bit[] = { 4, 5, 13 }; static const int bit[] = { 4, 5, 13 };
*val = (data->alarms >> bit[channel]) & 1; *val = (data->alarms >> bit[channel]) & 1;
return 0; return 0;
} }
@ -1479,7 +1480,8 @@ w83627ehf_do_read_in(struct w83627ehf_data *data, u32 attr,
return 0; return 0;
case hwmon_in_alarm: case hwmon_in_alarm:
if (channel < 10) { if (channel < 10) {
int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 }; static const int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 };
*val = (data->alarms >> bit[channel]) & 1; *val = (data->alarms >> bit[channel]) & 1;
return 0; return 0;
} }
@ -1507,7 +1509,8 @@ w83627ehf_do_read_fan(struct w83627ehf_data *data, u32 attr,
return 0; return 0;
case hwmon_fan_alarm: case hwmon_fan_alarm:
if (channel < 5) { if (channel < 5) {
int bit[] = { 6, 7, 11, 10, 23 }; static const int bit[] = { 6, 7, 11, 10, 23 };
*val = (data->alarms >> bit[channel]) & 1; *val = (data->alarms >> bit[channel]) & 1;
return 0; return 0;
} }

View File

@ -9,14 +9,20 @@
* struct emc2305_platform_data - EMC2305 driver platform data * struct emc2305_platform_data - EMC2305 driver platform data
* @max_state: maximum cooling state of the cooling device; * @max_state: maximum cooling state of the cooling device;
* @pwm_num: number of active channels; * @pwm_num: number of active channels;
* @pwm_output_mask: PWM output mask
* @pwm_polarity_mask: PWM polarity mask
* @pwm_separate: separate PWM settings for every channel; * @pwm_separate: separate PWM settings for every channel;
* @pwm_min: array of minimum PWM per channel; * @pwm_min: array of minimum PWM per channel;
* @pwm_freq: array of PWM frequency per channel
*/ */
struct emc2305_platform_data { struct emc2305_platform_data {
u8 max_state; u8 max_state;
u8 pwm_num; u8 pwm_num;
u8 pwm_output_mask;
u8 pwm_polarity_mask;
bool pwm_separate; bool pwm_separate;
u8 pwm_min[EMC2305_PWM_MAX]; u8 pwm_min[EMC2305_PWM_MAX];
u16 pwm_freq[EMC2305_PWM_MAX];
}; };
#endif #endif