Fwd: [PATCH linux dev-4.13 2/5] pmbus (max31785): Add support for devicetree configuration
George Keishing
gkeishin at in.ibm.com
Wed Apr 4 14:01:34 AEST 2018
Test and verified working.
Tested-by: George Keishing <gkeishin at in.ibm.com>
Thanks and Regards,
George Keishing
IBM Systems &Technology Lab, Firmware Development,
“ There isn't enough time in a day to be lazy!!! .”
From: Andrew Jeffery <andrew at aj.id.au>
To: gkeishin at in.ibm.com
Date: 04/04/2018 09:23 AM
Subject: Fwd: [PATCH linux dev-4.13 2/5] pmbus (max31785): Add
support for devicetree configuration
----- Original message -----
From: Andrew Jeffery <andrew at aj.id.au>
To: joel at jms.id.au
Cc: Andrew Jeffery <andrew at aj.id.au>, openbmc at lists.ozlabs.org
Subject: [PATCH linux dev-4.13 2/5] pmbus (max31785): Add support for
devicetree configuration
Date: Tue, 3 Apr 2018 23:56:52 +0930
Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
drivers/hwmon/pmbus/max31785.c | 318
+++++++++++++++++++++++++++++++++++++++++
1 file changed, 318 insertions(+)
diff --git a/drivers/hwmon/pmbus/max31785.c
b/drivers/hwmon/pmbus/max31785.c
index bffab449be39..9a7e745b6b31 100644
--- a/drivers/hwmon/pmbus/max31785.c
+++ b/drivers/hwmon/pmbus/max31785.c
@@ -16,13 +16,23 @@
enum max31785_regs {
MFR_REVISION = 0x9b,
+ MFR_FAULT_RESPONSE = 0xd9,
+ MFR_TEMP_SENSOR_CONFIG = 0xf0,
MFR_FAN_CONFIG = 0xf1,
+ MFR_FAN_FAULT_LIMIT = 0xf5,
};
#define MAX31785 0x3030
#define MAX31785A 0x3040
#define MFR_FAN_CONFIG_DUAL_TACH BIT(12)
+#define MFR_FAN_CONFIG_TSFO BIT(9)
+#define MFR_FAN_CONFIG_TACHO BIT(8)
+#define MFR_FAN_CONFIG_HEALTH BIT(4)
+#define MFR_FAN_CONFIG_ROTOR_HI_LO BIT(3)
+#define MFR_FAN_CONFIG_ROTOR BIT(2)
+
+#define MFR_FAULT_RESPONSE_MONITOR BIT(0)
#define MAX31785_NR_PAGES 23
#define MAX31785_NR_FAN_PAGES 6
@@ -239,6 +249,271 @@ static int max31785_write_word_data(struct
i2c_client *client, int page,
return -ENODATA;
}
+/*
+ * Returns negative error codes if an unrecoverable problem is detected,
0 if a
+ * recoverable problem is detected, or a positive value on success.
+ */
+static int max31785_of_fan_config(struct i2c_client *client,
+ struct
pmbus_driver_info *info,
+ struct
device_node *child)
+{
+ int mfr_cfg = 0, mfr_fault_resp = 0, pb_cfg;
+ struct device *dev = &client->dev;
+ char *lock_polarity = NULL;
+ const char *sval;
+ u32 page;
+ u32 uval;
+ int ret;
+
+ if (!of_device_is_compatible(child, "pmbus-fan"))
+ return 0;
+
+ ret = of_property_read_u32(child, "reg", &page);
+ if (ret < 0) {
+ dev_err(&client->dev, "Missing valid reg
property\n");
+ return ret;
+ }
+
+ if (!(info->func[page] & PMBUS_HAVE_FAN12)) {
+ dev_err(dev, "Page %d does not have fan
capabilities\n", page);
+ return -ENXIO;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE,
page);
+ if (ret < 0)
+ return ret;
+
+ pb_cfg = i2c_smbus_read_byte_data(client,
PMBUS_FAN_CONFIG_12);
+ if (pb_cfg < 0)
+ return pb_cfg;
+
+ if (of_property_read_bool(child->parent,
"use-stored-presence")) {
+ if (!(pb_cfg & PB_FAN_1_INSTALLED))
+ dev_info(dev, "Fan %d is
configured but not installed\n",
+ page);
+ } else {
+ pb_cfg |= PB_FAN_1_INSTALLED;
+ }
+
+ ret = of_property_read_string(child,
"maxim,fan-rotor-input", &sval);
+ if (ret < 0) {
+ dev_err(dev, "Missing valid
maxim,fan-rotor-input property for fan %d\n",
+ page);
+ return ret;
+ }
+
+ if (strcmp("tach", sval) && strcmp("lock", sval)) {
+ dev_err(dev, "maxim,fan-rotor-input has
invalid value for fan %d: %s\n",
+ page,
sval);
+ return -EINVAL;
+ } else if (!strcmp("lock", sval)) {
+ mfr_cfg |= MFR_FAN_CONFIG_ROTOR;
+
+ ret = i2c_smbus_write_word_data(client,
MFR_FAN_FAULT_LIMIT, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_read_string(child,
"maxim,fan-lock-polarity",
+ &sval);
+ if (ret < 0) {
+ dev_err(dev, "Missing
valid maxim,fan-lock-polarity property for fan %d\n",
+ page);
+ return ret;
+ }
+
+ if (strcmp("low", sval) && strcmp("high",
sval)) {
+ dev_err(dev,
"maxim,fan-lock-polarity has invalid value for fan %d: %s\n",
+ page, lock_polarity);
+ return -EINVAL;
+ } else if (!strcmp("high", sval))
+ mfr_cfg |=
MFR_FAN_CONFIG_ROTOR_HI_LO;
+ }
+
+ if (!of_property_read_string(child, "fan-mode", &sval)) {
+ if (!strcmp("rpm", sval))
+ pb_cfg |= PB_FAN_1_RPM;
+ else if (!strcmp("pwm", sval))
+ pb_cfg &= ~PB_FAN_1_RPM;
+ else {
+ dev_err(dev, "fan-mode
has invalid value for fan %d: %s\n",
+ page, sval);
+ return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(child, "tach-pulses", &uval);
+ if (ret < 0) {
+ pb_cfg &= ~PB_FAN_1_PULSE_MASK;
+ } else if (uval && (uval - 1) < 4) {
+ pb_cfg = ((pb_cfg & ~PB_FAN_1_PULSE_MASK)
| ((uval - 1) << 4));
+ } else {
+ dev_err(dev, "tach-pulses has invalid
value for fan %d: %u\n",
+ page,
uval);
+ return -EINVAL;
+ }
+
+ if (of_property_read_bool(child, "maxim,fan-health"))
+ mfr_cfg |= MFR_FAN_CONFIG_HEALTH;
+
+ if (of_property_read_bool(child, "maxim,fan-no-watchdog")
||
+ of_property_read_bool(child,
"maxim,tmp-no-fault-ramp"))
+ mfr_cfg |= MFR_FAN_CONFIG_TSFO;
+
+ if (of_property_read_bool(child, "maxim,fan-dual-tach"))
+ mfr_cfg |= MFR_FAN_CONFIG_DUAL_TACH;
+
+ if (of_property_read_bool(child,
"maxim,fan-no-fault-ramp"))
+ mfr_cfg |= MFR_FAN_CONFIG_TACHO;
+
+ if (!of_property_read_u32(child, "maxim,fan-startup",
&uval)) {
+ uval /= 2;
+ if (uval < 5) {
+ mfr_cfg |= uval;
+ } else {
+ dev_err(dev,
"maxim,fan-startup has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,fan-ramp",
&uval)) {
+ if (uval < 8) {
+ mfr_cfg |= uval << 5;
+ } else {
+ dev_err(dev,
"maxim,fan-ramp has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,tmp-hysteresis",
&uval)) {
+ uval /= 2;
+ uval -= 1;
+ if (uval < 4) {
+ mfr_cfg |= uval << 10;
+ } else {
+ dev_err(dev,
"maxim,tmp-hysteresis has invalid value for fan %d, %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,fan-pwm-freq",
&uval)) {
+ u16 val;
+
+ if (uval == 30) {
+ val = 0;
+ } else if (uval == 50) {
+ val = 1;
+ } else if (uval == 100) {
+ val = 2;
+ } else if (uval == 150) {
+ val = 3;
+ } else if (uval == 25000) {
+ val = 7;
+ } else {
+ dev_err(dev,
"maxim,fan-pwm-freq has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+
+ mfr_cfg |= val << 13;
+ }
+
+ if (of_property_read_bool(child,
"maxim,fan-fault-pin-mon"))
+ mfr_fault_resp |=
MFR_FAULT_RESPONSE_MONITOR;
+
+ ret = i2c_smbus_write_byte_data(client,
PMBUS_FAN_CONFIG_12,
+ pb_cfg & ~PB_FAN_1_INSTALLED);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_word_data(client, MFR_FAN_CONFIG,
mfr_cfg);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client,
MFR_FAULT_RESPONSE,
+ mfr_fault_resp);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client,
PMBUS_FAN_CONFIG_12, pb_cfg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Fans are on pages 0 - 5. If the page property of a fan
node is
+ * greater than 5 we will have errored in checks above
out above.
+ * Therefore we don't need to cope with values up to 31,
and the int
+ * return type is enough.
+ *
+ * The bit mask return value is used to populate a
bitfield of fans
+ * who are both configured in the devicetree _and_
reported as
+ * installed by the hardware. Any fans that are not
configured in the
+ * devicetree but are reported as installed by the
hardware will have
+ * their hardware configuration updated to unset the
installed bit.
+ */
+ return BIT(page);
+}
+
+static int max31785_of_tmp_config(struct i2c_client *client,
+ struct
pmbus_driver_info *info,
+ struct
device_node *child)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np;
+ u16 mfr_tmp_cfg = 0;
+ u32 page;
+ u32 uval;
+ int ret;
+ int i;
+
+ if (!of_device_is_compatible(child, "pmbus-temperature"))
+ return 0;
+
+ ret = of_property_read_u32(child, "reg", &page);
+ if (ret < 0) {
+ dev_err(&client->dev, "Missing valid reg
property\n");
+ return ret;
+ }
+
+ if (!(info->func[page] & PMBUS_HAVE_TEMP)) {
+ dev_err(dev, "Page %d does not have temp
capabilities\n", page);
+ return -ENXIO;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE,
page);
+ if (ret < 0)
+ return ret;
+
+ if (!of_property_read_u32(child, "maxim,tmp-offset",
&uval)) {
+ if (uval < 32)
+ mfr_tmp_cfg |= uval <<
10;
+ }
+
+ i = 0;
+ while ((np = of_parse_phandle(child, "maxim,tmp-fans",
i))) {
+ if (of_property_read_u32(np, "reg",
&uval)) {
+ dev_err(&client->dev,
"Failed to read fan reg property for phandle index %d\n",
+ i);
+ } else {
+ if (uval < 6)
+ mfr_tmp_cfg |= BIT(uval);
+ else
+ dev_warn(&client->dev, "Invalid fan page: %d\n",
+ uval);
+ }
+ i++;
+ }
+
+ ret = i2c_smbus_write_word_data(client,
MFR_TEMP_SENSOR_CONFIG,
+ mfr_tmp_cfg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
#define MAX31785_FAN_FUNCS \
(PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
PMBUS_HAVE_PWM12)
@@ -334,9 +609,12 @@ static int max31785_probe(struct i2c_client *client,
const struct
i2c_device_id *id)
{
struct device *dev = &client->dev;
+ struct device_node *child;
struct pmbus_driver_info *info;
bool dual_tach = false;
+ u32 fans;
s64 ret;
+ int i;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
@@ -366,6 +644,46 @@ static int max31785_probe(struct i2c_client *client,
return -ENODEV;
}
+ fans = 0;
+ for_each_child_of_node(dev->of_node, child) {
+ ret = max31785_of_fan_config(client,
info, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+
+ if (ret)
+ fans |= ret;
+
+ ret = max31785_of_tmp_config(client,
info, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < MAX31785_NR_PAGES; i++) {
+ bool have_fan = !!(info->func[i] &
PMBUS_HAVE_FAN12);
+ bool fan_configured = !!(fans & BIT(i));
+
+ if (!have_fan || fan_configured)
+ continue;
+
+ ret = i2c_smbus_write_byte_data(client,
PMBUS_PAGE, i);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_byte_data(client,
PMBUS_FAN_CONFIG_12);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~PB_FAN_1_INSTALLED;
+ ret = i2c_smbus_write_word_data(client,
PMBUS_FAN_CONFIG_12,
+ ret);
+ if (ret < 0)
+ return ret;
+ }
+
if (dual_tach) {
ret =
max31785_configure_dual_tach(client, info);
if (ret < 0)
--
2.14.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20180404/0627e9fd/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: image/jpeg
Size: 7547 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20180404/0627e9fd/attachment-0001.jpe>
More information about the openbmc
mailing list