mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-12 08:45:39 -05:00
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:
@@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
84
Documentation/devicetree/bindings/hwmon/adt7475.yaml
Normal file
84
Documentation/devicetree/bindings/hwmon/adt7475.yaml
Normal file
@@ -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.
|
||||
|
||||
178
Documentation/hwmon/tps53679.rst
Normal file
178
Documentation/hwmon/tps53679.rst
Normal file
@@ -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:
|
||||
|
||||
469
drivers/hwmon/axi-fan-control.c
Normal file
469
drivers/hwmon/axi-fan-control.c
Normal file
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user