Re: [PATCH 4/6] hwmon: Add Delta TN48M CPLD HWMON driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 5/19/21 5:01 AM, Robert Marko wrote:
On Fri, Apr 30, 2021 at 3:12 PM Guenter Roeck <linux@xxxxxxxxxxxx> wrote:

On 4/30/21 5:35 AM, Robert Marko wrote:
Delta TN48M has a CPLD that also monitors the power supply
statuses.

These are useful to be presented to the users, so lets
add a driver for HWMON part of the CPLD.

Signed-off-by: Robert Marko <robert.marko@xxxxxxxxxx>
---
  drivers/hwmon/Kconfig       |  10 +++
  drivers/hwmon/Makefile      |   1 +
  drivers/hwmon/tn48m-hwmon.c | 148 ++++++++++++++++++++++++++++++++++++
  drivers/mfd/tn48m-cpld.c    |   3 +
  include/linux/mfd/tn48m.h   |   1 +
  5 files changed, 163 insertions(+)
  create mode 100644 drivers/hwmon/tn48m-hwmon.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 54f04e61fb83..89271dfeb775 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1924,6 +1924,16 @@ config SENSORS_TMP513
         This driver can also be built as a module. If so, the module
         will be called tmp513.

+config SENSORS_TN48M
+     tristate "Delta Networks TN48M switch CPLD HWMON driver"
+     depends on MFD_TN48M_CPLD
+     help
+       If you say yes here you get support for Delta Networks TN48M
+       CPLD.
+
+       This driver can also be built as a module. If so, the module
+       will be called tn48m-hwmon.
+
  config SENSORS_VEXPRESS
       tristate "Versatile Express"
       depends on VEXPRESS_CONFIG
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index fe38e8a5c979..22e470057ffe 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -187,6 +187,7 @@ obj-$(CONFIG_SENSORS_TMP108)      += tmp108.o
  obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
  obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
  obj-$(CONFIG_SENSORS_TMP513) += tmp513.o
+obj-$(CONFIG_SENSORS_TN48M)  += tn48m-hwmon.o
  obj-$(CONFIG_SENSORS_VEXPRESS)       += vexpress-hwmon.o
  obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
  obj-$(CONFIG_SENSORS_VIA686A)        += via686a.o
