This adds hwmon support for the temperature sensor on RTL822x. It's available on the standalone versions of the PHY's, and on the integrated PHY's in RTL8125B/RTL8125D/RTL8126. Notes: - over-temp threshold is set by PHY power-on default or BIOS / boot loader and it's read-only - over-temp alarm remains set, even if temperature drops below threshold Signed-off-by: Heiner Kallweit <hkallweit1@xxxxxxxxx> --- drivers/net/phy/Kconfig | 6 +++ drivers/net/phy/Makefile | 1 + drivers/net/phy/realtek.h | 10 ++++ drivers/net/phy/realtek_hwmon.c | 83 +++++++++++++++++++++++++++++++++ drivers/net/phy/realtek_main.c | 12 +++++ 5 files changed, 112 insertions(+) create mode 100644 drivers/net/phy/realtek.h create mode 100644 drivers/net/phy/realtek_hwmon.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index dc625f2b3..eae53ef88 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -355,6 +355,12 @@ config REALTEK_PHY help Supports the Realtek 821x PHY. +config REALTEK_PHY_HWMON + def_bool REALTEK_PHY && HWMON + depends on !(REALTEK_PHY=y && HWMON=m) + help + Optional hwmon support for the temperature sensor + config RENESAS_PHY tristate "Renesas PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index ec480e733..ca369a5c9 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o realtek-y += realtek_main.o +realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o diff --git a/drivers/net/phy/realtek.h b/drivers/net/phy/realtek.h new file mode 100644 index 000000000..a39b44fa1 --- /dev/null +++ b/drivers/net/phy/realtek.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef REALTEK_H +#define REALTEK_H + +#include <linux/phy.h> + +int rtl822x_hwmon_init(struct phy_device *phydev); + +#endif /* REALTEK_H */ diff --git a/drivers/net/phy/realtek_hwmon.c b/drivers/net/phy/realtek_hwmon.c new file mode 100644 index 000000000..d3284c83f --- /dev/null +++ b/drivers/net/phy/realtek_hwmon.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ + * + * HWMON support for Realtek PHY's + * + * Author: Heiner Kallweit <hkallweit1@xxxxxxxxx> + */ + +#include <linux/hwmon.h> +#include <linux/phy.h> + +#include "realtek.h" + +#define RTL822X_VND2_TSALRM 0xa662 +#define RTL822X_VND2_TSRR 0xbd84 +#define RTL822X_VND2_TSSR 0xb54c + +static int rtl822x_hwmon_get_temp(int raw) +{ + if (raw >= 512) + raw -= 1024; + + return 1000 * raw / 2; +} + +static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + int raw; + + switch (attr) { + case hwmon_temp_input: + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; + *val = rtl822x_hwmon_get_temp(raw); + break; + case hwmon_temp_max: + /* Chip reduces speed to 1G if threshold is exceeded */ + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; + *val = rtl822x_hwmon_get_temp(raw); + break; + case hwmon_temp_alarm: + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM); + *val = !!(raw & 3); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct hwmon_ops rtl822x_hwmon_ops = { + .visible = 0444, + .read = rtl822x_hwmon_read, +}; + +static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM), + NULL +}; + +static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { + .ops = &rtl822x_hwmon_ops, + .info = rtl822x_hwmon_info, +}; + +int rtl822x_hwmon_init(struct phy_device *phydev) +{ + struct device *hwdev, *dev = &phydev->mdio.dev; + const char *name; + + /* Ensure over-temp alarm is reset. */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); + + name = devm_hwmon_sanitize_name(dev, dev_name(dev)); + if (IS_ERR(name)) + return PTR_ERR(name); + + hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, + &rtl822x_hwmon_chip_info, + NULL); + return PTR_ERR_OR_ZERO(hwdev); +} diff --git a/drivers/net/phy/realtek_main.c b/drivers/net/phy/realtek_main.c index af9874143..38149958d 100644 --- a/drivers/net/phy/realtek_main.c +++ b/drivers/net/phy/realtek_main.c @@ -14,6 +14,8 @@ #include <linux/delay.h> #include <linux/clk.h> +#include "realtek.h" + #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX BIT(13) #define RTL821x_PHYSR_SPEED GENMASK(15, 14) @@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, return ret; } +static int rtl822x_probe(struct phy_device *phydev) +{ + if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && + phydev->phy_id != RTL_GENERIC_PHYID) + return rtl822x_hwmon_init(phydev); + + return 0; +} + static int rtl822xb_config_init(struct phy_device *phydev) { bool has_2500, has_sgmii; @@ -1519,6 +1530,7 @@ static struct phy_driver realtek_drvs[] = { .match_phy_device = rtl_internal_nbaset_match_phy_device, .name = "Realtek Internal NBASE-T PHY", .flags = PHY_IS_INTERNAL, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -- 2.47.1