Commit 47acac8c authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents ff7b862a 5b10a819
# 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>;
};
};
...
# 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
......
This diff is collapsed.
......@@ -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.
This diff is collapsed.
......@@ -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.
......
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:
......
This diff is collapsed.
......@@ -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)
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:
/* Show temperature labels only on Zen CPUs */
if (!data->is_zen || !HAVE_TEMP(data, channel))
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), &regval);
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:
......
// 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;
......
This diff is collapsed.
......@@ -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,
......
This diff is collapsed.
......@@ -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;
if (dev->of_node)
chip_id = (enum chips)of_device_get_match_data(dev);
else
chip_id = id->driver_data;
info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info),
GFP_KERNEL);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment