hwmon patches for v5.7
New driver for AXI fan control. Attenuator bypass support and support for inverting pwm output in adt7475 driver. Support for new power supply version in ibm-cffps driver. PMBus drivers: Support for multi-phase chips. Support for LTC2972, LTC2979, LTC3884, LTC3889, LTC7880, LTM4664, LTM4677, LTM4678, LTM4680, and LTM4700 added to ltc2978 driver. Support for TPS53681, TPS53647, and TPS53667 added to tps53679 driver. Support for various 2nd Gen Renesas digital multiphase chips added to isl68137 driver. Minor improvements and fixes in nct7904, ibmpowernv, lm73, ibmaem, and k10temp drivers. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAl6CFCEACgkQyx8mb86f mYHoHA/+OnoYUyknO9zpdH4DJ9Hte7GqnNKUE6txORInZXqICQAHfrRYbFA6HGxi 8BYlV1b3A/9nvi9uR1XNheDTjlnvkJYMvZEYABSxDvdVkzSgPo2lvW/SvIf4Dq0k OhqFKnCZ/decs7VhsnqaNK5iyv26wWDt8YMXiSC9PmSoUi4YhVgUfLFJXSU2QlGh tRg97gVGVVJyimpaP+5b6khC3JiS1XPpbkD8d95Xqw6w6JUxN75O9ezWRTyz8Dbe DqT+9uOFnvZrIyoPRatb3zVdtM8FwFMaJmQDOlIqYJ7mzzDW7visViKVu2sjODe8 6CM587vbuFOrzXzPqjjDho9T2ejz3oL3c25SuO1Jxu3KGJ/Aq61rP0V1PNoGDAWx rqPLwhGgLqtiBpLFPoNnRvzI10wmPGaaVlk3JCFZOj2uUv7RFuGw99sckucmW2dd 9XRcp7ig6LxhnaFozBfLJsXiHaaFQvV+wZdT43reEE78Uv9HWOUZ8UH/w/nPDuit YnOQon9BHU+bC9ebpgtkBiWdA+sU8nk14T7xNMunR/+bYYDQEXjUms9z2gHtv9lX f0ZO4r8wCLL3Mn+cAwk4S32nnSu2A1pUoQAqg2c6UpYcr4kVJRP1FTA25bzh9MRH IdOGhQ54FK8mENARLpzLYaxgI4K/FsF70z9DZFsvjpd4lKT9Fyk= =S/bJ -----END PGP SIGNATURE----- Merge tag 'hwmon-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: - New driver for AXI fan control - Attenuator bypass support and support for inverting pwm output in adt7475 driver - Support for new power supply version in ibm-cffps driver - PMBus drivers: * support for multi-phase chips * ltc2978 driver: add support for LTC2972, LTC2979, LTC3884, LTC3889, LTC7880, LTM4664, LTM4677, LTM4678, LTM4680, and LTM4700/ * tps53679 driver: add support for TPS53681, TPS53647, and TPS53667 * isl68137 driver: support for various 2nd Gen Renesas digital multiphase chips added to isl68137 driver - Minor improvements and fixes in nct7904, ibmpowernv, lm73, ibmaem, and k10temp drivers * tag 'hwmon-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (29 commits) docs: hwmon: Update documentation for isl68137 pmbus driver hwmon: (pmbus) add support for 2nd Gen Renesas digital multiphase hwmon: (pmbus/ibm-cffps) Add another PSU CCIN to version detection hwmon: (nct7904) Fix the incorrect quantity for fan & temp attributes hwmon: (ibmpowernv) Use scnprintf() for avoiding potential buffer overflow hwmon: (adt7475) Add support for inverting pwm output hwmon: (adt7475) Add attenuator bypass support dt-bindings: hwmon: Document adt7475 pwm-active-state property dt-bindings: hwmon: Document adt7475 bypass-attenuator property dt-bindings: hwmon: Document adt7475 binding hwmon: (lm73) Add support for of_match_table dt-bindings: Add TI LM73 as a trivial device hwmon: (pmbus/tps53679) Add documentation hwmon: (pmbus/tps53679) Add support for TPS53647 and TPS53667 hwmon: (pmbus/tps53679) Add support for TPS53681 hwmon: (pmbus/tps53679) Add support for IIN and PIN to TPS53679 and TPS53688 hwmon: (pmbus/tps53679) Add support for multiple chips IDs hwmon: (pmbus) Implement multi-phase support hwmon: (pmbus) Add 'phase' parameter where needed for multi-phase support hwmon: (pmbus) Add IC_DEVICE_ID and IC_DEVICE_REV command definitions ...
This commit is contained in:
Коммит
47acac8cae
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright 2019 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/bindings/hwmon/adi,axi-fan-control.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AXI FAN Control Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |+
|
||||
Bindings for the Analog Devices AXI FAN Control driver. Spefications of the
|
||||
core can be found in:
|
||||
|
||||
https://wiki.analog.com/resources/fpga/docs/axi_fan_control
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,axi-fan-control-1.00.a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
pulses-per-revolution:
|
||||
description:
|
||||
Value specifying the number of pulses per revolution of the controlled
|
||||
FAN.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2, 4]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
- pulses-per-revolution
|
||||
|
||||
examples:
|
||||
- |
|
||||
fpga_axi: fpga-axi@0 {
|
||||
#address-cells = <0x2>;
|
||||
#size-cells = <0x1>;
|
||||
|
||||
axi_fan_control: axi-fan-control@80000000 {
|
||||
compatible = "adi,axi-fan-control-1.00.a";
|
||||
reg = <0x0 0x80000000 0x10000>;
|
||||
clocks = <&clk 71>;
|
||||
interrupts = <0 110 0>;
|
||||
pulses-per-revolution = <2>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,84 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/adt7475.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ADT7475 hwmon sensor
|
||||
|
||||
maintainers:
|
||||
- Jean Delvare <jdelvare@suse.com>
|
||||
|
||||
description: |
|
||||
The ADT7473, ADT7475, ADT7476, and ADT7490 are thermal monitors and multiple
|
||||
PWN fan controllers.
|
||||
|
||||
They support monitoring and controlling up to four fans (the ADT7490 can only
|
||||
control up to three). They support reading a single on chip temperature
|
||||
sensor and two off chip temperature sensors (the ADT7490 additionally
|
||||
supports measuring up to three current external temperature sensors with
|
||||
series resistance cancellation (SRC)).
|
||||
|
||||
Datasheets:
|
||||
https://www.onsemi.com/pub/Collateral/ADT7473-D.PDF
|
||||
https://www.onsemi.com/pub/Collateral/ADT7475-D.PDF
|
||||
https://www.onsemi.com/pub/Collateral/ADT7476-D.PDF
|
||||
https://www.onsemi.com/pub/Collateral/ADT7490-D.PDF
|
||||
|
||||
Description taken from onsemiconductors specification sheets, with minor
|
||||
rephrasing.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adt7473
|
||||
- adi,adt7475
|
||||
- adi,adt7476
|
||||
- adi,adt7490
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^adi,bypass-attenuator-in[0-4]$":
|
||||
description: |
|
||||
Configures bypassing the individual voltage input attenuator. If
|
||||
set to 1 the attenuator is bypassed if set to 0 the attenuator is
|
||||
not bypassed. If the property is absent then the attenuator
|
||||
retains it's configuration from the bios/bootloader.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [0, 1]
|
||||
|
||||
"^adi,pwm-active-state$":
|
||||
description: |
|
||||
Integer array, represents the active state of the pwm outputs If set to 0
|
||||
the pwm uses a logic low output for 100% duty cycle. If set to 1 the pwm
|
||||
uses a logic high output for 100% duty cycle.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
- minItems: 3
|
||||
maxItems: 3
|
||||
items:
|
||||
enum: [0, 1]
|
||||
default: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hwmon@2e {
|
||||
compatible = "adi,adt7476";
|
||||
reg = <0x2e>;
|
||||
adi,bypass-attenuator-in0 = <1>;
|
||||
adi,bypass-attenuator-in1 = <0>;
|
||||
adi,pwm-active-state = <1 0 1>;
|
||||
};
|
||||
};
|
||||
|
|
@ -2,20 +2,30 @@ ltc2978
|
|||
|
||||
Required properties:
|
||||
- compatible: should contain one of:
|
||||
* "lltc,ltc2972"
|
||||
* "lltc,ltc2974"
|
||||
* "lltc,ltc2975"
|
||||
* "lltc,ltc2977"
|
||||
* "lltc,ltc2978"
|
||||
* "lltc,ltc2979"
|
||||
* "lltc,ltc2980"
|
||||
* "lltc,ltc3880"
|
||||
* "lltc,ltc3882"
|
||||
* "lltc,ltc3883"
|
||||
* "lltc,ltc3884"
|
||||
* "lltc,ltc3886"
|
||||
* "lltc,ltc3887"
|
||||
* "lltc,ltc3889"
|
||||
* "lltc,ltc7880"
|
||||
* "lltc,ltm2987"
|
||||
* "lltc,ltm4664"
|
||||
* "lltc,ltm4675"
|
||||
* "lltc,ltm4676"
|
||||
* "lltc,ltm4677"
|
||||
* "lltc,ltm4678"
|
||||
* "lltc,ltm4680"
|
||||
* "lltc,ltm4686"
|
||||
* "lltc,ltm4700"
|
||||
- reg: I2C slave address
|
||||
|
||||
Optional properties:
|
||||
|
@ -25,13 +35,17 @@ Optional properties:
|
|||
standard binding for regulators; see regulator.txt.
|
||||
|
||||
Valid names of regulators depend on number of supplies supported per device:
|
||||
* ltc2972 vout0 - vout1
|
||||
* ltc2974, ltc2975 : vout0 - vout3
|
||||
* ltc2977, ltc2980, ltm2987 : vout0 - vout7
|
||||
* ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7
|
||||
* ltc2978 : vout0 - vout7
|
||||
* ltc3880, ltc3882, ltc3886 : vout0 - vout1
|
||||
* ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1
|
||||
* ltc7880 : vout0 - vout1
|
||||
* ltc3883 : vout0
|
||||
* ltm4676 : vout0 - vout1
|
||||
* ltm4686 : vout0 - vout1
|
||||
* ltm4664 : vout0 - vout1
|
||||
* ltm4675, ltm4676, ltm4677, ltm4678 : vout0 - vout1
|
||||
* ltm4680, ltm4686 : vout0 - vout1
|
||||
* ltm4700 : vout0 - vout1
|
||||
|
||||
Example:
|
||||
ltc2978@5e {
|
||||
|
|
|
@ -34,14 +34,6 @@ properties:
|
|||
- adi,adt7461
|
||||
# +/-1C TDM Extended Temp Range I.C
|
||||
- adt7461
|
||||
# +/-1C TDM Extended Temp Range I.C
|
||||
- adi,adt7473
|
||||
# +/-1C TDM Extended Temp Range I.C
|
||||
- adi,adt7475
|
||||
# +/-1C TDM Extended Temp Range I.C
|
||||
- adi,adt7476
|
||||
# +/-1C TDM Extended Temp Range I.C
|
||||
- adi,adt7490
|
||||
# Three-Axis Digital Accelerometer
|
||||
- adi,adxl345
|
||||
# Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
|
||||
|
@ -350,6 +342,8 @@ properties:
|
|||
- ti,ads7830
|
||||
# Temperature Monitoring and Fan Control
|
||||
- ti,amc6821
|
||||
# Temperature sensor with 2-wire interface
|
||||
- ti,lm73
|
||||
# Temperature sensor with integrated fan control
|
||||
- ti,lm96000
|
||||
# I2C Touch-Screen Controller
|
||||
|
|
|
@ -162,6 +162,7 @@ Hardware Monitoring Kernel Drivers
|
|||
tmp421
|
||||
tmp513
|
||||
tps40422
|
||||
tps53679
|
||||
twl4030-madc-hwmon
|
||||
ucd9000
|
||||
ucd9200
|
||||
|
|
|
@ -3,7 +3,7 @@ Kernel driver isl68137
|
|||
|
||||
Supported chips:
|
||||
|
||||
* Intersil ISL68137
|
||||
* Renesas ISL68137
|
||||
|
||||
Prefix: 'isl68137'
|
||||
|
||||
|
@ -11,19 +11,405 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
Publicly available at the Intersil website
|
||||
https://www.intersil.com/content/dam/Intersil/documents/isl6/isl68137.pdf
|
||||
Publicly available at the Renesas website
|
||||
https://www.renesas.com/us/en/www/doc/datasheet/isl68137.pdf
|
||||
|
||||
* Renesas ISL68220
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68221
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68222
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68223
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68224
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68225
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68226
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68227
|
||||
|
||||
Prefix: 'raa_dmpvr2_1rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68229
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68233
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL68239
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69222
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69223
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69224
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69225
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69227
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69228
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69234
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69236
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69239
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69242
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69243
|
||||
|
||||
Prefix: 'raa_dmpvr2_1rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69247
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69248
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69254
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69255
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69256
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69259
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69260
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69268
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69269
|
||||
|
||||
Prefix: 'raa_dmpvr2_3rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas ISL69298
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA228000
|
||||
|
||||
Prefix: 'raa_dmpvr2_hv'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA228004
|
||||
|
||||
Prefix: 'raa_dmpvr2_hv'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA228006
|
||||
|
||||
Prefix: 'raa_dmpvr2_hv'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA228228
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA229001
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA229004
|
||||
|
||||
Prefix: 'raa_dmpvr2_2rail'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
Authors:
|
||||
- Maxim Sloyko <maxims@google.com>
|
||||
- Robert Lippert <rlippert@google.com>
|
||||
- Patrick Venture <venture@google.com>
|
||||
- Grant Peltier <grant.peltier.jg@renesas.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Intersil ISL68137 is a digital output 7-phase configurable PWM
|
||||
controller with an AVSBus interface.
|
||||
This driver supports the Renesas ISL68137 and all 2nd generation Renesas
|
||||
digital multiphase voltage regulators (raa_dmpvr2). The ISL68137 is a digital
|
||||
output 7-phase configurable PWM controller with an AVSBus interface. 2nd
|
||||
generation devices are grouped into 4 distinct configurations: '1rail' for
|
||||
single-rail devices, '2rail' for dual-rail devices, '3rail' for 3-rail devices,
|
||||
and 'hv' for high voltage single-rail devices. Consult the individual datasheets
|
||||
for more information.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
@ -33,10 +419,14 @@ devices explicitly.
|
|||
|
||||
The ISL68137 AVS operation mode must be enabled/disabled at runtime.
|
||||
|
||||
Beyond the normal sysfs pmbus attributes, the driver exposes a control attribute.
|
||||
Beyond the normal sysfs pmbus attributes, the driver exposes a control attribute
|
||||
for the ISL68137.
|
||||
|
||||
Additional Sysfs attributes
|
||||
---------------------------
|
||||
For 2nd generation Renesas digital multiphase voltage regulators, only the
|
||||
normal sysfs pmbus attributes are supported.
|
||||
|
||||
ISL68137 sysfs attributes
|
||||
-------------------------
|
||||
|
||||
======================= ====================================
|
||||
avs(0|1)_enable Controls the AVS state of each rail.
|
||||
|
@ -78,3 +468,138 @@ temp[1-3]_crit_alarm Chip temperature critical high alarm
|
|||
temp[1-3]_max Maximum temperature
|
||||
temp[1-3]_max_alarm Chip temperature high alarm
|
||||
======================= ====================================
|
||||
|
||||
raa_dmpvr2_1rail/hv sysfs attributes
|
||||
------------------------------------
|
||||
|
||||
======================= ==========================================
|
||||
curr1_label "iin"
|
||||
curr1_input Measured input current
|
||||
curr1_crit Critical maximum current
|
||||
curr1_crit_alarm Current critical high alarm
|
||||
|
||||
curr2_label "iout"
|
||||
curr2_input Measured output current
|
||||
curr2_crit Critical maximum current
|
||||
curr2_crit_alarm Current critical high alarm
|
||||
|
||||
in1_label "vin"
|
||||
in1_input Measured input voltage
|
||||
in1_lcrit Critical minimum input voltage
|
||||
in1_lcrit_alarm Input voltage critical low alarm
|
||||
in1_crit Critical maximum input voltage
|
||||
in1_crit_alarm Input voltage critical high alarm
|
||||
|
||||
in2_label "vmon"
|
||||
in2_input Scaled VMON voltage read from the VMON pin
|
||||
|
||||
in3_label "vout"
|
||||
in3_input Measured output voltage
|
||||
in3_lcrit Critical minimum output voltage
|
||||
in3_lcrit_alarm Output voltage critical low alarm
|
||||
in3_crit Critical maximum output voltage
|
||||
in3_crit_alarm Output voltage critical high alarm
|
||||
|
||||
power1_label "pin"
|
||||
power1_input Measured input power
|
||||
power1_alarm Input power high alarm
|
||||
|
||||
power2_label "pout"
|
||||
power2_input Measured output power
|
||||
|
||||
temp[1-3]_input Measured temperature
|
||||
temp[1-3]_crit Critical high temperature
|
||||
temp[1-3]_crit_alarm Chip temperature critical high alarm
|
||||
temp[1-3]_max Maximum temperature
|
||||
temp[1-3]_max_alarm Chip temperature high alarm
|
||||
======================= ==========================================
|
||||
|
||||
raa_dmpvr2_2rail sysfs attributes
|
||||
---------------------------------
|
||||
|
||||
======================= ==========================================
|
||||
curr[1-2]_label "iin[1-2]"
|
||||
curr[1-2]_input Measured input current
|
||||
curr[1-2]_crit Critical maximum current
|
||||
curr[1-2]_crit_alarm Current critical high alarm
|
||||
|
||||
curr[3-4]_label "iout[1-2]"
|
||||
curr[3-4]_input Measured output current
|
||||
curr[3-4]_crit Critical maximum current
|
||||
curr[3-4]_crit_alarm Current critical high alarm
|
||||
|
||||
in1_label "vin"
|
||||
in1_input Measured input voltage
|
||||
in1_lcrit Critical minimum input voltage
|
||||
in1_lcrit_alarm Input voltage critical low alarm
|
||||
in1_crit Critical maximum input voltage
|
||||
in1_crit_alarm Input voltage critical high alarm
|
||||
|
||||
in2_label "vmon"
|
||||
in2_input Scaled VMON voltage read from the VMON pin
|
||||
|
||||
in[3-4]_label "vout[1-2]"
|
||||
in[3-4]_input Measured output voltage
|
||||
in[3-4]_lcrit Critical minimum output voltage
|
||||
in[3-4]_lcrit_alarm Output voltage critical low alarm
|
||||
in[3-4]_crit Critical maximum output voltage
|
||||
in[3-4]_crit_alarm Output voltage critical high alarm
|
||||
|
||||
power[1-2]_label "pin[1-2]"
|
||||
power[1-2]_input Measured input power
|
||||
power[1-2]_alarm Input power high alarm
|
||||
|
||||
power[3-4]_label "pout[1-2]"
|
||||
power[3-4]_input Measured output power
|
||||
|
||||
temp[1-5]_input Measured temperature
|
||||
temp[1-5]_crit Critical high temperature
|
||||
temp[1-5]_crit_alarm Chip temperature critical high alarm
|
||||
temp[1-5]_max Maximum temperature
|
||||
temp[1-5]_max_alarm Chip temperature high alarm
|
||||
======================= ==========================================
|
||||
|
||||
raa_dmpvr2_3rail sysfs attributes
|
||||
---------------------------------
|
||||
|
||||
======================= ==========================================
|
||||
curr[1-3]_label "iin[1-3]"
|
||||
curr[1-3]_input Measured input current
|
||||
curr[1-3]_crit Critical maximum current
|
||||
curr[1-3]_crit_alarm Current critical high alarm
|
||||
|
||||
curr[4-6]_label "iout[1-3]"
|
||||
curr[4-6]_input Measured output current
|
||||
curr[4-6]_crit Critical maximum current
|
||||
curr[4-6]_crit_alarm Current critical high alarm
|
||||
|
||||
in1_label "vin"
|
||||
in1_input Measured input voltage
|
||||
in1_lcrit Critical minimum input voltage
|
||||
in1_lcrit_alarm Input voltage critical low alarm
|
||||
in1_crit Critical maximum input voltage
|
||||
in1_crit_alarm Input voltage critical high alarm
|
||||
|
||||
in2_label "vmon"
|
||||
in2_input Scaled VMON voltage read from the VMON pin
|
||||
|
||||
in[3-5]_label "vout[1-3]"
|
||||
in[3-5]_input Measured output voltage
|
||||
in[3-5]_lcrit Critical minimum output voltage
|
||||
in[3-5]_lcrit_alarm Output voltage critical low alarm
|
||||
in[3-5]_crit Critical maximum output voltage
|
||||
in[3-5]_crit_alarm Output voltage critical high alarm
|
||||
|
||||
power[1-3]_label "pin[1-3]"
|
||||
power[1-3]_input Measured input power
|
||||
power[1-3]_alarm Input power high alarm
|
||||
|
||||
power[4-6]_label "pout[1-3]"
|
||||
power[4-6]_input Measured output power
|
||||
|
||||
temp[1-7]_input Measured temperature
|
||||
temp[1-7]_crit Critical high temperature
|
||||
temp[1-7]_crit_alarm Chip temperature critical high alarm
|
||||
temp[1-7]_max Maximum temperature
|
||||
temp[1-7]_max_alarm Chip temperature high alarm
|
||||
======================= ==========================================
|
||||
|
|
|
@ -100,9 +100,10 @@ socket type, not the processor's actual capabilities. Therefore, if you
|
|||
are using an AM3 processor on an AM2+ mainboard, you can safely use the
|
||||
"force=1" parameter.
|
||||
|
||||
There is one temperature measurement value, available as temp1_input in
|
||||
sysfs. It is measured in degrees Celsius with a resolution of 1/8th degree.
|
||||
Please note that it is defined as a relative value; to quote the AMD manual::
|
||||
For CPUs older than Family 17h, there is one temperature measurement value,
|
||||
available as temp1_input in sysfs. It is measured in degrees Celsius with a
|
||||
resolution of 1/8th degree. Please note that it is defined as a relative
|
||||
value; to quote the AMD manual::
|
||||
|
||||
Tctl is the processor temperature control value, used by the platform to
|
||||
control cooling systems. Tctl is a non-physical temperature on an
|
||||
|
@ -126,3 +127,25 @@ it.
|
|||
|
||||
Models from 17h family report relative temperature, the driver aims to
|
||||
compensate and report the real temperature.
|
||||
|
||||
On Family 17h and Family 18h CPUs, additional temperature sensors may report
|
||||
Core Complex Die (CCD) temperatures. Up to 8 such temperatures are reported
|
||||
as temp{3..10}_input, labeled Tccd{1..8}. Actual support depends on the CPU
|
||||
variant.
|
||||
|
||||
Various Family 17h and 18h CPUs report voltage and current telemetry
|
||||
information. The following attributes may be reported.
|
||||
|
||||
Attribute Label Description
|
||||
=============== ======= ================
|
||||
in0_input Vcore Core voltage
|
||||
in1_input Vsoc SoC voltage
|
||||
curr1_input Icore Core current
|
||||
curr2_input Isoc SoC current
|
||||
=============== ======= ================
|
||||
|
||||
Current values are raw (unscaled) as reported by the CPU. Core current is
|
||||
reported as multiples of 1A / LSB. SoC is reported as multiples of 0.25A
|
||||
/ LSB. The real current is board specific. Reported currents should be seen
|
||||
as rough guidance, and should be scaled using sensors3.conf as appropriate
|
||||
for a given board.
|
||||
|
|
|
@ -3,13 +3,21 @@ Kernel driver ltc2978
|
|||
|
||||
Supported chips:
|
||||
|
||||
* Linear Technology LTC2972
|
||||
|
||||
Prefix: 'ltc2972'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltc2972.html
|
||||
|
||||
* Linear Technology LTC2974
|
||||
|
||||
Prefix: 'ltc2974'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc2974
|
||||
Datasheet: https://www.analog.com/en/products/ltc2974
|
||||
|
||||
* Linear Technology LTC2975
|
||||
|
||||
|
@ -17,7 +25,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc2975
|
||||
Datasheet: https://www.analog.com/en/products/ltc2975
|
||||
|
||||
* Linear Technology LTC2977
|
||||
|
||||
|
@ -25,7 +33,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc2977
|
||||
Datasheet: https://www.analog.com/en/products/ltc2977
|
||||
|
||||
* Linear Technology LTC2978, LTC2978A
|
||||
|
||||
|
@ -33,9 +41,17 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc2978
|
||||
Datasheet: https://www.analog.com/en/products/ltc2978
|
||||
|
||||
http://www.linear.com/product/ltc2978a
|
||||
https://www.analog.com/en/products/ltc2978a
|
||||
|
||||
* Linear Technology LTC2979
|
||||
|
||||
Prefix: 'ltc2979'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltc2979
|
||||
|
||||
* Linear Technology LTC2980
|
||||
|
||||
|
@ -43,7 +59,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc2980
|
||||
Datasheet: https://www.analog.com/en/products/ltc2980
|
||||
|
||||
* Linear Technology LTC3880
|
||||
|
||||
|
@ -51,7 +67,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc3880
|
||||
Datasheet: https://www.analog.com/en/products/ltc3880
|
||||
|
||||
* Linear Technology LTC3882
|
||||
|
||||
|
@ -59,7 +75,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc3882
|
||||
Datasheet: https://www.analog.com/en/products/ltc3882
|
||||
|
||||
* Linear Technology LTC3883
|
||||
|
||||
|
@ -67,7 +83,15 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc3883
|
||||
Datasheet: https://www.analog.com/en/products/ltc3883
|
||||
|
||||
* Linear Technology LTC3884
|
||||
|
||||
Prefix: 'ltc3884'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltc3884
|
||||
|
||||
* Linear Technology LTC3886
|
||||
|
||||
|
@ -75,7 +99,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc3886
|
||||
Datasheet: https://www.analog.com/en/products/ltc3886
|
||||
|
||||
* Linear Technology LTC3887
|
||||
|
||||
|
@ -83,7 +107,23 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltc3887
|
||||
Datasheet: https://www.analog.com/en/products/ltc3887
|
||||
|
||||
* Linear Technology LTC3889
|
||||
|
||||
Prefix: 'ltc3889'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltc3889
|
||||
|
||||
* Linear Technology LTC7880
|
||||
|
||||
Prefix: 'ltc7880'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltc7880
|
||||
|
||||
* Linear Technology LTM2987
|
||||
|
||||
|
@ -91,15 +131,23 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltm2987
|
||||
Datasheet: https://www.analog.com/en/products/ltm2987
|
||||
|
||||
* Linear Technology LTM4675
|
||||
* Linear Technology LTM4644
|
||||
|
||||
Prefix: 'ltm4644'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltm4644
|
||||
|
||||
* Linear Technology LTM4675
|
||||
|
||||
Prefix: 'ltm4675'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltm4675
|
||||
Datasheet: https://www.analog.com/en/products/ltm4675
|
||||
|
||||
* Linear Technology LTM4676
|
||||
|
||||
|
@ -107,7 +155,31 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.linear.com/product/ltm4676
|
||||
Datasheet: https://www.analog.com/en/products/ltm4676
|
||||
|
||||
* Linear Technology LTM4677
|
||||
|
||||
Prefix: 'ltm4677'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltm4677
|
||||
|
||||
* Linear Technology LTM4678
|
||||
|
||||
Prefix: 'ltm4678'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/en/products/ltm4678
|
||||
|
||||
* Analog Devices LTM4680
|
||||
|
||||
Prefix: 'ltm4680'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.analog.com/ltm4680
|
||||
|
||||
* Analog Devices LTM4686
|
||||
|
||||
|
@ -117,6 +189,15 @@ Supported chips:
|
|||
|
||||
Datasheet: http://www.analog.com/ltm4686
|
||||
|
||||
* Analog Devices LTM4700
|
||||
|
||||
Prefix: 'ltm4700'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.analog.com/ltm4700
|
||||
|
||||
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
@ -166,13 +247,13 @@ in1_min Minimum input voltage.
|
|||
|
||||
in1_max Maximum input voltage.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
|
||||
LTC2979 and LTM2987 only.
|
||||
|
||||
in1_lcrit Critical minimum input voltage.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
|
||||
LTC2979 and LTM2987 only.
|
||||
|
||||
in1_crit Critical maximum input voltage.
|
||||
|
||||
|
@ -180,29 +261,34 @@ in1_min_alarm Input voltage low alarm.
|
|||
|
||||
in1_max_alarm Input voltage high alarm.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
|
||||
LTC2979 and LTM2987 only.
|
||||
|
||||
in1_lcrit_alarm Input voltage critical low alarm.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
|
||||
LTC2979 and LTM2987 only.
|
||||
|
||||
in1_crit_alarm Input voltage critical high alarm.
|
||||
|
||||
in1_lowest Lowest input voltage.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
|
||||
and LTM2987 only.
|
||||
|
||||
in1_highest Highest input voltage.
|
||||
|
||||
in1_reset_history Reset input voltage history.
|
||||
|
||||
in[N]_label "vout[1-8]".
|
||||
|
||||
- LTC2972: N=2-3
|
||||
- LTC2974, LTC2975: N=2-5
|
||||
- LTC2977, LTC2980, LTM2987: N=2-9
|
||||
- LTC2977, LTC2979, LTC2980, LTM2987: N=2-9
|
||||
- LTC2978: N=2-9
|
||||
- LTC3880, LTC3882, LTC23886 LTC3887, LTM4675, LTM4676:
|
||||
N=2-3
|
||||
- LTC3880, LTC3882, LTC3884, LTC23886 LTC3887, LTC3889,
|
||||
LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678,
|
||||
LTM4680, LTM4700: N=2-3
|
||||
- LTC3883: N=2
|
||||
|
||||
in[N]_input Measured output voltage.
|
||||
|
@ -225,8 +311,7 @@ in[N]_crit_alarm Output voltage critical high alarm.
|
|||
|
||||
in[N]_lowest Lowest output voltage.
|
||||
|
||||
|
||||
LTC2974, LTC2975,and LTC2978 only.
|
||||
LTC2972, LTC2974, LTC2975,and LTC2978 only.
|
||||
|
||||
in[N]_highest Highest output voltage.
|
||||
|
||||
|
@ -234,20 +319,24 @@ in[N]_reset_history Reset output voltage history.
|
|||
|
||||
temp[N]_input Measured temperature.
|
||||
|
||||
- On LTC2972, temp[1-2] report external temperatures,
|
||||
and temp 3 reports the chip temperature.
|
||||
- On LTC2974 and LTC2975, temp[1-4] report external
|
||||
temperatures, and temp5 reports the chip temperature.
|
||||
- On LTC2977, LTC2980, LTC2978, and LTM2987, only one
|
||||
temperature measurement is supported and reports
|
||||
the chip temperature.
|
||||
- On LTC3880, LTC3882, LTC3887, LTM4675, and LTM4676,
|
||||
temp1 and temp2 report external temperatures, and
|
||||
temp3 reports the chip temperature.
|
||||
- On LTC2977, LTC2979, LTC2980, LTC2978, and LTM2987,
|
||||
only one temperature measurement is supported and
|
||||
reports the chip temperature.
|
||||
- On LTC3880, LTC3882, LTC3886, LTC3887, LTC3889,
|
||||
LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
|
||||
and LTM4700, temp1 and temp2 report external
|
||||
temperatures, and temp3 reports the chip temperature.
|
||||
- On LTC3883, temp1 reports an external temperature,
|
||||
and temp2 reports the chip temperature.
|
||||
|
||||
temp[N]_min Mimimum temperature.
|
||||
|
||||
LTC2974, LCT2977, LTM2980, LTC2978, and LTM2987 only.
|
||||
LTC2972, LTC2974, LCT2977, LTM2980, LTC2978,
|
||||
LTC2979, and LTM2987 only.
|
||||
|
||||
temp[N]_max Maximum temperature.
|
||||
|
||||
|
@ -257,8 +346,8 @@ temp[N]_crit Critical high temperature.
|
|||
|
||||
temp[N]_min_alarm Temperature low alarm.
|
||||
|
||||
LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
LTC2972, LTC2974, LTC2975, LTC2977, LTM2980, LTC2978,
|
||||
LTC2979, and LTM2987 only.
|
||||
|
||||
temp[N]_max_alarm Temperature high alarm.
|
||||
|
||||
|
@ -269,8 +358,8 @@ temp[N]_crit_alarm Temperature critical high alarm.
|
|||
|
||||
temp[N]_lowest Lowest measured temperature.
|
||||
|
||||
- LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and
|
||||
LTM2987 only.
|
||||
- LTC2972, LTC2974, LTC2975, LTC2977, LTM2980, LTC2978,
|
||||
LTC2979, and LTM2987 only.
|
||||
- Not supported for chip temperature sensor on LTC2974
|
||||
and LTC2975.
|
||||
|
||||
|
@ -290,19 +379,22 @@ power1_input Measured input power.
|
|||
|
||||
power[N]_label "pout[1-4]".
|
||||
|
||||
- LTC2972: N=1-2
|
||||
- LTC2974, LTC2975: N=1-4
|
||||
- LTC2977, LTC2980, LTM2987: Not supported
|
||||
- LTC2977, LTC2979, LTC2980, LTM2987: Not supported
|
||||
- LTC2978: Not supported
|
||||
- LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676:
|
||||
N=1-2
|
||||
- LTC3880, LTC3882, LTC3884, LTC3886, LTC3887, LTC3889,
|
||||
LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
|
||||
LTM4700: N=1-2
|
||||
- LTC3883: N=2
|
||||
|
||||
power[N]_input Measured output power.
|
||||
|
||||
curr1_label "iin".
|
||||
|
||||
LTC3880, LTC3883, LTC3886, LTC3887, LTM4675,
|
||||
and LTM4676 only.
|
||||
LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889,
|
||||
LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
|
||||
and LTM4700 only.
|
||||
|
||||
curr1_input Measured input current.
|
||||
|
||||
|
@ -320,11 +412,13 @@ curr1_reset_history Reset input current history.
|
|||
|
||||
curr[N]_label "iout[1-4]".
|
||||
|
||||
- LTC2972: N-1-2
|
||||
- LTC2974, LTC2975: N=1-4
|
||||
- LTC2977, LTC2980, LTM2987: not supported
|
||||
- LTC2977, LTC2979, LTC2980, LTM2987: not supported
|
||||
- LTC2978: not supported
|
||||
- LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676:
|
||||
N=2-3
|
||||
- LTC3880, LTC3882, LTC3884, LTC3886, LTC3887, LTC3889,
|
||||
LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
|
||||
LTM4700: N=2-3
|
||||
- LTC3883: N=2
|
||||
|
||||
curr[N]_input Measured output current.
|
||||
|
@ -335,7 +429,7 @@ curr[N]_crit Critical high output current.
|
|||
|
||||
curr[N]_lcrit Critical low output current.
|
||||
|
||||
LTC2974 and LTC2975 only.
|
||||
LTC2972, LTC2974 and LTC2975 only.
|
||||
|
||||
curr[N]_max_alarm Output current high alarm.
|
||||
|
||||
|
@ -343,11 +437,11 @@ curr[N]_crit_alarm Output current critical high alarm.
|
|||
|
||||
curr[N]_lcrit_alarm Output current critical low alarm.
|
||||
|
||||
LTC2974 and LTC2975 only.
|
||||
LTC2972, LTC2974 and LTC2975 only.
|
||||
|
||||
curr[N]_lowest Lowest output current.
|
||||
|
||||
LTC2974 and LTC2975 only.
|
||||
LTC2972, LTC2974 and LTC2975 only.
|
||||
|
||||
curr[N]_highest Highest output current.
|
||||
|
||||
|
|
|
@ -162,9 +162,12 @@ Read byte from page <page>, register <reg>.
|
|||
|
||||
::
|
||||
|
||||
int (*read_word_data)(struct i2c_client *client, int page, int reg);
|
||||
int (*read_word_data)(struct i2c_client *client, int page, int phase,
|
||||
int reg);
|
||||
|
||||
Read word from page <page>, register <reg>.
|
||||
Read word from page <page>, phase <pase>, register <reg>. If the chip does not
|
||||
support multiple phases, the phase parameter can be ignored. If the chip
|
||||
supports multiple phases, a phase value of 0xff indicates all phases.
|
||||
|
||||
::
|
||||
|
||||
|
@ -201,16 +204,21 @@ is mandatory.
|
|||
|
||||
::
|
||||
|
||||
int pmbus_set_page(struct i2c_client *client, u8 page);
|
||||
int pmbus_set_page(struct i2c_client *client, u8 page, u8 phase);
|
||||
|
||||
Set PMBus page register to <page> for subsequent commands.
|
||||
Set PMBus page register to <page> and <phase> for subsequent commands.
|
||||
If the chip does not support multiple phases, the phase parameter is
|
||||
ignored. Otherwise, a phase value of 0xff selects all phases.
|
||||
|
||||
::
|
||||
|
||||
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
|
||||
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 phase,
|
||||
u8 reg);
|
||||
|
||||
Read word data from <page>, <reg>. Similar to i2c_smbus_read_word_data(), but
|
||||
selects page first.
|
||||
Read word data from <page>, <phase>, <reg>. Similar to
|
||||
i2c_smbus_read_word_data(), but selects page and phase first. If the chip does
|
||||
not support multiple phases, the phase parameter is ignored. Otherwise, a phase
|
||||
value of 0xff selects all phases.
|
||||
|
||||
::
|
||||
|
||||
|
|
|
@ -227,7 +227,9 @@ currX_lcrit_alarm Output current critical low alarm.
|
|||
From IOUT_UC_FAULT status.
|
||||
currX_crit_alarm Current critical high alarm.
|
||||
From IIN_OC_FAULT or IOUT_OC_FAULT status.
|
||||
currX_label "iin" or "ioutY"
|
||||
currX_label "iin", "iinY", "iinY.Z", "ioutY", or "ioutY.Z",
|
||||
where Y reflects the page number and Z reflects the
|
||||
phase.
|
||||
|
||||
powerX_input Measured power. From READ_PIN or READ_POUT register.
|
||||
powerX_cap Output power cap. From POUT_MAX register.
|
||||
|
@ -239,7 +241,9 @@ powerX_alarm Power high alarm.
|
|||
From PIN_OP_WARNING or POUT_OP_WARNING status.
|
||||
powerX_crit_alarm Output power critical high alarm.
|
||||
From POUT_OP_FAULT status.
|
||||
powerX_label "pin" or "poutY"
|
||||
powerX_label "pin", "pinY", "pinY.Z", "poutY", or "poutY.Z",
|
||||
where Y reflects the page number and Z reflects the
|
||||
phase.
|
||||
|
||||
tempX_input Measured temperature.
|
||||
From READ_TEMPERATURE_X register.
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
Kernel driver tps53679
|
||||
======================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Texas Instruments TPS53647
|
||||
|
||||
Prefix: 'tps53647'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.ti.com/lit/gpn/tps53647
|
||||
|
||||
* Texas Instruments TPS53667
|
||||
|
||||
Prefix: 'tps53667'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.ti.com/lit/gpn/TPS53667
|
||||
|
||||
* Texas Instruments TPS53679
|
||||
|
||||
Prefix: 'tps53679'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.ti.com/lit/gpn/TPS53679 (short version)
|
||||
|
||||
* Texas Instruments TPS53681
|
||||
|
||||
Prefix: 'tps53681'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://www.ti.com/lit/gpn/TPS53681
|
||||
|
||||
* Texas Instruments TPS53688
|
||||
|
||||
Prefix: 'tps53688'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: Available under NDA
|
||||
|
||||
|
||||
Authors:
|
||||
Vadim Pasternak <vadimp@mellanox.com>
|
||||
Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Chips in this series are multi-phase step-down converters with one or two
|
||||
output channels and up to 8 phases per channel.
|
||||
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not probe for PMBus devices. You will have to instantiate
|
||||
devices explicitly.
|
||||
|
||||
Example: the following commands will load the driver for an TPS53681 at address
|
||||
0x60 on I2C bus #1::
|
||||
|
||||
# modprobe tps53679
|
||||
# echo tps53681 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
|
||||
|
||||
Sysfs attributes
|
||||
----------------
|
||||
|
||||
======================= ========================================================
|
||||
in1_label "vin"
|
||||
|
||||
in1_input Measured input voltage.
|
||||
|
||||
in1_lcrit Critical minimum input voltage
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
in1_lcrit_alarm Input voltage critical low alarm.
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
in1_crit Critical maximum input voltage.
|
||||
|
||||
in1_crit_alarm Input voltage critical high alarm.
|
||||
|
||||
in[N]_label "vout[1-2]"
|
||||
|
||||
- TPS53647, TPS53667: N=2
|
||||
- TPS53679, TPS53588: N=2,3
|
||||
|
||||
in[N]_input Measured output voltage.
|
||||
|
||||
in[N]_lcrit Critical minimum input voltage.
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
in[N]_lcrit_alarm Critical minimum voltage alarm.
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
in[N]_alarm Output voltage alarm.
|
||||
|
||||
TPS53647, TPS53667 only.
|
||||
|
||||
in[N]_crit Critical maximum output voltage.
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
in[N]_crit_alarm Output voltage critical high alarm.
|
||||
|
||||
TPS53679, TPS53681, TPS53688 only.
|
||||
|
||||
temp[N]_input Measured temperature.
|
||||
|
||||
- TPS53647, TPS53667: N=1
|
||||
- TPS53679, TPS53681, TPS53588: N=1,2
|
||||
|
||||
temp[N]_max Maximum temperature.
|
||||
|
||||
temp[N]_crit Critical high temperature.
|
||||
|
||||
temp[N]_max_alarm Temperature high alarm.
|
||||
|
||||
temp[N]_crit_alarm Temperature critical high alarm.
|
||||
|
||||
power1_label "pin".
|
||||
|
||||
power1_input Measured input power.
|
||||
|
||||
power[N]_label "pout[1-2]".
|
||||
|
||||
- TPS53647, TPS53667: N=2
|
||||
- TPS53679, TPS53681, TPS53588: N=2,3
|
||||
|
||||
power[N]_input Measured output power.
|
||||
|
||||
curr1_label "iin".
|
||||
|
||||
curr1_input Measured input current.
|
||||
|
||||
curr1_max Maximum input current.
|
||||
|
||||
curr1_max_alarm Input current high alarm.
|
||||
|
||||
curr1_crit Critical input current.
|
||||
|
||||
curr1_crit_alarm Input current critical alarm.
|
||||
|
||||
curr[N]_label "iout[1-2]" or "iout1.[0-5]".
|
||||
|
||||
The first digit is the output channel, the second
|
||||
digit is the phase within the channel. Per-phase
|
||||
telemetry supported on TPS53681 only.
|
||||
|
||||
- TPS53647, TPS53667: N=2
|
||||
- TPS53679, TPS53588: N=2,3
|
||||
- TPS53681: N=2-9
|
||||
|
||||
curr[N]_input Measured output current.
|
||||
|
||||
curr[N]_max Maximum output current.
|
||||
|
||||
curr[N]_crit Critical high output current.
|
||||
|
||||
curr[N]_max_alarm Output current high alarm.
|
||||
|
||||
curr[N]_crit_alarm Output current critical high alarm.
|
||||
|
||||
Limit and alarm attributes are only available for
|
||||
non-phase telemetry (iout1, iout2).
|
||||
|
||||
======================= ========================================================
|
|
@ -2957,6 +2957,14 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/sound/axentia,*
|
||||
F: sound/soc/atmel/tse850-pcm5142.c
|
||||
|
||||
AXI-FAN-CONTROL HARDWARE MONITOR DRIVER
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/hwmon/axi-fan-control.c
|
||||
F: Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
|
||||
|
||||
AXXIA I2C CONTROLLER
|
||||
M: Krzysztof Adamski <krzysztof.adamski@nokia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
|
|
|
@ -280,6 +280,15 @@ config SENSORS_ASC7621
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called asc7621.
|
||||
|
||||
config SENSORS_AXI_FAN_CONTROL
|
||||
tristate "Analog Devices FAN Control HDL Core driver"
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
AXI HDL FAN monitoring core.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called axi-fan-control
|
||||
|
||||
config SENSORS_K8TEMP
|
||||
tristate "AMD Athlon64/FX or Opteron temperature sensor"
|
||||
depends on X86 && PCI
|
||||
|
|
|
@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_AS370) += as370-hwmon.o
|
|||
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
|
||||
obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
|
||||
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
|
||||
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
/* Indexes for the sysfs hooks */
|
||||
|
@ -193,6 +194,7 @@ struct adt7475_data {
|
|||
unsigned long measure_updated;
|
||||
bool valid;
|
||||
|
||||
u8 config2;
|
||||
u8 config4;
|
||||
u8 config5;
|
||||
u8 has_voltage;
|
||||
|
@ -1458,6 +1460,85 @@ static int adt7475_update_limits(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_property_bit(const struct i2c_client *client, char *property,
|
||||
u8 *config, u8 bit_index)
|
||||
{
|
||||
u32 prop_value = 0;
|
||||
int ret = of_property_read_u32(client->dev.of_node, property,
|
||||
&prop_value);
|
||||
|
||||
if (!ret) {
|
||||
if (prop_value)
|
||||
*config |= (1 << bit_index);
|
||||
else
|
||||
*config &= ~(1 << bit_index);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int load_attenuators(const struct i2c_client *client, int chip,
|
||||
struct adt7475_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (chip == adt7476 || chip == adt7490) {
|
||||
set_property_bit(client, "adi,bypass-attenuator-in0",
|
||||
&data->config4, 4);
|
||||
set_property_bit(client, "adi,bypass-attenuator-in1",
|
||||
&data->config4, 5);
|
||||
set_property_bit(client, "adi,bypass-attenuator-in3",
|
||||
&data->config4, 6);
|
||||
set_property_bit(client, "adi,bypass-attenuator-in4",
|
||||
&data->config4, 7);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, REG_CONFIG4,
|
||||
data->config4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (chip == adt7473 || chip == adt7475) {
|
||||
set_property_bit(client, "adi,bypass-attenuator-in1",
|
||||
&data->config2, 5);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, REG_CONFIG2,
|
||||
data->config2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adt7475_set_pwm_polarity(struct i2c_client *client)
|
||||
{
|
||||
u32 states[ADT7475_PWM_COUNT];
|
||||
int ret, i;
|
||||
u8 val;
|
||||
|
||||
ret = of_property_read_u32_array(client->dev.of_node,
|
||||
"adi,pwm-active-state", states,
|
||||
ARRAY_SIZE(states));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ADT7475_PWM_COUNT; i++) {
|
||||
ret = adt7475_read(PWM_CONFIG_REG(i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
val = ret;
|
||||
if (states[i])
|
||||
val &= ~BIT(4);
|
||||
else
|
||||
val |= BIT(4);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(i), val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adt7475_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -1472,7 +1553,7 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
struct adt7475_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int i, ret = 0, revision, group_num = 0;
|
||||
u8 config2, config3;
|
||||
u8 config3;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
|
@ -1546,8 +1627,12 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
/* Voltage attenuators can be bypassed, globally or individually */
|
||||
config2 = adt7475_read(REG_CONFIG2);
|
||||
if (config2 & CONFIG2_ATTN) {
|
||||
data->config2 = adt7475_read(REG_CONFIG2);
|
||||
ret = load_attenuators(client, chip, data);
|
||||
if (ret)
|
||||
dev_warn(&client->dev, "Error configuring attenuator bypass\n");
|
||||
|
||||
if (data->config2 & CONFIG2_ATTN) {
|
||||
data->bypass_attn = (0x3 << 3) | 0x3;
|
||||
} else {
|
||||
data->bypass_attn = ((data->config4 & CONFIG4_ATTN_IN10) >> 4) |
|
||||
|
@ -1562,6 +1647,10 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
for (i = 0; i < ADT7475_PWM_COUNT; i++)
|
||||
adt7475_read_pwm(client, i);
|
||||
|
||||
ret = adt7475_set_pwm_polarity(client);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_warn(&client->dev, "Error configuring pwm polarity\n");
|
||||
|
||||
/* Start monitoring */
|
||||
switch (chip) {
|
||||
case adt7475:
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Fan Control HDL CORE driver
|
||||
*
|
||||
* Copyright 2019 Analog Devices Inc.
|
||||
*/
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/fpga/adi-axi-common.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define ADI_AXI_PCORE_VER_MAJOR(version) (((version) >> 16) & 0xff)
|
||||
#define ADI_AXI_PCORE_VER_MINOR(version) (((version) >> 8) & 0xff)
|
||||
#define ADI_AXI_PCORE_VER_PATCH(version) ((version) & 0xff)
|
||||
|
||||
/* register map */
|
||||
#define ADI_REG_RSTN 0x0080
|
||||
#define ADI_REG_PWM_WIDTH 0x0084
|
||||
#define ADI_REG_TACH_PERIOD 0x0088
|
||||
#define ADI_REG_TACH_TOLERANCE 0x008c
|
||||
#define ADI_REG_PWM_PERIOD 0x00c0
|
||||
#define ADI_REG_TACH_MEASUR 0x00c4
|
||||
#define ADI_REG_TEMPERATURE 0x00c8
|
||||
|
||||
#define ADI_REG_IRQ_MASK 0x0040
|
||||
#define ADI_REG_IRQ_PENDING 0x0044
|
||||
#define ADI_REG_IRQ_SRC 0x0048
|
||||
|
||||
/* IRQ sources */
|
||||
#define ADI_IRQ_SRC_PWM_CHANGED BIT(0)
|
||||
#define ADI_IRQ_SRC_TACH_ERR BIT(1)
|
||||
#define ADI_IRQ_SRC_TEMP_INCREASE BIT(2)
|
||||
#define ADI_IRQ_SRC_NEW_MEASUR BIT(3)
|
||||
#define ADI_IRQ_SRC_MASK GENMASK(3, 0)
|
||||
#define ADI_IRQ_MASK_OUT_ALL 0xFFFFFFFFU
|
||||
|
||||
#define SYSFS_PWM_MAX 255
|
||||
|
||||
struct axi_fan_control_data {
|
||||
void __iomem *base;
|
||||
struct device *hdev;
|
||||
unsigned long clk_rate;
|
||||
int irq;
|
||||
/* pulses per revolution */
|
||||
u32 ppr;
|
||||
bool hw_pwm_req;
|
||||
bool update_tacho_params;
|
||||
u8 fan_fault;
|
||||
};
|
||||
|
||||
static inline void axi_iowrite(const u32 val, const u32 reg,
|
||||
const struct axi_fan_control_data *ctl)
|
||||
{
|
||||
iowrite32(val, ctl->base + reg);
|
||||
}
|
||||
|
||||
static inline u32 axi_ioread(const u32 reg,
|
||||
const struct axi_fan_control_data *ctl)
|
||||
{
|
||||
return ioread32(ctl->base + reg);
|
||||
}
|
||||
|
||||
static long axi_fan_control_get_pwm_duty(const struct axi_fan_control_data *ctl)
|
||||
{
|
||||
u32 pwm_width = axi_ioread(ADI_REG_PWM_WIDTH, ctl);
|
||||
u32 pwm_period = axi_ioread(ADI_REG_PWM_PERIOD, ctl);
|
||||
/*
|
||||
* PWM_PERIOD is a RO register set by the core. It should never be 0.
|
||||
* For now we are trusting the HW...
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST(pwm_width * SYSFS_PWM_MAX, pwm_period);
|
||||
}
|
||||
|
||||
static int axi_fan_control_set_pwm_duty(const long val,
|
||||
struct axi_fan_control_data *ctl)
|
||||
{
|
||||
u32 pwm_period = axi_ioread(ADI_REG_PWM_PERIOD, ctl);
|
||||
u32 new_width;
|
||||
long __val = clamp_val(val, 0, SYSFS_PWM_MAX);
|
||||
|
||||
new_width = DIV_ROUND_CLOSEST(__val * pwm_period, SYSFS_PWM_MAX);
|
||||
|
||||
axi_iowrite(new_width, ADI_REG_PWM_WIDTH, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long axi_fan_control_get_fan_rpm(const struct axi_fan_control_data *ctl)
|
||||
{
|
||||
const u32 tach = axi_ioread(ADI_REG_TACH_MEASUR, ctl);
|
||||
|
||||
if (tach == 0)
|
||||
/* should we return error, EAGAIN maybe? */
|
||||
return 0;
|
||||
/*
|
||||
* The tacho period should be:
|
||||
* TACH = 60/(ppr * rpm), where rpm is revolutions per second
|
||||
* and ppr is pulses per revolution.
|
||||
* Given the tacho period, we can multiply it by the input clock
|
||||
* so that we know how many clocks we need to have this period.
|
||||
* From this, we can derive the RPM value.
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST(60 * ctl->clk_rate, ctl->ppr * tach);
|
||||
}
|
||||
|
||||
static int axi_fan_control_read_temp(struct device *dev, u32 attr, long *val)
|
||||
{
|
||||
struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
|
||||
long raw_temp;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
raw_temp = axi_ioread(ADI_REG_TEMPERATURE, ctl);
|
||||
/*
|
||||
* The formula for the temperature is:
|
||||
* T = (ADC * 501.3743 / 2^bits) - 273.6777
|
||||
* It's multiplied by 1000 to have millidegrees as
|
||||
* specified by the hwmon sysfs interface.
|
||||
*/
|
||||
*val = ((raw_temp * 501374) >> 16) - 273677;
|
||||
return 0;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_read_fan(struct device *dev, u32 attr, long *val)
|
||||
{
|
||||
struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_fan_fault:
|
||||
*val = ctl->fan_fault;
|
||||
/* clear it now */
|
||||
ctl->fan_fault = 0;
|
||||
return 0;
|
||||
case hwmon_fan_input:
|
||||
*val = axi_fan_control_get_fan_rpm(ctl);
|
||||
return 0;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_read_pwm(struct device *dev, u32 attr, long *val)
|
||||
{
|
||||
struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
*val = axi_fan_control_get_pwm_duty(ctl);
|
||||
return 0;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_write_pwm(struct device *dev, u32 attr, long val)
|
||||
{
|
||||
struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
return axi_fan_control_set_pwm_duty(val, ctl);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_read_labels(struct device *dev,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, const char **str)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
*str = "FAN";
|
||||
return 0;
|
||||
case hwmon_temp:
|
||||
*str = "SYSMON4";
|
||||
return 0;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_read(struct device *dev,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
return axi_fan_control_read_fan(dev, attr, val);
|
||||
case hwmon_pwm:
|
||||
return axi_fan_control_read_pwm(dev, attr, val);
|
||||
case hwmon_temp:
|
||||
return axi_fan_control_read_temp(dev, attr, val);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_fan_control_write(struct device *dev,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
return axi_fan_control_write_pwm(dev, attr, val);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t axi_fan_control_fan_is_visible(const u32 attr)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
case hwmon_fan_fault:
|
||||
case hwmon_fan_label:
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t axi_fan_control_pwm_is_visible(const u32 attr)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
return 0644;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t axi_fan_control_temp_is_visible(const u32 attr)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
case hwmon_temp_label:
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t axi_fan_control_is_visible(const void *data,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
return axi_fan_control_fan_is_visible(attr);
|
||||
case hwmon_pwm:
|
||||
return axi_fan_control_pwm_is_visible(attr);
|
||||
case hwmon_temp:
|
||||
return axi_fan_control_temp_is_visible(attr);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This core has two main ways of changing the PWM duty cycle. It is done,
|
||||
* either by a request from userspace (writing on pwm1_input) or by the
|
||||
* core itself. When the change is done by the core, it will use predefined
|
||||
* parameters to evaluate the tach signal and, on that case we cannot set them.
|
||||
* On the other hand, when the request is done by the user, with some arbitrary
|
||||
* value that the core does not now about, we have to provide the tach
|
||||
* parameters so that, the core can evaluate the signal. On the IRQ handler we
|
||||
* distinguish this by using the ADI_IRQ_SRC_TEMP_INCREASE interrupt. This tell
|
||||
* us that the CORE requested a new duty cycle. After this, there is 5s delay
|
||||
* on which the core waits for the fan rotation speed to stabilize. After this
|
||||
* we get ADI_IRQ_SRC_PWM_CHANGED irq where we will decide if we need to set
|
||||
* the tach parameters or not on the next tach measurement cycle (corresponding
|
||||
* already to the ney duty cycle) based on the %ctl->hw_pwm_req flag.
|
||||
*/
|
||||
static irqreturn_t axi_fan_control_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct axi_fan_control_data *ctl = (struct axi_fan_control_data *)data;
|
||||
u32 irq_pending = axi_ioread(ADI_REG_IRQ_PENDING, ctl);
|
||||
u32 clear_mask;
|
||||
|
||||
if (irq_pending & ADI_IRQ_SRC_NEW_MEASUR) {
|
||||
if (ctl->update_tacho_params) {
|
||||
u32 new_tach = axi_ioread(ADI_REG_TACH_MEASUR, ctl);
|
||||
|
||||
/* get 25% tolerance */
|
||||
u32 tach_tol = DIV_ROUND_CLOSEST(new_tach * 25, 100);
|
||||
/* set new tacho parameters */
|
||||
axi_iowrite(new_tach, ADI_REG_TACH_PERIOD, ctl);
|
||||
axi_iowrite(tach_tol, ADI_REG_TACH_TOLERANCE, ctl);
|
||||
ctl->update_tacho_params = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_pending & ADI_IRQ_SRC_PWM_CHANGED) {
|
||||
/*
|
||||
* if the pwm changes on behalf of software,
|
||||
* we need to provide new tacho parameters to the core.
|
||||
* Wait for the next measurement for that...
|
||||
*/
|
||||
if (!ctl->hw_pwm_req) {
|
||||
ctl->update_tacho_params = true;
|
||||
} else {
|
||||
ctl->hw_pwm_req = false;
|
||||
sysfs_notify(&ctl->hdev->kobj, NULL, "pwm1");
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_pending & ADI_IRQ_SRC_TEMP_INCREASE)
|
||||
/* hardware requested a new pwm */
|
||||
ctl->hw_pwm_req = true;
|
||||
|
||||
if (irq_pending & ADI_IRQ_SRC_TACH_ERR)
|
||||
ctl->fan_fault = 1;
|
||||
|
||||
/* clear all interrupts */
|
||||
clear_mask = irq_pending & ADI_IRQ_SRC_MASK;
|
||||
axi_iowrite(clear_mask, ADI_REG_IRQ_PENDING, ctl);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int axi_fan_control_init(struct axi_fan_control_data *ctl,
|
||||
const struct device_node *np)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* get fan pulses per revolution */
|
||||
ret = of_property_read_u32(np, "pulses-per-revolution", &ctl->ppr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 1, 2 and 4 are the typical and accepted values */
|
||||
if (ctl->ppr != 1 && ctl->ppr != 2 && ctl->ppr != 4)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Enable all IRQs
|
||||
*/
|
||||
axi_iowrite(ADI_IRQ_MASK_OUT_ALL &
|
||||
~(ADI_IRQ_SRC_NEW_MEASUR | ADI_IRQ_SRC_TACH_ERR |
|
||||
ADI_IRQ_SRC_PWM_CHANGED | ADI_IRQ_SRC_TEMP_INCREASE),
|
||||
ADI_REG_IRQ_MASK, ctl);
|
||||
|
||||
/* bring the device out of reset */
|
||||
axi_iowrite(0x01, ADI_REG_RSTN, ctl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *axi_fan_control_info[] = {
|
||||
HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops axi_fan_control_hwmon_ops = {
|
||||
.is_visible = axi_fan_control_is_visible,
|
||||
.read = axi_fan_control_read,
|
||||
.write = axi_fan_control_write,
|
||||
.read_string = axi_fan_control_read_labels,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info axi_chip_info = {
|
||||
.ops = &axi_fan_control_hwmon_ops,
|
||||
.info = axi_fan_control_info,
|
||||
};
|
||||
|
||||
static const u32 version_1_0_0 = ADI_AXI_PCORE_VER(1, 0, 'a');
|
||||
|
||||
static const struct of_device_id axi_fan_control_of_match[] = {
|
||||
{ .compatible = "adi,axi-fan-control-1.00.a",
|
||||
.data = (void *)&version_1_0_0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_fan_control_of_match);
|
||||
|
||||
static int axi_fan_control_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axi_fan_control_data *ctl;
|
||||
struct clk *clk;
|
||||
const struct of_device_id *id;
|
||||
const char *name = "axi_fan_control";
|
||||
u32 version;
|
||||
int ret;
|
||||
|
||||
id = of_match_node(axi_fan_control_of_match, pdev->dev.of_node);
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
ctl = devm_kzalloc(&pdev->dev, sizeof(*ctl), GFP_KERNEL);
|
||||
if (!ctl)
|
||||
return -ENOMEM;
|
||||
|
||||
ctl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctl->base))
|
||||
return PTR_ERR(ctl->base);
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "clk_get failed with %ld\n", PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
ctl->clk_rate = clk_get_rate(clk);
|
||||
if (!ctl->clk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
version = axi_ioread(ADI_AXI_REG_VERSION, ctl);
|
||||
if (ADI_AXI_PCORE_VER_MAJOR(version) !=
|
||||
ADI_AXI_PCORE_VER_MAJOR((*(u32 *)id->data))) {
|
||||
dev_err(&pdev->dev, "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
|
||||
ADI_AXI_PCORE_VER_MAJOR((*(u32 *)id->data)),
|
||||
ADI_AXI_PCORE_VER_MINOR((*(u32 *)id->data)),
|
||||
ADI_AXI_PCORE_VER_PATCH((*(u32 *)id->data)),
|
||||
ADI_AXI_PCORE_VER_MAJOR(version),
|
||||
ADI_AXI_PCORE_VER_MINOR(version),
|
||||
ADI_AXI_PCORE_VER_PATCH(version));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctl->irq = platform_get_irq(pdev, 0);
|
||||
if (ctl->irq < 0)
|
||||
return ctl->irq;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL,
|
||||
axi_fan_control_irq_handler,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
||||
pdev->driver_override, ctl);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request an irq, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = axi_fan_control_init(ctl, pdev->dev.of_node);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctl->hdev = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
name,
|
||||
ctl,
|
||||
&axi_chip_info,
|
||||
NULL);
|
||||
|
||||
return PTR_ERR_OR_ZERO(ctl->hdev);
|
||||
}
|
||||
|
||||
static struct platform_driver axi_fan_control_driver = {
|
||||
.driver = {
|
||||
.name = "axi_fan_control_driver",
|
||||
.of_match_table = axi_fan_control_of_match,
|
||||
},
|
||||
.probe = axi_fan_control_probe,
|
||||
};
|
||||
module_platform_driver(axi_fan_control_driver);
|
||||
|
||||
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices Fan Control HDL CORE driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -219,7 +219,7 @@ struct aem_read_sensor_req {
|
|||
|
||||
struct aem_read_sensor_resp {
|
||||
struct aem_iana_id id;
|
||||
u8 bytes[0];
|
||||
u8 bytes[];
|
||||
} __packed;
|
||||
|
||||
/* Data structures to talk to the IPMI layer */
|
||||
|
|
|
@ -186,7 +186,7 @@ static void make_sensor_label(struct device_node *np,
|
|||
u32 id;
|
||||
size_t n;
|
||||
|
||||
n = snprintf(sdata->label, sizeof(sdata->label), "%s", label);
|
||||
n = scnprintf(sdata->label, sizeof(sdata->label), "%s", label);
|
||||
|
||||
/*
|
||||
* Core temp pretty print
|
||||
|
@ -199,11 +199,11 @@ static void make_sensor_label(struct device_node *np,
|
|||
* The digital thermal sensors are associated
|
||||
* with a core.
|
||||
*/
|
||||
n += snprintf(sdata->label + n,
|
||||
n += scnprintf(sdata->label + n,
|
||||
sizeof(sdata->label) - n, " %d",
|
||||
cpuid);
|
||||
else
|
||||
n += snprintf(sdata->label + n,
|
||||
n += scnprintf(sdata->label + n,
|
||||
sizeof(sdata->label) - n, " phy%d", id);
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ static void make_sensor_label(struct device_node *np,
|
|||
* Membuffer pretty print
|
||||
*/
|
||||
if (!of_property_read_u32(np, "ibm,chip-id", &id))
|
||||
n += snprintf(sdata->label + n, sizeof(sdata->label) - n,
|
||||
n += scnprintf(sdata->label + n, sizeof(sdata->label) - n,
|
||||
" %d", id & 0xffff);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,13 +96,20 @@ struct k10temp_data {
|
|||
void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
|
||||
int temp_offset;
|
||||
u32 temp_adjust_mask;
|
||||
bool show_tdie;
|
||||
u32 show_tccd;
|
||||
u32 show_temp;
|
||||
u32 svi_addr[2];
|
||||
bool is_zen;
|
||||
bool show_current;
|
||||
int cfactor[2];
|
||||
};
|
||||
|
||||
#define TCTL_BIT 0
|
||||
#define TDIE_BIT 1
|
||||
#define TCCD_BIT(x) ((x) + 2)
|
||||
|
||||
#define HAVE_TEMP(d, channel) ((d)->show_temp & BIT(channel))
|
||||
#define HAVE_TDIE(d) HAVE_TEMP(d, TDIE_BIT)
|
||||
|
||||
struct tctl_offset {
|
||||
u8 model;
|
||||
char const *id;
|
||||
|
@ -180,8 +187,8 @@ static long get_raw_temp(struct k10temp_data *data)
|
|||
}
|
||||
|
||||
const char *k10temp_temp_label[] = {
|
||||
"Tdie",
|
||||
"Tctl",
|
||||
"Tdie",
|
||||
"Tccd1",
|
||||
"Tccd2",
|
||||
"Tccd3",
|
||||
|
@ -269,13 +276,13 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
|
|||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
switch (channel) {
|
||||
case 0: /* Tdie */
|
||||
*val = get_raw_temp(data) - data->temp_offset;
|
||||
case 0: /* Tctl */
|
||||
*val = get_raw_temp(data);
|
||||
if (*val < 0)
|
||||
*val = 0;
|
||||
break;
|
||||
case 1: /* Tctl */
|
||||
*val = get_raw_temp(data);
|
||||
case 1: /* Tdie */
|
||||
*val = get_raw_temp(data) - data->temp_offset;
|
||||
if (*val < 0)
|
||||
*val = 0;
|
||||
break;
|
||||
|
@ -333,23 +340,11 @@ static umode_t k10temp_is_visible(const void *_data,
|
|||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
switch (channel) {
|
||||
case 0: /* Tdie, or Tctl if we don't show it */
|
||||
break;
|
||||
case 1: /* Tctl */
|
||||
if (!data->show_tdie)
|
||||
return 0;
|
||||
break;
|
||||
case 2 ... 9: /* Tccd{1-8} */
|
||||
if (!(data->show_tccd & BIT(channel - 2)))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
if (!HAVE_TEMP(data, channel))
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case hwmon_temp_max:
|
||||
if (channel || data->show_tdie)
|
||||
if (channel || data->is_zen)
|
||||
return 0;
|
||||
break;
|
||||
case hwmon_temp_crit:
|
||||
|
@ -368,20 +363,9 @@ static umode_t k10temp_is_visible(const void *_data,
|
|||
return 0;
|
||||
break;
|
||||
case hwmon_temp_label:
|
||||
/* No labels if we don't show the die temperature */
|
||||
if (!data->show_tdie)
|
||||
/* Show temperature labels only on Zen CPUs */
|
||||
if (!data->is_zen || !HAVE_TEMP(data, channel))
|
||||
return 0;
|
||||
switch (channel) {
|
||||
case 0: /* Tdie */
|
||||
case 1: /* Tctl */
|
||||
break;
|
||||
case 2 ... 9: /* Tccd{1-8} */
|
||||
if (!(data->show_tccd & BIT(channel - 2)))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -480,7 +464,7 @@ static void k10temp_init_debugfs(struct k10temp_data *data)
|
|||
char name[32];
|
||||
|
||||
/* Only show debugfs data for Family 17h/18h CPUs */
|
||||
if (!data->show_tdie)
|
||||
if (!data->is_zen)
|
||||
return;
|
||||
|
||||
scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev));
|
||||
|
@ -546,7 +530,7 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev,
|
|||
amd_smn_read(amd_pci_dev_to_node_id(pdev),
|
||||
F17H_M70H_CCD_TEMP(i), ®val);
|
||||
if (regval & F17H_M70H_CCD_TEMP_VALID)
|
||||
data->show_tccd |= BIT(i);
|
||||
data->show_temp |= BIT(TCCD_BIT(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,6 +557,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
return -ENOMEM;
|
||||
|
||||
data->pdev = pdev;
|
||||
data->show_temp |= BIT(TCTL_BIT); /* Always show Tctl */
|
||||
|
||||
if (boot_cpu_data.x86 == 0x15 &&
|
||||
((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
|
||||
|
@ -582,7 +567,8 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
} else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
|
||||
data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK;
|
||||
data->read_tempreg = read_tempreg_nb_f17;
|
||||
data->show_tdie = true;
|
||||
data->show_temp |= BIT(TDIE_BIT); /* show Tdie */
|
||||
data->is_zen = true;
|
||||
|
||||
switch (boot_cpu_data.x86_model) {
|
||||
case 0x1: /* Zen */
|
||||
|
|
|
@ -262,10 +262,20 @@ static int lm73_detect(struct i2c_client *new_client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lm73_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,lm73",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, lm73_of_match);
|
||||
|
||||
static struct i2c_driver lm73_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "lm73",
|
||||
.of_match_table = lm73_of_match,
|
||||
},
|
||||
.probe = lm73_probe,
|
||||
.id_table = lm73_ids,
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
*
|
||||
* Copyright (c) 2019 Advantech
|
||||
* Author: Amy.Shih <amy.shih@advantech.com.tw>
|
||||
*
|
||||
* Supports the following chips:
|
||||
*
|
||||
* Chip #vin #fan #pwm #temp #dts chip ID
|
||||
* nct7904d 20 12 4 5 8 0xc5
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -820,6 +825,10 @@ static const struct hwmon_channel_info *nct7904_info[] = {
|
|||
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_ENABLE,
|
||||
|
@ -853,6 +862,18 @@ static const struct hwmon_channel_info *nct7904_info[] = {
|
|||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST),
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -92,10 +92,10 @@ config SENSORS_IRPS5401
|
|||
be called irps5401.
|
||||
|
||||
config SENSORS_ISL68137
|
||||
tristate "Intersil ISL68137"
|
||||
tristate "Renesas Digital Multiphase Voltage Regulators"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Intersil
|
||||
ISL68137.
|
||||
If you say yes here you get hardware monitoring support for Renesas
|
||||
digital multiphase voltage regulators.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called isl68137.
|
||||
|
@ -113,8 +113,8 @@ config SENSORS_LTC2978
|
|||
tristate "Linear Technologies LTC2978 and compatibles"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Linear
|
||||
Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
|
||||
LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676.
|
||||
Technology LTC2972, LTC2974, LTC2975, LTC2977, LTC2978, LTC2979,
|
||||
LTC2980, and LTM2987.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc2978.
|
||||
|
@ -123,9 +123,10 @@ config SENSORS_LTC2978_REGULATOR
|
|||
bool "Regulator support for LTC2978 and compatibles"
|
||||
depends on SENSORS_LTC2978 && REGULATOR
|
||||
help
|
||||
If you say yes here you get regulator support for Linear
|
||||
Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676
|
||||
and LTM4686.
|
||||
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.
|
||||
|
||||
config SENSORS_LTC3815
|
||||
tristate "Linear Technologies LTC3815"
|
||||
|
@ -209,10 +210,10 @@ config SENSORS_TPS40422
|
|||
be called tps40422.
|
||||
|
||||
config SENSORS_TPS53679
|
||||
tristate "TI TPS53679, TPS53688"
|
||||
tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for TI
|
||||
TPS53679, TPS53688
|
||||
TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tps53679.
|
||||
|
|
|
@ -226,7 +226,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int adm1275_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 adm1275_data *data = to_adm1275_data(info);
|
||||
|
@ -239,58 +240,68 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
case PMBUS_IOUT_UC_FAULT_LIMIT:
|
||||
if (!data->have_uc_fault)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1275_IOUT_WARN2_LIMIT);
|
||||
break;
|
||||
case PMBUS_IOUT_OC_FAULT_LIMIT:
|
||||
if (!data->have_oc_fault)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1275_IOUT_WARN2_LIMIT);
|
||||
break;
|
||||
case PMBUS_VOUT_OV_WARN_LIMIT:
|
||||
if (data->have_vout)
|
||||
return -ENODATA;
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1075_VAUX_OV_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_VOUT_UV_WARN_LIMIT:
|
||||
if (data->have_vout)
|
||||
return -ENODATA;
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1075_VAUX_UV_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_READ_VOUT:
|
||||
if (data->have_vout)
|
||||
return -ENODATA;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1075_READ_VAUX);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MIN:
|
||||
if (!data->have_iout_min)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1293_IOUT_MIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1275_PEAK_IOUT);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1275_PEAK_VOUT);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VIN_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1275_PEAK_VIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_PIN_MIN:
|
||||
if (!data->have_pin_min)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1293_PIN_MIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_PIN_MAX:
|
||||
if (!data->have_pin_max)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1276_PEAK_PIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
if (!data->have_temp_max)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
ADM1278_PEAK_TEMP);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
|
|
|
@ -33,9 +33,12 @@
|
|||
#define CFFPS_INPUT_HISTORY_CMD 0xD6
|
||||
#define CFFPS_INPUT_HISTORY_SIZE 100
|
||||
|
||||
#define CFFPS_CCIN_REVISION GENMASK(7, 0)
|
||||
#define CFFPS_CCIN_REVISION_LEGACY 0xde
|
||||
#define CFFPS_CCIN_VERSION GENMASK(15, 8)
|
||||
#define CFFPS_CCIN_VERSION_1 0x2b
|
||||
#define CFFPS_CCIN_VERSION_2 0x2e
|
||||
#define CFFPS_CCIN_VERSION_3 0x51
|
||||
|
||||
/* STATUS_MFR_SPECIFIC bits */
|
||||
#define CFFPS_MFR_FAN_FAULT BIT(0)
|
||||
|
@ -148,7 +151,7 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
|
|||
struct ibm_cffps *psu = to_psu(idxp, idx);
|
||||
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
|
||||
switch (idx) {
|
||||
case CFFPS_DEBUGFS_INPUT_HISTORY:
|
||||
|
@ -247,7 +250,7 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file,
|
|||
|
||||
switch (idx) {
|
||||
case CFFPS_DEBUGFS_ON_OFF_CONFIG:
|
||||
pmbus_set_page(psu->client, 0);
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
|
||||
rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
|
||||
if (rc <= 0)
|
||||
|
@ -325,13 +328,13 @@ static int ibm_cffps_read_byte_data(struct i2c_client *client, int page,
|
|||
}
|
||||
|
||||
static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
|
||||
int reg)
|
||||
int phase, int reg)
|
||||
{
|
||||
int rc, mfr;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_WORD:
|
||||
rc = pmbus_read_word_data(client, page, reg);
|
||||
rc = pmbus_read_word_data(client, page, phase, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -348,7 +351,8 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
|
|||
rc |= PB_STATUS_OFF;
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VMON:
|
||||
rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD);
|
||||
rc = pmbus_read_word_data(client, page, phase,
|
||||
CFFPS_12VCS_VOUT_CMD);
|
||||
break;
|
||||
default:
|
||||
rc = -ENODATA;
|
||||
|
@ -379,7 +383,7 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
|
|||
dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
|
||||
brightness, next_led_state);
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
next_led_state);
|
||||
|
@ -401,7 +405,7 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
|
|||
|
||||
dev_dbg(&psu->client->dev, "LED blink set.\n");
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
CFFPS_LED_BLINK);
|
||||
|
@ -485,11 +489,14 @@ static int ibm_cffps_probe(struct i2c_client *client,
|
|||
vs = (enum versions)id->driver_data;
|
||||
|
||||
if (vs == cffps_unknown) {
|
||||
u16 ccin_revision = 0;
|
||||
u16 ccin_version = CFFPS_CCIN_VERSION_1;
|
||||
int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
|
||||
|
||||
if (ccin > 0)
|
||||
if (ccin > 0) {
|
||||
ccin_revision = FIELD_GET(CFFPS_CCIN_REVISION, ccin);
|
||||
ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
|
||||
}
|
||||
|
||||
switch (ccin_version) {
|
||||
default:
|
||||
|
@ -499,6 +506,12 @@ static int ibm_cffps_probe(struct i2c_client *client,
|
|||
case CFFPS_CCIN_VERSION_2:
|
||||
vs = cffps2;
|
||||
break;
|
||||
case CFFPS_CCIN_VERSION_3:
|
||||
if (ccin_revision == CFFPS_CCIN_REVISION_LEGACY)
|
||||
vs = cffps1;
|
||||
else
|
||||
vs = cffps2;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the client name to include the version number. */
|
||||
|
|
|
@ -21,37 +21,42 @@
|
|||
#define IR35221_MFR_IOUT_VALLEY 0xcb
|
||||
#define IR35221_MFR_TEMP_VALLEY 0xcc
|
||||
|
||||
static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ir35221_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VIN_MAX:
|
||||
ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_VIN_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_IOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_TEMP_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VIN_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_VIN_VALLEY);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_VOUT_VALLEY);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_IOUT_VALLEY);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
IR35221_MFR_TEMP_VALLEY);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Hardware monitoring driver for Intersil ISL68137
|
||||
* Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators
|
||||
*
|
||||
* Copyright (c) 2017 Google Inc
|
||||
* Copyright (c) 2020 Renesas Electronics America
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -14,9 +15,19 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include "pmbus.h"
|
||||
|
||||
#define ISL68137_VOUT_AVS 0x30
|
||||
#define RAA_DMPVR2_READ_VMON 0xc8
|
||||
|
||||
enum versions {
|
||||
isl68137,
|
||||
raa_dmpvr2_1rail,
|
||||
raa_dmpvr2_2rail,
|
||||
raa_dmpvr2_3rail,
|
||||
raa_dmpvr2_hv,
|
||||
};
|
||||
|
||||
static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
|
||||
int page,
|
||||
|
@ -49,7 +60,8 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
|
|||
* enabling AVS control is the workaround.
|
||||
*/
|
||||
if (op_val == ISL68137_VOUT_AVS) {
|
||||
rc = pmbus_read_word_data(client, page, PMBUS_VOUT_COMMAND);
|
||||
rc = pmbus_read_word_data(client, page, 0xff,
|
||||
PMBUS_VOUT_COMMAND);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -98,13 +110,31 @@ static const struct attribute_group enable_group = {
|
|||
.attrs = enable_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *attribute_groups[] = {
|
||||
static const struct attribute_group *isl68137_attribute_groups[] = {
|
||||
&enable_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct pmbus_driver_info isl68137_info = {
|
||||
.pages = 2,
|
||||
static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VMON:
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
RAA_DMPVR2_READ_VMON);
|
||||
break;
|
||||
default:
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pmbus_driver_info raa_dmpvr_info = {
|
||||
.pages = 3,
|
||||
.format[PSC_VOLTAGE_IN] = direct,
|
||||
.format[PSC_VOLTAGE_OUT] = direct,
|
||||
.format[PSC_CURRENT_IN] = direct,
|
||||
|
@ -113,7 +143,7 @@ static struct pmbus_driver_info isl68137_info = {
|
|||
.format[PSC_TEMPERATURE] = direct,
|
||||
.m[PSC_VOLTAGE_IN] = 1,
|
||||
.b[PSC_VOLTAGE_IN] = 0,
|
||||
.R[PSC_VOLTAGE_IN] = 3,
|
||||
.R[PSC_VOLTAGE_IN] = 2,
|
||||
.m[PSC_VOLTAGE_OUT] = 1,
|
||||
.b[PSC_VOLTAGE_OUT] = 0,
|
||||
.R[PSC_VOLTAGE_OUT] = 3,
|
||||
|
@ -133,24 +163,76 @@ static struct pmbus_driver_info isl68137_info = {
|
|||
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
|
||||
| PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
.groups = attribute_groups,
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT
|
||||
| PMBUS_HAVE_VMON,
|
||||
.func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT
|
||||
| PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
.func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT
|
||||
| PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
};
|
||||
|
||||
static int isl68137_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return pmbus_do_probe(client, id, &isl68137_info);
|
||||
struct pmbus_driver_info *info;
|
||||
|
||||
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
memcpy(info, &raa_dmpvr_info, sizeof(*info));
|
||||
|
||||
switch (id->driver_data) {
|
||||
case isl68137:
|
||||
info->pages = 2;
|
||||
info->R[PSC_VOLTAGE_IN] = 3;
|
||||
info->func[0] &= ~PMBUS_HAVE_VMON;
|
||||
info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
|
||||
| PMBUS_HAVE_POUT;
|
||||
info->groups = isl68137_attribute_groups;
|
||||
break;
|
||||
case raa_dmpvr2_1rail:
|
||||
info->pages = 1;
|
||||
info->read_word_data = raa_dmpvr2_read_word_data;
|
||||
break;
|
||||
case raa_dmpvr2_2rail:
|
||||
info->pages = 2;
|
||||
info->read_word_data = raa_dmpvr2_read_word_data;
|
||||
break;
|
||||
case raa_dmpvr2_3rail:
|
||||
info->read_word_data = raa_dmpvr2_read_word_data;
|
||||
break;
|
||||
case raa_dmpvr2_hv:
|
||||
info->pages = 1;
|
||||
info->R[PSC_VOLTAGE_IN] = 1;
|
||||
info->m[PSC_VOLTAGE_OUT] = 2;
|
||||
info->R[PSC_VOLTAGE_OUT] = 2;
|
||||
info->m[PSC_CURRENT_IN] = 2;
|
||||
info->m[PSC_POWER] = 2;
|
||||
info->R[PSC_POWER] = -1;
|
||||
info->read_word_data = raa_dmpvr2_read_word_data;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id isl68137_id[] = {
|
||||
{"isl68137", 0},
|
||||
static const struct i2c_device_id raa_dmpvr_id[] = {
|
||||
{"isl68137", isl68137},
|
||||
{"raa_dmpvr2_1rail", raa_dmpvr2_1rail},
|
||||
{"raa_dmpvr2_2rail", raa_dmpvr2_2rail},
|
||||
{"raa_dmpvr2_3rail", raa_dmpvr2_3rail},
|
||||
{"raa_dmpvr2_hv", raa_dmpvr2_hv},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, isl68137_id);
|
||||
MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver isl68137_driver = {
|
||||
|
@ -159,11 +241,11 @@ static struct i2c_driver isl68137_driver = {
|
|||
},
|
||||
.probe = isl68137_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = isl68137_id,
|
||||
.id_table = raa_dmpvr_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(isl68137_driver);
|
||||
|
||||
MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
|
||||
MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137");
|
||||
MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -211,7 +211,8 @@ struct lm25066_data {
|
|||
|
||||
#define to_lm25066_data(x) container_of(x, struct lm25066_data, info)
|
||||
|
||||
static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int lm25066_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 lm25066_data *data = to_lm25066_data(info);
|
||||
|
@ -219,7 +220,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VMON:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff, LM25066_READ_VAUX);
|
||||
if (ret < 0)
|
||||
break;
|
||||
/* Adjust returned value to match VIN coefficients */
|
||||
|
@ -244,33 +245,40 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
}
|
||||
break;
|
||||
case PMBUS_READ_IIN:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_MFR_READ_IIN);
|
||||
break;
|
||||
case PMBUS_READ_PIN:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_MFR_READ_PIN);
|
||||
break;
|
||||
case PMBUS_IIN_OC_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_MFR_IIN_OC_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_PIN_OP_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_MFR_PIN_OP_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VIN_AVG:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_READ_AVG_VIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_AVG:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_READ_AVG_VOUT);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IIN_AVG:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_READ_AVG_IIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_PIN_AVG:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_READ_AVG_PIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_PIN_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25066_READ_PIN_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_PIN_HISTORY:
|
||||
ret = 0;
|
||||
|
@ -288,13 +296,14 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int lm25056_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25056_VAUX_UV_WARN_LIMIT);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
@ -302,7 +311,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
|
||||
break;
|
||||
case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
LM25056_VAUX_OV_WARN_LIMIT);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
@ -310,7 +319,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
|
||||
break;
|
||||
default:
|
||||
ret = lm25066_read_word_data(client, page, reg);
|
||||
ret = lm25066_read_word_data(client, page, phase, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -19,8 +19,15 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
|
||||
ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 };
|
||||
enum chips {
|
||||
/* Managers */
|
||||
ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980,
|
||||
/* Controllers */
|
||||
ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880,
|
||||
/* Modules */
|
||||
ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686,
|
||||
ltm4700,
|
||||
};
|
||||
|
||||
/* Common for all chips */
|
||||
#define LTC2978_MFR_VOUT_PEAK 0xdd
|
||||
|
@ -43,9 +50,10 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
|
|||
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
|
||||
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
|
||||
|
||||
/* LTC3883 and LTC3886 only */
|
||||
/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */
|
||||
#define LTC3883_MFR_IIN_PEAK 0xe1
|
||||
|
||||
|
||||
/* LTC2975 only */
|
||||
#define LTC2975_MFR_IIN_PEAK 0xc4
|
||||
#define LTC2975_MFR_IIN_MIN 0xc5
|
||||
|
@ -54,27 +62,41 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
|
|||
|
||||
#define LTC2978_ID_MASK 0xfff0
|
||||
|
||||
#define LTC2972_ID 0x0310
|
||||
#define LTC2974_ID 0x0210
|
||||
#define LTC2975_ID 0x0220
|
||||
#define LTC2977_ID 0x0130
|
||||
#define LTC2978_ID_REV1 0x0110 /* Early revision */
|
||||
#define LTC2978_ID_REV2 0x0120
|
||||
#define LTC2979_ID_A 0x8060
|
||||
#define LTC2979_ID_B 0x8070
|
||||
#define LTC2980_ID_A 0x8030 /* A/B for two die IDs */
|
||||
#define LTC2980_ID_B 0x8040
|
||||
#define LTC3880_ID 0x4020
|
||||
#define LTC3882_ID 0x4200
|
||||
#define LTC3882_ID_D1 0x4240 /* Dash 1 */
|
||||
#define LTC3883_ID 0x4300
|
||||
#define LTC3884_ID 0x4C00
|
||||
#define LTC3886_ID 0x4600
|
||||
#define LTC3887_ID 0x4700
|
||||
#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */
|
||||
#define LTM2987_ID_B 0x8020
|
||||
#define LTC3889_ID 0x4900
|
||||
#define LTC7880_ID 0x49E0
|
||||
#define LTM4664_ID 0x4120
|
||||
#define LTM4675_ID 0x47a0
|
||||
#define LTM4676_ID_REV1 0x4400
|
||||
#define LTM4676_ID_REV2 0x4480
|
||||
#define LTM4676A_ID 0x47e0
|
||||
#define LTM4677_ID_REV1 0x47B0
|
||||
#define LTM4677_ID_REV2 0x47D0
|
||||
#define LTM4678_ID_REV1 0x4100
|
||||
#define LTM4678_ID_REV2 0x4110
|
||||
#define LTM4680_ID 0x4140
|
||||
#define LTM4686_ID 0x4770
|
||||
#define LTM4700_ID 0x4130
|
||||
|
||||
#define LTC2972_NUM_PAGES 2
|
||||
#define LTC2974_NUM_PAGES 4
|
||||
#define LTC2978_NUM_PAGES 8
|
||||
#define LTC3880_NUM_PAGES 2
|
||||
|
@ -151,7 +173,8 @@ static int ltc_wait_ready(struct i2c_client *client)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc_read_word_data(struct i2c_client *client, int page, int phase,
|
||||
int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -159,7 +182,7 @@ static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return pmbus_read_word_data(client, page, reg);
|
||||
return pmbus_read_word_data(client, page, 0xff, reg);
|
||||
}
|
||||
|
||||
static int ltc_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
|
@ -202,7 +225,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = ltc_read_word_data(client, page, reg);
|
||||
ret = ltc_read_word_data(client, page, 0xff, reg);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret) > lin11_to_val(*pmax))
|
||||
*pmax = ret;
|
||||
|
@ -216,7 +239,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = ltc_read_word_data(client, page, reg);
|
||||
ret = ltc_read_word_data(client, page, 0xff, reg);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret) < lin11_to_val(*pmin))
|
||||
*pmin = ret;
|
||||
|
@ -238,7 +261,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
|
|||
&data->vin_max);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
|
||||
ret = ltc_read_word_data(client, page, 0xff,
|
||||
LTC2978_MFR_VOUT_PEAK);
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
* VOUT is 16 bit unsigned with fixed exponent,
|
||||
|
@ -269,7 +293,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc2978_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
@ -281,7 +306,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
&data->vin_min);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
|
||||
ret = ltc_read_word_data(client, page, phase,
|
||||
LTC2978_MFR_VOUT_MIN);
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
* VOUT_MIN is known to not be supported on some lots
|
||||
|
@ -314,7 +340,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc2974_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
@ -333,13 +360,14 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = ltc2978_read_word_data(client, page, reg);
|
||||
ret = ltc2978_read_word_data(client, page, phase, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc2975_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
@ -367,13 +395,14 @@ static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = ltc2978_read_word_data(client, page, reg);
|
||||
ret = ltc2978_read_word_data(client, page, phase, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc3880_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
@ -405,7 +434,8 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc3883_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
@ -420,7 +450,7 @@ static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = ltc3880_read_word_data(client, page, reg);
|
||||
ret = ltc3880_read_word_data(client, page, phase, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
@ -492,20 +522,30 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ltc2978_id[] = {
|
||||
{"ltc2972", ltc2972},
|
||||
{"ltc2974", ltc2974},
|
||||
{"ltc2975", ltc2975},
|
||||
{"ltc2977", ltc2977},
|
||||
{"ltc2978", ltc2978},
|
||||
{"ltc2979", ltc2979},
|
||||
{"ltc2980", ltc2980},
|
||||
{"ltc3880", ltc3880},
|
||||
{"ltc3882", ltc3882},
|
||||
{"ltc3883", ltc3883},
|
||||
{"ltc3884", ltc3884},
|
||||
{"ltc3886", ltc3886},
|
||||
{"ltc3887", ltc3887},
|
||||
{"ltc3889", ltc3889},
|
||||
{"ltc7880", ltc7880},
|
||||
{"ltm2987", ltm2987},
|
||||
{"ltm4664", ltm4664},
|
||||
{"ltm4675", ltm4675},
|
||||
{"ltm4676", ltm4676},
|
||||
{"ltm4677", ltm4677},
|
||||
{"ltm4678", ltm4678},
|
||||
{"ltm4680", ltm4680},
|
||||
{"ltm4686", ltm4686},
|
||||
{"ltm4700", ltm4700},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
||||
|
@ -555,7 +595,9 @@ static int ltc2978_get_id(struct i2c_client *client)
|
|||
|
||||
chip_id &= LTC2978_ID_MASK;
|
||||
|
||||
if (chip_id == LTC2974_ID)
|
||||
if (chip_id == LTC2972_ID)
|
||||
return ltc2972;
|
||||
else if (chip_id == LTC2974_ID)
|
||||
return ltc2974;
|
||||
else if (chip_id == LTC2975_ID)
|
||||
return ltc2975;
|
||||
|
@ -563,6 +605,8 @@ static int ltc2978_get_id(struct i2c_client *client)
|
|||
return ltc2977;
|
||||
else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2)
|
||||
return ltc2978;
|
||||
else if (chip_id == LTC2979_ID_A || chip_id == LTC2979_ID_B)
|
||||
return ltc2979;
|
||||
else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B)
|
||||
return ltc2980;
|
||||
else if (chip_id == LTC3880_ID)
|
||||
|
@ -571,19 +615,35 @@ static int ltc2978_get_id(struct i2c_client *client)
|
|||
return ltc3882;
|
||||
else if (chip_id == LTC3883_ID)
|
||||
return ltc3883;
|
||||
else if (chip_id == LTC3884_ID)
|
||||
return ltc3884;
|
||||
else if (chip_id == LTC3886_ID)
|
||||
return ltc3886;
|
||||
else if (chip_id == LTC3887_ID)
|
||||
return ltc3887;
|
||||
else if (chip_id == LTC3889_ID)
|
||||
return ltc3889;
|
||||
else if (chip_id == LTC7880_ID)
|
||||
return ltc7880;
|
||||
else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B)
|
||||
return ltm2987;
|
||||
else if (chip_id == LTM4664_ID)
|
||||
return ltm4664;
|
||||
else if (chip_id == LTM4675_ID)
|
||||
return ltm4675;
|
||||
else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
|
||||
chip_id == LTM4676A_ID)
|
||||
return ltm4676;
|
||||
else if (chip_id == LTM4677_ID_REV1 || chip_id == LTM4677_ID_REV2)
|
||||
return ltm4677;
|
||||
else if (chip_id == LTM4678_ID_REV1 || chip_id == LTM4678_ID_REV2)
|
||||
return ltm4678;
|
||||
else if (chip_id == LTM4680_ID)
|
||||
return ltm4680;
|
||||
else if (chip_id == LTM4686_ID)
|
||||
return ltm4686;
|
||||
else if (chip_id == LTM4700_ID)
|
||||
return ltm4700;
|
||||
|
||||
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
|
||||
return -ENODEV;
|
||||
|
@ -637,6 +697,19 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
data->temp2_max = 0x7c00;
|
||||
|
||||
switch (data->id) {
|
||||
case ltc2972:
|
||||
info->read_word_data = ltc2975_read_word_data;
|
||||
info->pages = LTC2972_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
|
||||
| PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP2;
|
||||
for (i = 0; i < info->pages; i++) {
|
||||
info->func[i] |= PMBUS_HAVE_VOUT
|
||||
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
|
||||
}
|
||||
break;
|
||||
case ltc2974:
|
||||
info->read_word_data = ltc2974_read_word_data;
|
||||
info->pages = LTC2974_NUM_PAGES;
|
||||
|
@ -662,8 +735,10 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case ltc2977:
|
||||
case ltc2978:
|
||||
case ltc2979:
|
||||
case ltc2980:
|
||||
case ltm2987:
|
||||
info->read_word_data = ltc2978_read_word_data;
|
||||
|
@ -680,6 +755,7 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
case ltc3887:
|
||||
case ltm4675:
|
||||
case ltm4676:
|
||||
case ltm4677:
|
||||
case ltm4686:
|
||||
data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
|
||||
info->read_word_data = ltc3880_read_word_data;
|
||||
|
@ -721,7 +797,14 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
| PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
|
||||
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
|
||||
break;
|
||||
case ltc3884:
|
||||
case ltc3886:
|
||||
case ltc3889:
|
||||
case ltc7880:
|
||||
case ltm4664:
|
||||
case ltm4678:
|
||||
case ltm4680:
|
||||
case ltm4700:
|
||||
data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
|
||||
info->read_word_data = ltc3883_read_word_data;
|
||||
info->pages = LTC3880_NUM_PAGES;
|
||||
|
@ -752,22 +835,33 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ltc2978_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2972" },
|
||||
{ .compatible = "lltc,ltc2974" },
|
||||
{ .compatible = "lltc,ltc2975" },
|
||||
{ .compatible = "lltc,ltc2977" },
|
||||
{ .compatible = "lltc,ltc2978" },
|
||||
{ .compatible = "lltc,ltc2979" },
|
||||
{ .compatible = "lltc,ltc2980" },
|
||||
{ .compatible = "lltc,ltc3880" },
|
||||
{ .compatible = "lltc,ltc3882" },
|
||||
{ .compatible = "lltc,ltc3883" },
|
||||
{ .compatible = "lltc,ltc3884" },
|
||||
{ .compatible = "lltc,ltc3886" },
|
||||
{ .compatible = "lltc,ltc3887" },
|
||||
{ .compatible = "lltc,ltc3889" },
|
||||
{ .compatible = "lltc,ltc7880" },
|
||||
{ .compatible = "lltc,ltm2987" },
|
||||
{ .compatible = "lltc,ltm4664" },
|
||||
{ .compatible = "lltc,ltm4675" },
|
||||
{ .compatible = "lltc,ltm4676" },
|
||||
{ .compatible = "lltc,ltm4677" },
|
||||
{ .compatible = "lltc,ltm4678" },
|
||||
{ .compatible = "lltc,ltm4680" },
|
||||
{ .compatible = "lltc,ltm4686" },
|
||||
{ .compatible = "lltc,ltm4700" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2978_of_match);
|
||||
|
|
|
@ -55,7 +55,7 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
|
|||
* LTC3815 does not support the CLEAR_FAULTS command.
|
||||
* Emulate it by clearing the status register.
|
||||
*/
|
||||
ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD);
|
||||
if (ret > 0) {
|
||||
pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
|
||||
ret);
|
||||
|
@ -69,25 +69,31 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int ltc3815_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VIN_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
LTC3815_MFR_VIN_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
LTC3815_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
LTC3815_MFR_TEMP_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
LTC3815_MFR_IOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IIN_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
LTC3815_MFR_IIN_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
case PMBUS_VIRT_RESET_VIN_HISTORY:
|
||||
|
|
|
@ -15,17 +15,18 @@
|
|||
#define MAX16064_MFR_VOUT_PEAK 0xd4
|
||||
#define MAX16064_MFR_TEMPERATURE_PEAK 0xd6
|
||||
|
||||
static int max16064_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int max16064_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX16064_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX16064_MFR_TEMPERATURE_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
|
|
|
@ -85,7 +85,8 @@ static u32 max_current[][5] = {
|
|||
[max20743] = { 18900, 24100, 29200, 34100 },
|
||||
};
|
||||
|
||||
static int max20730_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int max20730_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 max20730_data *data = to_max20730_data(info);
|
||||
|
|
|
@ -72,7 +72,7 @@ static int max31785_read_long_data(struct i2c_client *client, int page,
|
|||
|
||||
cmdbuf[0] = reg;
|
||||
|
||||
rc = pmbus_set_page(client, page);
|
||||
rc = pmbus_set_page(client, page, 0xff);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -110,7 +110,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
|
|||
if (config < 0)
|
||||
return config;
|
||||
|
||||
command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
|
||||
command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1);
|
||||
if (command < 0)
|
||||
return command;
|
||||
|
||||
|
@ -126,7 +126,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
|
|||
}
|
||||
|
||||
static int max31785_read_word_data(struct i2c_client *client, int page,
|
||||
int reg)
|
||||
int phase, int reg)
|
||||
{
|
||||
u32 val;
|
||||
int rv;
|
||||
|
|
|
@ -41,7 +41,8 @@ struct max34440_data {
|
|||
|
||||
#define to_max34440_data(x) container_of(x, struct max34440_data, info)
|
||||
|
||||
static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int max34440_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
|
@ -49,44 +50,44 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_VOUT_MIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_AVG:
|
||||
if (data->id != max34446 && data->id != max34451)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34446_MFR_IOUT_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_IOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_POUT_AVG:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34446_MFR_POUT_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_POUT_MAX:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34446_MFR_POUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_AVG:
|
||||
if (data->id != max34446 && data->id != max34460 &&
|
||||
data->id != max34461)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34446_MFR_TEMPERATURE_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_TEMPERATURE_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_POUT_HISTORY:
|
||||
|
@ -159,14 +160,14 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
|
|||
int mfg_status;
|
||||
|
||||
if (page >= 0) {
|
||||
ret = pmbus_set_page(client, page);
|
||||
ret = pmbus_set_page(client, page, 0xff);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_IOUT:
|
||||
mfg_status = pmbus_read_word_data(client, 0,
|
||||
mfg_status = pmbus_read_word_data(client, 0, 0xff,
|
||||
PMBUS_STATUS_MFR_SPECIFIC);
|
||||
if (mfg_status < 0)
|
||||
return mfg_status;
|
||||
|
@ -176,7 +177,7 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
|
|||
ret |= PB_IOUT_OC_FAULT;
|
||||
break;
|
||||
case PMBUS_STATUS_TEMPERATURE:
|
||||
mfg_status = pmbus_read_word_data(client, 0,
|
||||
mfg_status = pmbus_read_word_data(client, 0, 0xff,
|
||||
PMBUS_STATUS_MFR_SPECIFIC);
|
||||
if (mfg_status < 0)
|
||||
return mfg_status;
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
#define MAX8688_STATUS_OT_FAULT BIT(13)
|
||||
#define MAX8688_STATUS_OT_WARNING BIT(14)
|
||||
|
||||
static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int max8688_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -37,13 +38,15 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK);
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFR_IOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ret = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFR_TEMPERATURE_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
|
@ -94,7 +97,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
|
|||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_VOUT:
|
||||
mfg_status = pmbus_read_word_data(client, 0,
|
||||
mfg_status = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFG_STATUS);
|
||||
if (mfg_status < 0)
|
||||
return mfg_status;
|
||||
|
@ -108,7 +111,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
|
|||
ret |= PB_VOLTAGE_OV_FAULT;
|
||||
break;
|
||||
case PMBUS_STATUS_IOUT:
|
||||
mfg_status = pmbus_read_word_data(client, 0,
|
||||
mfg_status = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFG_STATUS);
|
||||
if (mfg_status < 0)
|
||||
return mfg_status;
|
||||
|
@ -120,7 +123,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
|
|||
ret |= PB_IOUT_OC_FAULT;
|
||||
break;
|
||||
case PMBUS_STATUS_TEMPERATURE:
|
||||
mfg_status = pmbus_read_word_data(client, 0,
|
||||
mfg_status = pmbus_read_word_data(client, 0, 0xff,
|
||||
MAX8688_MFG_STATUS);
|
||||
if (mfg_status < 0)
|
||||
return mfg_status;
|
||||
|
|
|
@ -102,10 +102,10 @@ static int pmbus_identify(struct i2c_client *client,
|
|||
int page;
|
||||
|
||||
for (page = 1; page < PMBUS_PAGES; page++) {
|
||||
if (pmbus_set_page(client, page) < 0)
|
||||
if (pmbus_set_page(client, page, 0xff) < 0)
|
||||
break;
|
||||
}
|
||||
pmbus_set_page(client, 0);
|
||||
pmbus_set_page(client, 0, 0xff);
|
||||
info->pages = page;
|
||||
} else {
|
||||
info->pages = 1;
|
||||
|
|
|
@ -119,6 +119,9 @@ enum pmbus_regs {
|
|||
PMBUS_MFR_DATE = 0x9D,
|
||||
PMBUS_MFR_SERIAL = 0x9E,
|
||||
|
||||
PMBUS_IC_DEVICE_ID = 0xAD,
|
||||
PMBUS_IC_DEVICE_REV = 0xAE,
|
||||
|
||||
/*
|
||||
* Virtual registers.
|
||||
* Useful to support attributes which are not supported by standard PMBus
|
||||
|
@ -359,6 +362,7 @@ enum pmbus_sensor_classes {
|
|||
};
|
||||
|
||||
#define PMBUS_PAGES 32 /* Per PMBus specification */
|
||||
#define PMBUS_PHASES 8 /* Maximum number of phases per page */
|
||||
|
||||
/* Functionality bit mask */
|
||||
#define PMBUS_HAVE_VIN BIT(0)
|
||||
|
@ -385,13 +389,15 @@ enum pmbus_sensor_classes {
|
|||
#define PMBUS_HAVE_PWM34 BIT(21)
|
||||
#define PMBUS_HAVE_SAMPLES BIT(22)
|
||||
|
||||
#define PMBUS_PAGE_VIRTUAL BIT(31)
|
||||
#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */
|
||||
#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */
|
||||
|
||||
enum pmbus_data_format { linear = 0, direct, vid };
|
||||
enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
|
||||
|
||||
struct pmbus_driver_info {
|
||||
int pages; /* Total number of pages */
|
||||
u8 phases[PMBUS_PAGES]; /* Number of phases per page */
|
||||
enum pmbus_data_format format[PSC_NUM_CLASSES];
|
||||
enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */
|
||||
/*
|
||||
|
@ -403,6 +409,7 @@ struct pmbus_driver_info {
|
|||
int R[PSC_NUM_CLASSES]; /* exponent */
|
||||
|
||||
u32 func[PMBUS_PAGES]; /* Functionality, per page */
|
||||
u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */
|
||||
/*
|
||||
* The following functions map manufacturing specific register values
|
||||
* to PMBus standard register values. Specify only if mapping is
|
||||
|
@ -415,7 +422,8 @@ struct pmbus_driver_info {
|
|||
* the standard register.
|
||||
*/
|
||||
int (*read_byte_data)(struct i2c_client *client, int page, int reg);
|
||||
int (*read_word_data)(struct i2c_client *client, int page, int reg);
|
||||
int (*read_word_data)(struct i2c_client *client, int page, int phase,
|
||||
int reg);
|
||||
int (*write_word_data)(struct i2c_client *client, int page, int reg,
|
||||
u16 word);
|
||||
int (*write_byte)(struct i2c_client *client, int page, u8 value);
|
||||
|
@ -454,9 +462,11 @@ extern const struct regulator_ops pmbus_regulator_ops;
|
|||
/* Function declarations */
|
||||
|
||||
void pmbus_clear_cache(struct i2c_client *client);
|
||||
int pmbus_set_page(struct i2c_client *client, int page);
|
||||
int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg);
|
||||
int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, u16 word);
|
||||
int pmbus_set_page(struct i2c_client *client, int page, int phase);
|
||||
int pmbus_read_word_data(struct i2c_client *client, int page, int phase,
|
||||
u8 reg);
|
||||
int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
|
||||
u16 word);
|
||||
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
|
||||
int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
|
||||
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
|
||||
|
|
|
@ -49,6 +49,7 @@ struct pmbus_sensor {
|
|||
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
|
||||
struct device_attribute attribute;
|
||||
u8 page; /* page number */
|
||||
u8 phase; /* phase number, 0xff for all phases */
|
||||
u16 reg; /* register */
|
||||
enum pmbus_sensor_classes class; /* sensor class */
|
||||
bool update; /* runtime sensor update needed */
|
||||
|
@ -109,6 +110,7 @@ struct pmbus_data {
|
|||
int (*read_status)(struct i2c_client *client, int page);
|
||||
|
||||
u8 currpage;
|
||||
u8 currphase; /* current phase, 0xff for all */
|
||||
};
|
||||
|
||||
struct pmbus_debugfs_entry {
|
||||
|
@ -146,15 +148,16 @@ void pmbus_clear_cache(struct i2c_client *client)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_clear_cache);
|
||||
|
||||
int pmbus_set_page(struct i2c_client *client, int page)
|
||||
int pmbus_set_page(struct i2c_client *client, int page, int phase)
|
||||
{
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
int rv;
|
||||
|
||||
if (page < 0 || page == data->currpage)
|
||||
if (page < 0)
|
||||
return 0;
|
||||
|
||||
if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) {
|
||||
if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) &&
|
||||
data->info->pages > 1 && page != data->currpage) {
|
||||
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
@ -166,9 +169,17 @@ int pmbus_set_page(struct i2c_client *client, int page)
|
|||
if (rv != page)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->currpage = page;
|
||||
|
||||
if (data->info->phases[page] && data->currphase != phase &&
|
||||
!(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) {
|
||||
rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
|
||||
phase);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
data->currphase = phase;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_set_page);
|
||||
|
@ -177,7 +188,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
|
|||
{
|
||||
int rv;
|
||||
|
||||
rv = pmbus_set_page(client, page);
|
||||
rv = pmbus_set_page(client, page, 0xff);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
|
@ -208,7 +219,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
|
|||
{
|
||||
int rv;
|
||||
|
||||
rv = pmbus_set_page(client, page);
|
||||
rv = pmbus_set_page(client, page, 0xff);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
|
@ -286,11 +297,11 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_update_fan);
|
||||
|
||||
int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg)
|
||||
int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = pmbus_set_page(client, page);
|
||||
rv = pmbus_set_page(client, page, phase);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
|
@ -320,14 +331,15 @@ static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg)
|
|||
* _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if
|
||||
* a device specific mapping function exists and calls it if necessary.
|
||||
*/
|
||||
static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int _pmbus_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
const struct pmbus_driver_info *info = data->info;
|
||||
int status;
|
||||
|
||||
if (info->read_word_data) {
|
||||
status = info->read_word_data(client, page, reg);
|
||||
status = info->read_word_data(client, page, phase, reg);
|
||||
if (status != -ENODATA)
|
||||
return status;
|
||||
}
|
||||
|
@ -335,14 +347,20 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
if (reg >= PMBUS_VIRT_BASE)
|
||||
return pmbus_read_virt_reg(client, page, reg);
|
||||
|
||||
return pmbus_read_word_data(client, page, reg);
|
||||
return pmbus_read_word_data(client, page, phase, reg);
|
||||
}
|
||||
|
||||
/* Same as above, but without phase parameter, for use in check functions */
|
||||
static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
return _pmbus_read_word_data(client, page, 0xff, reg);
|
||||
}
|
||||
|
||||
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = pmbus_set_page(client, page);
|
||||
rv = pmbus_set_page(client, page, 0xff);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
|
@ -354,7 +372,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
|
|||
{
|
||||
int rv;
|
||||
|
||||
rv = pmbus_set_page(client, page);
|
||||
rv = pmbus_set_page(client, page, 0xff);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
|
@ -440,7 +458,7 @@ static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id,
|
|||
|
||||
have_rpm = !!(config & pmbus_fan_rpm_mask[id]);
|
||||
if (want_rpm == have_rpm)
|
||||
return pmbus_read_word_data(client, page,
|
||||
return pmbus_read_word_data(client, page, 0xff,
|
||||
pmbus_fan_command_registers[id]);
|
||||
|
||||
/* Can't sensibly map between RPM and PWM, just return zero */
|
||||
|
@ -530,7 +548,7 @@ EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
|
|||
|
||||
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
|
||||
return pmbus_check_register(client, __pmbus_read_word_data, page, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_check_word_register);
|
||||
|
||||
|
@ -595,6 +613,7 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
|
|||
sensor->data
|
||||
= _pmbus_read_word_data(client,
|
||||
sensor->page,
|
||||
sensor->phase,
|
||||
sensor->reg);
|
||||
}
|
||||
pmbus_clear_faults(client);
|
||||
|
@ -1076,7 +1095,8 @@ static int pmbus_add_boolean(struct pmbus_data *data,
|
|||
|
||||
static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
||||
const char *name, const char *type,
|
||||
int seq, int page, int reg,
|
||||
int seq, int page, int phase,
|
||||
int reg,
|
||||
enum pmbus_sensor_classes class,
|
||||
bool update, bool readonly,
|
||||
bool convert)
|
||||
|
@ -1100,6 +1120,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
|||
readonly = true;
|
||||
|
||||
sensor->page = page;
|
||||
sensor->phase = phase;
|
||||
sensor->reg = reg;
|
||||
sensor->class = class;
|
||||
sensor->update = update;
|
||||
|
@ -1119,7 +1140,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
|||
|
||||
static int pmbus_add_label(struct pmbus_data *data,
|
||||
const char *name, int seq,
|
||||
const char *lstring, int index)
|
||||
const char *lstring, int index, int phase)
|
||||
{
|
||||
struct pmbus_label *label;
|
||||
struct device_attribute *a;
|
||||
|
@ -1131,11 +1152,21 @@ static int pmbus_add_label(struct pmbus_data *data,
|
|||
a = &label->attribute;
|
||||
|
||||
snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
|
||||
if (!index)
|
||||
strncpy(label->label, lstring, sizeof(label->label) - 1);
|
||||
else
|
||||
snprintf(label->label, sizeof(label->label), "%s%d", lstring,
|
||||
index);
|
||||
if (!index) {
|
||||
if (phase == 0xff)
|
||||
strncpy(label->label, lstring,
|
||||
sizeof(label->label) - 1);
|
||||
else
|
||||
snprintf(label->label, sizeof(label->label), "%s.%d",
|
||||
lstring, phase);
|
||||
} else {
|
||||
if (phase == 0xff)
|
||||
snprintf(label->label, sizeof(label->label), "%s%d",
|
||||
lstring, index);
|
||||
else
|
||||
snprintf(label->label, sizeof(label->label), "%s%d.%d",
|
||||
lstring, index, phase);
|
||||
}
|
||||
|
||||
pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
|
||||
return pmbus_add_attribute(data, &a->attr);
|
||||
|
@ -1200,7 +1231,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
|
|||
for (i = 0; i < nlimit; i++) {
|
||||
if (pmbus_check_word_register(client, page, l->reg)) {
|
||||
curr = pmbus_add_sensor(data, name, l->attr, index,
|
||||
page, l->reg, attr->class,
|
||||
page, 0xff, l->reg, attr->class,
|
||||
attr->update || l->update,
|
||||
false, true);
|
||||
if (!curr)
|
||||
|
@ -1227,7 +1258,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
|
|||
struct pmbus_data *data,
|
||||
const struct pmbus_driver_info *info,
|
||||
const char *name,
|
||||
int index, int page,
|
||||
int index, int page, int phase,
|
||||
const struct pmbus_sensor_attr *attr,
|
||||
bool paged)
|
||||
{
|
||||
|
@ -1237,15 +1268,16 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
|
|||
|
||||
if (attr->label) {
|
||||
ret = pmbus_add_label(data, name, index, attr->label,
|
||||
paged ? page + 1 : 0);
|
||||
paged ? page + 1 : 0, phase);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
|
||||
attr->class, true, true, true);
|
||||
base = pmbus_add_sensor(data, name, "input", index, page, phase,
|
||||
attr->reg, attr->class, true, true, true);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
if (attr->sfunc) {
|
||||
/* No limit and alarm attributes for phase specific sensors */
|
||||
if (attr->sfunc && phase == 0xff) {
|
||||
ret = pmbus_add_limit_attrs(client, data, info, name,
|
||||
index, page, base, attr);
|
||||
if (ret < 0)
|
||||
|
@ -1315,10 +1347,25 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client,
|
|||
continue;
|
||||
ret = pmbus_add_sensor_attrs_one(client, data, info,
|
||||
name, index, page,
|
||||
attrs, paged);
|
||||
0xff, attrs, paged);
|
||||
if (ret)
|
||||
return ret;
|
||||
index++;
|
||||
if (info->phases[page]) {
|
||||
int phase;
|
||||
|
||||
for (phase = 0; phase < info->phases[page];
|
||||
phase++) {
|
||||
if (!(info->pfunc[phase] & attrs->func))
|
||||
continue;
|
||||
ret = pmbus_add_sensor_attrs_one(client,
|
||||
data, info, name, index, page,
|
||||
phase, attrs, paged);
|
||||
if (ret)
|
||||
return ret;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
attrs++;
|
||||
}
|
||||
|
@ -1822,7 +1869,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
|
|||
struct pmbus_sensor *sensor;
|
||||
|
||||
sensor = pmbus_add_sensor(data, "fan", "target", index, page,
|
||||
PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
|
||||
PMBUS_VIRT_FAN_TARGET_1 + id, 0xff, PSC_FAN,
|
||||
false, false, true);
|
||||
|
||||
if (!sensor)
|
||||
|
@ -1833,14 +1880,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
|
||||
PMBUS_VIRT_PWM_1 + id, PSC_PWM,
|
||||
PMBUS_VIRT_PWM_1 + id, 0xff, PSC_PWM,
|
||||
false, false, true);
|
||||
|
||||
if (!sensor)
|
||||
return -ENOMEM;
|
||||
|
||||
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
|
||||
PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
|
||||
PMBUS_VIRT_PWM_ENABLE_1 + id, 0xff, PSC_PWM,
|
||||
true, false, false);
|
||||
|
||||
if (!sensor)
|
||||
|
@ -1882,7 +1929,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
|
|||
continue;
|
||||
|
||||
if (pmbus_add_sensor(data, "fan", "input", index,
|
||||
page, pmbus_fan_registers[f],
|
||||
page, pmbus_fan_registers[f], 0xff,
|
||||
PSC_FAN, true, true, true) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1964,7 +2011,7 @@ static ssize_t pmbus_show_samples(struct device *dev,
|
|||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_samples_reg *reg = to_samples_reg(devattr);
|
||||
|
||||
val = _pmbus_read_word_data(client, reg->page, reg->attr->reg);
|
||||
val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
|
@ -2120,7 +2167,7 @@ static int pmbus_read_status_byte(struct i2c_client *client, int page)
|
|||
|
||||
static int pmbus_read_status_word(struct i2c_client *client, int page)
|
||||
{
|
||||
return _pmbus_read_word_data(client, page, PMBUS_STATUS_WORD);
|
||||
return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD);
|
||||
}
|
||||
|
||||
static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
|
||||
|
@ -2482,6 +2529,8 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
|||
if (pdata)
|
||||
data->flags = pdata->flags;
|
||||
data->info = info;
|
||||
data->currpage = 0xff;
|
||||
data->currphase = 0xfe;
|
||||
|
||||
ret = pmbus_init_common(client, data, info);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -6,13 +6,21 @@
|
|||
* Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips {
|
||||
tps53647, tps53667, tps53679, tps53681, tps53688
|
||||
};
|
||||
|
||||
#define TPS53647_PAGE_NUM 1
|
||||
|
||||
#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
|
||||
#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
|
||||
#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */
|
||||
|
@ -20,13 +28,19 @@
|
|||
#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */
|
||||
#define TPS53679_PAGE_NUM 2
|
||||
|
||||
static int tps53679_identify(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info)
|
||||
#define TPS53681_DEVICE_ID 0x81
|
||||
|
||||
#define TPS53681_PMBUS_REVISION 0x33
|
||||
|
||||
#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */
|
||||
|
||||
static int tps53679_identify_mode(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info)
|
||||
{
|
||||
u8 vout_params;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < TPS53679_PAGE_NUM; i++) {
|
||||
for (i = 0; i < info->pages; i++) {
|
||||
/* Read the register with VOUT scaling value.*/
|
||||
ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
|
||||
if (ret < 0)
|
||||
|
@ -52,48 +66,180 @@ static int tps53679_identify(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tps53679_identify_phases(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* On TPS53681, only channel A provides per-phase output current */
|
||||
ret = pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
info->phases[0] = (ret & 0x07) + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps53679_identify_chip(struct i2c_client *client,
|
||||
u8 revision, u16 id)
|
||||
{
|
||||
u8 buf[I2C_SMBUS_BLOCK_MAX];
|
||||
int ret;
|
||||
|
||||
ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != revision) {
|
||||
dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != 1 || buf[0] != id) {
|
||||
dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common identification function for chips with multi-phase support.
|
||||
* Since those chips have special configuration registers, we want to have
|
||||
* some level of reassurance that we are really talking with the chip
|
||||
* being probed. Check PMBus revision and chip ID.
|
||||
*/
|
||||
static int tps53679_identify_multiphase(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info,
|
||||
int pmbus_rev, int device_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = tps53679_identify_chip(client, pmbus_rev, device_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = tps53679_identify_mode(client, info);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return tps53679_identify_phases(client, info);
|
||||
}
|
||||
|
||||
static int tps53679_identify(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info)
|
||||
{
|
||||
return tps53679_identify_mode(client, info);
|
||||
}
|
||||
|
||||
static int tps53681_identify(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info)
|
||||
{
|
||||
return tps53679_identify_multiphase(client, info,
|
||||
TPS53681_PMBUS_REVISION,
|
||||
TPS53681_DEVICE_ID);
|
||||
}
|
||||
|
||||
static int tps53681_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
/*
|
||||
* For reading the total output current (READ_IOUT) for all phases,
|
||||
* the chip datasheet is a bit vague. It says "PHASE must be set to
|
||||
* FFh to access all phases simultaneously. PHASE may also be set to
|
||||
* 80h readack (!) the total phase current".
|
||||
* Experiments show that the command does _not_ report the total
|
||||
* current for all phases if the phase is set to 0xff. Instead, it
|
||||
* appears to report the current of one of the phases. Override phase
|
||||
* parameter with 0x80 when reading the total output current on page 0.
|
||||
*/
|
||||
if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff)
|
||||
return pmbus_read_word_data(client, page, 0x80, reg);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
static struct pmbus_driver_info tps53679_info = {
|
||||
.pages = TPS53679_PAGE_NUM,
|
||||
.format[PSC_VOLTAGE_IN] = linear,
|
||||
.format[PSC_VOLTAGE_OUT] = vid,
|
||||
.format[PSC_TEMPERATURE] = linear,
|
||||
.format[PSC_CURRENT_OUT] = linear,
|
||||
.format[PSC_POWER] = linear,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
|
||||
PMBUS_HAVE_STATUS_INPUT |
|
||||
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_POUT,
|
||||
.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_POUT,
|
||||
.identify = tps53679_identify,
|
||||
.pfunc[0] = PMBUS_HAVE_IOUT,
|
||||
.pfunc[1] = PMBUS_HAVE_IOUT,
|
||||
.pfunc[2] = PMBUS_HAVE_IOUT,
|
||||
.pfunc[3] = PMBUS_HAVE_IOUT,
|
||||
.pfunc[4] = PMBUS_HAVE_IOUT,
|
||||
.pfunc[5] = PMBUS_HAVE_IOUT,
|
||||
};
|
||||
|
||||
static int tps53679_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct pmbus_driver_info *info;
|
||||
enum chips chip_id;
|
||||
|
||||
info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info),
|
||||
GFP_KERNEL);
|
||||
if (dev->of_node)
|
||||
chip_id = (enum chips)of_device_get_match_data(dev);
|
||||
else
|
||||
chip_id = id->driver_data;
|
||||
|
||||
info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (chip_id) {
|
||||
case tps53647:
|
||||
case tps53667:
|
||||
info->pages = TPS53647_PAGE_NUM;
|
||||
info->identify = tps53679_identify;
|
||||
break;
|
||||
case tps53679:
|
||||
case tps53688:
|
||||
info->pages = TPS53679_PAGE_NUM;
|
||||
info->identify = tps53679_identify;
|
||||
break;
|
||||
case tps53681:
|
||||
info->pages = TPS53679_PAGE_NUM;
|
||||
info->phases[0] = 6;
|
||||
info->identify = tps53681_identify;
|
||||
info->read_word_data = tps53681_read_word_data;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tps53679_id[] = {
|
||||
{"tps53679", 0},
|
||||
{"tps53688", 0},
|
||||
{"tps53647", tps53647},
|
||||
{"tps53667", tps53667},
|
||||
{"tps53679", tps53679},
|
||||
{"tps53681", tps53681},
|
||||
{"tps53688", tps53688},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tps53679_id);
|
||||
|
||||
static const struct of_device_id __maybe_unused tps53679_of_match[] = {
|
||||
{.compatible = "ti,tps53679"},
|
||||
{.compatible = "ti,tps53688"},
|
||||
{.compatible = "ti,tps53647", .data = (void *)tps53647},
|
||||
{.compatible = "ti,tps53667", .data = (void *)tps53667},
|
||||
{.compatible = "ti,tps53679", .data = (void *)tps53679},
|
||||
{.compatible = "ti,tps53681", .data = (void *)tps53681},
|
||||
{.compatible = "ti,tps53688", .data = (void *)tps53688},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps53679_of_match);
|
||||
|
|
|
@ -370,7 +370,7 @@ static void ucd9000_probe_gpio(struct i2c_client *client,
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer)
|
||||
{
|
||||
int ret = pmbus_set_page(client, 0);
|
||||
int ret = pmbus_set_page(client, 0, 0xff);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */
|
||||
#define XDPE122_PAGE_NUM 2
|
||||
|
||||
static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int xdpe122_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
long val;
|
||||
|
@ -29,7 +30,7 @@ static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
switch (reg) {
|
||||
case PMBUS_VOUT_OV_FAULT_LIMIT:
|
||||
case PMBUS_VOUT_UV_FAULT_LIMIT:
|
||||
ret = pmbus_read_word_data(client, page, reg);
|
||||
ret = pmbus_read_word_data(client, page, phase, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -125,7 +125,8 @@ static inline void zl6100_wait(const struct zl6100_data *data)
|
|||
}
|
||||
}
|
||||
|
||||
static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int zl6100_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct zl6100_data *data = to_zl6100_data(info);
|
||||
|
@ -167,7 +168,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
}
|
||||
|
||||
zl6100_wait(data);
|
||||
ret = pmbus_read_word_data(client, page, vreg);
|
||||
ret = pmbus_read_word_data(client, page, phase, vreg);
|
||||
data->access = ktime_get();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
Загрузка…
Ссылка в новой задаче