4c1e2f062404079617bee795358e2e7508de0efe
[openwrt/staging/blocktrron.git] /
1 From 33700ca45b7d2e1655d4cad95e25671e8a94e2f0 Mon Sep 17 00:00:00 2001
2 From: Heiner Kallweit <hkallweit1@gmail.com>
3 Date: Sat, 11 Jan 2025 21:51:24 +0100
4 Subject: [PATCH] net: phy: realtek: add hwmon support for temp sensor on
5 RTL822x
6
7 This adds hwmon support for the temperature sensor on RTL822x.
8 It's available on the standalone versions of the PHY's, and on
9 the integrated PHY's in RTL8125B/RTL8125D/RTL8126.
10
11 Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
12 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
13 Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com
14 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
15 ---
16 drivers/net/phy/realtek/Kconfig | 6 ++
17 drivers/net/phy/realtek/Makefile | 1 +
18 drivers/net/phy/realtek/realtek.h | 10 ++++
19 drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++
20 drivers/net/phy/realtek/realtek_main.c | 12 ++++
21 5 files changed, 108 insertions(+)
22 create mode 100644 drivers/net/phy/realtek/realtek.h
23 create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c
24
25 --- a/drivers/net/phy/realtek/Kconfig
26 +++ b/drivers/net/phy/realtek/Kconfig
27 @@ -3,3 +3,9 @@ config REALTEK_PHY
28 tristate "Realtek PHYs"
29 help
30 Currently supports RTL821x/RTL822x and fast ethernet PHYs
31 +
32 +config REALTEK_PHY_HWMON
33 + def_bool REALTEK_PHY && HWMON
34 + depends on !(REALTEK_PHY=y && HWMON=m)
35 + help
36 + Optional hwmon support for the temperature sensor
37 --- a/drivers/net/phy/realtek/Makefile
38 +++ b/drivers/net/phy/realtek/Makefile
39 @@ -1,3 +1,4 @@
40 # SPDX-License-Identifier: GPL-2.0
41 realtek-y += realtek_main.o
42 +realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o
43 obj-$(CONFIG_REALTEK_PHY) += realtek.o
44 --- /dev/null
45 +++ b/drivers/net/phy/realtek/realtek.h
46 @@ -0,0 +1,10 @@
47 +/* SPDX-License-Identifier: GPL-2.0 */
48 +
49 +#ifndef REALTEK_H
50 +#define REALTEK_H
51 +
52 +#include <linux/phy.h>
53 +
54 +int rtl822x_hwmon_init(struct phy_device *phydev);
55 +
56 +#endif /* REALTEK_H */
57 --- /dev/null
58 +++ b/drivers/net/phy/realtek/realtek_hwmon.c
59 @@ -0,0 +1,86 @@
60 +// SPDX-License-Identifier: GPL-2.0+
61 +/*
62 + * HWMON support for Realtek PHY's
63 + *
64 + * Author: Heiner Kallweit <hkallweit1@gmail.com>
65 + */
66 +
67 +#include <linux/hwmon.h>
68 +#include <linux/phy.h>
69 +
70 +#include "realtek.h"
71 +
72 +#define RTL822X_VND2_TSALRM 0xa662
73 +#define RTL822X_VND2_TSRR 0xbd84
74 +#define RTL822X_VND2_TSSR 0xb54c
75 +
76 +static umode_t rtl822x_hwmon_is_visible(const void *drvdata,
77 + enum hwmon_sensor_types type,
78 + u32 attr, int channel)
79 +{
80 + return 0444;
81 +}
82 +
83 +static int rtl822x_hwmon_get_temp(int raw)
84 +{
85 + if (raw >= 512)
86 + raw -= 1024;
87 +
88 + return 1000 * raw / 2;
89 +}
90 +
91 +static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
92 + u32 attr, int channel, long *val)
93 +{
94 + struct phy_device *phydev = dev_get_drvdata(dev);
95 + int raw;
96 +
97 + switch (attr) {
98 + case hwmon_temp_input:
99 + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff;
100 + *val = rtl822x_hwmon_get_temp(raw);
101 + break;
102 + case hwmon_temp_max:
103 + /* Chip reduces speed to 1G if threshold is exceeded */
104 + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6;
105 + *val = rtl822x_hwmon_get_temp(raw);
106 + break;
107 + default:
108 + return -EINVAL;
109 + }
110 +
111 + return 0;
112 +}
113 +
114 +static const struct hwmon_ops rtl822x_hwmon_ops = {
115 + .is_visible = rtl822x_hwmon_is_visible,
116 + .read = rtl822x_hwmon_read,
117 +};
118 +
119 +static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = {
120 + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX),
121 + NULL
122 +};
123 +
124 +static const struct hwmon_chip_info rtl822x_hwmon_chip_info = {
125 + .ops = &rtl822x_hwmon_ops,
126 + .info = rtl822x_hwmon_info,
127 +};
128 +
129 +int rtl822x_hwmon_init(struct phy_device *phydev)
130 +{
131 + struct device *hwdev, *dev = &phydev->mdio.dev;
132 + const char *name;
133 +
134 + /* Ensure over-temp alarm is reset. */
135 + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3);
136 +
137 + name = devm_hwmon_sanitize_name(dev, dev_name(dev));
138 + if (IS_ERR(name))
139 + return PTR_ERR(name);
140 +
141 + hwdev = devm_hwmon_device_register_with_info(dev, name, phydev,
142 + &rtl822x_hwmon_chip_info,
143 + NULL);
144 + return PTR_ERR_OR_ZERO(hwdev);
145 +}
146 --- a/drivers/net/phy/realtek/realtek_main.c
147 +++ b/drivers/net/phy/realtek/realtek_main.c
148 @@ -14,6 +14,8 @@
149 #include <linux/delay.h>
150 #include <linux/clk.h>
151
152 +#include "realtek.h"
153 +
154 #define RTL821x_PHYSR 0x11
155 #define RTL821x_PHYSR_DUPLEX BIT(13)
156 #define RTL821x_PHYSR_SPEED GENMASK(15, 14)
157 @@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_
158 return ret;
159 }
160
161 +static int rtl822x_probe(struct phy_device *phydev)
162 +{
163 + if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) &&
164 + phydev->phy_id != RTL_GENERIC_PHYID)
165 + return rtl822x_hwmon_init(phydev);
166 +
167 + return 0;
168 +}
169 +
170 static int rtl822xb_config_init(struct phy_device *phydev)
171 {
172 bool has_2500, has_sgmii;
173 @@ -1519,6 +1530,7 @@ static struct phy_driver realtek_drvs[]
174 .match_phy_device = rtl_internal_nbaset_match_phy_device,
175 .name = "Realtek Internal NBASE-T PHY",
176 .flags = PHY_IS_INTERNAL,
177 + .probe = rtl822x_probe,
178 .get_features = rtl822x_get_features,
179 .config_aneg = rtl822x_config_aneg,
180 .read_status = rtl822x_read_status,