diff --git a/drivers/hwmon/tn48m-hwmon.c b/drivers/hwmon/tn48m-hwmon.c
new file mode 100644
index 000000000000..80fd18d74f1d
--- /dev/null
+++ b/drivers/hwmon/tn48m-hwmon.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Delta TN48M CPLD HWMON driver
+ *
+ * Copyright 2020 Sartura Ltd
+ *
+ * Author: Robert Marko <robert.marko@xxxxxxxxxx>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/tn48m.h>
+
+#define PSU1_PRESENT_MASK    BIT(0)
+#define PSU2_PRESENT_MASK    BIT(1)
+#define PSU1_POWERGOOD_MASK  BIT(2)
+#define PSU2_POWERGOOD_MASK  BIT(3)
+#define PSU1_ALERT_MASK              BIT(4)
+#define PSU2_ALERT_MASK              BIT(5)
+
+static int board_id_get(struct tn48m_data *data)
+{
+     unsigned int regval;
+
+     regmap_read(data->regmap, BOARD_ID, &regval);
+
+     switch (regval) {
+     case BOARD_ID_TN48M:
+             return BOARD_ID_TN48M;
+     case BOARD_ID_TN48M_P:
+             return BOARD_ID_TN48M_P;
+     default:
+             return -EINVAL;
+     }
+}
+
+static ssize_t psu_present_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+     struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+     struct tn48m_data *data = dev_get_drvdata(dev);
+     unsigned int regval, status;
+
+     if (board_id_get(data) == BOARD_ID_TN48M_P) {
+             regmap_read(data->regmap, attr2->nr, &regval);
+
+             if (attr2->index == 1)
+                     status = !FIELD_GET(PSU1_PRESENT_MASK, regval);
+             else
+                     status = !FIELD_GET(PSU2_PRESENT_MASK, regval);
+     } else
+             status = 0;
+
+     return sprintf(buf, "%d\n", status);
+}
+
+static ssize_t psu_pg_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+     struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+     struct tn48m_data *data = dev_get_drvdata(dev);
+     unsigned int regval, status;
+
+     regmap_read(data->regmap, attr2->nr, &regval);
+
+     if (attr2->index == 1)
+             status = FIELD_GET(PSU1_POWERGOOD_MASK, regval);
+     else
+             status = FIELD_GET(PSU2_POWERGOOD_MASK, regval);
+
+     return sprintf(buf, "%d\n", status);
+}
+
+static ssize_t psu_alert_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+     struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+     struct tn48m_data *data = dev_get_drvdata(dev);
+     unsigned int regval, status;
+
+     if (board_id_get(data) == BOARD_ID_TN48M_P) {
+             regmap_read(data->regmap, attr2->nr, &regval);
+
+             if (attr2->index == 1)
+                     status = !FIELD_GET(PSU1_ALERT_MASK, regval);
+             else
+                     status = !FIELD_GET(PSU2_ALERT_MASK, regval);
+     } else
+             status = 0;
+
+     return sprintf(buf, "%d\n", status);
+}
+
+static SENSOR_DEVICE_ATTR_2_RO(psu1_present, psu_present, PSU_STATUS, 1);
+static SENSOR_DEVICE_ATTR_2_RO(psu2_present, psu_present, PSU_STATUS, 2);
+static SENSOR_DEVICE_ATTR_2_RO(psu1_pg, psu_pg, PSU_STATUS, 1);
+static SENSOR_DEVICE_ATTR_2_RO(psu2_pg, psu_pg, PSU_STATUS, 2);
+static SENSOR_DEVICE_ATTR_2_RO(psu1_alert, psu_alert, PSU_STATUS, 1);
+static SENSOR_DEVICE_ATTR_2_RO(psu2_alert, psu_alert, PSU_STATUS, 2);
+
+static struct attribute *tn48m_hwmon_attrs[] = {
+     &sensor_dev_attr_psu1_present.dev_attr.attr,
+     &sensor_dev_attr_psu2_present.dev_attr.attr,
+     &sensor_dev_attr_psu1_pg.dev_attr.attr,
+     &sensor_dev_attr_psu2_pg.dev_attr.attr,
+     &sensor_dev_attr_psu1_alert.dev_attr.attr,
+     &sensor_dev_attr_psu2_alert.dev_attr.attr,

Literally none of those attributes are standard hwmon attributes.
I don't know what this is, but it is not a hardware monitoring driver.

Yes, I agree that it does not expose any of the standard attributes, but these
are the only ones the CPLD exposes.

I don't know where else to put them, MFD driver did not seem logical to me.

+     NULL
+};
+
+ATTRIBUTE_GROUPS(tn48m_hwmon);
+
+static int tn48m_hwmon_probe(struct platform_device *pdev)
+{
+     struct tn48m_data *data = dev_get_drvdata(pdev->dev.parent);
+     struct device *hwmon_dev;
+
+     hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+                                                        "tn48m_hwmon",
+                                                        data,
+                                                        tn48m_hwmon_groups);

Please use devm_hwmon_device_register_with_info() to register hwmon devices.
Of course, that only makes sense for actual hardware monitoring drivers
which do support standard attributes.

Yes, devm_hwmon_device_register_with_info() made no sense without any of the
standard attributes.


I would suggest to expose the information using debugfs.
Again, this is not a hardware monitoring driver.

Guenter

Robert

+     return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct platform_device_id tn48m_hwmon_id_table[] = {
+     { "delta,tn48m-hwmon", },
+     { }
+};
+MODULE_DEVICE_TABLE(platform, tn48m_hwmon_id_table);
+
+static struct platform_driver tn48m_hwmon_driver = {
+     .driver = {
+             .name = "tn48m-hwmon",
+     },
+     .probe = tn48m_hwmon_probe,
+     .id_table = tn48m_hwmon_id_table,
+};
+module_platform_driver(tn48m_hwmon_driver);
+
+MODULE_AUTHOR("Robert Marko <robert.marko@xxxxxxxxxx>");
+MODULE_DESCRIPTION("Delta TN48M CPLD HWMON driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tn48m-cpld.c b/drivers/mfd/tn48m-cpld.c
index f22a15ddd22d..4d837aca01e7 100644
--- a/drivers/mfd/tn48m-cpld.c
+++ b/drivers/mfd/tn48m-cpld.c
@@ -20,6 +20,9 @@
  static const struct mfd_cell tn48m_cell[] = {
       {
               .name = "delta,tn48m-gpio",
+     },
+     {
+             .name = "delta,tn48m-hwmon",
       }
  };

diff --git a/include/linux/mfd/tn48m.h b/include/linux/mfd/tn48m.h
index 9cc2b04c8d69..eb2cfc3a5db7 100644
--- a/include/linux/mfd/tn48m.h
+++ b/include/linux/mfd/tn48m.h
@@ -22,6 +22,7 @@
  #define SFP_TX_DISABLE               0x31
  #define SFP_PRESENT          0x3a
  #define SFP_LOS                      0x40
+#define PSU_STATUS           0xa

  struct tn48m_data {
       struct device *dev;








[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux