Commit 35417d57 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-v5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:
 "core:
   - Add support for enable attributes to hwmon core
   - Add intrusion templates

  pmbus:
   - Support for Infineon Multi-phase xdpe122 family controllers
   - Support for Intel IMVP9 and AMD 6.25mV modes
   - Support for vid mode detection per page bases
   - Detect if chip is write protected
   - Support for MAX20730, MAX20734, MAX20743, MAX20796, UCD90320,
     TPS53688
   - Various improvements to ibm-cffps driver

  k10temp:
   - Support for additional temperature sensors as well as voltage and
     current telemetry for Zen CPUs

  w83627ehf:
   - Remove support for NCT6775, NCT6776 (they have their own driver)

  New drivers:
   - ADM1177
   - MAX31730
   - Driver for disk and solid state drives with temperature sensors

  Other:
   - pwm-fan: stop fan on shutdown"

* tag 'hwmon-for-v5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (35 commits)
  hwmon: (k10temp) Display up to eight sets of CCD temperatures
  hwmon: (k10temp) Add debugfs support
  hwmon: (k10temp) Don't show temperature limits on Ryzen (Zen) CPUs
  hwmon: (k10temp) Show core and SoC current and voltages on Ryzen CPUs
  hwmon: (k10temp) Report temperatures per CPU die
  hmon: (k10temp) Convert to use devm_hwmon_device_register_with_info
  hwmon: (k10temp) Use bitops
  hwmon: (pwm-fan) stop fan on shutdown
  MAINTAINERS: add entry for ADM1177 driver
  dt-binding: hwmon: Add documentation for ADM1177
  hwmon: (adm1177) Add ADM1177 Hot Swap Controller and Digital Power Monitor driver
  docs: hwmon: Include 'xdpe12284.rst' into docs
  hwmon: (pmbus) Add support for Infineon Multi-phase xdpe122 family controllers
  hwmon: (pmbus/tps53679) Extend device list supported by driver
  hwmon: (pmbus/core) Add support for Intel IMVP9 and AMD 6.25mV modes
  hwmon: (pmbus/core) Add support for vid mode detection per page bases
  hwmon: (pmbus/ibm-cffps) Prevent writing on_off_config with bad data
  hwmon: (w83627ehf) Remove set but not used variable 'fan4min'
  hwmon: Driver for disk and solid state drives with temperature sensors
  hwmon: (pmbus/ibm-cffps) Fix the LED behavior when turned off
  ...
