diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml index 1f98da32f3fe..37e1dc9c7dd3 100644 --- a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml +++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml @@ -26,6 +26,7 @@ properties: - lltc,ltc3886 - lltc,ltc3887 - lltc,ltc3889 + - lltc,ltc7841 - lltc,ltc7880 - lltc,ltm2987 - lltc,ltm4664 @@ -50,6 +51,7 @@ properties: * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1 + * ltc7841 : vout0 * ltc7880 : vout0 - vout1 * ltc3883 : vout0 * ltm4664 : vout0 - vout1 diff --git a/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml new file mode 100644 index 000000000000..c1e5dedc2f6a --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/nuvoton,nct7363.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NCT7363Y Hardware Monitoring IC + +maintainers: + - Ban Feng + +description: | + The NCT7363Y is a fan controller which provides up to 16 independent + FAN input monitors, and up to 16 independent PWM outputs with SMBus interface. + + Datasheets: Available from Nuvoton upon request + +properties: + compatible: + enum: + - nuvoton,nct7363 + - nuvoton,nct7362 + + reg: + maxItems: 1 + + "#pwm-cells": + const: 2 + +patternProperties: + "^fan-[0-9]+$": + $ref: fan-common.yaml# + unevaluatedProperties: false + required: + - pwms + - tach-ch + +required: + - compatible + - reg + - "#pwm-cells" + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hwmon: hwmon@22 { + compatible = "nuvoton,nct7363"; + reg = <0x22>; + #pwm-cells = <2>; + + fan-0 { + pwms = <&hwmon 0 50000>; + tach-ch = /bits/ 8 <0x00>; + }; + fan-1 { + pwms = <&hwmon 1 50000>; + tach-ch = /bits/ 8 <0x01>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml new file mode 100644 index 000000000000..bac5f8e352aa --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml @@ -0,0 +1,148 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/isil,isl68137.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Digital Multiphase Voltage Regulators with PMBus + +maintainers: + - Grant Peltier + +description: | + Renesas digital multiphase voltage regulators with PMBus. + https://www.renesas.com/en/products/power-management/multiphase-power/multiphase-dcdc-switching-controllers + +properties: + compatible: + enum: + - isil,isl68137 + - renesas,isl68220 + - renesas,isl68221 + - renesas,isl68222 + - renesas,isl68223 + - renesas,isl68224 + - renesas,isl68225 + - renesas,isl68226 + - renesas,isl68227 + - renesas,isl68229 + - renesas,isl68233 + - renesas,isl68239 + - renesas,isl69222 + - renesas,isl69223 + - renesas,isl69224 + - renesas,isl69225 + - renesas,isl69227 + - renesas,isl69228 + - renesas,isl69234 + - renesas,isl69236 + - renesas,isl69239 + - renesas,isl69242 + - renesas,isl69243 + - renesas,isl69247 + - renesas,isl69248 + - renesas,isl69254 + - renesas,isl69255 + - renesas,isl69256 + - renesas,isl69259 + - isil,isl69260 + - renesas,isl69268 + - isil,isl69269 + - renesas,isl69298 + - renesas,raa228000 + - renesas,raa228004 + - renesas,raa228006 + - renesas,raa228228 + - renesas,raa229001 + - renesas,raa229004 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@([0-3])$": + type: object + description: + Container for properties specific to a particular channel (rail). + + properties: + reg: + description: The channel (rail) index. + items: + minimum: 0 + maximum: 3 + + vout-voltage-divider: + description: | + Resistances of a voltage divider placed between Vout and the voltage + sense (Vsense) pin for the given channel (rail). It has two numbers + representing the resistances of the voltage divider provided as + which yields an adjusted Vout as + Vout_adj = Vout * Rtotal / Rout given the original Vout as reported + by the Vsense pin. Given a circuit configuration similar to the one + below, Rtotal = R1 + Rout. + + Vout ----. + | + .-----. + | R1 | + '-----' + | + +---- Vsense + | + .-----. + | Rout| + '-----' + | + GND + + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + isl68239@60 { + compatible = "isil,isl68137"; + reg = <0x60>; + }; + }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + isl68239@60 { + compatible = "renesas,isl68239"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + vout-voltage-divider = <1000 2000>; // Reported Vout/Pout would be scaled by 2 + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml new file mode 100644 index 000000000000..f7bc4f077929 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/pmbus/mps,mp2975.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MPS MP2975 Synchronous Buck Regulator + +maintainers: + - Naresh Solanki + +description: + The MPS MP2971, MP2973 & MP2975 is a multi-phase voltage regulator + designed for use in high-performance computing and server + applications. It supports I2C/PMBus for control and monitoring. + +properties: + compatible: + enum: + - mps,mp2971 + - mps,mp2973 + - mps,mp2975 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + regulators: + type: object + description: + List of regulators provided by this controller. + + patternProperties: + "^vout[0-1]$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@58 { + compatible = "mps,mp2973"; + reg = <0x58>; + + interrupt-parent = <&smb_pex_cpu1_event>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + + regulators { + vout0 { + regulator-name = "pvccin_cpu1"; + regulator-enable-ramp-delay = <200>; + }; + vout1 { + regulator-name = "pvccfa_ehv_fivra_cpu1"; + regulator-enable-ramp-delay = <200>; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml new file mode 100644 index 000000000000..f4115870e450 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/ti,tps25990.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TPS25990 Stackable eFuse + +maintainers: + - Jerome Brunet + +description: + The TI TPS25990 is an integrated, high-current circuit + protection and power management device with PMBUS interface + +properties: + compatible: + const: ti,tps25990 + + reg: + maxItems: 1 + + ti,rimon-micro-ohms: + description: + micro Ohms value of the resistance installed between the Imon pin + and the ground reference. + + interrupts: + description: PMBUS SMB Alert Interrupt. + maxItems: 1 + + regulators: + type: object + description: + list of regulators provided by this controller. + + properties: + vout: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac1: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac2: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + additionalProperties: false + +required: + - compatible + - reg + - ti,rimon-micro-ohms + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hw-monitor@46 { + compatible = "ti,tps25990"; + reg = <0x46>; + + interrupt-parent = <&gpio>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; + ti,rimon-micro-ohms = <1370000000>; + + regulators { + cpu0_vout: vout { + regulator-name = "main_cpu0"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml new file mode 100644 index 000000000000..4aa62d67e1a9 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/pmbus/vicor,pli1209bc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Vicor PLI1209BC Power Regulator + +maintainers: + - Marcello Sylvester Bauer + - Naresh Solanki + +description: + The Vicor PLI1209BC is a Digital Supervisor with Isolation for use + with BCM Bus Converter Modules. + +properties: + compatible: + enum: + - vicor,pli1209bc + + reg: + maxItems: 1 + + regulators: + type: object + description: + List of regulators provided by this controller. + + properties: + vout2: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@5f { + compatible = "vicor,pli1209bc"; + reg = <0x5f>; + + regulators { + p12v_d: vout2 { + regulator-name = "bcm3"; + regulator-boot-on; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml index 4e5abf7580cc..8b4ed5ee962f 100644 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml @@ -31,6 +31,16 @@ properties: it must be self resetting edge interrupts. maxItems: 1 + fan-stop-to-start-percent: + description: + Minimum fan RPM in percent to start when stopped. + minimum: 0 + maximum: 100 + + fan-stop-to-start-us: + description: + Time to wait in microseconds after start when stopped. + pulses-per-revolution: description: Define the number of pulses per fan revolution for each tachometer diff --git a/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml b/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml new file mode 100644 index 000000000000..dd82a80e4115 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/renesas,isl28022.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas ISL28022 power monitor + +maintainers: + - Carsten Spieß + +description: | + The ISL28022 is a power monitor with I2C interface. The device monitors + voltage, current via shunt resistor and calculated power. + + Datasheets: + https://www.renesas.com/us/en/www/doc/datasheet/isl28022.pdf + +properties: + compatible: + const: renesas,isl28022 + + reg: + maxItems: 1 + + shunt-resistor-micro-ohms: + description: + Shunt resistor value in micro-Ohm + minimum: 800 + default: 10000 + + renesas,shunt-range-microvolt: + description: + Maximal shunt voltage range of +/- 40 mV, 80 mV, 160 mV or 320 mV + default: 320000 + enum: [40000, 80000, 160000, 320000] + + renesas,average-samples: + description: + Number of samples to be used to report voltage, current and power values. + default: 1 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8, 16, 32, 64, 128] + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + power-monitor@40 { + compatible = "renesas,isl28022"; + reg = <0x40>; + shunt-resistor-micro-ohms = <8000>; + renesas,shunt-range-microvolt = <40000>; + renesas,average-samples = <128>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml new file mode 100644 index 000000000000..5d33f1a23d03 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/ti,amc6821.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AMC6821 Intelligent Temperature Monitor and PWM Fan Controller + +maintainers: + - Farouk Bouabid + - Quentin Schulz + +description: + Intelligent temperature monitor and pulse-width modulation (PWM) fan + controller. + +properties: + compatible: + oneOf: + - items: + - const: tsd,mule + - const: ti,amc6821 + - const: ti,amc6821 + + reg: + maxItems: 1 + + i2c-mux: + type: object + +required: + - compatible + - reg + +if: + properties: + compatible: + contains: + const: tsd,mule + +then: + required: + - i2c-mux + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fan@18 { + compatible = "tsd,mule", "ti,amc6821"; + reg = <0x18>; + + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index 6ae961732e6b..05a9cb36cd82 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -20,6 +20,7 @@ description: | properties: compatible: enum: + - silergy,sy24655 - ti,ina209 - ti,ina219 - ti,ina220 diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml index 0ad10d43fac0..a6f9319e068d 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml @@ -4,22 +4,26 @@ $id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: TMP108 temperature sensor +title: TMP108/P3T1085(NXP) temperature sensor maintainers: - Krzysztof Kozlowski description: | - The TMP108 is a digital-output temperature sensor with a + The TMP108/P3T1085(NXP) is a digital-output temperature sensor with a dynamically-programmable limit window, and under- and overtemperature alert functions. + P3T1085(NXP) support I3C. + Datasheets: https://www.ti.com/product/TMP108 + https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf properties: compatible: enum: + - nxp,p3t1085 - ti,tmp108 interrupts: diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 9bf0fb17a05e..bf7dded9451d 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -153,12 +153,6 @@ properties: - isil,isl29028 # Intersil ISL29030 Ambient Light and Proximity Sensor - isil,isl29030 - # Intersil ISL68137 Digital Output Configurable PWM Controller - - isil,isl68137 - # Intersil ISL69260 PMBus Voltage Regulator - - isil,isl69260 - # Intersil ISL69269 PMBus Voltage Regulator - - isil,isl69269 # Intersil ISL76682 Ambient Light Sensor - isil,isl76682 # JEDEC JESD300 (SPD5118) Hub and Serial Presence Detect @@ -279,12 +273,6 @@ properties: - mps,mp2888 # Monolithic Power Systems Inc. multi-phase controller mp2891 - mps,mp2891 - # Monolithic Power Systems Inc. multi-phase controller mp2971 - - mps,mp2971 - # Monolithic Power Systems Inc. multi-phase controller mp2973 - - mps,mp2973 - # Monolithic Power Systems Inc. multi-phase controller mp2975 - - mps,mp2975 # Monolithic Power Systems Inc. multi-phase controller mp2993 - mps,mp2993 # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5920 @@ -357,8 +345,6 @@ properties: - swir,mangoh-iotport-spi # Ambient Light Sensor with SMBUS/Two Wire Serial Interface - taos,tsl2550 - # Temperature Monitoring and Fan Control - - ti,amc6821 # Temperature and humidity sensor with i2c interface - ti,hdc1000 # Temperature and humidity sensor with i2c interface @@ -400,8 +386,6 @@ properties: - ti,tps546d24 # I2C Touch-Screen Controller - ti,tsc2003 - # Vicor Corporation Digital Supervisor - - vicor,pli1209bc # Winbond/Nuvoton H/W Monitor - winbond,w83793 diff --git a/Documentation/hwmon/f71882fg.rst b/Documentation/hwmon/f71882fg.rst index 38e30fbd4806..53d32bf06b70 100644 --- a/Documentation/hwmon/f71882fg.rst +++ b/Documentation/hwmon/f71882fg.rst @@ -178,10 +178,11 @@ Writing an unsupported mode will result in an invalid parameter error. available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode - You can define a number of temperature/fan speed trip points, which % the - fan should run at at this temp and which temp a fan should follow using the - standard sysfs interface. The number and type of trip points is chip - depended, see which files are available in sysfs. + You can define a number of temperature/fan speed trip points that specify + the percentage at which the fan should run at each temperature, and which + temperature sensor a fan should follow, using the standard sysfs interface. + The number and type of trip points are chip dependent - see the available + files in sysfs. Fan/PWM channel 3 of the F8000 is always in this mode! * 3: Thermostat mode (Only available on the F8000 when in duty cycle mode) diff --git a/Documentation/hwmon/ina2xx.rst b/Documentation/hwmon/ina2xx.rst index 7f1939b40f74..a3860aae444c 100644 --- a/Documentation/hwmon/ina2xx.rst +++ b/Documentation/hwmon/ina2xx.rst @@ -53,6 +53,27 @@ Supported chips: https://www.ti.com/ + * Texas Instruments INA260 + + Prefix: 'ina260' + + Addresses: I2C 0x40 - 0x4f + + Datasheet: Publicly available at the Texas Instruments website + + https://www.ti.com/ + + * Silergy SY24655 + + Prefix: 'sy24655' + + Addresses: I2C 0x40 - 0x4f + + Datasheet: Publicly available at the Silergy website + + https://us1.silergy.com/ + + Author: Lothar Felten Description @@ -72,6 +93,14 @@ INA230 and INA231 are high or low side current shunt and power monitors with an I2C interface. The chips monitor both a shunt voltage drop and bus supply voltage. +INA260 is a high or low side current and power monitor with integrated shunt +resistor. + +The SY24655 is a high- and low-side current shunt and power monitor with an I2C +interface. The SY24655 supports both shunt drop and supply voltage, with +programmable calibration value and conversion times. The SY24655 can also +calculate average power for use in energy conversion. + The shunt value in micro-ohms can be set via platform data or device tree at compile-time or via the shunt_resistor attribute in sysfs at run-time. Please refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings @@ -87,16 +116,16 @@ The actual programmed interval may vary from the desired value. General sysfs entries --------------------- -======================= =============================== +======================= =============================================== in0_input Shunt voltage(mV) channel in1_input Bus voltage(mV) channel curr1_input Current(mA) measurement channel power1_input Power(uW) measurement channel -shunt_resistor Shunt resistance(uOhm) channel -======================= =============================== +shunt_resistor Shunt resistance(uOhm) channel (not for ina260) +======================= =============================================== -Sysfs entries for ina226, ina230 and ina231 only ------------------------------------------------- +Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655 +------------------------------------------------------------------------ ======================= ==================================================== curr1_lcrit Critical low current @@ -117,6 +146,13 @@ update_interval data conversion time; affects number of samples used to average results for shunt and bus voltages. ======================= ==================================================== +Sysfs entries for sy24655 only +------------------------------ + +======================= ==================================================== +power1_average average power from last reading to the present. +======================= ==================================================== + .. note:: - Configure `shunt_resistor` before configure `power1_crit`, because power diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index ea3b5be8fe4f..55f1111594b2 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -96,6 +96,7 @@ Hardware Monitoring Kernel Drivers ir35221 ir38064 ir36021 + isl28022 isl68137 it87 jc42 @@ -174,6 +175,7 @@ Hardware Monitoring Kernel Drivers mpq8785 nct6683 nct6775 + nct7363 nct7802 nct7904 npcm750-pwm-fan diff --git a/Documentation/hwmon/isl28022.rst b/Documentation/hwmon/isl28022.rst new file mode 100644 index 000000000000..8d4422a2dacd --- /dev/null +++ b/Documentation/hwmon/isl28022.rst @@ -0,0 +1,63 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver isl28022 +====================== + +Supported chips: + + * Renesas ISL28022 + + Prefix: 'isl28022' + + Addresses scanned: none + + Datasheet: Publicly available at the Renesas website + + https://www.renesas.com/us/en/www/doc/datasheet/isl28022.pdf + +Author: + Carsten Spieß + +Description +----------- + +The ISL28022 is a power monitor with I2C interface. The device monitors +voltage, current via shunt resistor and calculated power. + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +device explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + +The shunt value in micro-ohms, shunt voltage range and averaging can be set +with device properties. +Please refer to the Documentation/devicetree/bindings/hwmon/isl,isl28022.yaml +for bindings if the device tree is used. + +The driver supports only shunt and bus continuous ADC mode at 15bit resolution. +Averaging can be set from 1 to 128 samples (power of 2) on both channels. +Shunt voltage range of 40, 80, 160 or 320mV is allowed +The bus voltage range is 60V fixed. + +Sysfs entries +------------- + +The following attributes are supported. All attributes are read-only. + +======================= ======================================================= +in0_input bus voltage (milli Volt) + +curr1_input current (milli Ampere) +power1_input power (micro Watt) +======================= ======================================================= + +Debugfs entries +--------------- + +The following attributes are supported. All attributes are read-only. + +======================= ======================================================= +shunt_voltage shunt voltage (micro Volt) +======================= ======================================================= diff --git a/Documentation/hwmon/ltc2978.rst b/Documentation/hwmon/ltc2978.rst index edf24e5e1e11..651ca4904c66 100644 --- a/Documentation/hwmon/ltc2978.rst +++ b/Documentation/hwmon/ltc2978.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + Kernel driver ltc2978 ===================== @@ -117,6 +119,14 @@ Supported chips: Datasheet: https://www.analog.com/en/products/ltc3889 + * Linear Technology LTC7841 + + Prefix: 'ltc7841' + + Addresses scanned: - + + Datasheet: https://www.analog.com/en/products/ltc7841 + * Linear Technology LTC7880 Prefix: 'ltc7880' @@ -290,6 +300,7 @@ in[N]_label "vout[1-8]". LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 in[N]_input Measured output voltage. @@ -420,6 +431,7 @@ curr[N]_label "iout[1-4]". LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 curr[N]_input Measured output current. diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index 9c11a9518c67..6cc5088b26b7 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -136,7 +136,7 @@ PEC Support When reading a register value, the PEC byte is computed and sent by the chip. -PEC on word data transaction respresents a signifcant increase in bandwitdh +PEC on word data transaction represents a significant increase in bandwidth usage (+33% for both write and reads) in normal conditions. Since this operation implies there will be an extra delay to each diff --git a/Documentation/hwmon/nct7363.rst b/Documentation/hwmon/nct7363.rst new file mode 100644 index 000000000000..623cb4f0c8ce --- /dev/null +++ b/Documentation/hwmon/nct7363.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver nct7363 +===================== + +Supported chip: + + * Nuvoton NCT7363Y + + Prefix: nct7363 + + Addresses: I2C 0x20, 0x21, 0x22, 0x23 + +Author: Ban Feng + + +Description +----------- + +The NCT7363Y is a fan controller which provides up to 16 independent +FAN input monitors, and up to 16 independent PWM outputs with SMBus interface. + + +Sysfs entries +------------- + +Currently, the driver supports the following features: + +========== ========================================== +fanX_input provide current fan rotation value in RPM +fanX_alarm report fan low speed real status +fanX_min get or set fan count threshold + +pwmX get or set PWM fan control value. +========== ========================================== diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 1eaf2b015837..686a00265bf7 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -308,6 +308,10 @@ currently provides a flags field with four bits used:: #define PMBUS_READ_STATUS_AFTER_FAILED_CHECK BIT(3) + #define PMBUS_NO_WRITE_PROTECT BIT(4) + + #define PMBUS_USE_COEFFICIENTS_CMD BIT(5) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ @@ -358,3 +362,14 @@ This can be done by reading a known register. By setting this flag the driver will try to read the STATUS register after each failed register check. This read may fail, but it will put the chip into a known state. + +PMBUS_NO_WRITE_PROTECT + +Some PMBus chips respond with invalid data when reading the WRITE_PROTECT +register. For such chips, this flag should be set so that the PMBus core +driver doesn't use the WRITE_PROTECT command to determine its behavior. + +PMBUS_USE_COEFFICIENTS_CMD + +When this flag is set the PMBus core driver will use the COEFFICIENTS +register to initialize the coefficients for the direct mode format. diff --git a/Documentation/hwmon/sch5627.rst b/Documentation/hwmon/sch5627.rst index 8639dff234fc..5f521c6e90ab 100644 --- a/Documentation/hwmon/sch5627.rst +++ b/Documentation/hwmon/sch5627.rst @@ -39,7 +39,7 @@ Controlling fan speed --------------------- The SCH5627 allows for partially controlling the fan speed. If a temperature -channel excedes tempX_max, all fans are forced to maximum speed. The same is not +channel exceeds tempX_max, all fans are forced to maximum speed. The same is not true for tempX_crit, presumably some other measures to cool down the system are take in this case. In which way the value of fanX_min affects the fan speed is currently unknown. diff --git a/Documentation/hwmon/sht4x.rst b/Documentation/hwmon/sht4x.rst index daf21e763425..ba094ad0e281 100644 --- a/Documentation/hwmon/sht4x.rst +++ b/Documentation/hwmon/sht4x.rst @@ -42,4 +42,18 @@ humidity1_input Measured humidity in %H update_interval The minimum interval for polling the sensor, in milliseconds. Writable. Must be at least 2000. +heater_power The requested heater power, in milliwatts. + Available values: 20, 110, 200 (default: 200). +heater_time The requested operating time of the heater, + in milliseconds. + Available values: 100, 1000 (default 1000). +heater_enable Enable the heater with the selected power + and for the selected time in order to remove + condensed water from the sensor surface. The + heater cannot be manually turned off once + enabled (it will automatically turn off + after completing its operation). + + - 0: turned off (read-only value) + - 1: turn on =============== ============================================ diff --git a/Documentation/hwmon/tmp108.rst b/Documentation/hwmon/tmp108.rst index 6df7cf1b42f4..bc4941d98268 100644 --- a/Documentation/hwmon/tmp108.rst +++ b/Documentation/hwmon/tmp108.rst @@ -3,6 +3,14 @@ Kernel driver tmp108 Supported chips: + * NXP P3T1085 + + Prefix: 'p3t1085' + + Addresses scanned: none + + Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf + * Texas Instruments TMP108 Prefix: 'tmp108' diff --git a/MAINTAINERS b/MAINTAINERS index 6b3ef1161f89..afd984b3cc6c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12104,6 +12104,14 @@ F: drivers/isdn/Makefile F: drivers/isdn/hardware/ F: drivers/isdn/mISDN/ +ISL28022 HARDWARE MONITORING DRIVER +M: Carsten Spieß +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml +F: Documentation/hwmon/isl28022.rst +F: drivers/hwmon/isl28022.c + ISOFS FILESYSTEM M: Jan Kara L: linux-fsdevel@vger.kernel.org @@ -15947,6 +15955,14 @@ S: Maintained F: Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml F: drivers/hwmon/nct6775-i2c.c +NCT7363 HARDWARE MONITOR DRIVER +M: Ban Feng +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml +F: Documentation/hwmon/nct7363.rst +F: drivers/hwmon/nct7363.c + NETCONSOLE M: Breno Leitao S: Maintained @@ -16743,13 +16759,6 @@ S: Maintained F: Documentation/hwmon/nzxt-kraken3.rst F: drivers/hwmon/nzxt-kraken3.c -NZXT-SMART2 HARDWARE MONITORING DRIVER -M: Aleksandr Mezin -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/hwmon/nzxt-smart2.rst -F: drivers/hwmon/nzxt-smart2.c - OBJAGG M: Jiri Pirko L: netdev@vger.kernel.org @@ -22928,6 +22937,12 @@ F: include/linux/dma/k3-udma-glue.h F: include/linux/dma/ti-cppi5.h X: drivers/dma/ti/cppi41.c +TEXAS INSTRUMENTS TPS25990 HARDWARE MONITOR DRIVER +M: Jerome Brunet +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml + TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER M: Robert Marko M: Luka Perkov diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 1e3a1f4d5c5e..dd376602f3f1 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -855,6 +855,17 @@ config SENSORS_CORETEMP sensor inside your CPU. Most of the family 6 CPUs are supported. Check Documentation/hwmon/coretemp.rst for details. +config SENSORS_ISL28022 + tristate "Renesas ISL28022" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for ISL28022 power monitor. + Check Documentation/hwmon/isl28022.rst for details. + + This driver can also be built as a module. If so, the module + will be called isl28022. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" depends on HAS_IOPORT @@ -1670,6 +1681,17 @@ config SENSORS_NCT6775_I2C This driver can also be built as a module. If so, the module will be called nct6775-i2c. +config SENSORS_NCT7363 + tristate "Nuvoton NCT7363Y" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7363Y + hardware monitoring chip. + + This driver can also be built as a module. If so, the module + will be called nct7363. + config SENSORS_NCT7802 tristate "Nuvoton NCT7802Y" depends on I2C @@ -2167,11 +2189,12 @@ config SENSORS_INA2XX select REGMAP_I2C help If you say yes here you get support for INA219, INA220, INA226, - INA230, and INA231 power monitor chips. + INA230, INA231, INA260, and SY24655 power monitor chips. The INA2xx driver is configured for the default configuration of the part as described in the datasheet. - Default value for Rshunt is 10 mOhms. + Default value for Rshunt is 10 mOhms except for INA260 which has an + internal 2 mOhm shunt resistor. This driver can also be built as a module. If so, the module will be called ina2xx. @@ -2274,10 +2297,12 @@ config SENSORS_TMP103 config SENSORS_TMP108 tristate "Texas Instruments TMP108" depends on I2C + depends on I3C || !I3C select REGMAP_I2C + select REGMAP_I3C if I3C help If you say yes here you get support for Texas Instruments TMP108 - sensor chips. + sensor chips and NXP P3T1085. This driver can also be built as a module. If so, the module will be called tmp108. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 9554d2fdcf7b..b827b92f2a78 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA238) += ina238.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o +obj-$(CONFIG_SENSORS_ISL28022) += isl28022.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o @@ -171,6 +172,7 @@ obj-$(CONFIG_SENSORS_NCT6775_CORE) += nct6775-core.o nct6775-objs := nct6775-platform.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT6775_I2C) += nct6775-i2c.o +obj-$(CONFIG_SENSORS_NCT7363) += nct7363.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 93653ea05430..ba8c68ae4595 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1531,7 +1531,7 @@ static struct platform_driver abituguru_driver = { .pm = pm_sleep_ptr(&abituguru_pm), }, .probe = abituguru_probe, - .remove_new = abituguru_remove, + .remove = abituguru_remove, }; static int __init abituguru_detect(void) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 4501f0e49efb..b70330dc2198 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1147,12 +1147,12 @@ static int abituguru3_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume); static struct platform_driver abituguru3_driver = { - .driver = { + .driver = { .name = ABIT_UGURU3_NAME, .pm = pm_sleep_ptr(&abituguru3_pm), }, .probe = abituguru3_probe, - .remove_new = abituguru3_remove, + .remove = abituguru3_remove, }; static int __init abituguru3_dmi_detect(void) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 6c8a9c863528..2f1c9d97ad21 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -680,8 +680,9 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) { int res = 0; + /* _PMD method is optional. */ res = read_domain_devices(resource); - if (res) + if (res != -ENODEV) return res; if (resource->caps.flags & POWER_METER_CAN_MEASURE) { diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index ac64b407ed0e..1e3c6acd8974 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -893,7 +894,6 @@ static bool amc6821_volatile_reg(struct device *dev, unsigned int reg) static const struct regmap_config amc6821_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = AMC6821_REG_CONF3, .volatile_reg = amc6821_volatile_reg, .cache_type = REGCACHE_MAPLE, }; @@ -920,6 +920,13 @@ static int amc6821_probe(struct i2c_client *client) if (err) return err; + if (of_device_is_compatible(dev->of_node, "tsd,mule")) { + err = devm_of_platform_populate(dev); + if (err) + return dev_err_probe(dev, err, + "Failed to create sub-devices\n"); + } + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &amc6821_chip_info, amc6821_groups); @@ -927,7 +934,7 @@ static int amc6821_probe(struct i2c_client *client) } static const struct i2c_device_id amc6821_id[] = { - { "amc6821", 0 }, + { "amc6821" }, { } }; @@ -937,6 +944,9 @@ static const struct of_device_id __maybe_unused amc6821_of_match[] = { { .compatible = "ti,amc6821", }, + { + .compatible = "tsd,mule", + }, { } }; diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c index 75eadda738ab..4174b129d1fc 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tach.c +++ b/drivers/hwmon/aspeed-g6-pwm-tach.c @@ -534,7 +534,7 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); static struct platform_driver aspeed_pwm_tach_driver = { .probe = aspeed_pwm_tach_probe, - .remove_new = aspeed_pwm_tach_remove, + .remove = aspeed_pwm_tach_remove, .driver = { .name = "aspeed-g6-pwm-tach", .of_match_table = aspeed_pwm_tach_match, diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c index 5514cf780b8b..9991c3fa020a 100644 --- a/drivers/hwmon/cros_ec_hwmon.c +++ b/drivers/hwmon/cros_ec_hwmon.c @@ -141,6 +141,7 @@ static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_type } static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index 7fb0c57dfef5..588e96790850 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -473,7 +473,7 @@ static void da9052_hwmon_remove(struct platform_device *pdev) static struct platform_driver da9052_hwmon_driver = { .probe = da9052_hwmon_probe, - .remove_new = da9052_hwmon_remove, + .remove = da9052_hwmon_remove, .driver = { .name = "da9052-hwmon", }, diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 1a9b28dc91e6..3d4057309950 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2721,7 +2721,7 @@ static struct platform_driver dme1737_isa_driver = { .name = "dme1737", }, .probe = dme1737_isa_probe, - .remove_new = dme1737_isa_remove, + .remove = dme1737_isa_remove, }; /* --------------------------------------------------------------------- diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 243c570dee4c..820f894d9ffd 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1497,7 +1497,7 @@ static struct platform_driver f71805f_driver = { .name = DRVNAME, }, .probe = f71805f_probe, - .remove_new = f71805f_remove, + .remove = f71805f_remove, }; static int __init f71805f_device_add(unsigned short address, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 7c941d320a18..df83f9866fbc 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -2658,7 +2658,7 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove_new = f71882fg_remove, + .remove = f71882fg_remove, }; static int __init f71882fg_init(void) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 4514f3ed90cc..14a6385cd7cc 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -231,15 +231,8 @@ gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, return 0; } -static umode_t -gsc_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, - int ch) -{ - return 0444; -} - static const struct hwmon_ops gsc_hwmon_ops = { - .is_visible = gsc_hwmon_is_visible, + .visible = 0444, .read = gsc_hwmon_read, .read_string = gsc_hwmon_read_string, }; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9c35c4d0369d..49b366254529 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -145,6 +145,17 @@ static const struct class hwmon_class = { static DEFINE_IDA(hwmon_ida); +static umode_t hwmon_is_visible(const struct hwmon_ops *ops, + const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (ops->visible) + return ops->visible; + + return ops->is_visible(drvdata, type, attr, channel); +} + /* Thermal zone handling */ /* @@ -267,8 +278,8 @@ static int hwmon_thermal_register_sensors(struct device *dev) int err; if (!(info[i]->config[j] & HWMON_T_INPUT) || - !chip->ops->is_visible(drvdata, hwmon_temp, - hwmon_temp_input, j)) + !hwmon_is_visible(chip->ops, drvdata, hwmon_temp, + hwmon_temp_input, j)) continue; err = hwmon_thermal_add_sensor(dev, j); @@ -506,7 +517,7 @@ static struct attribute *hwmon_genattr(const void *drvdata, const char *name; bool is_string = is_string_attr(type, attr); - mode = ops->is_visible(drvdata, type, attr, index); + mode = hwmon_is_visible(ops, drvdata, type, attr, index); if (!mode) return ERR_PTR(-ENOENT); @@ -1033,7 +1044,7 @@ hwmon_device_register_with_info(struct device *dev, const char *name, if (!dev || !name || !chip) return ERR_PTR(-EINVAL); - if (!chip->ops || !chip->ops->is_visible || !chip->info) + if (!chip->ops || !(chip->ops->visible || chip->ops->is_visible) || !chip->info) return ERR_PTR(-EINVAL); return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c index 7b00b38c7f7b..2a530da21949 100644 --- a/drivers/hwmon/i5500_temp.c +++ b/drivers/hwmon/i5500_temp.c @@ -29,12 +29,6 @@ #define REG_CTCTRL 0xF7 #define REG_TSTIMER 0xF8 -static umode_t i5500_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, - int channel) -{ - return 0444; -} - static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -84,7 +78,7 @@ static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr } static const struct hwmon_ops i5500_ops = { - .is_visible = i5500_is_visible, + .visible = 0444, .read = i5500_read, }; diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 02f5d35dd319..b22e0423e324 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -568,7 +568,7 @@ static struct platform_driver i5k_amb_driver = { .name = DRVNAME, }, .probe = i5k_amb_probe, - .remove_new = i5k_amb_remove, + .remove = i5k_amb_remove, }; static int __init i5k_amb_init(void) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index f0fa6d073627..345fe7db9de9 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -51,17 +51,26 @@ #define INA226_ALERT_LIMIT 0x07 #define INA226_DIE_ID 0xFF -#define INA2XX_MAX_REGISTERS 8 +/* SY24655 register definitions */ +#define SY24655_EIN 0x0A +#define SY24655_ACCUM_CONFIG 0x0D +#define INA2XX_MAX_REGISTERS 0x0D /* settings - depend on use case */ #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ +#define INA260_CONFIG_DEFAULT 0x6527 /* averages=16 */ +#define SY24655_CONFIG_DEFAULT 0x4527 /* averages=16 */ + +/* (only for sy24655) */ +#define SY24655_ACCUM_CONFIG_DEFAULT 0x044C /* continuous mode, clear after read*/ /* worst case is 68.10 ms (~14.6Hz, ina219) */ #define INA2XX_CONVERSION_RATE 15 #define INA2XX_MAX_DELAY 69 /* worst case delay in ms */ #define INA2XX_RSHUNT_DEFAULT 10000 +#define INA260_RSHUNT 2000 /* bit mask for reading the averaging setting in the configuration register */ #define INA226_AVG_RD_MASK GENMASK(11, 9) @@ -95,6 +104,7 @@ static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg) case INA2XX_CALIBRATION: case INA226_MASK_ENABLE: case INA226_ALERT_LIMIT: + case SY24655_ACCUM_CONFIG: return true; default: return false; @@ -125,10 +135,13 @@ static const struct regmap_config ina2xx_regmap_config = { .writeable_reg = ina2xx_writeable_reg, }; -enum ina2xx_ids { ina219, ina226 }; +enum ina2xx_ids { ina219, ina226, ina260, sy24655 }; struct ina2xx_config { u16 config_default; + bool has_alerts; /* chip supports alerts and limits */ + bool has_ishunt; /* chip has internal shunt resistor */ + bool has_power_average; /* chip has internal shunt resistor */ int calibration_value; int shunt_div; int bus_voltage_shift; @@ -145,6 +158,7 @@ struct ina2xx_data { long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; + struct i2c_client *client; }; static const struct ina2xx_config ina2xx_config[] = { @@ -155,6 +169,9 @@ static const struct ina2xx_config ina2xx_config[] = { .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, .power_lsb_factor = 20, + .has_alerts = false, + .has_ishunt = false, + .has_power_average = false, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, @@ -163,6 +180,30 @@ static const struct ina2xx_config ina2xx_config[] = { .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, .power_lsb_factor = 25, + .has_alerts = true, + .has_ishunt = false, + .has_power_average = false, + }, + [ina260] = { + .config_default = INA260_CONFIG_DEFAULT, + .shunt_div = 400, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1250, + .power_lsb_factor = 8, + .has_alerts = true, + .has_ishunt = true, + .has_power_average = false, + }, + [sy24655] = { + .config_default = SY24655_CONFIG_DEFAULT, + .calibration_value = 4096, + .shunt_div = 400, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1250, + .power_lsb_factor = 25, + .has_alerts = true, + .has_ishunt = false, + .has_power_average = true, }, }; @@ -254,6 +295,15 @@ static int ina2xx_read_init(struct device *dev, int reg, long *val) unsigned int regval; int ret, retry; + if (data->config->has_ishunt) { + /* No calibration needed */ + ret = regmap_read(regmap, reg, ®val); + if (ret < 0) + return ret; + *val = ina2xx_get_value(data, reg, regval); + return 0; + } + for (retry = 5; retry; retry--) { ret = regmap_read(regmap, reg, ®val); if (ret < 0) @@ -459,6 +509,41 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) return 0; } +/* + * Configuring the READ_EIN (bit 10) of the ACCUM_CONFIG register to 1 + * can clear accumulator and sample_count after reading the EIN register. + * This way, the average power between the last read and the current + * read can be obtained. By combining with accurate time data from + * outside, the energy consumption during that period can be calculated. + */ +static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *val) +{ + u8 template[6]; + int ret; + long accumulator_24, sample_count; + + /* 48-bit register read */ + ret = i2c_smbus_read_i2c_block_data(data->client, reg, 6, template); + if (ret < 0) + return ret; + if (ret != 6) + return -EIO; + accumulator_24 = ((template[3] << 16) | + (template[4] << 8) | + template[5]); + sample_count = ((template[0] << 16) | + (template[1] << 8) | + template[2]); + if (sample_count <= 0) { + *val = 0; + return 0; + } + + *val = DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW; + + return 0; +} + static int ina2xx_power_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); @@ -466,6 +551,8 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val) switch (attr) { case hwmon_power_input: return ina2xx_read_init(dev, INA2XX_POWER, val); + case hwmon_power_average: + return sy24655_average_power_read(data, SY24655_EIN, val); case hwmon_power_crit: return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK, INA2XX_POWER, val); @@ -624,6 +711,8 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type u32 attr, int channel) { const struct ina2xx_data *data = _data; + bool has_alerts = data->config->has_alerts; + bool has_power_average = data->config->has_power_average; enum ina2xx_ids chip = data->chip; switch (type) { @@ -633,12 +722,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type return 0444; case hwmon_in_lcrit: case hwmon_in_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_in_lcrit_alarm: case hwmon_in_crit_alarm: - if (chip == ina226) + if (has_alerts) return 0444; break; default: @@ -651,12 +740,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type return 0444; case hwmon_curr_lcrit: case hwmon_curr_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_curr_lcrit_alarm: case hwmon_curr_crit_alarm: - if (chip == ina226) + if (has_alerts) return 0444; break; default: @@ -668,11 +757,15 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type case hwmon_power_input: return 0444; case hwmon_power_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_power_crit_alarm: - if (chip == ina226) + if (has_alerts) + return 0444; + break; + case hwmon_power_average: + if (has_power_average) return 0444; break; default: @@ -682,7 +775,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type case hwmon_chip: switch (attr) { case hwmon_chip_update_interval: - if (chip == ina226) + if (chip == ina226 || chip == ina260) return 0644; break; default: @@ -707,7 +800,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = { HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM), HWMON_CHANNEL_INFO(power, - HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), + HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM | + HWMON_P_AVERAGE), NULL }; @@ -791,7 +885,9 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) u32 shunt; int ret; - if (device_property_read_u32(dev, "shunt-resistor", &shunt) < 0) + if (data->config->has_ishunt) + shunt = INA260_RSHUNT; + else if (device_property_read_u32(dev, "shunt-resistor", &shunt) < 0) shunt = INA2XX_RSHUNT_DEFAULT; ret = ina2xx_set_shunt(data, shunt); @@ -802,7 +898,7 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) if (ret < 0) return ret; - if (data->chip == ina226) { + if (data->config->has_alerts) { bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high"); regmap_update_bits(regmap, INA226_MASK_ENABLE, @@ -810,6 +906,22 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) INA226_ALERT_LATCH_ENABLE | FIELD_PREP(INA226_ALERT_POLARITY, active_high)); } + if (data->config->has_power_average) { + if (data->chip == sy24655) { + /* + * Initialize the power accumulation method to continuous + * mode and clear the EIN register after each read of the + * EIN register + */ + ret = regmap_write(regmap, SY24655_ACCUM_CONFIG, + SY24655_ACCUM_CONFIG_DEFAULT); + if (ret < 0) + return ret; + } + } + + if (data->config->has_ishunt) + return 0; /* * Calibration register is set to the best value, which eliminates @@ -836,6 +948,7 @@ static int ina2xx_probe(struct i2c_client *client) return -ENOMEM; /* set the device type */ + data->client = client; data->config = &ina2xx_config[chip]; data->chip = chip; mutex_init(&data->config_lock); @@ -856,7 +969,8 @@ static int ina2xx_probe(struct i2c_client *client) hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &ina2xx_chip_info, - ina2xx_groups); + data->config->has_ishunt ? + NULL : ina2xx_groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); @@ -872,11 +986,17 @@ static const struct i2c_device_id ina2xx_id[] = { { "ina226", ina226 }, { "ina230", ina226 }, { "ina231", ina226 }, + { "ina260", ina260 }, + { "sy24655", sy24655 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); static const struct of_device_id __maybe_unused ina2xx_of_match[] = { + { + .compatible = "silergy,sy24655", + .data = (void *)sy24655 + }, { .compatible = "ti,ina219", .data = (void *)ina219 @@ -897,7 +1017,11 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = { .compatible = "ti,ina231", .data = (void *)ina226 }, - { }, + { + .compatible = "ti,ina260", + .data = (void *)ina260 + }, + { } }; MODULE_DEVICE_TABLE(of, ina2xx_of_match); diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 96397ae6ff18..e221f2c1f332 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -565,13 +565,6 @@ static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = { .hinfo = n6000bmc_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) @@ -729,7 +722,7 @@ static int m10bmc_hwmon_read_string(struct device *dev, } static const struct hwmon_ops m10bmc_hwmon_ops = { - .is_visible = m10bmc_hwmon_is_visible, + .visible = 0444, .read = m10bmc_hwmon_read, .read_string = m10bmc_hwmon_read_string, }; diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c new file mode 100644 index 000000000000..f9edcfd164c2 --- /dev/null +++ b/drivers/hwmon/isl28022.c @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * isl28022.c - driver for Renesas ISL28022 power monitor chip monitoring + * + * Copyright (c) 2023 Carsten Spieß + */ + +#include +#include +#include +#include +#include +#include + +/* ISL28022 registers */ +#define ISL28022_REG_CONFIG 0x00 +#define ISL28022_REG_SHUNT 0x01 +#define ISL28022_REG_BUS 0x02 +#define ISL28022_REG_POWER 0x03 +#define ISL28022_REG_CURRENT 0x04 +#define ISL28022_REG_CALIB 0x05 +#define ISL28022_REG_SHUNT_THR 0x06 +#define ISL28022_REG_BUS_THR 0x07 +#define ISL28022_REG_INT 0x08 +#define ISL28022_REG_AUX 0x09 +#define ISL28022_REG_MAX ISL28022_REG_AUX + +/* ISL28022 config flags */ +/* mode flags */ +#define ISL28022_MODE_SHIFT 0 +#define ISL28022_MODE_MASK 0x0007 + +#define ISL28022_MODE_PWR_DOWN 0x0 +#define ISL28022_MODE_TRG_S 0x1 +#define ISL28022_MODE_TRG_B 0x2 +#define ISL28022_MODE_TRG_SB 0x3 +#define ISL28022_MODE_ADC_OFF 0x4 +#define ISL28022_MODE_CONT_S 0x5 +#define ISL28022_MODE_CONT_B 0x6 +#define ISL28022_MODE_CONT_SB 0x7 + +/* shunt ADC settings */ +#define ISL28022_SADC_SHIFT 3 +#define ISL28022_SADC_MASK 0x0078 + +#define ISL28022_BADC_SHIFT 7 +#define ISL28022_BADC_MASK 0x0780 + +#define ISL28022_ADC_12 0x0 /* 12 bit ADC */ +#define ISL28022_ADC_13 0x1 /* 13 bit ADC */ +#define ISL28022_ADC_14 0x2 /* 14 bit ADC */ +#define ISL28022_ADC_15 0x3 /* 15 bit ADC */ +#define ISL28022_ADC_15_1 0x8 /* 15 bit ADC, 1 sample */ +#define ISL28022_ADC_15_2 0x9 /* 15 bit ADC, 2 samples */ +#define ISL28022_ADC_15_4 0xA /* 15 bit ADC, 4 samples */ +#define ISL28022_ADC_15_8 0xB /* 15 bit ADC, 8 samples */ +#define ISL28022_ADC_15_16 0xC /* 15 bit ADC, 16 samples */ +#define ISL28022_ADC_15_32 0xD /* 15 bit ADC, 32 samples */ +#define ISL28022_ADC_15_64 0xE /* 15 bit ADC, 64 samples */ +#define ISL28022_ADC_15_128 0xF /* 15 bit ADC, 128 samples */ + +/* shunt voltage range */ +#define ISL28022_PG_SHIFT 11 +#define ISL28022_PG_MASK 0x1800 + +#define ISL28022_PG_40 0x0 /* +/-40 mV */ +#define ISL28022_PG_80 0x1 /* +/-80 mV */ +#define ISL28022_PG_160 0x2 /* +/-160 mV */ +#define ISL28022_PG_320 0x3 /* +/-3200 mV */ + +/* bus voltage range */ +#define ISL28022_BRNG_SHIFT 13 +#define ISL28022_BRNG_MASK 0x6000 + +#define ISL28022_BRNG_16 0x0 /* 16 V */ +#define ISL28022_BRNG_32 0x1 /* 32 V */ +#define ISL28022_BRNG_60 0x3 /* 60 V */ + +/* reset */ +#define ISL28022_RESET 0x8000 + +struct isl28022_data { + struct regmap *regmap; + u32 shunt; + u32 gain; + u32 average; +}; + +static int isl28022_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + u16 sign_bit; + + switch (channel) { + case 0: + switch (attr) { + case hwmon_in_input: + err = regmap_read(data->regmap, + ISL28022_REG_BUS, ®val); + if (err < 0) + return err; + /* driver supports only 60V mode (BRNG 11) */ + *val = (long)(((u16)regval) & 0xFFFC); + break; + default: + return -EOPNOTSUPP; + } + break; + case 1: + switch (attr) { + case hwmon_in_input: + err = regmap_read(data->regmap, + ISL28022_REG_SHUNT, ®val); + if (err < 0) + return err; + switch (data->gain) { + case 8: + sign_bit = (regval >> 15) & 0x01; + *val = (long)((((u16)regval) & 0x7FFF) - + (sign_bit * 32768)) / 100; + break; + case 4: + sign_bit = (regval >> 14) & 0x01; + *val = (long)((((u16)regval) & 0x3FFF) - + (sign_bit * 16384)) / 100; + break; + case 2: + sign_bit = (regval >> 13) & 0x01; + *val = (long)((((u16)regval) & 0x1FFF) - + (sign_bit * 8192)) / 100; + break; + case 1: + sign_bit = (regval >> 12) & 0x01; + *val = (long)((((u16)regval) & 0x0FFF) - + (sign_bit * 4096)) / 100; + break; + } + break; + default: + return -EOPNOTSUPP; + } + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read_current(struct device *dev, u32 attr, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_curr_input: + err = regmap_read(data->regmap, + ISL28022_REG_CURRENT, ®val); + if (err < 0) + return err; + *val = ((long)regval * 1250L * (long)data->gain) / + (long)data->shunt; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read_power(struct device *dev, u32 attr, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_power_input: + err = regmap_read(data->regmap, + ISL28022_REG_POWER, ®val); + if (err < 0) + return err; + *val = ((51200000L * ((long)data->gain)) / + (long)data->shunt) * (long)regval; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_in: + return isl28022_read_in(dev, attr, channel, val); + case hwmon_curr: + return isl28022_read_current(dev, attr, val); + case hwmon_power: + return isl28022_read_power(dev, attr, val); + default: + return -EOPNOTSUPP; + } + return 0; +} + +static umode_t isl28022_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_input: + return 0444; + default: + break; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + return 0444; + default: + break; + } + break; + case hwmon_power: + switch (attr) { + case hwmon_power_input: + return 0444; + default: + break; + } + break; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info *isl28022_info[] = { + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT, /* channel 0: bus voltage (mV) */ + HWMON_I_INPUT), /* channel 1: shunt voltage (mV) */ + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT), /* channel 1: current (mA) */ + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT), /* channel 1: power (µW) */ + NULL +}; + +static const struct hwmon_ops isl28022_hwmon_ops = { + .is_visible = isl28022_is_visible, + .read = isl28022_read, +}; + +static const struct hwmon_chip_info isl28022_chip_info = { + .ops = &isl28022_hwmon_ops, + .info = isl28022_info, +}; + +static bool isl28022_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL28022_REG_CONFIG: + case ISL28022_REG_CALIB: + case ISL28022_REG_SHUNT_THR: + case ISL28022_REG_BUS_THR: + case ISL28022_REG_INT: + case ISL28022_REG_AUX: + return true; + } + + return false; +} + +static bool isl28022_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL28022_REG_CONFIG: + case ISL28022_REG_SHUNT: + case ISL28022_REG_BUS: + case ISL28022_REG_POWER: + case ISL28022_REG_CURRENT: + case ISL28022_REG_INT: + case ISL28022_REG_AUX: + return true; + } + return true; +} + +static const struct regmap_config isl28022_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = ISL28022_REG_MAX, + .writeable_reg = isl28022_is_writeable_reg, + .volatile_reg = isl28022_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int shunt_voltage_show(struct seq_file *seqf, void *unused) +{ + struct isl28022_data *data = seqf->private; + unsigned int regval; + int err; + + err = regmap_read(data->regmap, + ISL28022_REG_SHUNT, ®val); + if (err) + return err; + + /* print shunt voltage in micro volt */ + seq_printf(seqf, "%d\n", regval * 10); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(shunt_voltage); + +static struct dentry *isl28022_debugfs_root; + +static void isl28022_debugfs_remove(void *res) +{ + debugfs_remove_recursive(res); +} + +static void isl28022_debugfs_init(struct i2c_client *client, struct isl28022_data *data) +{ + char name[16]; + struct dentry *debugfs; + + scnprintf(name, sizeof(name), "%d-%04hx", client->adapter->nr, client->addr); + + debugfs = debugfs_create_dir(name, isl28022_debugfs_root); + debugfs_create_file("shunt_voltage", 0444, debugfs, data, &shunt_voltage_fops); + + devm_add_action_or_reset(&client->dev, isl28022_debugfs_remove, debugfs); +} + +/* + * read property values and make consistency checks. + * + * following values for shunt range and resistor are allowed: + * 40 mV -> gain 1, shunt min. 800 micro ohms + * 80 mV -> gain 2, shunt min. 1600 micro ohms + * 160 mV -> gain 4, shunt min. 3200 micro ohms + * 320 mV -> gain 8, shunt min. 6400 micro ohms + */ +static int isl28022_read_properties(struct device *dev, struct isl28022_data *data) +{ + u32 val; + int err; + + err = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val); + if (err == -EINVAL) + val = 10000; + else if (err < 0) + return err; + data->shunt = val; + + err = device_property_read_u32(dev, "renesas,shunt-range-microvolt", &val); + if (err == -EINVAL) + val = 320000; + else if (err < 0) + return err; + + switch (val) { + case 40000: + data->gain = 1; + if (data->shunt < 800) + goto shunt_invalid; + break; + case 80000: + data->gain = 2; + if (data->shunt < 1600) + goto shunt_invalid; + break; + case 160000: + data->gain = 4; + if (data->shunt < 3200) + goto shunt_invalid; + break; + case 320000: + data->gain = 8; + if (data->shunt < 6400) + goto shunt_invalid; + break; + default: + return dev_err_probe(dev, -EINVAL, + "renesas,shunt-range-microvolt invalid value %d\n", + val); + } + + err = device_property_read_u32(dev, "renesas,average-samples", &val); + if (err == -EINVAL) + val = 1; + else if (err < 0) + return err; + if (val > 128 || hweight32(val) != 1) + return dev_err_probe(dev, -EINVAL, + "renesas,average-samples invalid value %d\n", + val); + + data->average = val; + + return 0; + +shunt_invalid: + return dev_err_probe(dev, -EINVAL, + "renesas,shunt-resistor-microvolt invalid value %d\n", + data->shunt); +} + +/* + * write configuration and calibration registers + * + * The driver supports only shunt and bus continuous ADC mode at 15bit resolution + * with averaging from 1 to 128 samples (pow of 2) on both channels. + * Shunt voltage gain 1,2,4 or 8 is allowed. + * The bus voltage range is 60V fixed. + */ +static int isl28022_config(struct isl28022_data *data) +{ + int err; + u16 config; + u16 calib; + + config = (ISL28022_MODE_CONT_SB << ISL28022_MODE_SHIFT) | + (ISL28022_BRNG_60 << ISL28022_BRNG_SHIFT) | + (__ffs(data->gain) << ISL28022_PG_SHIFT) | + ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_SADC_SHIFT) | + ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_BADC_SHIFT); + + calib = data->shunt ? 0x8000 / data->gain : 0; + + err = regmap_write(data->regmap, ISL28022_REG_CONFIG, config); + if (err < 0) + return err; + + return regmap_write(data->regmap, ISL28022_REG_CALIB, calib); +} + +static int isl28022_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct isl28022_data *data; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(struct isl28022_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = isl28022_read_properties(dev, data); + if (err) + return err; + + data->regmap = devm_regmap_init_i2c(client, &isl28022_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + err = isl28022_config(data); + if (err) + return err; + + isl28022_debugfs_init(client, data); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, &isl28022_chip_info, NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + return 0; +} + +static const struct i2c_device_id isl28022_ids[] = { + { "isl28022", 0}, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, isl28022_ids); + +static const struct of_device_id __maybe_unused isl28022_of_match[] = { + { .compatible = "renesas,isl28022"}, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(of, isl28022_of_match); + +static struct i2c_driver isl28022_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "isl28022", + }, + .probe = isl28022_probe, + .id_table = isl28022_ids, +}; + +static int __init +isl28022_init(void) +{ + int err; + + isl28022_debugfs_root = debugfs_create_dir("isl28022", NULL); + err = i2c_add_driver(&isl28022_driver); + if (!err) + return 0; + + debugfs_remove_recursive(isl28022_debugfs_root); + return err; +} + +static void __exit +isl28022_exit(void) +{ + i2c_del_driver(&isl28022_driver); + debugfs_remove_recursive(isl28022_debugfs_root); +} + +module_init(isl28022_init); +module_exit(isl28022_exit); + +MODULE_AUTHOR("Carsten Spieß "); +MODULE_DESCRIPTION("ISL28022 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index c459dce496a6..06f0ab2f52fa 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include /* Addresses to scan */ @@ -595,20 +595,18 @@ static const struct i2c_device_id jc42_id[] = { }; MODULE_DEVICE_TABLE(i2c, jc42_id); -#ifdef CONFIG_OF static const struct of_device_id jc42_of_ids[] = { { .compatible = "jedec,jc-42.4-temp", }, { } }; MODULE_DEVICE_TABLE(of, jc42_of_ids); -#endif static struct i2c_driver jc42_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "jc42", .pm = JC42_DEV_PM_OPS, - .of_match_table = of_match_ptr(jc42_of_ids), + .of_match_table = jc42_of_ids, }, .probe = jc42_probe, .remove = jc42_remove, diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index bb30403f81ca..f0048ff37607 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -332,7 +332,7 @@ static struct platform_driver max197_driver = { .name = "max197", }, .probe = max197_probe, - .remove_new = max197_remove, + .remove = max197_remove, .id_table = max197_device_ids, }; module_platform_driver(max197_driver); diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index c955b0f3a8d3..32b4d54b2076 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -531,14 +530,49 @@ static int rpm_range_to_reg(int range) return 1; /* default: 4000 RPM */ } +static int max6639_probe_child_from_dt(struct i2c_client *client, + struct device_node *child, + struct max6639_data *data) + +{ + struct device *dev = &client->dev; + u32 i; + int err, val; + + err = of_property_read_u32(child, "reg", &i); + if (err) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return err; + } + + if (i > 1) { + dev_err(dev, "Invalid fan index reg %d\n", i); + return -EINVAL; + } + + err = of_property_read_u32(child, "pulses-per-revolution", &val); + if (!err) { + if (val < 1 || val > 5) { + dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child); + return -EINVAL; + } + data->ppr[i] = val; + } + + err = of_property_read_u32(child, "max-rpm", &val); + if (!err) + data->rpm_range[i] = rpm_range_to_reg(val); + + return 0; +} + static int max6639_init_client(struct i2c_client *client, struct max6639_data *data) { - struct max6639_platform_data *max6639_info = - dev_get_platdata(&client->dev); - int i; - int rpm_range = 1; /* default: 4000 RPM */ - int err, ppr; + struct device *dev = &client->dev; + const struct device_node *np = dev->of_node; + struct device_node *child; + int i, err; /* Reset chip to default values, see below for GCONFIG setup */ err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR); @@ -546,21 +580,29 @@ static int max6639_init_client(struct i2c_client *client, return err; /* Fans pulse per revolution is 2 by default */ - if (max6639_info && max6639_info->ppr > 0 && - max6639_info->ppr < 5) - ppr = max6639_info->ppr; - else - ppr = 2; + data->ppr[0] = 2; + data->ppr[1] = 2; - data->ppr[0] = ppr; - data->ppr[1] = ppr; + /* default: 4000 RPM */ + data->rpm_range[0] = 1; + data->rpm_range[1] = 1; - if (max6639_info) - rpm_range = rpm_range_to_reg(max6639_info->rpm_range); - data->rpm_range[0] = rpm_range; - data->rpm_range[1] = rpm_range; + for_each_child_of_node(np, child) { + if (strcmp(child->name, "fan")) + continue; + + err = max6639_probe_child_from_dt(client, child, data); + if (err) { + of_node_put(child); + return err; + } + } for (i = 0; i < MAX6639_NUM_CHANNELS; i++) { + err = regmap_set_bits(data->regmap, MAX6639_REG_OUTPUT_MASK, BIT(1 - i)); + if (err) + return err; + /* Set Fan pulse per revolution */ err = max6639_set_ppr(data, i, data->ppr[i]); if (err) @@ -573,12 +615,7 @@ static int max6639_init_client(struct i2c_client *client, return err; /* Fans PWM polarity high by default */ - if (max6639_info) { - if (max6639_info->pwm_polarity == 0) - err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); - else - err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02); - } + err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); if (err) return err; diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 67471c9cd4d4..66304d48d33a 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -315,7 +315,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); static struct platform_driver mc13783_adc_driver = { - .remove_new = mc13783_adc_remove, + .remove = mc13783_adc_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index 934fed3dd586..ee04795b98aa 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -2878,8 +2878,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, - data->target_temp_mask); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, data->target_temp_mask * 1000), 1000); mutex_lock(&data->update_lock); data->target_temp[nr] = val; @@ -2959,7 +2958,7 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr, return err; /* Limit tolerance as needed */ - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, data->tolerance_mask * 1000), 1000); mutex_lock(&data->update_lock); data->temp_tolerance[index][nr] = val; @@ -3085,7 +3084,7 @@ store_weight_temp(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 255000), 1000); mutex_lock(&data->update_lock); data->weight_temp[index][nr] = val; diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 096f1daa8f2b..1218a3b449a8 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -1350,6 +1350,8 @@ static const char * const asus_msi_boards[] = { "Pro H610M-CT D4", "Pro H610T D4", "Pro Q670M-C", + "Pro WS 600M-CL", + "Pro WS 665-ACE", "Pro WS W680-ACE", "Pro WS W680-ACE IPMI", "Pro WS W790-ACE", diff --git a/drivers/hwmon/nct7363.c b/drivers/hwmon/nct7363.c new file mode 100644 index 000000000000..be7bf32f6e68 --- /dev/null +++ b/drivers/hwmon/nct7363.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Nuvoton Technology corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NCT7363_REG_FUNC_CFG_BASE(x) (0x20 + (x)) +#define NCT7363_REG_LSRS(x) (0x34 + ((x) / 8)) +#define NCT7363_REG_PWMEN_BASE(x) (0x38 + (x)) +#define NCT7363_REG_FANINEN_BASE(x) (0x41 + (x)) +#define NCT7363_REG_FANINX_HVAL(x) (0x48 + ((x) * 2)) +#define NCT7363_REG_FANINX_LVAL(x) (0x49 + ((x) * 2)) +#define NCT7363_REG_FANINX_HL(x) (0x6C + ((x) * 2)) +#define NCT7363_REG_FANINX_LL(x) (0x6D + ((x) * 2)) +#define NCT7363_REG_FSCPXDUTY(x) (0x90 + ((x) * 2)) +#define NCT7363_REG_FSCPXDIV(x) (0x91 + ((x) * 2)) + +#define PWM_SEL(x) (BIT(0) << ((x) * 2)) +#define FANIN_SEL(_x) ({typeof(_x) (x) = (_x); \ + BIT(1) << (((x) < 8) ? \ + (((x) + 8) * 2) : \ + (((x) % 8) * 2)); }) +#define ALARM_SEL(x, y) ((x) & (BIT((y) % 8))) +#define VALUE_TO_REG(x, y) (((x) >> ((y) * 8)) & 0xFF) + +#define NCT7363_FANINX_LVAL_MASK GENMASK(4, 0) +#define NCT7363_FANIN_MASK GENMASK(12, 0) + +#define NCT7363_PWM_COUNT 16 + +static inline unsigned int fan_from_reg(u16 val) +{ + if (val == NCT7363_FANIN_MASK || val == 0) + return 0; + + return (1350000UL / val); +} + +static const struct of_device_id nct7363_of_match[] = { + { .compatible = "nuvoton,nct7363", }, + { .compatible = "nuvoton,nct7362", }, + { } +}; +MODULE_DEVICE_TABLE(of, nct7363_of_match); + +struct nct7363_data { + struct regmap *regmap; + + u16 fanin_mask; + u16 pwm_mask; +}; + +static int nct7363_read_fan(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 regval[2]; + int ret; + u16 cnt; + + switch (attr) { + case hwmon_fan_input: + /* + * High-byte register should be read first to latch + * synchronous low-byte value + */ + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HVAL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_min: + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_alarm: + ret = regmap_read(data->regmap, + NCT7363_REG_LSRS(channel), ®); + if (ret) + return ret; + + *val = (long)ALARM_SEL(reg, channel) > 0 ? 1 : 0; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_fan(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + u8 regval[2]; + int ret; + + if (val <= 0) + return -EINVAL; + + switch (attr) { + case hwmon_fan_min: + val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), + 1, NCT7363_FANIN_MASK); + regval[0] = val >> 5; + regval[1] = val & NCT7363_FANINX_LVAL_MASK; + + ret = regmap_bulk_write(data->regmap, + NCT7363_REG_FANINX_HL(channel), + regval, 2); + return ret; + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_fan_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_alarm: + if (data->fanin_mask & BIT(channel)) + return 0444; + break; + case hwmon_fan_min: + if (data->fanin_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read_pwm(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + switch (attr) { + case hwmon_pwm_input: + ret = regmap_read(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), ®val); + if (ret) + return ret; + + *val = (long)regval; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_pwm(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + int ret; + + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + + ret = regmap_write(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), val); + + return ret; + + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_pwm_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_pwm_input: + if (data->pwm_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_fan: + return nct7363_read_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_read_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_fan: + return nct7363_write_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_write_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + return nct7363_fan_is_visible(data, attr, channel); + case hwmon_pwm: + return nct7363_pwm_is_visible(data, attr, channel); + default: + return 0; + } +} + +static const struct hwmon_channel_info *nct7363_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_ops nct7363_hwmon_ops = { + .is_visible = nct7363_is_visible, + .read = nct7363_read, + .write = nct7363_write, +}; + +static const struct hwmon_chip_info nct7363_chip_info = { + .ops = &nct7363_hwmon_ops, + .info = nct7363_info, +}; + +static int nct7363_init_chip(struct nct7363_data *data) +{ + u32 func_config = 0; + int i, ret; + + /* Pin Function Configuration */ + for (i = 0; i < NCT7363_PWM_COUNT; i++) { + if (data->pwm_mask & BIT(i)) + func_config |= PWM_SEL(i); + if (data->fanin_mask & BIT(i)) + func_config |= FANIN_SEL(i); + } + + for (i = 0; i < 4; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_FUNC_CFG_BASE(i), + VALUE_TO_REG(func_config, i)); + if (ret < 0) + return ret; + } + + /* PWM and FANIN Monitoring Enable */ + for (i = 0; i < 2; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_PWMEN_BASE(i), + VALUE_TO_REG(data->pwm_mask, i)); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, NCT7363_REG_FANINEN_BASE(i), + VALUE_TO_REG(data->fanin_mask, i)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int nct7363_present_pwm_fanin(struct device *dev, + struct device_node *child, + struct nct7363_data *data) +{ + u8 fanin_ch[NCT7363_PWM_COUNT]; + struct of_phandle_args args; + int ret, fanin_cnt; + u8 ch, index; + + ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", + 0, &args); + if (ret) + return ret; + + if (args.args[0] >= NCT7363_PWM_COUNT) + return -EINVAL; + data->pwm_mask |= BIT(args.args[0]); + + fanin_cnt = of_property_count_u8_elems(child, "tach-ch"); + if (fanin_cnt < 1 || fanin_cnt > NCT7363_PWM_COUNT) + return -EINVAL; + + ret = of_property_read_u8_array(child, "tach-ch", fanin_ch, fanin_cnt); + if (ret) + return ret; + + for (ch = 0; ch < fanin_cnt; ch++) { + index = fanin_ch[ch]; + if (index >= NCT7363_PWM_COUNT) + return -EINVAL; + data->fanin_mask |= BIT(index); + } + + return 0; +} + +static bool nct7363_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NCT7363_REG_LSRS(0) ... NCT7363_REG_LSRS(15): + case NCT7363_REG_FANINX_HVAL(0) ... NCT7363_REG_FANINX_LVAL(15): + case NCT7363_REG_FANINX_HL(0) ... NCT7363_REG_FANINX_LL(15): + case NCT7363_REG_FSCPXDUTY(0) ... NCT7363_REG_FSCPXDIV(15): + return true; + default: + return false; + } +} + +static const struct regmap_config nct7363_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = nct7363_regmap_is_volatile, +}; + +static int nct7363_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *child; + struct nct7363_data *data; + struct device *hwmon_dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &nct7363_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + for_each_child_of_node(dev->of_node, child) { + ret = nct7363_present_pwm_fanin(dev, child, data); + if (ret) { + of_node_put(child); + return ret; + } + } + + /* Initialize the chip */ + ret = nct7363_init_chip(data); + if (ret) + return ret; + + hwmon_dev = + devm_hwmon_device_register_with_info(dev, client->name, data, + &nct7363_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct i2c_driver nct7363_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "nct7363", + .of_match_table = nct7363_of_match, + }, + .probe = nct7363_probe, +}; + +module_i2c_driver(nct7363_driver); + +MODULE_AUTHOR("CW Ho "); +MODULE_AUTHOR("Ban Feng "); +MODULE_DESCRIPTION("NCT7363 Hardware Monitoring Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c index ed38645a1dc2..034698232758 100644 --- a/drivers/hwmon/nzxt-kraken2.c +++ b/drivers/hwmon/nzxt-kraken2.c @@ -35,13 +35,6 @@ struct kraken2_priv_data { unsigned long updated; /* jiffies */ }; -static umode_t kraken2_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int kraken2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -81,7 +74,7 @@ static int kraken2_read_string(struct device *dev, enum hwmon_sensor_types type, } static const struct hwmon_ops kraken2_hwmon_ops = { - .is_visible = kraken2_is_visible, + .visible = 0444, .read = kraken2_read, .read_string = kraken2_read_string, }; diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index b5993c79c09e..89761a9c8892 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -192,8 +192,8 @@ static struct platform_driver p9_sbe_occ_driver = { .name = "occ-hwmon", .of_match_table = p9_sbe_occ_of_match, }, - .probe = p9_sbe_occ_probe, - .remove_new = p9_sbe_occ_remove, + .probe = p9_sbe_occ_probe, + .remove = p9_sbe_occ_remove, }; module_platform_driver(p9_sbe_occ_driver); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 788b5d58f77e..0f8aa6b42164 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -1606,7 +1606,7 @@ static struct platform_driver pc87360_driver = { .name = DRIVER_NAME, }, .probe = pc87360_probe, - .remove_new = pc87360_remove, + .remove = pc87360_remove, }; /* diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 7bca04eb4ee4..571402a89368 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1129,7 +1129,7 @@ static struct platform_driver pc87427_driver = { .name = DRVNAME, }, .probe = pc87427_probe, - .remove_new = pc87427_remove, + .remove = pc87427_remove, }; static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index a4f02cad92fd..f6d352841953 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -224,9 +224,9 @@ config SENSORS_LTC2978_REGULATOR depends on SENSORS_LTC2978 && REGULATOR help If you say yes here you get regulator support for Linear Technology - LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880, - LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686, - and LTM4700. + LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7841, + LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, + LTM4686, and LTM4700. config SENSORS_LTC3815 tristate "Linear Technologies LTC3815" diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 7e53fb1d5ea3..97cc951a13a4 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #define ISL68137_VOUT_AVS 0x30 #define RAA_DMPVR2_READ_VMON 0xc8 +#define MAX_CHANNELS 4 enum chips { isl68137, @@ -72,6 +74,17 @@ enum variants { raa_dmpvr2_hv, }; +struct isl68137_channel { + u32 vout_voltage_divider[2]; +}; + +struct isl68137_data { + struct pmbus_driver_info info; + struct isl68137_channel channel[MAX_CHANNELS]; +}; + +#define to_isl68137_data(x) container_of(x, struct isl68137_data, info) + static const struct i2c_device_id raa_dmpvr_id[]; static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, @@ -163,13 +176,32 @@ static const struct attribute_group *isl68137_attribute_groups[] = { static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, int phase, int reg) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct isl68137_data *data = to_isl68137_data(info); int ret; + u64 temp; switch (reg) { case PMBUS_VIRT_READ_VMON: ret = pmbus_read_word_data(client, page, phase, RAA_DMPVR2_READ_VMON); break; + case PMBUS_READ_POUT: + case PMBUS_READ_VOUT: + /* + * In cases where a voltage divider is attached to the target + * rail between Vout and the Vsense pin, both Vout and Pout + * should be scaled by the voltage divider scaling factor. + * I.e. Vout = Vsense * Rtotal / Rout + */ + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret > 0) { + temp = DIV_U64_ROUND_CLOSEST((u64)ret * + data->channel[page].vout_voltage_divider[1], + data->channel[page].vout_voltage_divider[0]); + ret = clamp_val(temp, 0, 0xffff); + } + break; default: ret = -ENODATA; break; @@ -178,6 +210,40 @@ static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, return ret; } +static int raa_dmpvr2_write_word_data(struct i2c_client *client, int page, + int reg, u16 word) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct isl68137_data *data = to_isl68137_data(info); + int ret; + u64 temp; + + switch (reg) { + case PMBUS_VOUT_MAX: + case PMBUS_VOUT_MARGIN_HIGH: + case PMBUS_VOUT_MARGIN_LOW: + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + case PMBUS_VOUT_COMMAND: + /* + * In cases where a voltage divider is attached to the target + * rail between Vout and the Vsense pin, Vout related PMBus + * commands should be scaled based on the expected voltage + * at the Vsense pin. + * I.e. Vsense = Vout * Rout / Rtotal + */ + temp = DIV_U64_ROUND_CLOSEST((u64)word * + data->channel[page].vout_voltage_divider[0], + data->channel[page].vout_voltage_divider[1]); + ret = clamp_val(temp, 0, 0xffff); + break; + default: + ret = -ENODATA; + break; + } + return ret; +} + static struct pmbus_driver_info raa_dmpvr_info = { .pages = 3, .format[PSC_VOLTAGE_IN] = direct, @@ -220,14 +286,90 @@ static struct pmbus_driver_info raa_dmpvr_info = { | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; +static int isl68137_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct isl68137_data *data) +{ + u32 channel, rout, rtotal; + int err; + + err = of_property_read_u32(child, "reg", &channel); + if (err) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return err; + } + if (channel >= data->info.pages) { + dev_err(dev, "invalid reg %d of %pOFn\n", channel, child); + return -EINVAL; + } + + err = of_property_read_u32_array(child, "vout-voltage-divider", + data->channel[channel].vout_voltage_divider, + ARRAY_SIZE(data->channel[channel].vout_voltage_divider)); + if (err && err != -EINVAL) { + dev_err(dev, + "malformed vout-voltage-divider value for channel %d\n", + channel); + return err; + } + + rout = data->channel[channel].vout_voltage_divider[0]; + rtotal = data->channel[channel].vout_voltage_divider[1]; + if (rout == 0) { + dev_err(dev, + "Voltage divider output resistance must be greater than 0\n"); + return -EINVAL; + } + if (rtotal < rout) { + dev_err(dev, + "Voltage divider total resistance is less than output resistance\n"); + return -EINVAL; + } + + return 0; +} + +static int isl68137_probe_from_dt(struct device *dev, + struct isl68137_data *data) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int err; + + for_each_child_of_node(np, child) { + if (strcmp(child->name, "channel")) + continue; + + err = isl68137_probe_child_from_dt(dev, child, data); + if (err) + return err; + } + + return 0; +} + static int isl68137_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct pmbus_driver_info *info; + struct isl68137_data *data; + int i, err; - info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); - if (!info) + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - memcpy(info, &raa_dmpvr_info, sizeof(*info)); + + /* + * Initialize all voltage dividers to Rout=1 and Rtotal=1 to simplify + * logic in PMBus word read/write functions + */ + for (i = 0; i < MAX_CHANNELS; i++) + memset(data->channel[i].vout_voltage_divider, + 1, + sizeof(data->channel[i].vout_voltage_divider)); + + memcpy(&data->info, &raa_dmpvr_info, sizeof(data->info)); + info = &data->info; switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { case raa_dmpvr1_2rail: @@ -237,11 +379,14 @@ static int isl68137_probe(struct i2c_client *client) info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT; + info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; info->groups = isl68137_attribute_groups; break; case raa_dmpvr2_1rail: info->pages = 1; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_2rail_nontc: info->func[0] &= ~PMBUS_HAVE_TEMP3; @@ -250,9 +395,11 @@ static int isl68137_probe(struct i2c_client *client) case raa_dmpvr2_2rail: info->pages = 2; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_3rail: info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_hv: info->pages = 1; @@ -263,11 +410,16 @@ static int isl68137_probe(struct i2c_client *client) info->m[PSC_POWER] = 2; info->R[PSC_POWER] = -1; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; default: return -ENODEV; } + err = isl68137_probe_from_dt(dev, data); + if (err) + return err; + return pmbus_do_probe(client, info); } @@ -318,11 +470,59 @@ static const struct i2c_device_id raa_dmpvr_id[] = { MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); +static const struct of_device_id isl68137_of_match[] = { + { .compatible = "isil,isl68137", .data = (void *)raa_dmpvr1_2rail }, + { .compatible = "renesas,isl68220", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68221", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68222", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68223", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68224", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68225", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68226", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68227", .data = (void *)raa_dmpvr2_1rail }, + { .compatible = "renesas,isl68229", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68233", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68239", .data = (void *)raa_dmpvr2_3rail }, + + { .compatible = "renesas,isl69222", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69223", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69224", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69225", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69227", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69228", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69234", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69236", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69239", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69242", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69243", .data = (void *)raa_dmpvr2_1rail }, + { .compatible = "renesas,isl69247", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69248", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69254", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69255", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69256", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69259", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "isil,isl69260", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69268", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "isil,isl69269", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69298", .data = (void *)raa_dmpvr2_2rail }, + + { .compatible = "renesas,raa228000", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228004", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228006", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc }, + { .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail }, + { }, +}; + +MODULE_DEVICE_TABLE(of, isl68137_of_match); + /* This is the driver that will be inserted */ static struct i2c_driver isl68137_driver = { .driver = { - .name = "isl68137", - }, + .name = "isl68137", + .of_match_table = isl68137_of_match, + }, .probe = isl68137_probe, .id_table = raa_dmpvr_id, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 73a86f4d6472..a6eb4d4b5487 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -23,7 +23,8 @@ enum chips { /* Managers */ ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, /* Controllers */ - ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880, + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, + ltc7841, ltc7880, /* Modules */ ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, ltm4700, @@ -50,7 +51,7 @@ enum chips { #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */ +/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7841 and LTC7880 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 /* LTC2975 only */ @@ -80,6 +81,7 @@ enum chips { #define LTC3887_ID 0x4700 #define LTC3889_ID 0x4900 #define LTC7132_ID 0x4CE0 +#define LTC7841_ID 0x40D0 #define LTC7880_ID 0x49E0 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 @@ -548,6 +550,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3887", ltc3887}, {"ltc3889", ltc3889}, {"ltc7132", ltc7132}, + {"ltc7841", ltc7841}, {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, {"ltm4664", ltm4664}, @@ -654,6 +657,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3889; else if (chip_id == LTC7132_ID) return ltc7132; + else if (chip_id == LTC7841_ID) + return ltc7841; else if (chip_id == LTC7880_ID) return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -854,6 +859,16 @@ static int ltc2978_probe(struct i2c_client *client) | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; + case ltc7841: + data->features |= FEAT_CLEAR_PEAKS; + info->read_word_data = ltc3883_read_word_data; + info->pages = LTC3883_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; default: return -ENODEV; } @@ -907,6 +922,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltc3889" }, { .compatible = "lltc,ltc7132" }, + { .compatible = "lltc,ltc7841" }, { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4664" }, diff --git a/drivers/hwmon/pmbus/mp2891.c b/drivers/hwmon/pmbus/mp2891.c index bb28b15a9103..94ab4ae5fba0 100644 --- a/drivers/hwmon/pmbus/mp2891.c +++ b/drivers/hwmon/pmbus/mp2891.c @@ -572,8 +572,8 @@ static int mp2891_probe(struct i2c_client *client) } static const struct i2c_device_id mp2891_id[] = { - {"mp2891", 0}, - {} + { "mp2891" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp2891_id); diff --git a/drivers/hwmon/pmbus/mp2993.c b/drivers/hwmon/pmbus/mp2993.c index 944593e13231..63691dac2281 100644 --- a/drivers/hwmon/pmbus/mp2993.c +++ b/drivers/hwmon/pmbus/mp2993.c @@ -233,8 +233,8 @@ static int mp2993_probe(struct i2c_client *client) } static const struct i2c_device_id mp2993_id[] = { - {"mp2993", 0}, - {} + { "mp2993" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp2993_id); diff --git a/drivers/hwmon/pmbus/mp9941.c b/drivers/hwmon/pmbus/mp9941.c index 543955cfce67..8ab5fc4d4092 100644 --- a/drivers/hwmon/pmbus/mp9941.c +++ b/drivers/hwmon/pmbus/mp9941.c @@ -291,8 +291,8 @@ static int mp9941_probe(struct i2c_client *client) } static const struct i2c_device_id mp9941_id[] = { - {"mp9941", 0}, - {} + { "mp9941" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp9941_id); diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c index 7f87e117b49d..0d16491cd770 100644 --- a/drivers/hwmon/pmbus/mpq8785.c +++ b/drivers/hwmon/pmbus/mpq8785.c @@ -22,7 +22,7 @@ static int mpq8785_identify(struct i2c_client *client, break; case 1: case 2: - info->format[PSC_VOLTAGE_OUT] = direct, + info->format[PSC_VOLTAGE_OUT] = direct; info->m[PSC_VOLTAGE_OUT] = 64; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = 1; diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ce7fd4ca9d89..a0109296a994 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2719,9 +2719,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, * limit registers need to be disabled. */ if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) { - pmbus_wait(client); - ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); - pmbus_update_ts(client, false); + ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); if (ret > 0 && (ret & PB_WP_ANY)) data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; @@ -3279,7 +3277,17 @@ static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val) { - return _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + int ret; + + ret = _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + + /* + * Clear fault systematically in case writing PMBUS_SMBALERT_MASK + * is not supported by the chip. + */ + pmbus_clear_fault_page(client, page); + + return ret; } static irqreturn_t pmbus_fault_handler(int irq, void *pdata) diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c index cfb635f94d66..4e663d5b4e33 100644 --- a/drivers/hwmon/powerz.c +++ b/drivers/hwmon/powerz.c @@ -54,12 +54,6 @@ static const struct hwmon_channel_info *const powerz_info[] = { NULL }; -static umode_t powerz_is_visible(const void *data, enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int powerz_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, const char **str) { @@ -201,7 +195,7 @@ static int powerz_read(struct device *dev, enum hwmon_sensor_types type, } static const struct hwmon_ops powerz_hwmon_ops = { - .is_visible = powerz_is_visible, + .visible = 0444, .read = powerz_read, .read_string = powerz_read_string, }; diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index c434db4656e7..53a1a968d00d 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -7,6 +7,7 @@ * Author: Kamil Debski */ +#include #include #include #include @@ -60,6 +61,9 @@ struct pwm_fan_ctx { struct hwmon_chip_info info; struct hwmon_channel_info fan_channel; + + u64 pwm_duty_cycle_from_stopped; + u32 pwm_usec_from_stopped; }; /* This handler assumes self resetting edge triggered interrupt. */ @@ -199,7 +203,9 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx, bool force_disable) static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { struct pwm_state *state = &ctx->pwm_state; + unsigned long final_pwm = pwm; unsigned long period; + bool update = false; int ret = 0; if (pwm > 0) { @@ -208,11 +214,22 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) return 0; period = state->period; - state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + update = state->duty_cycle < ctx->pwm_duty_cycle_from_stopped; + if (update) + state->duty_cycle = ctx->pwm_duty_cycle_from_stopped; + else + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); ret = pwm_apply_might_sleep(ctx->pwm, state); if (ret) return ret; ret = pwm_fan_power_on(ctx); + if (!ret && update) { + pwm = final_pwm; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + usleep_range(ctx->pwm_usec_from_stopped, + ctx->pwm_usec_from_stopped * 2); + ret = pwm_apply_might_sleep(ctx->pwm, state); + } } else { ret = pwm_fan_power_off(ctx, false); } @@ -480,6 +497,7 @@ static int pwm_fan_probe(struct platform_device *pdev) struct device *hwmon; int ret; const struct hwmon_channel_info **channels; + u32 pwm_min_from_stopped = 0; u32 *fan_channel_config; int channel_count = 1; /* We always have a PWM channel. */ int i; @@ -620,6 +638,19 @@ static int pwm_fan_probe(struct platform_device *pdev) channels[1] = &ctx->fan_channel; } + ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-percent", + &pwm_min_from_stopped); + if (!ret && pwm_min_from_stopped) { + ctx->pwm_duty_cycle_from_stopped = + DIV_ROUND_UP_ULL(pwm_min_from_stopped * + (ctx->pwm_state.period - 1), + 100); + } + ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-us", + &ctx->pwm_usec_from_stopped); + if (ret) + ctx->pwm_usec_from_stopped = 250000; + ctx->info.ops = &pwm_fan_hwmon_ops; ctx->info.info = channels; diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index 65cc52e47db0..10ef1e1f9458 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -81,12 +81,6 @@ static int rpi_read(struct device *dev, enum hwmon_sensor_types type, return 0; } -static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static const struct hwmon_channel_info * const rpi_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_LCRIT_ALARM), @@ -94,7 +88,7 @@ static const struct hwmon_channel_info * const rpi_info[] = { }; static const struct hwmon_ops rpi_hwmon_ops = { - .is_visible = rpi_is_visible, + .visible = 0444, .read = rpi_read, }; diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index a4b05ebb0546..d00bd5cc6b15 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -512,7 +512,7 @@ static struct platform_driver sch5636_driver = { .name = DRVNAME, }, .probe = sch5636_probe, - .remove_new = sch5636_remove, + .remove = sch5636_remove, .id_table = sch5636_device_id, }; diff --git a/drivers/hwmon/sg2042-mcu.c b/drivers/hwmon/sg2042-mcu.c index 141045769354..aa3fb773602c 100644 --- a/drivers/hwmon/sg2042-mcu.c +++ b/drivers/hwmon/sg2042-mcu.c @@ -346,8 +346,8 @@ static void sg2042_mcu_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id sg2042_mcu_id[] = { - { "sg2042-hwmon-mcu", 0 }, - {}, + { "sg2042-hwmon-mcu" }, + { } }; MODULE_DEVICE_TABLE(i2c, sg2042_mcu_id); diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 494f9655f44f..3d55047e9baf 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -1051,7 +1051,7 @@ static struct platform_driver sht15_driver = { .of_match_table = of_match_ptr(sht15_dt_match), }, .probe = sht15_probe, - .remove_new = sht15_remove, + .remove = sht15_remove, .id_table = sht15_device_ids, }; module_platform_driver(sht15_driver); diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index b8916d2735b5..6c9b776237c2 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,12 @@ */ #define SHT4X_CMD_MEASURE_HPM 0b11111101 #define SHT4X_CMD_RESET 0b10010100 +#define SHT4X_CMD_HEATER_20_1 0b00011110 +#define SHT4X_CMD_HEATER_20_01 0b00010101 +#define SHT4X_CMD_HEATER_110_1 0b00101111 +#define SHT4X_CMD_HEATER_110_01 0b00100100 +#define SHT4X_CMD_HEATER_200_1 0b00111001 +#define SHT4X_CMD_HEATER_200_01 0b00110010 #define SHT4X_CMD_LEN 1 #define SHT4X_CRC8_LEN 1 @@ -49,6 +56,10 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); * struct sht4x_data - All the data required to operate an SHT4X chip * @client: the i2c client associated with the SHT4X * @lock: a mutex that is used to prevent parallel access to the i2c client + * @heating_complete: the time that the last heating finished + * @data_pending: true if and only if there are measurements to retrieve after heating + * @heater_power: the power at which the heater will be started + * @heater_time: the time for which the heater will remain turned on * @valid: validity of fields below * @update_interval: the minimum poll interval * @last_updated: the previous time that the SHT4X was polled @@ -58,6 +69,10 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); struct sht4x_data { struct i2c_client *client; struct mutex lock; /* atomic read data updates */ + unsigned long heating_complete; /* in jiffies */ + bool data_pending; + u32 heater_power; /* in milli-watts */ + u32 heater_time; /* in milli-seconds */ bool valid; /* validity of fields below */ long update_interval; /* in milli-seconds */ long last_updated; /* in jiffies */ @@ -79,19 +94,30 @@ static int sht4x_read_values(struct sht4x_data *data) u8 crc; u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM}; u8 raw_data[SHT4X_RESPONSE_LENGTH]; + unsigned long curr_jiffies; mutex_lock(&data->lock); - next_update = data->last_updated + - msecs_to_jiffies(data->update_interval); - if (data->valid && time_before_eq(jiffies, next_update)) - goto unlock; + curr_jiffies = jiffies; + if (time_before(curr_jiffies, data->heating_complete)) + msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies)); - ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); - if (ret < 0) - goto unlock; + if (data->data_pending && + time_before(jiffies, data->heating_complete + data->update_interval)) { + data->data_pending = false; + } else { + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); - usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA); + if (data->valid && time_before_eq(jiffies, next_update)) + goto unlock; + + ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); + if (ret < 0) + goto unlock; + + usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA); + } ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH); if (ret != SHT4X_RESPONSE_LENGTH) { @@ -215,6 +241,143 @@ static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type, } } +static ssize_t heater_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", time_before(jiffies, data->heating_complete)); +} + +static ssize_t heater_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + bool status; + ssize_t ret; + u8 cmd; + u32 heating_time_bound; + + ret = kstrtobool(buf, &status); + if (ret) + return ret; + if (!status) + return -EINVAL; + + if (data->heater_time == 100) { + if (data->heater_power == 20) + cmd = SHT4X_CMD_HEATER_20_01; + else if (data->heater_power == 110) + cmd = SHT4X_CMD_HEATER_110_01; + else /* data->heater_power == 200 */ + cmd = SHT4X_CMD_HEATER_200_01; + + heating_time_bound = 110; + } else { /* data->heater_time == 1000 */ + if (data->heater_power == 20) + cmd = SHT4X_CMD_HEATER_20_1; + else if (data->heater_power == 110) + cmd = SHT4X_CMD_HEATER_110_1; + else /* data->heater_power == 200 */ + cmd = SHT4X_CMD_HEATER_200_1; + + heating_time_bound = 1100; + } + + mutex_lock(&data->lock); + + if (time_before(jiffies, data->heating_complete)) { + ret = -EBUSY; + goto unlock; + } + + ret = i2c_master_send(data->client, &cmd, SHT4X_CMD_LEN); + if (ret < 0) + goto unlock; + + data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound); + data->data_pending = true; +unlock: + mutex_unlock(&data->lock); + return ret; +} + +static ssize_t heater_power_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", data->heater_power); +} + +static ssize_t heater_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + u32 power; + ssize_t ret; + + ret = kstrtou32(buf, 10, &power); + if (ret) + return ret; + + if (power != 20 && power != 110 && power != 200) + return -EINVAL; + + data->heater_power = power; + + return count; +} + +static ssize_t heater_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", data->heater_time); +} + +static ssize_t heater_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + u32 time; + ssize_t ret; + + ret = kstrtou32(buf, 10, &time); + if (ret) + return ret; + + if (time != 100 && time != 1000) + return -EINVAL; + + data->heater_time = time; + + return count; +} + +static DEVICE_ATTR_RW(heater_enable); +static DEVICE_ATTR_RW(heater_power); +static DEVICE_ATTR_RW(heater_time); + +static struct attribute *sht4x_attrs[] = { + &dev_attr_heater_enable.attr, + &dev_attr_heater_power.attr, + &dev_attr_heater_time.attr, + NULL +}; + +ATTRIBUTE_GROUPS(sht4x); + static const struct hwmon_channel_info * const sht4x_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), @@ -255,6 +418,9 @@ static int sht4x_probe(struct i2c_client *client) data->update_interval = SHT4X_MIN_POLL_INTERVAL; data->client = client; + data->heater_power = 200; + data->heater_time = 1000; + data->heating_complete = jiffies; mutex_init(&data->lock); @@ -270,7 +436,7 @@ static int sht4x_probe(struct i2c_client *client) client->name, data, &sht4x_chip_info, - NULL); + sht4x_groups); return PTR_ERR_OR_ZERO(hwmon_dev); } diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index e73b1522f3ce..b7a7bcd6d3af 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -784,7 +784,7 @@ static struct platform_driver sis5595_driver = { .name = DRIVER_NAME, }, .probe = sis5595_probe, - .remove_new = sis5595_remove, + .remove = sis5595_remove, }; static int sis5595_pci_probe(struct pci_dev *dev, diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c index e020f25c9300..454cc844fb9d 100644 --- a/drivers/hwmon/sl28cpld-hwmon.c +++ b/drivers/hwmon/sl28cpld-hwmon.c @@ -23,13 +23,6 @@ struct sl28cpld_hwmon { u32 offset; }; -static umode_t sl28cpld_hwmon_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int sl28cpld_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *input) @@ -73,7 +66,7 @@ static const struct hwmon_channel_info * const sl28cpld_hwmon_info[] = { }; static const struct hwmon_ops sl28cpld_hwmon_ops = { - .is_visible = sl28cpld_hwmon_is_visible, + .visible = 0444, .read = sl28cpld_hwmon_read, }; diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 0d46edbcb144..595bceb78d76 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -858,7 +858,7 @@ static struct platform_driver smsc47m1_driver __refdata = { .driver = { .name = DRVNAME, }, - .remove_new = __exit_p(smsc47m1_remove), + .remove = __exit_p(smsc47m1_remove), }; static int __init smsc47m1_device_add(unsigned short address, diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c index fcbce5a01e55..6cee48a3e5c3 100644 --- a/drivers/hwmon/spd5118.c +++ b/drivers/hwmon/spd5118.c @@ -671,7 +671,7 @@ static int spd5118_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume); static const struct i2c_device_id spd5118_id[] = { - { "spd5118", 0 }, + { "spd5118" }, { } }; MODULE_DEVICE_TABLE(i2c, spd5118_id); diff --git a/drivers/hwmon/surface_fan.c b/drivers/hwmon/surface_fan.c index de3c5a2409c6..aafb4ac92e6c 100644 --- a/drivers/hwmon/surface_fan.c +++ b/drivers/hwmon/surface_fan.c @@ -18,14 +18,6 @@ SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, { .command_id = 0x01, }); -// hwmon -static umode_t surface_fan_hwmon_is_visible(const void *drvdata, - enum hwmon_sensor_types type, u32 attr, - int channel) -{ - return 0444; -} - static int surface_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) @@ -49,7 +41,7 @@ static const struct hwmon_channel_info *const surface_fan_info[] = { }; static const struct hwmon_ops surface_fan_hwmon_ops = { - .is_visible = surface_fan_hwmon_is_visible, + .visible = 0444, .read = surface_fan_hwmon_read, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index a82bbc959eb1..1f36af2cd2d9 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -323,33 +324,19 @@ static const struct regmap_config tmp108_regmap_config = { .use_single_write = true, }; -static int tmp108_probe(struct i2c_client *client) +static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name) { - struct device *dev = &client->dev; struct device *hwmon_dev; struct tmp108 *tmp108; - int err; u32 config; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(dev, - "adapter doesn't support SMBus word transactions\n"); - return -ENODEV; - } + int err; tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); if (!tmp108) return -ENOMEM; dev_set_drvdata(dev, tmp108); - - tmp108->regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); - if (IS_ERR(tmp108->regmap)) { - err = PTR_ERR(tmp108->regmap); - dev_err(dev, "regmap init failed: %d", err); - return err; - } + tmp108->regmap = regmap; err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config); if (err < 0) { @@ -383,13 +370,30 @@ static int tmp108_probe(struct i2c_client *client) return err; } - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + hwmon_dev = devm_hwmon_device_register_with_info(dev, name, tmp108, &tmp108_chip_info, NULL); return PTR_ERR_OR_ZERO(hwmon_dev); } +static int tmp108_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) + return dev_err_probe(dev, -ENODEV, + "adapter doesn't support SMBus word transactions\n"); + + regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed"); + + return tmp108_common_probe(dev, regmap, client->name); +} + static int tmp108_suspend(struct device *dev) { struct tmp108 *tmp108 = dev_get_drvdata(dev); @@ -420,6 +424,7 @@ MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id tmp108_of_ids[] = { + { .compatible = "nxp,p3t1085", }, { .compatible = "ti,tmp108", }, {} }; @@ -436,7 +441,39 @@ static struct i2c_driver tmp108_driver = { .id_table = tmp108_i2c_ids, }; -module_i2c_driver(tmp108_driver); +static const struct i3c_device_id p3t1085_i3c_ids[] = { + I3C_DEVICE(0x011b, 0x1529, NULL), + {} +}; +MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids); + +static int p3t1085_i3c_probe(struct i3c_device *i3cdev) +{ + struct device *dev = i3cdev_to_dev(i3cdev); + struct regmap *regmap; + +#ifdef CONFIG_REGMAP_I3C + regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config); +#else + regmap = ERR_PTR(-ENODEV); +#endif + + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to register i3c regmap\n"); + + return tmp108_common_probe(dev, regmap, "p3t1085_i3c"); +} + +static struct i3c_driver p3t1085_driver = { + .driver = { + .name = "p3t1085_i3c", + }, + .probe = p3t1085_i3c_probe, + .id_table = p3t1085_i3c_ids, +}; + +module_i3c_i2c_driver(p3t1085_driver, &tmp108_driver) MODULE_AUTHOR("John Muir "); MODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver"); diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 2765d5f1b7f0..e4f1bb538628 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -317,7 +317,7 @@ static struct platform_driver env_driver = { .of_match_table = env_match, }, .probe = env_probe, - .remove_new = env_remove, + .remove = env_remove, }; module_platform_driver(env_driver); diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 5abe95b683c0..823bff2871e1 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -197,7 +197,7 @@ static struct platform_driver via_cputemp_driver = { .name = DRVNAME, }, .probe = via_cputemp_probe, - .remove_new = via_cputemp_remove, + .remove = via_cputemp_remove, }; struct pdev_entry { diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 3a002ad3c005..bbaeb808cc15 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -799,7 +799,7 @@ static struct platform_driver via686a_driver = { .name = DRIVER_NAME, }, .probe = via686a_probe, - .remove_new = via686a_remove, + .remove = via686a_remove, }; static const struct pci_device_id via686a_pci_ids[] = { diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 2f3890463e18..386edea6b69e 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1221,7 +1221,7 @@ static struct platform_driver vt1211_driver = { .name = DRVNAME, }, .probe = vt1211_probe, - .remove_new = vt1211_remove, + .remove = vt1211_remove, }; static int __init vt1211_device_add(unsigned short address) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index dcdd14ccd115..3bf27c21845b 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -910,11 +910,11 @@ static void vt8231_remove(struct platform_device *pdev) static struct platform_driver vt8231_driver = { - .driver = { + .driver = { .name = DRIVER_NAME, }, .probe = vt8231_probe, - .remove_new = vt8231_remove, + .remove = vt8231_remove, }; static const struct pci_device_id vt8231_pci_ids[] = { diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 2fc9b718e2ab..95115d7b863e 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1844,7 +1844,7 @@ static struct platform_driver w83627hf_driver = { .pm = W83627HF_DEV_PM_OPS, }, .probe = w83627hf_probe, - .remove_new = w83627hf_remove, + .remove = w83627hf_remove, }; static int __init w83627hf_find(int sioaddr, unsigned short *addr, diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index b7957c84d235..076200ed2ec9 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1828,7 +1828,7 @@ static struct platform_driver w83781d_isa_driver = { .name = "w83781d", }, .probe = w83781d_isa_probe, - .remove_new = w83781d_isa_remove, + .remove = w83781d_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c index 5e0759a70f6d..1e3bd129a922 100644 --- a/drivers/hwmon/xgene-hwmon.c +++ b/drivers/hwmon/xgene-hwmon.c @@ -772,7 +772,7 @@ MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match); static struct platform_driver xgene_hwmon_driver = { .probe = xgene_hwmon_probe, - .remove_new = xgene_hwmon_remove, + .remove = xgene_hwmon_remove, .driver = { .name = "xgene-slimpro-hwmon", .of_match_table = xgene_hwmon_of_match, diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 5c6a421ad580..3a63dff62d03 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -368,7 +368,9 @@ enum hwmon_intrusion_attributes { /** * struct hwmon_ops - hwmon device operations - * @is_visible: Callback to return attribute visibility. Mandatory. + * @visible: Static visibility. If non-zero, 'is_visible' is ignored. + * @is_visible: Callback to return attribute visibility. Mandatory unless + * 'visible' is non-zero. * Parameters are: * @const void *drvdata: * Pointer to driver-private data structure passed @@ -412,6 +414,7 @@ enum hwmon_intrusion_attributes { * The function returns 0 on success or a negative error number. */ struct hwmon_ops { + umode_t visible; umode_t (*is_visible)(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel); int (*read)(struct device *dev, enum hwmon_sensor_types type, diff --git a/include/linux/platform_data/max6639.h b/include/linux/platform_data/max6639.h deleted file mode 100644 index 65bfdb4fdc15..000000000000 --- a/include/linux/platform_data/max6639.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_MAX6639_H -#define _LINUX_MAX6639_H - -#include - -/* platform data for the MAX6639 temperature sensor and fan control */ - -struct max6639_platform_data { - bool pwm_polarity; /* Polarity low (0) or high (1, default) */ - int ppr; /* Pulses per rotation 1..4 (default == 2) */ - int rpm_range; /* 2000, 4000 (default), 8000 or 16000 */ -}; - -#endif /* _LINUX_MAX6639_H */