[PATCH net-next 1/3] dpll: zl3073x: add hwmon support for die temperature

Ivan Vecera posted 3 patches 2 weeks ago
[PATCH net-next 1/3] dpll: zl3073x: add hwmon support for die temperature
Posted by Ivan Vecera 2 weeks ago
Register an hwmon device to expose the chip die temperature via the
standard hwmon temperature interface. The temperature sensor is only
available on chip variants that have the ZL3073X_FLAG_DIE_TEMP flag
set and its visibility is controlled via the is_visible callback.

The die temperature register provides a value in 0.1°C units that is
converted to millidegrees Celsius for the hwmon subsystem.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 drivers/dpll/zl3073x/Makefile |  1 +
 drivers/dpll/zl3073x/core.c   |  7 ++++
 drivers/dpll/zl3073x/hwmon.c  | 67 +++++++++++++++++++++++++++++++++++
 drivers/dpll/zl3073x/hwmon.h  | 16 +++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 drivers/dpll/zl3073x/hwmon.c
 create mode 100644 drivers/dpll/zl3073x/hwmon.h

diff --git a/drivers/dpll/zl3073x/Makefile b/drivers/dpll/zl3073x/Makefile
index 906ec3fbcc202..6930bf7867151 100644
--- a/drivers/dpll/zl3073x/Makefile
+++ b/drivers/dpll/zl3073x/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_ZL3073X)		+= zl3073x.o
 zl3073x-objs			:= chan.o core.o devlink.o dpll.o	\
 				   flash.o fw.o out.o prop.o ref.o synth.o
+zl3073x-$(CONFIG_HWMON)		+= hwmon.o
 
 obj-$(CONFIG_ZL3073X_I2C)	+= zl3073x_i2c.o
 zl3073x_i2c-objs		:= i2c.o
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 7eebfc1ad1019..dcea98c31d694 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -18,6 +18,7 @@
 #include "core.h"
 #include "devlink.h"
 #include "dpll.h"
+#include "hwmon.h"
 #include "regs.h"
 
 #define ZL_CHIP_INFO(_id, _nchannels, _flags)				\
@@ -1038,6 +1039,12 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev)
 	if (rc)
 		return rc;
 
+	/* Register hwmon interface */
+	rc = zl3073x_hwmon_init(zldev);
+	if (rc)
+		return dev_err_probe(zldev->dev, rc,
+				     "Failed to register hwmon device\n");
+
 	/* Register the devlink instance and parameters */
 	rc = zl3073x_devlink_register(zldev);
 	if (rc)
diff --git a/drivers/dpll/zl3073x/hwmon.c b/drivers/dpll/zl3073x/hwmon.c
new file mode 100644
index 0000000000000..4b44df4def820
--- /dev/null
+++ b/drivers/dpll/zl3073x/hwmon.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/device.h>
+#include <linux/hwmon.h>
+
+#include "core.h"
+#include "hwmon.h"
+#include "regs.h"
+
+static int zl3073x_hwmon_read(struct device *dev,
+			      enum hwmon_sensor_types type,
+			      u32 attr, int channel, long *val)
+{
+	struct zl3073x_dev *zldev = dev_get_drvdata(dev);
+	u16 raw;
+	int rc;
+
+	if (type != hwmon_temp || attr != hwmon_temp_input)
+		return -EOPNOTSUPP;
+
+	rc = zl3073x_read_u16(zldev, ZL_REG_DIE_TEMP_STATUS, &raw);
+	if (rc)
+		return rc;
+
+	/* Convert from 0.1°C units to millidegrees Celsius */
+	*val = (s16)raw * 100;
+
+	return 0;
+}
+
+static umode_t zl3073x_hwmon_is_visible(const void *data,
+					enum hwmon_sensor_types type,
+					u32 attr, int channel)
+{
+	const struct zl3073x_dev *zldev = data;
+
+	if (type == hwmon_temp && (zldev->info->flags & ZL3073X_FLAG_DIE_TEMP))
+		return 0444;
+
+	return 0;
+}
+
+static const struct hwmon_channel_info * const zl3073x_hwmon_info[] = {
+	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+	NULL,
+};
+
+static const struct hwmon_ops zl3073x_hwmon_ops = {
+	.is_visible = zl3073x_hwmon_is_visible,
+	.read = zl3073x_hwmon_read,
+};
+
+static const struct hwmon_chip_info zl3073x_hwmon_chip_info = {
+	.ops = &zl3073x_hwmon_ops,
+	.info = zl3073x_hwmon_info,
+};
+
+int zl3073x_hwmon_init(struct zl3073x_dev *zldev)
+{
+	struct device *hwmon;
+
+	hwmon = devm_hwmon_device_register_with_info(zldev->dev, "zl3073x",
+						     zldev,
+						     &zl3073x_hwmon_chip_info,
+						     NULL);
+	return PTR_ERR_OR_ZERO(hwmon);
+}
diff --git a/drivers/dpll/zl3073x/hwmon.h b/drivers/dpll/zl3073x/hwmon.h
new file mode 100644
index 0000000000000..6048d596985ad
--- /dev/null
+++ b/drivers/dpll/zl3073x/hwmon.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ZL3073X_HWMON_H
+#define _ZL3073X_HWMON_H
+
+#include <linux/kconfig.h>
+
+struct zl3073x_dev;
+
+#if IS_REACHABLE(CONFIG_HWMON)
+int zl3073x_hwmon_init(struct zl3073x_dev *zldev);
+#else
+static inline int zl3073x_hwmon_init(struct zl3073x_dev *zldev) { return 0; }
+#endif
+
+#endif /* _ZL3073X_HWMON_H */
-- 
2.52.0