-
Notifications
You must be signed in to change notification settings - Fork 53.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hwmon: (pmbus) Add driver for Delta DPS-920AB PSU
This adds support for the Delta DPS-920AB PSU. Only missing feature is fan control which the PSU supports. Signed-off-by: Robert Marko <[email protected]> Link: https://lore.kernel.org/r/[email protected] [groeck: Add MODULE_IMPORT_NS(PMBUS);] Signed-off-by: Guenter Roeck <[email protected]>
- Loading branch information
Showing
5 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
.. SPDX-License-Identifier: GPL-2.0-or-later | ||
Kernel driver dps920ab | ||
======================== | ||
|
||
Supported chips: | ||
|
||
* Delta DPS920AB | ||
|
||
Prefix: 'dps920ab' | ||
|
||
Addresses scanned: - | ||
|
||
Authors: | ||
Robert Marko <[email protected]> | ||
|
||
|
||
Description | ||
----------- | ||
|
||
This driver implements support for Delta DPS920AB 920W 54V DC single output | ||
power supply 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_label "iin" | ||
curr1_input Measured input current | ||
curr1_alarm Input current high alarm | ||
|
||
curr2_label "iout1" | ||
curr2_input Measured output current | ||
curr2_max Maximum output current | ||
curr2_rated_max Maximum rated output current | ||
|
||
in1_label "vin" | ||
in1_input Measured input voltage | ||
in1_alarm Input voltage alarm | ||
|
||
in2_label "vout1" | ||
in2_input Measured output voltage | ||
in2_rated_min Minimum rated output voltage | ||
in2_rated_max Maximum rated output voltage | ||
in2_alarm Output voltage alarm | ||
|
||
power1_label "pin" | ||
power1_input Measured input power | ||
power1_alarm Input power high alarm | ||
|
||
power2_label "pout1" | ||
power2_input Measured output power | ||
power2_rated_max Maximum rated output power | ||
|
||
temp[1-3]_input Measured temperature | ||
temp[1-3]_alarm Temperature alarm | ||
|
||
fan1_alarm Fan 1 warning. | ||
fan1_fault Fan 1 fault. | ||
fan1_input Fan 1 speed in RPM. | ||
======================= ====================================================== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,7 @@ Hardware Monitoring Kernel Drivers | |
da9055 | ||
dell-smm-hwmon | ||
dme1737 | ||
dps920ab | ||
drivetemp | ||
ds1621 | ||
ds620 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Driver for Delta DPS920AB PSU | ||
* | ||
* Copyright (C) 2021 Delta Networks, Inc. | ||
* Copyright (C) 2021 Sartura Ltd. | ||
*/ | ||
|
||
#include <linux/debugfs.h> | ||
#include <linux/i2c.h> | ||
#include <linux/module.h> | ||
#include <linux/of_device.h> | ||
#include "pmbus.h" | ||
|
||
struct dps920ab_data { | ||
char *mfr_model; | ||
char *mfr_id; | ||
}; | ||
|
||
static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg) | ||
{ | ||
/* | ||
* This masks commands which are not supported. | ||
* PSU advertises that all features are supported, | ||
* in reality that unfortunately is not true. | ||
* So enable only those that the datasheet confirms. | ||
*/ | ||
switch (reg) { | ||
case PMBUS_FAN_COMMAND_1: | ||
case PMBUS_IOUT_OC_WARN_LIMIT: | ||
case PMBUS_STATUS_WORD: | ||
case PMBUS_READ_VIN: | ||
case PMBUS_READ_IIN: | ||
case PMBUS_READ_VOUT: | ||
case PMBUS_READ_IOUT: | ||
case PMBUS_READ_TEMPERATURE_1: | ||
case PMBUS_READ_TEMPERATURE_2: | ||
case PMBUS_READ_TEMPERATURE_3: | ||
case PMBUS_READ_FAN_SPEED_1: | ||
case PMBUS_READ_POUT: | ||
case PMBUS_READ_PIN: | ||
case PMBUS_MFR_VOUT_MIN: | ||
case PMBUS_MFR_VOUT_MAX: | ||
case PMBUS_MFR_IOUT_MAX: | ||
case PMBUS_MFR_POUT_MAX: | ||
return pmbus_read_word_data(client, page, phase, reg); | ||
default: | ||
return -ENXIO; | ||
} | ||
} | ||
|
||
static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg, | ||
u16 word) | ||
{ | ||
/* | ||
* This masks commands which are not supported. | ||
* PSU only has one R/W register and that is | ||
* for the fan. | ||
*/ | ||
switch (reg) { | ||
case PMBUS_FAN_COMMAND_1: | ||
return pmbus_write_word_data(client, page, reg, word); | ||
default: | ||
return -EACCES; | ||
} | ||
} | ||
|
||
static struct pmbus_driver_info dps920ab_info = { | ||
.pages = 1, | ||
|
||
.format[PSC_VOLTAGE_IN] = linear, | ||
.format[PSC_VOLTAGE_OUT] = linear, | ||
.format[PSC_CURRENT_IN] = linear, | ||
.format[PSC_CURRENT_OUT] = linear, | ||
.format[PSC_POWER] = linear, | ||
.format[PSC_FAN] = linear, | ||
.format[PSC_TEMPERATURE] = linear, | ||
|
||
.func[0] = | ||
PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | | ||
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | | ||
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | | ||
PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | | ||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | | ||
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, | ||
.read_word_data = dps920ab_read_word_data, | ||
.write_word_data = dps920ab_write_word_data, | ||
}; | ||
|
||
static int dps920ab_mfr_id_show(struct seq_file *s, void *data) | ||
{ | ||
struct dps920ab_data *priv = s->private; | ||
|
||
seq_printf(s, "%s\n", priv->mfr_id); | ||
|
||
return 0; | ||
} | ||
|
||
DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id); | ||
|
||
static int dps920ab_mfr_model_show(struct seq_file *s, void *data) | ||
{ | ||
struct dps920ab_data *priv = s->private; | ||
|
||
seq_printf(s, "%s\n", priv->mfr_model); | ||
|
||
return 0; | ||
} | ||
|
||
DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model); | ||
|
||
static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client) | ||
{ | ||
struct dentry *debugfs_dir; | ||
struct dentry *root; | ||
|
||
root = pmbus_get_debugfs_dir(client); | ||
if (!root) | ||
return; | ||
|
||
debugfs_dir = debugfs_create_dir(client->name, root); | ||
if (!debugfs_dir) | ||
return; | ||
|
||
debugfs_create_file("mfr_id", | ||
0400, | ||
debugfs_dir, | ||
data, | ||
&dps920ab_mfr_id_fops); | ||
|
||
debugfs_create_file("mfr_model", | ||
0400, | ||
debugfs_dir, | ||
data, | ||
&dps920ab_mfr_model_fops); | ||
} | ||
|
||
static int dps920ab_probe(struct i2c_client *client) | ||
{ | ||
u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; | ||
struct dps920ab_data *data; | ||
int ret; | ||
|
||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); | ||
if (!data) | ||
return -ENOMEM; | ||
|
||
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; | ||
} | ||
|
||
buf[ret] = '\0'; | ||
if (ret != 5 || strncmp(buf, "DELTA", 5)) { | ||
buf[ret] = '\0'; | ||
dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf); | ||
return -ENODEV; | ||
} | ||
data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL); | ||
if (!data->mfr_id) | ||
return -ENOMEM; | ||
|
||
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); | ||
if (ret < 0) { | ||
dev_err(&client->dev, "Failed to read Manufacturer Model\n"); | ||
return ret; | ||
} | ||
|
||
buf[ret] = '\0'; | ||
if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) { | ||
dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf); | ||
return -ENODEV; | ||
} | ||
data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL); | ||
if (!data->mfr_model) | ||
return -ENOMEM; | ||
|
||
ret = pmbus_do_probe(client, &dps920ab_info); | ||
if (ret) | ||
return ret; | ||
|
||
dps920ab_init_debugfs(data, client); | ||
|
||
return 0; | ||
} | ||
|
||
static const struct of_device_id __maybe_unused dps920ab_of_match[] = { | ||
{ .compatible = "delta,dps920ab", }, | ||
{} | ||
}; | ||
|
||
MODULE_DEVICE_TABLE(of, dps920ab_of_match); | ||
|
||
static struct i2c_driver dps920ab_driver = { | ||
.driver = { | ||
.name = "dps920ab", | ||
.of_match_table = of_match_ptr(dps920ab_of_match), | ||
}, | ||
.probe_new = dps920ab_probe, | ||
}; | ||
|
||
module_i2c_driver(dps920ab_driver); | ||
|
||
MODULE_AUTHOR("Robert Marko <[email protected]>"); | ||
MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU"); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_IMPORT_NS(PMBUS); |