parents 189fc98e fd8bdb23
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/adi,adm1177.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADM1177 Hot Swap Controller and Digital Power Monitor
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
- Beniamin Bia <beniamin.bia@analog.com>
description: |
Analog Devices ADM1177 Hot Swap Controller and Digital Power Monitor
https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1177.pdf
properties:
compatible:
enum:
- adi,adm1177
reg:
maxItems: 1
avcc-supply:
description:
Phandle to the Avcc power supply
shunt-resistor-micro-ohms:
description:
The value of curent sense resistor in microohms. If not provided,
the current reading and overcurrent alert is disabled.
adi,shutdown-threshold-microamp:
description:
Specifies the current level at which an over current alert occurs.
If not provided, the overcurrent alert is configured to max ADC range
based on shunt-resistor-micro-ohms.
adi,vrange-high-enable:
description:
Specifies which internal voltage divider to be used. A 1 selects
a 7:2 voltage divider while a 0 selects a 14:1 voltage divider.
type: boolean
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
pwmon@5a {
compatible = "adi,adm1177";
reg = <0x5a>;
shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */
adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */
adi,vrange-high-enable;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/pmbus/ti,ucd90320.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: UCD90320 power sequencer
maintainers:
- Jim Wright <wrightj@linux.vnet.ibm.com>
description: |
The UCD90320 is a 32-rail PMBus/I2C addressable power-supply sequencer and
monitor. The 24 integrated ADC channels (AMONx) monitor the power supply
voltage, current, and temperature. Of the 84 GPIO pins, 8 can be used as
digital monitors (DMONx), 32 to enable the power supply (ENx), 24 for
margining (MARx), 16 for logical GPO, and 32 GPIs for cascading, and system
function.
http://focus.ti.com/lit/ds/symlink/ucd90320.pdf
properties:
compatible:
enum:
- ti,ucd90320
reg:
maxItems: 1
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
ucd90320@11 {
compatible = "ti,ucd90320";
reg = <0x11>;
};
};
Kernel driver adm1177
=====================
Supported chips:
* Analog Devices ADM1177
Prefix: 'adm1177'
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1177.pdf
Author: Beniamin Bia <beniamin.bia@analog.com>
Description
-----------
This driver supports hardware monitoring for Analog Devices ADM1177
Hot-Swap Controller and Digital Power Monitors with Soft Start Pin.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices for
details.
Sysfs entries
-------------
The following attributes are supported. Current maxim attribute
is read-write, all other attributes are read-only.
in0_input Measured voltage in microvolts.
curr1_input Measured current in microamperes.
curr1_max_alarm Overcurrent alarm in microamperes.
.. SPDX-License-Identifier: GPL-2.0
Kernel driver drivetemp
=======================
References
----------
ANS T13/1699-D
Information technology - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
ANS Project T10/BSR INCITS 513
Information technology - SCSI Primary Commands - 4 (SPC-4)
ANS Project INCITS 557
Information technology - SCSI / ATA Translation - 5 (SAT-5)
Description
-----------
This driver supports reporting the temperature of disk and solid state
drives with temperature sensors.
If supported, it uses the ATA SCT Command Transport feature to read
the current drive temperature and, if available, temperature limits
as well as historic minimum and maximum temperatures. If SCT Command
Transport is not supported, the driver uses SMART attributes to read
the drive temperature.
Sysfs entries
-------------
Only the temp1_input attribute is always available. Other attributes are
available only if reported by the drive. All temperatures are reported in
milli-degrees Celsius.
======================= =====================================================
temp1_input Current drive temperature
temp1_lcrit Minimum temperature limit. Operating the device below
this temperature may cause physical damage to the
device.
temp1_min Minimum recommended continuous operating limit
temp1_max Maximum recommended continuous operating temperature
temp1_crit Maximum temperature limit. Operating the device above
this temperature may cause physical damage to the
device.
temp1_lowest Minimum temperature seen this power cycle
temp1_highest Maximum temperature seen this power cycle
======================= =====================================================
......@@ -29,6 +29,7 @@ Hardware Monitoring Kernel Drivers
adm1025
adm1026
adm1031
adm1177
adm1275
adm9240
ads7828
......@@ -47,6 +48,7 @@ Hardware Monitoring Kernel Drivers
da9055
dell-smm-hwmon
dme1737
drivetemp
ds1621
ds620
emc1403
......@@ -106,8 +108,10 @@ Hardware Monitoring Kernel Drivers
max1619
max1668
max197
max20730
max20751
max31722
max31730
max31785
max31790
max34440
......@@ -177,6 +181,7 @@ Hardware Monitoring Kernel Drivers
wm831x
wm8350
xgene-hwmon
xdpe12284
zl6100
.. only:: subproject and html
......
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver max20730
======================
Supported chips:
* Maxim MAX20730
Prefix: 'max20730'
Addresses scanned: -
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20730.pdf
* Maxim MAX20734
Prefix: 'max20734'
Addresses scanned: -
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20734.pdf
* Maxim MAX20743
Prefix: 'max20743'
Addresses scanned: -
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20743.pdf
Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
This driver implements support for Maxim MAX20730, MAX20734, and MAX20743
Integrated, Step-Down Switching Regulators with PMBus support.
The driver is a client driver to the core PMBus driver.
Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
details.
Sysfs entries
-------------
=================== ===== =======================================================
curr1_crit RW/RO Critical output current. Please see datasheet for
supported limits. Read-only if the chip is
write protected; read-write otherwise.
curr1_crit_alarm RO Output current critical alarm
curr1_input RO Output current
curr1_label RO 'iout1'
in1_alarm RO Input voltage alarm
in1_input RO Input voltage
in1_label RO 'vin'
in2_alarm RO Output voltage alarm
in2_input RO Output voltage
in2_label RO 'vout1'
temp1_crit RW/RO Critical temeperature. Supported values are 130 or 150
degrees C. Read-only if the chip is write protected;
read-write otherwise.
temp1_crit_alarm RO Temperature critical alarm
temp1_input RO Chip temperature
=================== ===== =======================================================
Kernel driver max31790
======================
Supported chips:
* Maxim MAX31730
Prefix: 'max31730'
Addresses scanned: 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, 0x4d, 0x4e, 0x4f
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31730.pdf
Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
This driver implements support for Maxim MAX31730.
The MAX31730 temperature sensor monitors its own temperature and the
temperatures of three external diode-connected transistors. The operating
supply voltage is from 3.0V to 3.6V. Resistance cancellation compensates
for high series resistance in circuit-board traces and the external thermal
diode, while beta compensation corrects for temperature-measurement
errors due to low-beta sensing transistors.
Sysfs entries
-------------
=================== == =======================================================
temp[1-4]_enable RW Temperature enable/disable
Set to 0 to enable channel, 0 to disable
temp[1-4]_input RO Temperature input
temp[2-4]_fault RO Fault indicator for remote channels
temp[1-4]_max RW Maximum temperature
temp[1-4]_max_alarm RW Maximum temperature alarm
temp[1-4]_min RW Minimum temperature. Common for all channels.
Only temp1_min is writeable.
temp[1-4]_min_alarm RO Minimum temperature alarm
temp[2-4]_offset RW Temperature offset for remote channels
=================== == =======================================================
......@@ -63,6 +63,16 @@ Supported chips:
http://www.ti.com/lit/gpn/tps544c25
* Maxim MAX20796
Prefix: 'max20796'
Addresses scanned: -
Datasheet:
Not published
* Generic PMBus devices
Prefix: 'pmbus'
......
......@@ -3,9 +3,10 @@ Kernel driver ucd9000
Supported chips:
* TI UCD90120, UCD90124, UCD90160, UCD9090, and UCD90910
* TI UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, and UCD90910
Prefixes: 'ucd90120', 'ucd90124', 'ucd90160', 'ucd9090', 'ucd90910'
Prefixes: 'ucd90120', 'ucd90124', 'ucd90160', 'ucd90320', 'ucd9090',
'ucd90910'
Addresses scanned: -
......@@ -14,6 +15,7 @@ Supported chips:
- http://focus.ti.com/lit/ds/symlink/ucd90120.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90124.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90160.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90320.pdf
- http://focus.ti.com/lit/ds/symlink/ucd9090.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90910.pdf
......@@ -45,6 +47,12 @@ power-on reset signals, external interrupts, cascading, or other system
functions. Twelve of these pins offer PWM functionality. Using these pins, the
UCD90160 offers support for margining, and general-purpose PWM functions.
The UCD90320 is a 32-rail PMBus/I2C addressable power-supply sequencer and
monitor. The 24 integrated ADC channels (AMONx) monitor the power supply
voltage, current, and temperature. Of the 84 GPIO pins, 8 can be used as
digital monitors (DMONx), 32 to enable the power supply (ENx), 24 for margining
(MARx), 16 for logical GPO, and 32 GPIs for cascading, and system function.
The UCD9090 is a 10-rail PMBus/I2C addressable power-supply sequencer and
monitor. The device integrates a 12-bit ADC for monitoring up to 10 power-supply
voltage inputs. Twenty-three GPIO pins can be used for power supply enables,
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver xdpe122
=====================
Supported chips:
* Infineon XDPE12254
Prefix: 'xdpe12254'
* Infineon XDPE12284
Prefix: 'xdpe12284'
Authors:
Vadim Pasternak <vadimp@mellanox.com>
Description
-----------
This driver implements support for Infineon Multi-phase XDPE122 family
dual loop voltage regulators.
The family includes XDPE12284 and XDPE12254 devices.
The devices from this family complaint with:
- Intel VR13 and VR13HC rev 1.3, IMVP8 rev 1.2 and IMPVP9 rev 1.3 DC-DC
converter specification.
- Intel SVID rev 1.9. protocol.
- PMBus rev 1.3 interface.
Devices support linear format for reading input voltage, input and output current,
input and output power and temperature.
Device supports VID format for reading output voltage. The below modes are
supported:
- VR12.0 mode, 5-mV DAC - 0x01.
- VR12.5 mode, 10-mV DAC - 0x02.
- IMVP9 mode, 5-mV DAC - 0x03.
- AMD mode 6.25mV - 0x10.
Devices support two pages for telemetry.
The driver provides for current: input, maximum and critical thresholds
and maximum and critical alarms. Critical thresholds and critical alarm are
supported only for current output.
The driver exports the following attributes for via the sysfs files, where
indexes 1, 2 are for "iin" and 3, 4 for "iout":
**curr[3-4]_crit**
**curr[3-4]_crit_alarm**
**curr[1-4]_input**
**curr[1-4]_label**
**curr[1-4]_max**
**curr[1-4]_max_alarm**
The driver provides for voltage: input, critical and low critical thresholds
and critical and low critical alarms.
The driver exports the following attributes for via the sysfs files, where
indexes 1, 2 are for "vin" and 3, 4 for "vout":
**in[1-4]_crit**
**in[1-4_crit_alarm**
**in[1-4]_input**
**in[1-4_label**
**in[1-4]_lcrit**
**in[1-41_lcrit_alarm**
The driver provides for power: input and alarms. Power alarm is supported only
for power input.
The driver exports the following attributes for via the sysfs files, where
indexes 1, 2 are for "pin" and 3, 4 for "pout":
**power[1-2]_alarm**
**power[1-4]_input**
**power[1-4]_label**
The driver provides for temperature: input, maximum and critical thresholds
and maximum and critical alarms.
The driver exports the following attributes for via the sysfs files:
**temp[1-2]_crit**
**temp[1-2]_crit_alarm**
**temp[1-2]_input**
**temp[1-2]_max**
**temp[1-2]_max_alarm**
......@@ -977,6 +977,15 @@ W: http://ez.analog.com/community/linux-device-drivers
F: drivers/iio/imu/adis16460.c
F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
ANALOG DEVICES INC ADM1177 DRIVER
M: Beniamin Bia <beniamin.bia@analog.com>
M: Michael Hennerich <Michael.Hennerich@analog.com>
L: linux-hwmon@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/hwmon/adm1177.c
F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml
ANALOG DEVICES INC ADP5061 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-pm@vger.kernel.org
......
......@@ -164,6 +164,16 @@ config SENSORS_ADM1031
This driver can also be built as a module. If so, the module
will be called adm1031.
config SENSORS_ADM1177
tristate "Analog Devices ADM1177 and compatibles"
depends on I2C
help
If you say yes here you get support for Analog Devices ADM1177
sensor chips.
This driver can also be built as a module. If so, the module
will be called adm1177.
config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles"
depends on I2C
......@@ -385,6 +395,16 @@ config SENSORS_ATXP1
This driver can also be built as a module. If so, the module
will be called atxp1.
config SENSORS_DRIVETEMP
tristate "Hard disk drives with temperature sensors"
depends on SCSI && ATA
help
If you say yes you get support for the temperature sensor on
hard disk drives.
This driver can also be built as a module. If so, the module
will be called satatemp.
config SENSORS_DS620
tristate "Dallas Semiconductor DS620"
depends on I2C
......@@ -889,7 +909,7 @@ config SENSORS_MAX197
will be called max197.
config SENSORS_MAX31722
tristate "MAX31722 temperature sensor"
tristate "MAX31722 temperature sensor"
depends on SPI
help
Support for the Maxim Integrated MAX31722/MAX31723 digital
......@@ -898,6 +918,16 @@ tristate "MAX31722 temperature sensor"
This driver can also be built as a module. If so, the module
will be called max31722.
config SENSORS_MAX31730
tristate "MAX31730 temperature sensor"
depends on I2C
help
Support for the Maxim Integrated MAX31730 3-Channel Remote
Temperature Sensor.
This driver can also be built as a module. If so, the module
will be called max31730.
config SENSORS_MAX6621
tristate "Maxim MAX6621 sensor chip"
depends on I2C
......@@ -1905,7 +1935,7 @@ config SENSORS_W83627HF
will be called w83627hf.
config SENSORS_W83627EHF
tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG, NCT6775F, NCT6776F"
tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG"
depends on !PPC
select HWMON_VID
help
......@@ -1918,8 +1948,7 @@ config SENSORS_W83627EHF
the Core 2 Duo. And also the W83627UHG, which is a stripped down
version of the W83627DHG (as far as hardware monitoring goes.)
This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F
(also known as W83667HG-I), and NCT6776F.
This driver also supports Nuvoton W83667HG and W83667HG-B.
This driver can also be built as a module. If so, the module
will be called w83627ehf.
......
......@@ -34,6 +34,7 @@ obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM1177) += adm1177.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
......@@ -56,6 +57,7 @@ obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
......@@ -123,6 +125,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
obj-$(CONFIG_SENSORS_MAX31730) += max31730.o
obj-$(CONFIG_SENSORS_MAX6621) += max6621.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* ADM1177 Hot Swap Controller and Digital Power Monitor with Soft Start Pin
*
* Copyright 2015-2019 Analog Devices Inc.
*/
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
/* Command Byte Operations */
#define ADM1177_CMD_V_CONT BIT(0)
#define ADM1177_CMD_I_CONT BIT(2)
#define ADM1177_CMD_VRANGE BIT(4)
/* Extended Register */
#define ADM1177_REG_ALERT_TH 2
#define ADM1177_BITS 12
/**
* struct adm1177_state - driver instance specific data
* @client pointer to i2c client
* @reg regulator info for the the power supply of the device
* @r_sense_uohm current sense resistor value
* @alert_threshold_ua current limit for shutdown
* @vrange_high internal voltage divider
*/
struct adm1177_state {
struct i2c_client *client;
struct regulator *reg;
u32 r_sense_uohm;
u32 alert_threshold_ua;
bool vrange_high;
};
static int adm1177_read_raw(struct adm1177_state *st, u8 num, u8 *data)
{
return i2c_master_recv(st->client, data, num);
}
static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
{
return i2c_smbus_write_byte(st->client, cmd);
}
static int adm1177_write_alert_thr(struct adm1177_state *st,
u32 alert_threshold_ua)
{
u64 val;
int ret;
val = 0xFFULL * alert_threshold_ua * st->r_sense_uohm;
val = div_u64(val, 105840000U);
val = div_u64(val, 1000U);
if (val > 0xFF)
val = 0xFF;
ret = i2c_smbus_write_byte_data(st->client, ADM1177_REG_ALERT_TH,
val);
if (ret)
return ret;
st->alert_threshold_ua = alert_threshold_ua;
return 0;
}
static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct adm1177_state *st = dev_get_drvdata(dev);
u8 data[3];
long dummy;
int ret;
switch (type) {
case hwmon_curr:
switch (attr) {
case hwmon_curr_input:
ret = adm1177_read_raw(st, 3, data);
if (ret < 0)
return ret;
dummy = (data[1] << 4) | (data[2] & 0xF);
/*
* convert to milliamperes
* ((105.84mV / 4096) x raw) / senseResistor(ohm)
*/
*val = div_u64((105840000ull * dummy),
4096 * st->r_sense_uohm);
return 0;
case hwmon_curr_max_alarm:
*val = st->alert_threshold_ua;
return 0;
default:
return -EOPNOTSUPP;
}
case hwmon_in:
ret = adm1177_read_raw(st, 3, data);
if (ret < 0)
return ret;
dummy = (data[0] << 4) | (data[2] >> 4);
/*
* convert to millivolts based on resistor devision
* (V_fullscale / 4096) * raw
*/
if (st->vrange_high)
dummy *= 26350;
else
dummy *= 6650;
*val = DIV_ROUND_CLOSEST(dummy, 4096);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct adm1177_state *st = dev_get_drvdata(dev);
switch (type) {
case hwmon_curr:
switch (attr) {
case hwmon_curr_max_alarm:
adm1177_write_alert_thr(st, val);
return 0;
default:
return -EOPNOTSUPP;
}
default:
return -EOPNOTSUPP;
}
}
static umode_t adm1177_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
const struct adm1177_state *st = data;
switch (type) {
case hwmon_in:
switch (attr) {
case hwmon_in_input:
return 0444;
}
break;
case hwmon_curr:
switch (attr) {
case hwmon_curr_input:
if (st->r_sense_uohm)
return 0444;
return 0;
case hwmon_curr_max_alarm:
if (st->r_sense_uohm)
return 0644;
return 0;
}
break;
default:
break;
}
return 0;
}
static const struct hwmon_channel_info *adm1177_info[] = {
HWMON_CHANNEL_INFO(curr,
HWMON_C_INPUT | HWMON_C_MAX_ALARM),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT),
NULL
};
static const struct hwmon_ops adm1177_hwmon_ops = {
.is_visible = adm1177_is_visible,
.read = adm1177_read,
.write = adm1177_write,
};
static const struct hwmon_chip_info adm1177_chip_info = {
.ops = &adm1177_hwmon_ops,
.info = adm1177_info,
};
static void adm1177_remove(void *data)
{
struct adm1177_state *st = data;
regulator_disable(st->reg);
}
static int adm1177_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm1177_state *st;
u32 alert_threshold_ua;
int ret;
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
st->client = client;
st->reg = devm_regulator_get_optional(&client->dev, "vref");
if (IS_ERR(st->reg)) {
if (PTR_ERR(st->reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
st->reg = NULL;
} else {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_add_action_or_reset(&client->dev, adm1177_remove,
st);
if (ret)
return ret;
}
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&st->r_sense_uohm))
st->r_sense_uohm = 0;
if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
&alert_threshold_ua)) {
if (st->r_sense_uohm)
/*
* set maximum default value from datasheet based on
* shunt-resistor
*/
alert_threshold_ua = div_u64(105840000000,
st->r_sense_uohm);
else
alert_threshold_ua = 0;
}
st->vrange_high = device_property_read_bool(dev,
"adi,vrange-high-enable");
if (alert_threshold_ua && st->r_sense_uohm)
adm1177_write_alert_thr(st, alert_threshold_ua);
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
ADM1177_CMD_I_CONT |
(st->vrange_high ? 0 : ADM1177_CMD_VRANGE));
if (ret)
return ret;
hwmon_dev =
devm_hwmon_device_register_with_info(dev, client->name, st,
&adm1177_chip_info, NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id adm1177_id[] = {
{"adm1177", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, adm1177_id);
static const struct of_device_id adm1177_dt_ids[] = {
{ .compatible = "adi,adm1177" },
{},
};
MODULE_DEVICE_TABLE(of, adm1177_dt_ids);
static struct i2c_driver adm1177_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1177",
.of_match_table = adm1177_dt_ids,
},
.probe = adm1177_probe,
.id_table = adm1177_id,
};
module_i2c_driver(adm1177_driver);
MODULE_AUTHOR("Beniamin Bia <beniamin.bia@analog.com>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADM1177 ADC driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
......@@ -188,7 +188,7 @@ static int hwmon_thermal_add_sensor(struct device *dev, int index)
static int hwmon_attr_base(enum hwmon_sensor_types type)
{
if (type == hwmon_in)
if (type == hwmon_in || type == hwmon_intrusion)
return 0;
return 1;
}
......@@ -343,6 +343,7 @@ static const char * const hwmon_chip_attrs[] = {
};
static const char * const hwmon_temp_attr_templates[] = {
[hwmon_temp_enable] = "temp%d_enable",
[hwmon_temp_input] = "temp%d_input",
[hwmon_temp_type] = "temp%d_type",
[hwmon_temp_lcrit] = "temp%d_lcrit",
......@@ -370,6 +371,7 @@ static const char * const hwmon_temp_attr_templates[] = {
};
static const char * const hwmon_in_attr_templates[] = {
[hwmon_in_enable] = "in%d_enable",
[hwmon_in_input] = "in%d_input",
[hwmon_in_min] = "in%d_min",
[hwmon_in_max] = "in%d_max",
......@@ -385,10 +387,10 @@ static const char * const hwmon_in_attr_templates[] = {
[hwmon_in_max_alarm] = "in%d_max_alarm",
[hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm",
[hwmon_in_crit_alarm] = "in%d_crit_alarm",
[hwmon_in_enable] = "in%d_enable",
};
static const char * const hwmon_curr_attr_templates[] = {
[hwmon_curr_enable] = "curr%d_enable",
[hwmon_curr_input] = "curr%d_input",
[hwmon_curr_min] = "curr%d_min",
[hwmon_curr_max] = "curr%d_max",
......@@ -407,6 +409,7 @@ static const char * const hwmon_curr_attr_templates[] = {
};
static const char * const hwmon_power_attr_templates[] = {
[hwmon_power_enable] = "power%d_enable",
[hwmon_power_average] = "power%d_average",
[hwmon_power_average_interval] = "power%d_average_interval",
[hwmon_power_average_interval_max] = "power%d_interval_max",
......@@ -438,11 +441,13 @@ static const char * const hwmon_power_attr_templates[] = {
};
static const char * const hwmon_energy_attr_templates[] = {
[hwmon_energy_enable] = "energy%d_enable",
[hwmon_energy_input] = "energy%d_input",
[hwmon_energy_label] = "energy%d_label",
};
static const char * const hwmon_humidity_attr_templates[] = {
[hwmon_humidity_enable] = "humidity%d_enable",
[hwmon_humidity_input] = "humidity%d_input",
[hwmon_humidity_label] = "humidity%d_label",
[hwmon_humidity_min] = "humidity%d_min",
......@@ -454,6 +459,7 @@ static const char * const hwmon_humidity_attr_templates[] = {
};
static const char * const hwmon_fan_attr_templates[] = {
[hwmon_fan_enable] = "fan%d_enable",
[hwmon_fan_input] = "fan%d_input",
[hwmon_fan_label] = "fan%d_label",
[hwmon_fan_min] = "fan%d_min",
......@@ -474,6 +480,11 @@ static const char * const hwmon_pwm_attr_templates[] = {
[hwmon_pwm_freq] = "pwm%d_freq",
};
static const char * const hwmon_intrusion_attr_templates[] = {
[hwmon_intrusion_alarm] = "intrusion%d_alarm",
[hwmon_intrusion_beep] = "intrusion%d_beep",
};
static const char * const *__templates[] = {
[hwmon_chip] = hwmon_chip_attrs,
[hwmon_temp] = hwmon_temp_attr_templates,
......@@ -484,6 +495,7 @@ static const char * const *__templates[] = {
[hwmon_humidity] = hwmon_humidity_attr_templates,
[hwmon_fan] = hwmon_fan_attr_templates,
[hwmon_pwm] = hwmon_pwm_attr_templates,
[hwmon_intrusion] = hwmon_intrusion_attr_templates,
};
static const int __templates_size[] = {
......@@ -496,6 +508,7 @@ static const int __templates_size[] = {
[hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates),
[hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates),
[hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates),
[hwmon_intrusion] = ARRAY_SIZE(hwmon_intrusion_attr_templates),
};
static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info)
......
This diff is collapsed.
This diff is collapsed.
......@@ -20,8 +20,8 @@ config SENSORS_PMBUS
help
If you say yes here you get hardware monitoring support for generic
PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, TPS544B20,
TPS544B25, TPS544C20, TPS544C25, and UDT020.
MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400,
TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020.
This driver can also be built as a module. If so, the module will
be called pmbus.
......@@ -145,6 +145,15 @@ config SENSORS_MAX16064
This driver can also be built as a module. If so, the module will
be called max16064.
config SENSORS_MAX20730
tristate "Maxim MAX20730, MAX20734, MAX20743"
help
If you say yes here you get hardware monitoring support for Maxim
MAX20730, MAX20734, and MAX20743.
This driver can also be built as a module. If so, the module will
be called max20730.
config SENSORS_MAX20751
tristate "Maxim MAX20751"
help
......@@ -200,20 +209,20 @@ config SENSORS_TPS40422
be called tps40422.
config SENSORS_TPS53679
tristate "TI TPS53679"
tristate "TI TPS53679, TPS53688"
help
If you say yes here you get hardware monitoring support for TI
TPS53679.
TPS53679, TPS53688
This driver can also be built as a module. If so, the module will
be called tps53679.
config SENSORS_UCD9000
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
tristate "TI UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, UCD90910"
help
If you say yes here you get hardware monitoring support for TI
UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System
Health Controllers.
UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, UCD90910, Sequencer
and System Health Controllers.
This driver can also be built as a module. If so, the module will
be called ucd9000.
......@@ -228,6 +237,15 @@ config SENSORS_UCD9200
This driver can also be built as a module. If so, the module will
be called ucd9200.
config SENSORS_XDPE122
tristate "Infineon XDPE122 family"
help
If you say yes here you get hardware monitoring support for Infineon
XDPE12254, XDPE12284, device.
This driver can also be built as a module. If so, the module will
be called xdpe12284.
config SENSORS_ZL6100
tristate "Intersil ZL6100 and compatibles"
help
......
......@@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX20730) += max20730.o
obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
......@@ -26,4 +27,5 @@ obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
......@@ -20,12 +20,15 @@
#define CFFPS_FRU_CMD 0x9A
#define CFFPS_PN_CMD 0x9B
#define CFFPS_HEADER_CMD 0x9C
#define CFFPS_SN_CMD 0x9E
#define CFFPS_MAX_POWER_OUT_CMD 0xA7
#define CFFPS_CCIN_CMD 0xBD
#define CFFPS_FW_CMD 0xFA
#define CFFPS1_FW_NUM_BYTES 4
#define CFFPS2_FW_NUM_WORDS 3
#define CFFPS_SYS_CONFIG_CMD 0xDA
#define CFFPS_12VCS_VOUT_CMD 0xDE
#define CFFPS_INPUT_HISTORY_CMD 0xD6
#define CFFPS_INPUT_HISTORY_SIZE 100
......@@ -44,22 +47,21 @@
#define CFFPS_MFR_VAUX_FAULT BIT(6)
#define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
/*
* LED off state actually relinquishes LED control to PSU firmware, so it can
* turn on the LED for faults.
*/
#define CFFPS_LED_OFF 0
#define CFFPS_LED_BLINK BIT(0)
#define CFFPS_LED_ON BIT(1)
#define CFFPS_LED_OFF BIT(2)
#define CFFPS_BLINK_RATE_MS 250
enum {
CFFPS_DEBUGFS_INPUT_HISTORY = 0,
CFFPS_DEBUGFS_FRU,
CFFPS_DEBUGFS_PN,
CFFPS_DEBUGFS_HEADER,
CFFPS_DEBUGFS_SN,
CFFPS_DEBUGFS_MAX_POWER_OUT,
CFFPS_DEBUGFS_CCIN,
CFFPS_DEBUGFS_FW,
CFFPS_DEBUGFS_ON_OFF_CONFIG,
CFFPS_DEBUGFS_NUM_ENTRIES
};
......@@ -136,15 +138,15 @@ static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu,
psu->input_history.byte_count);
}
static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
u8 cmd;
int i, rc;
int *idxp = file->private_data;
int idx = *idxp;
struct ibm_cffps *psu = to_psu(idxp, idx);
char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
pmbus_set_page(psu->client, 0);
......@@ -157,9 +159,20 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
case CFFPS_DEBUGFS_PN:
cmd = CFFPS_PN_CMD;
break;
case CFFPS_DEBUGFS_HEADER:
cmd = CFFPS_HEADER_CMD;
break;
case CFFPS_DEBUGFS_SN:
cmd = CFFPS_SN_CMD;
break;
case CFFPS_DEBUGFS_MAX_POWER_OUT:
rc = i2c_smbus_read_word_swapped(psu->client,
CFFPS_MAX_POWER_OUT_CMD);
if (rc < 0)
return rc;
rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc);
goto done;
case CFFPS_DEBUGFS_CCIN:
rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD);
if (rc < 0)
......@@ -199,6 +212,14 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
return -EOPNOTSUPP;
}
goto done;
case CFFPS_DEBUGFS_ON_OFF_CONFIG:
rc = i2c_smbus_read_byte_data(psu->client,
PMBUS_ON_OFF_CONFIG);
if (rc < 0)
return rc;
rc = snprintf(data, 3, "%02x", rc);
goto done;
default:
return -EINVAL;
}
......@@ -214,9 +235,42 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
return simple_read_from_buffer(buf, count, ppos, data, rc);
}
static ssize_t ibm_cffps_debugfs_write(struct file *file,
const char __user *buf, size_t count,
loff_t *ppos)
{
u8 data;
ssize_t rc;
int *idxp = file->private_data;
int idx = *idxp;
struct ibm_cffps *psu = to_psu(idxp, idx);
switch (idx) {
case CFFPS_DEBUGFS_ON_OFF_CONFIG:
pmbus_set_page(psu->client, 0);
rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
if (rc <= 0)
return rc;
rc = i2c_smbus_write_byte_data(psu->client,
PMBUS_ON_OFF_CONFIG, data);
if (rc)
return rc;
rc = 1;
break;
default:
return -EINVAL;
}
return rc;
}
static const struct file_operations ibm_cffps_fops = {
.llseek = noop_llseek,
.read = ibm_cffps_debugfs_op,
.read = ibm_cffps_debugfs_read,
.write = ibm_cffps_debugfs_write,
.open = simple_open,
};
......@@ -293,6 +347,9 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
if (mfr & CFFPS_MFR_PS_KILL)
rc |= PB_STATUS_OFF;
break;
case PMBUS_VIRT_READ_VMON:
rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD);
break;
default:
rc = -ENODATA;
break;
......@@ -375,6 +432,9 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
rc = devm_led_classdev_register(dev, &psu->led);
if (rc)
dev_warn(dev, "failed to register led class: %d\n", rc);
else
i2c_smbus_write_byte_data(client, CFFPS_SYS_CONFIG_CMD,
CFFPS_LED_OFF);
}
static struct pmbus_driver_info ibm_cffps_info[] = {
......@@ -396,7 +456,7 @@ static struct pmbus_driver_info ibm_cffps_info[] = {
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_STATUS_FAN12,
PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON,
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
......@@ -486,15 +546,24 @@ static int ibm_cffps_probe(struct i2c_client *client,
debugfs_create_file("part_number", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_PN],
&ibm_cffps_fops);
debugfs_create_file("header", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_HEADER],
&ibm_cffps_fops);
debugfs_create_file("serial_number", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_SN],
&ibm_cffps_fops);
debugfs_create_file("max_power_out", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT],
&ibm_cffps_fops);
debugfs_create_file("ccin", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_CCIN],
&ibm_cffps_fops);
debugfs_create_file("fw_version", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_FW],
&ibm_cffps_fops);
debugfs_create_file("on_off_config", 0644, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG],
&ibm_cffps_fops);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for MAX20730, MAX20734, and MAX20743 Integrated, Step-Down
* Switching Regulators
*
* Copyright 2019 Google LLC.
*/
#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/mutex.h>
#include <linux/of_device.h>
#include <linux/pmbus.h>
#include <linux/util_macros.h>
#include "pmbus.h"
enum chips {
max20730,
max20734,
max20743
};
struct max20730_data {
enum chips id;
struct pmbus_driver_info info;
struct mutex lock; /* Used to protect against parallel writes */
u16 mfr_devset1;
};
#define to_max20730_data(x) container_of(x, struct max20730_data, info)
#define MAX20730_MFR_DEVSET1 0xd2
/*
* Convert discreet value to direct data format. Strictly speaking, all passed
* values are constants, so we could do that calculation manually. On the
* downside, that would make the driver more difficult to maintain, so lets
* use this approach.
*/
static u16 val_to_direct(int v, enum pmbus_sensor_classes class,
const struct pmbus_driver_info *info)
{
int R = info->R[class] - 3; /* take milli-units into account */
int b = info->b[class] * 1000;
long d;
d = v * info->m[class] + b;
/*
* R < 0 is true for all callers, so we don't need to bother
* about the R > 0 case.
*/
while (R < 0) {
d = DIV_ROUND_CLOSEST(d, 10);
R++;
}
return (u16)d;
}
static long direct_to_val(u16 w, enum pmbus_sensor_classes class,
const struct pmbus_driver_info *info)
{
int R = info->R[class] - 3;
int b = info->b[class] * 1000;
int m = info->m[class];
long d = (s16)w;
if (m == 0)
return 0;
while (R < 0) {
d *= 10;
R++;
}
d = (d - b) / m;
return d;
}
static u32 max_current[][5] = {
[max20730] = { 13000, 16600, 20100, 23600 },
[max20734] = { 21000, 27000, 32000, 38000 },
[max20743] = { 18900, 24100, 29200, 34100 },
};
static int max20730_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct max20730_data *data = to_max20730_data(info);
int ret = 0;
u32 max_c;
switch (reg) {
case PMBUS_OT_FAULT_LIMIT:
switch ((data->mfr_devset1 >> 11) & 0x3) {
case 0x0:
ret = val_to_direct(150000, PSC_TEMPERATURE, info);
break;
case 0x1:
ret = val_to_direct(130000, PSC_TEMPERATURE, info);
break;
default:
ret = -ENODATA;
break;
}
break;
case PMBUS_IOUT_OC_FAULT_LIMIT:
max_c = max_current[data->id][(data->mfr_devset1 >> 5) & 0x3];
ret = val_to_direct(max_c, PSC_CURRENT_OUT, info);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int max20730_write_word_data(struct i2c_client *client, int page,
int reg, u16 word)
{
struct pmbus_driver_info *info;
struct max20730_data *data;
u16 devset1;
int ret = 0;
int idx;
info = (struct pmbus_driver_info *)pmbus_get_driver_info(client);
data = to_max20730_data(info);
mutex_lock(&data->lock);
devset1 = data->mfr_devset1;
switch (reg) {
case PMBUS_OT_FAULT_LIMIT:
devset1 &= ~(BIT(11) | BIT(12));
if (direct_to_val(word, PSC_TEMPERATURE, info) < 140000)
devset1 |= BIT(11);
break;
case PMBUS_IOUT_OC_FAULT_LIMIT:
devset1 &= ~(BIT(5) | BIT(6));
idx = find_closest(direct_to_val(word, PSC_CURRENT_OUT, info),
max_current[data->id], 4);
devset1 |= (idx << 5);
break;
default:
ret = -ENODATA;
break;
}
if (!ret && devset1 != data->mfr_devset1) {
ret = i2c_smbus_write_word_data(client, MAX20730_MFR_DEVSET1,
devset1);
if (!ret) {
data->mfr_devset1 = devset1;
pmbus_clear_cache(client);
}
}
mutex_unlock(&data->lock);
return ret;
}
static const struct pmbus_driver_info max20730_info[] = {
[max20730] = {
.pages = 1,
.read_word_data = max20730_read_word_data,
.write_word_data = max20730_write_word_data,
/* Source : Maxim AN6042 */
.format[PSC_TEMPERATURE] = direct,
.m[PSC_TEMPERATURE] = 21,
.b[PSC_TEMPERATURE] = 5887,
.R[PSC_TEMPERATURE] = -1,
.format[PSC_VOLTAGE_IN] = direct,
.m[PSC_VOLTAGE_IN] = 3609,
.b[PSC_VOLTAGE_IN] = 0,
.R[PSC_VOLTAGE_IN] = -2,
/*
* Values in the datasheet are adjusted for temperature and
* for the relationship between Vin and Vout.
* Unfortunately, the data sheet suggests that Vout measurement
* may be scaled with a resistor array. This is indeed the case
* at least on the evaulation boards. As a result, any in-driver
* adjustments would either be wrong or require elaborate means
* to configure the scaling. Instead of doing that, just report
* raw values and let userspace handle adjustments.
*/
.format[PSC_CURRENT_OUT] = direct,
.m[PSC_CURRENT_OUT] = 153,
.b[PSC_CURRENT_OUT] = 4976,
.R[PSC_CURRENT_OUT] = -1,
.format[PSC_VOLTAGE_OUT] = linear,
.func[0] = PMBUS_HAVE_VIN |
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
},
[max20734] = {
.pages = 1,
.read_word_data = max20730_read_word_data,
.write_word_data = max20730_write_word_data,
/* Source : Maxim AN6209 */
.format[PSC_TEMPERATURE] = direct,
.m[PSC_TEMPERATURE] = 21,
.b[PSC_TEMPERATURE] = 5887,
.R[PSC_TEMPERATURE] = -1,
.format[PSC_VOLTAGE_IN] = direct,
.m[PSC_VOLTAGE_IN] = 3592,
.b[PSC_VOLTAGE_IN] = 0,
.R[PSC_VOLTAGE_IN] = -2,
.format[PSC_CURRENT_OUT] = direct,
.m[PSC_CURRENT_OUT] = 111,
.b[PSC_CURRENT_OUT] = 3461,
.R[PSC_CURRENT_OUT] = -1,
.format[PSC_VOLTAGE_OUT] = linear,
.func[0] = PMBUS_HAVE_VIN |
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
},
[max20743] = {
.pages = 1,
.read_word_data = max20730_read_word_data,
.write_word_data = max20730_write_word_data,
/* Source : Maxim AN6042 */
.format[PSC_TEMPERATURE] = direct,
.m[PSC_TEMPERATURE] = 21,
.b[PSC_TEMPERATURE] = 5887,
.R[PSC_TEMPERATURE] = -1,
.format[PSC_VOLTAGE_IN] = direct,
.m[PSC_VOLTAGE_IN] = 3597,
.b[PSC_VOLTAGE_IN] = 0,
.R[PSC_VOLTAGE_IN] = -2,
.format[PSC_CURRENT_OUT] = direct,
.m[PSC_CURRENT_OUT] = 95,
.b[PSC_CURRENT_OUT] = 5014,
.R[PSC_CURRENT_OUT] = -1,
.format[PSC_VOLTAGE_OUT] = linear,
.func[0] = PMBUS_HAVE_VIN |
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
},
};
static int max20730_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
struct max20730_data *data;
enum chips chip_id;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA))
return -ENODEV;
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
if (ret < 0) {
dev_err(&client->dev, "Failed to read Manufacturer ID\n");
return ret;
}
if (ret != 5 || strncmp(buf, "MAXIM", 5)) {
buf[ret] = '\0';
dev_err(dev, "Unsupported Manufacturer ID '%s'\n", buf);
return -ENODEV;
}
/*
* The chips support reading PMBUS_MFR_MODEL. On both MAX20730
* and MAX20734, reading it returns M20743. Presumably that is
* the reason why the command is not documented. Unfortunately,
* that means that there is no reliable means to detect the chip.
* However, we can at least detect the chip series. Compare
* the returned value against 'M20743' and bail out if there is
* a mismatch. If that doesn't work for all chips, we may have
* to remove this check.
*/
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
if (ret < 0) {
dev_err(dev, "Failed to read Manufacturer Model\n");
return ret;
}
if (ret != 6 || strncmp(buf, "M20743", 6)) {
buf[ret] = '\0';
dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
return -ENODEV;
}
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf);
if (ret < 0) {
dev_err(dev, "Failed to read Manufacturer Revision\n");
return ret;
}
if (ret != 1 || buf[0] != 'F') {
buf[ret] = '\0';
dev_err(dev, "Unsupported Manufacturer Revision '%s'\n", buf);
return -ENODEV;
}
if (client->dev.of_node)
chip_id = (enum chips)of_device_get_match_data(dev);
else
chip_id = id->driver_data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->id = chip_id;
mutex_init(&data->lock);
memcpy(&data->info, &max20730_info[chip_id], sizeof(data->info));
ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET1);
if (ret < 0)
return ret;
data->mfr_devset1 = ret;
return pmbus_do_probe(client, id, &data->info);
}
static const struct i2c_device_id max20730_id[] = {
{ "max20730", max20730 },
{ "max20734", max20734 },
{ "max20743", max20743 },
{ },
};
MODULE_DEVICE_TABLE(i2c, max20730_id);
static const struct of_device_id max20730_of_match[] = {
{ .compatible = "maxim,max20730", .data = (void *)max20730 },
{ .compatible = "maxim,max20734", .data = (void *)max20734 },
{ .compatible = "maxim,max20743", .data = (void *)max20743 },
{ },
};
MODULE_DEVICE_TABLE(of, max20730_of_match);
static struct i2c_driver max20730_driver = {
.driver = {
.name = "max20730",
.of_match_table = max20730_of_match,
},
.probe = max20730_probe,
.remove = pmbus_do_remove,
.id_table = max20730_id,
};
module_i2c_driver(max20730_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX20730 / MAX20734 / MAX20743");
MODULE_LICENSE("GPL");
......@@ -16,7 +16,7 @@ static struct pmbus_driver_info max20751_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = vid,
.vrm_version = vr12,
.vrm_version[0] = vr12,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
......
......@@ -115,7 +115,7 @@ static int pmbus_identify(struct i2c_client *client,
}
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
int vout_mode;
int vout_mode, i;
vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (vout_mode >= 0 && vout_mode != 0xff) {
......@@ -124,7 +124,8 @@ static int pmbus_identify(struct i2c_client *client,
break;
case 1:
info->format[PSC_VOLTAGE_OUT] = vid;
info->vrm_version = vr11;
for (i = 0; i < info->pages; i++)
info->vrm_version[i] = vr11;
break;
case 2:
info->format[PSC_VOLTAGE_OUT] = direct;
......@@ -210,6 +211,7 @@ static const struct i2c_device_id pmbus_id[] = {
{"dps460", (kernel_ulong_t)&pmbus_info_one_skip},
{"dps650ab", (kernel_ulong_t)&pmbus_info_one_skip},
{"dps800", (kernel_ulong_t)&pmbus_info_one_skip},
{"max20796", (kernel_ulong_t)&pmbus_info_one},
{"mdt040", (kernel_ulong_t)&pmbus_info_one},
{"ncp4200", (kernel_ulong_t)&pmbus_info_one},
{"ncp4208", (kernel_ulong_t)&pmbus_info_one},
......
......@@ -22,6 +22,8 @@ enum pmbus_regs {
PMBUS_CLEAR_FAULTS = 0x03,
PMBUS_PHASE = 0x04,
PMBUS_WRITE_PROTECT = 0x10,
PMBUS_CAPABILITY = 0x19,
PMBUS_QUERY = 0x1A,
......@@ -225,6 +227,15 @@ enum pmbus_regs {
*/
#define PB_OPERATION_CONTROL_ON BIT(7)
/*
* WRITE_PROTECT
*/
#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */
#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */
#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */
#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT)
/*
* CAPABILITY
*/
......@@ -377,12 +388,12 @@ enum pmbus_sensor_classes {
#define PMBUS_PAGE_VIRTUAL BIT(31)
enum pmbus_data_format { linear = 0, direct, vid };
enum vrm_version { vr11 = 0, vr12, vr13 };
enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
struct pmbus_driver_info {
int pages; /* Total number of pages */
enum pmbus_data_format format[PSC_NUM_CLASSES];
enum vrm_version vrm_version;
enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */
/*
* Support one set of coefficients for each sensor type
* Used for chips providing data in direct mode.
......
......@@ -696,7 +696,7 @@ static long pmbus_reg2data_vid(struct pmbus_data *data,
long val = sensor->data;
long rv = 0;
switch (data->info->vrm_version) {
switch (data->info->vrm_version[sensor->page]) {
case vr11:
if (val >= 0x02 && val <= 0xb2)
rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100);
......@@ -709,6 +709,14 @@ static long pmbus_reg2data_vid(struct pmbus_data *data,
if (val >= 0x01)
rv = 500 + (val - 1) * 10;
break;
case imvp9:
if (val >= 0x01)
rv = 200 + (val - 1) * 10;
break;
case amd625mv:
if (val >= 0x0 && val <= 0xd8)
rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100);
break;
}
return rv;
}
......@@ -1088,6 +1096,9 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
snprintf(sensor->name, sizeof(sensor->name), "%s%d",
name, seq);
if (data->flags & PMBUS_WRITE_PROTECTED)
readonly = true;
sensor->page = page;
sensor->reg = reg;
sensor->class = class;
......@@ -2141,6 +2152,15 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
client->flags |= I2C_CLIENT_PEC;
/*
* Check if the chip is write protected. If it is, we can not clear
* faults, and we should not try it. Also, in that case, writes into
* limit registers need to be disabled.
*/
ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
if (ret > 0 && (ret & PB_WP_ANY))
data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
if (data->info->pages)
pmbus_clear_faults(client);
else
......
......@@ -19,26 +19,30 @@
static int pxe1610_identify(struct i2c_client *client,
struct pmbus_driver_info *info)
{
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
u8 vout_mode;
int ret;
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_mode = ret & GENMASK(4, 0);
switch (vout_mode) {
case 1:
info->vrm_version = vr12;
break;
case 2:
info->vrm_version = vr13;
break;
default:
return -ENODEV;
int i;
for (i = 0; i < PXE1610_NUM_PAGES; i++) {
if (pmbus_check_byte_register(client, i, PMBUS_VOUT_MODE)) {
u8 vout_mode;
int ret;
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_mode = ret & GENMASK(4, 0);
switch (vout_mode) {
case 1:
info->vrm_version[i] = vr12;
break;
case 2:
info->vrm_version[i] = vr13;
break;
default:
return -ENODEV;
}
}
}
......
......@@ -24,27 +24,29 @@ static int tps53679_identify(struct i2c_client *client,
struct pmbus_driver_info *info)
{
u8 vout_params;
int ret;
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_params = ret & GENMASK(4, 0);
switch (vout_params) {
case TPS53679_PROT_VR13_10MV:
case TPS53679_PROT_VR12_5_10MV:
info->vrm_version = vr13;
break;
case TPS53679_PROT_VR13_5MV:
case TPS53679_PROT_VR12_5MV:
case TPS53679_PROT_IMVP8_5MV:
info->vrm_version = vr12;
break;
default:
return -EINVAL;
int i, ret;
for (i = 0; i < TPS53679_PAGE_NUM; i++) {
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_params = ret & GENMASK(4, 0);
switch (vout_params) {
case TPS53679_PROT_VR13_10MV:
case TPS53679_PROT_VR12_5_10MV:
info->vrm_version[i] = vr13;
break;
case TPS53679_PROT_VR13_5MV:
case TPS53679_PROT_VR12_5MV:
case TPS53679_PROT_IMVP8_5MV:
info->vrm_version[i] = vr12;
break;
default:
return -EINVAL;
}
}
return 0;
......@@ -83,6 +85,7 @@ static int tps53679_probe(struct i2c_client *client,
static const struct i2c_device_id tps53679_id[] = {
{"tps53679", 0},
{"tps53688", 0},
{}
};
......@@ -90,6 +93,7 @@ MODULE_DEVICE_TABLE(i2c, tps53679_id);
static const struct of_device_id __maybe_unused tps53679_of_match[] = {
{.compatible = "ti,tps53679"},
{.compatible = "ti,tps53688"},
{}
};
MODULE_DEVICE_TABLE(of, tps53679_of_match);
......
......@@ -18,7 +18,8 @@
#include <linux/gpio/driver.h>
#include "pmbus.h"
enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090,
ucd90910 };
#define UCD9000_MONITOR_CONFIG 0xd5
#define UCD9000_NUM_PAGES 0xd6
......@@ -38,7 +39,7 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_GPIO_OUTPUT 1
#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07)
#define UCD9000_MON_PAGE(x) ((x) & 0x0f)
#define UCD9000_MON_PAGE(x) ((x) & 0x1f)
#define UCD9000_MON_VOLTAGE 1
#define UCD9000_MON_TEMPERATURE 2
......@@ -50,10 +51,12 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_GPIO_NAME_LEN 16
#define UCD9090_NUM_GPIOS 23
#define UCD901XX_NUM_GPIOS 26
#define UCD90320_NUM_GPIOS 84
#define UCD90910_NUM_GPIOS 26
#define UCD9000_DEBUGFS_NAME_LEN 24
#define UCD9000_GPI_COUNT 8
#define UCD90320_GPI_COUNT 32
struct ucd9000_data {
u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
......@@ -131,6 +134,7 @@ static const struct i2c_device_id ucd9000_id[] = {
{"ucd90120", ucd90120},
{"ucd90124", ucd90124},
{"ucd90160", ucd90160},
{"ucd90320", ucd90320},
{"ucd9090", ucd9090},
{"ucd90910", ucd90910},
{}
......@@ -154,6 +158,10 @@ static const struct of_device_id __maybe_unused ucd9000_of_match[] = {
.compatible = "ti,ucd90160",
.data = (void *)ucd90160
},
{
.compatible = "ti,ucd90320",
.data = (void *)ucd90320
},
{
.compatible = "ti,ucd9090",
.data = (void *)ucd9090
......@@ -322,6 +330,9 @@ static void ucd9000_probe_gpio(struct i2c_client *client,
case ucd90160:
data->gpio.ngpio = UCD901XX_NUM_GPIOS;
break;
case ucd90320:
data->gpio.ngpio = UCD90320_NUM_GPIOS;
break;
case ucd90910:
data->gpio.ngpio = UCD90910_NUM_GPIOS;
break;
......@@ -372,17 +383,18 @@ static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val)
struct ucd9000_debugfs_entry *entry = data;
struct i2c_client *client = entry->client;
u8 buffer[I2C_SMBUS_BLOCK_MAX];
int ret;
int ret, i;
ret = ucd9000_get_mfr_status(client, buffer);
if (ret < 0)
return ret;
/*
* Attribute only created for devices with gpi fault bits at bits
* 16-23, which is the second byte of the response.
* GPI fault bits are in sets of 8, two bytes from end of response.
*/
*val = !!(buffer[1] & BIT(entry->index));
i = ret - 3 - entry->index / 8;
if (i >= 0)
*val = !!(buffer[i] & BIT(entry->index % 8));
return 0;
}
......@@ -422,7 +434,7 @@ static int ucd9000_init_debugfs(struct i2c_client *client,
{
struct dentry *debugfs;
struct ucd9000_debugfs_entry *entries;
int i;
int i, gpi_count;
char name[UCD9000_DEBUGFS_NAME_LEN];
debugfs = pmbus_get_debugfs_dir(client);
......@@ -435,18 +447,21 @@ static int ucd9000_init_debugfs(struct i2c_client *client,
/*
* Of the chips this driver supports, only the UCD9090, UCD90160,
* and UCD90910 report GPI faults in their MFR_STATUS register, so only
* create the GPI fault debugfs attributes for those chips.
* UCD90320, and UCD90910 report GPI faults in their MFR_STATUS
* register, so only create the GPI fault debugfs attributes for those
* chips.
*/
if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 ||
mid->driver_data == ucd90910) {
mid->driver_data == ucd90320 || mid->driver_data == ucd90910) {
gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT
: UCD9000_GPI_COUNT;
entries = devm_kcalloc(&client->dev,
UCD9000_GPI_COUNT, sizeof(*entries),
gpi_count, sizeof(*entries),
GFP_KERNEL);
if (!entries)
return -ENOMEM;
for (i = 0; i < UCD9000_GPI_COUNT; i++) {
for (i = 0; i < gpi_count; i++) {
entries[i].client = client;
entries[i].index = i;
scnprintf(name, UCD9000_DEBUGFS_NAME_LEN,
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers
*
* Copyright (c) 2020 Mellanox Technologies. All rights reserved.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
#define XDPE122_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
#define XDPE122_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
#define XDPE122_PROT_IMVP9_10MV 0x03 /* IMVP9 mode, 10-mV DAC */
#define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */
#define XDPE122_PAGE_NUM 2
static int xdpe122_identify(struct i2c_client *client,
struct pmbus_driver_info *info)
{
u8 vout_params;
int i, ret;
for (i = 0; i < XDPE122_PAGE_NUM; i++) {
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_params = ret & GENMASK(4, 0);
switch (vout_params) {
case XDPE122_PROT_VR12_5_10MV:
info->vrm_version[i] = vr13;
break;
case XDPE122_PROT_VR12_5MV:
info->vrm_version[i] = vr12;
break;
case XDPE122_PROT_IMVP9_10MV:
info->vrm_version[i] = imvp9;
break;
case XDPE122_AMD_625MV:
info->vrm_version[i] = amd625mv;
break;
default:
return -EINVAL;
}
}
return 0;
}
static struct pmbus_driver_info xdpe122_info = {
.pages = XDPE122_PAGE_NUM,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = vid,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
.identify = xdpe122_identify,
};
static int xdpe122_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pmbus_driver_info *info;
info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
return pmbus_do_probe(client, id, info);
}
static const struct i2c_device_id xdpe122_id[] = {
{"xdpe12254", 0},
{"xdpe12284", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, xdpe122_id);
static const struct of_device_id __maybe_unused xdpe122_of_match[] = {
{.compatible = "infineon, xdpe12254"},
{.compatible = "infineon, xdpe12284"},
{}
};
MODULE_DEVICE_TABLE(of, xdpe122_of_match);
static struct i2c_driver xdpe122_driver = {
.driver = {
.name = "xdpe12284",
.of_match_table = of_match_ptr(xdpe122_of_match),
},
.probe = xdpe122_probe,
.remove = pmbus_do_remove,
.id_table = xdpe122_id,
};
module_i2c_driver(xdpe122_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
MODULE_LICENSE("GPL");
......@@ -390,8 +390,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pwm_fan_suspend(struct device *dev)
static int pwm_fan_disable(struct device *dev)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
struct pwm_args args;
......@@ -418,6 +417,17 @@ static int pwm_fan_suspend(struct device *dev)
return 0;
}
static void pwm_fan_shutdown(struct platform_device *pdev)
{
pwm_fan_disable(&pdev->dev);
}
#ifdef CONFIG_PM_SLEEP
static int pwm_fan_suspend(struct device *dev)
{
return pwm_fan_disable(dev);
}
static int pwm_fan_resume(struct device *dev)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
......@@ -455,6 +465,7 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
static struct platform_driver pwm_fan_driver = {
.probe = pwm_fan_probe,
.shutdown = pwm_fan_shutdown,
.driver = {
.name = "pwm-fan",
.pm = &pwm_fan_pm,
......
This diff is collapsed.
......@@ -27,6 +27,7 @@ enum hwmon_sensor_types {
hwmon_humidity,
hwmon_fan,
hwmon_pwm,
hwmon_intrusion,
hwmon_max,
};
......@@ -59,7 +60,8 @@ enum hwmon_chip_attributes {
#define HWMON_C_TEMP_SAMPLES BIT(hwmon_chip_temp_samples)
enum hwmon_temp_attributes {
hwmon_temp_input = 0,
hwmon_temp_enable,
hwmon_temp_input,
hwmon_temp_type,
hwmon_temp_lcrit,
hwmon_temp_lcrit_hyst,
......@@ -85,6 +87,7 @@ enum hwmon_temp_attributes {
hwmon_temp_reset_history,
};
#define HWMON_T_ENABLE BIT(hwmon_temp_enable)
#define HWMON_T_INPUT BIT(hwmon_temp_input)
#define HWMON_T_TYPE BIT(hwmon_temp_type)
#define HWMON_T_LCRIT BIT(hwmon_temp_lcrit)
......@@ -111,6 +114,7 @@ enum hwmon_temp_attributes {
#define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history)
enum hwmon_in_attributes {
hwmon_in_enable,
hwmon_in_input,
hwmon_in_min,
hwmon_in_max,
......@@ -126,9 +130,9 @@ enum hwmon_in_attributes {
hwmon_in_max_alarm,
hwmon_in_lcrit_alarm,
hwmon_in_crit_alarm,
hwmon_in_enable,
};
#define HWMON_I_ENABLE BIT(hwmon_in_enable)
#define HWMON_I_INPUT BIT(hwmon_in_input)
#define HWMON_I_MIN BIT(hwmon_in_min)
#define HWMON_I_MAX BIT(hwmon_in_max)
......@@ -144,9 +148,9 @@ enum hwmon_in_attributes {
#define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm)
#define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm)
#define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm)
#define HWMON_I_ENABLE BIT(hwmon_in_enable)
enum hwmon_curr_attributes {
hwmon_curr_enable,
hwmon_curr_input,
hwmon_curr_min,
hwmon_curr_max,
......@@ -164,6 +168,7 @@ enum hwmon_curr_attributes {
hwmon_curr_crit_alarm,
};
#define HWMON_C_ENABLE BIT(hwmon_curr_enable)
#define HWMON_C_INPUT BIT(hwmon_curr_input)
#define HWMON_C_MIN BIT(hwmon_curr_min)
#define HWMON_C_MAX BIT(hwmon_curr_max)
......@@ -181,6 +186,7 @@ enum hwmon_curr_attributes {
#define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm)
enum hwmon_power_attributes {
hwmon_power_enable,
hwmon_power_average,
hwmon_power_average_interval,
hwmon_power_average_interval_max,
......@@ -211,6 +217,7 @@ enum hwmon_power_attributes {
hwmon_power_crit_alarm,
};
#define HWMON_P_ENABLE BIT(hwmon_power_enable)
#define HWMON_P_AVERAGE BIT(hwmon_power_average)
#define HWMON_P_AVERAGE_INTERVAL BIT(hwmon_power_average_interval)
#define HWMON_P_AVERAGE_INTERVAL_MAX BIT(hwmon_power_average_interval_max)
......@@ -241,14 +248,17 @@ enum hwmon_power_attributes {
#define HWMON_P_CRIT_ALARM BIT(hwmon_power_crit_alarm)
enum hwmon_energy_attributes {
hwmon_energy_enable,
hwmon_energy_input,
hwmon_energy_label,
};
#define HWMON_E_ENABLE BIT(hwmon_energy_enable)
#define HWMON_E_INPUT BIT(hwmon_energy_input)
#define HWMON_E_LABEL BIT(hwmon_energy_label)
enum hwmon_humidity_attributes {
hwmon_humidity_enable,
hwmon_humidity_input,
hwmon_humidity_label,
hwmon_humidity_min,
......@@ -259,6 +269,7 @@ enum hwmon_humidity_attributes {
hwmon_humidity_fault,
};
#define HWMON_H_ENABLE BIT(hwmon_humidity_enable)
#define HWMON_H_INPUT BIT(hwmon_humidity_input)
#define HWMON_H_LABEL BIT(hwmon_humidity_label)
#define HWMON_H_MIN BIT(hwmon_humidity_min)
......@@ -269,6 +280,7 @@ enum hwmon_humidity_attributes {
#define HWMON_H_FAULT BIT(hwmon_humidity_fault)
enum hwmon_fan_attributes {
hwmon_fan_enable,
hwmon_fan_input,
hwmon_fan_label,
hwmon_fan_min,
......@@ -282,6 +294,7 @@ enum hwmon_fan_attributes {
hwmon_fan_fault,
};
#define HWMON_F_ENABLE BIT(hwmon_fan_enable)
#define HWMON_F_INPUT BIT(hwmon_fan_input)
#define HWMON_F_LABEL BIT(hwmon_fan_label)
#define HWMON_F_MIN BIT(hwmon_fan_min)
......@@ -306,6 +319,13 @@ enum hwmon_pwm_attributes {
#define HWMON_PWM_MODE BIT(hwmon_pwm_mode)
#define HWMON_PWM_FREQ BIT(hwmon_pwm_freq)
enum hwmon_intrusion_attributes {
hwmon_intrusion_alarm,
hwmon_intrusion_beep,
};
#define HWMON_INTRUSION_ALARM BIT(hwmon_intrusion_alarm)
#define HWMON_INTRUSION_BEEP BIT(hwmon_intrusion_beep)
/**
* struct hwmon_ops - hwmon device operations
* @is_visible: Callback to return attribute visibility. Mandatory.
......
......@@ -8,6 +8,8 @@
#ifndef _PMBUS_H_
#define _PMBUS_H_
#include <linux/bits.h>
/* flags */
/*
......@@ -23,7 +25,14 @@
* communication errors for no explicable reason. For such chips, checking
* the status register must be disabled.
*/
#define PMBUS_SKIP_STATUS_CHECK (1 << 0)
#define PMBUS_SKIP_STATUS_CHECK BIT(0)
/*
* PMBUS_WRITE_PROTECTED
* Set if the chip is write protected and write protection is not determined
* by the standard WRITE_PROTECT command.
*/
#define PMBUS_WRITE_PROTECTED BIT(1)
struct pmbus_platform_data {
u32 flags; /* Device specific flags */
......
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