mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 04:04:26 +08:00
hmon updates for v6.13-rc1
* New drivers - ISL28022 power monitor - Nuvoton NCT7363Y * Added support for new chips to existing drivers - The tmp180 driver now supports NXP p3t1085, including its I3C mode - The ina2xx driver now supports SY24655 and INA260 - The amc6821 driver now supports tsd,mule * Other notable improvements - The sht4x driver now supports the chip heater - The pmbus/isl68137 driver now supports a voltage divider on Vout - The cros_ec driver registers with the thermal framework - The pmbus/ltc2978 driver now supports LTC7841 - The PMBus core now allow drivers to override WRITE_PROTECT * Various other minor improvements and cleanups -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmc6tlAACgkQyx8mb86f mYEmThAAi85J4hUepnrpfKwzqzTgXhU3Y1ih7qWyIK0ErI5tjmYiCR3PHHd7jNb0 A5STfbpRkomvepQq9H79lv5EiOMFvudYLj2QuxFbSchz0J2XqXtg2RxUi9AK0/SE b+KLRjNNNHc2J2tDrLj14ZJJxMbqx35kx2x6TDGI+zoBhQ0XwEWkbtNuXipSpHQ8 OkTjbtGKlQrjtc7fJ/fWGlTDeVS2LWtCbJhybcL47IkPeIBQH/FIhoEnnKqj9/EV KROuVAIoAYK9r+w7ZDfp2iBpR0gOaWZ5I2w2cCufsO9pFEuMIeVDgfFP2XGLBXEi NlVlMMyk6X7XqvnHYmun6r9chuPtFc9+Rr7SnJkVaNviY7BmRcuWk1BGxA4GIAIR 6F3sBxlXdisnjVkYd1ENhCGlso/fXQizKUro3KZka0sXEnjxA+SE0dzIK8d77kip P6Mjg3hC6DZlA0eIlnbCWasu0gra4duVTpGTOcbfZQHN+50Fi4va9w2+1UDfIPnn f2gIUubtzrWZqKAPnN6ckIE7BQubsPukx7Zef0wgDRpxOgCBrKeQVX8LYtXQfkda G+LkSk1N1bUIpTbzGQPg7YLbVCQPQYqaSryFPL2lQtfEY58Tgt+EMCKSROmXMBOV tk9uDaN8OjXdYmU90jcHJR7v1WDkLRkRV0fsh6eFUpc8gQDiY+k= =BG/M -----END PGP SIGNATURE----- Merge tag 'hwmon-for-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hmon updates from Guenter Roeck: "New drivers: - ISL28022 power monitor - Nuvoton NCT7363Y Added support for new chips to existing drivers: - The tmp180 driver now supports NXP p3t1085, including its I3C mode - The ina2xx driver now supports SY24655 and INA260 - The amc6821 driver now supports tsd,mule Other notable improvements: - The sht4x driver now supports the chip heater - The pmbus/isl68137 driver now supports a voltage divider on Vout - The cros_ec driver registers with the thermal framework - The pmbus/ltc2978 driver now supports LTC7841 - The PMBus core now allow drivers to override WRITE_PROTECT Various other minor improvements and cleanups" * tag 'hwmon-for-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (51 commits) hwmon: (pmbus/isl68137) add support for voltage divider on Vout dt-bindings: hwmon: isl68137: add bindings to support voltage dividers hwmon: tmp108: fix I3C dependency hwmon: (cros_ec) register thermal sensors to thermal framework hwmon: (tmp108) Add support for I3C device hwmon: (tmp108) Add helper function tmp108_common_probe() to prepare I3C support hwmon: (acpi_power_meter) Fix fail to load module on platform without _PMD method hwmon: (nct6775-core) Fix overflows seen when writing limit attributes hwmon: (pwm-fan) Introduce start from stopped state handling dt-bindings: hwmon: pwm-fan: Document start from stopped state properties hwmon: (tmp108) Add NXP p3t1085 support dt-bindings: hwmon: ti,tmp108: Add nxp,p3t1085 compatible string hwmon: (sch5627, max31827) Fix typos in driver documentation hwmon: (jc42) Drop of_match_ptr() protection hwmon: (f71882fg) Fix grammar in fan speed trip points explanation dt-bindings: hwmon: pmbus: add ti tps25990 support hwmon: (pmbus/core) clear faults after setting smbalert mask hwmon: (pmbus/core) allow drivers to override WRITE_PROTECT hwmon: (pmbus) add documentation for existing flags hwmon: (ina226) Add support for SY24655 ...
This commit is contained in:
commit
2b5d5f23d4
@ -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
|
||||
|
66
Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml
Normal file
66
Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml
Normal file
@ -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 <kcfeng0@nuvoton.com>
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
148
Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml
Normal file
148
Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml
Normal file
@ -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 <grant.peltier.jg@renesas.com>
|
||||
|
||||
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
|
||||
<Rout Rtotal> 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
|
||||
};
|
||||
};
|
||||
};
|
@ -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 <naresh.solanki@9elements.com>
|
||||
|
||||
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 <dt-bindings/interrupt-controller/irq.h>
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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 <jbrunet@baylibre.com>
|
||||
|
||||
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 <dt-bindings/interrupt-controller/irq.h>
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -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 <sylv@sylv.io>
|
||||
- Naresh Solanki <naresh.solanki@9elements.com>
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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ß <mail@carsten-spiess.de>
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
86
Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml
Normal file
86
Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml
Normal file
@ -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 <farouk.bouabid@cherry.de>
|
||||
- Quentin Schulz <quentin.schulz@cherry.de>
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -20,6 +20,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- silergy,sy24655
|
||||
- ti,ina209
|
||||
- ti,ina219
|
||||
- ti,ina220
|
||||
|
@ -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 <krzk@kernel.org>
|
||||
|
||||
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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 <lothar.felten@gmail.com>
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
63
Documentation/hwmon/isl28022.rst
Normal file
63
Documentation/hwmon/isl28022.rst
Normal file
@ -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ß <mail@carsten-spiess.de>
|
||||
|
||||
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)
|
||||
======================= =======================================================
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
35
Documentation/hwmon/nct7363.rst
Normal file
35
Documentation/hwmon/nct7363.rst
Normal file
@ -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 <kcfeng0@nuvoton.com>
|
||||
|
||||
|
||||
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.
|
||||
========== ==========================================
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
=============== ============================================
|
||||
|
@ -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'
|
||||
|
29
MAINTAINERS
29
MAINTAINERS
@ -12104,6 +12104,14 @@ F: drivers/isdn/Makefile
|
||||
F: drivers/isdn/hardware/
|
||||
F: drivers/isdn/mISDN/
|
||||
|
||||
ISL28022 HARDWARE MONITORING DRIVER
|
||||
M: Carsten Spieß <mail@carsten-spiess.de>
|
||||
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 <jack@suse.cz>
|
||||
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 <kcfeng0@nuvoton.com>
|
||||
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 <leitao@debian.org>
|
||||
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 <mezin.alexander@gmail.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/nzxt-smart2.rst
|
||||
F: drivers/hwmon/nzxt-smart2.c
|
||||
|
||||
OBJAGG
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
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 <jbrunet@baylibre.com>
|
||||
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 <robert.marko@sartura.hr>
|
||||
M: Luka Perkov <luka.perkov@sartura.hr>
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -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",
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
535
drivers/hwmon/isl28022.c
Normal file
535
drivers/hwmon/isl28022.c
Normal file
@ -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ß <mail@carsten-spiess.de>
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* 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ß <mail@carsten-spiess.de>");
|
||||
MODULE_DESCRIPTION("ISL28022 driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@ -19,7 +20,6 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* 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,
|
||||
|
@ -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);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_data/max6639.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
447
drivers/hwmon/nct7363.c
Normal file
447
drivers/hwmon/nct7363.c
Normal file
@ -0,0 +1,447 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#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 <cwho@nuvoton.com>");
|
||||
MODULE_AUTHOR("Ban Feng <kcfeng0@nuvoton.com>");
|
||||
MODULE_DESCRIPTION("NCT7363 Hardware Monitoring Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -1606,7 +1606,7 @@ static struct platform_driver pc87360_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = pc87360_probe,
|
||||
.remove_new = pc87360_remove,
|
||||
.remove = pc87360_remove,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
@ -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" },
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 @@ out:
|
||||
}
|
||||
|
||||
static const struct hwmon_ops powerz_hwmon_ops = {
|
||||
.is_visible = powerz_is_visible,
|
||||
.visible = 0444,
|
||||
.read = powerz_read,
|
||||
.read_string = powerz_read_string,
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Author: Kamil Debski <k.debski@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i3c/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -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 <john@jmuir.com>");
|
||||
MODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver");
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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[] = {
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -1,15 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_MAX6639_H
|
||||
#define _LINUX_MAX6639_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* 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 */
|
Loading…
Reference in New Issue
Block a user