xref: /linux/drivers/net/phy/realtek/realtek_hwmon.c (revision 2ee738e90e80850582cbe10f34c6447965c1d87b)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * HWMON support for Realtek PHY's
4  *
5  * Author: Heiner Kallweit <hkallweit1@gmail.com>
6  */
7 
8 #include <linux/hwmon.h>
9 #include <linux/phy.h>
10 
11 #include "realtek.h"
12 
13 #define RTL822X_VND2_TSALRM				0xa662
14 #define RTL822X_VND2_TSRR				0xbd84
15 #define RTL822X_VND2_TSSR				0xb54c
16 
17 static int rtl822x_hwmon_get_temp(int raw)
18 {
19 	if (raw >= 512)
20 		raw -= 1024;
21 
22 	return 1000 * raw / 2;
23 }
24 
25 static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
26 			      u32 attr, int channel, long *val)
27 {
28 	struct phy_device *phydev = dev_get_drvdata(dev);
29 	int raw;
30 
31 	switch (attr) {
32 	case hwmon_temp_input:
33 		raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff;
34 		*val = rtl822x_hwmon_get_temp(raw);
35 		break;
36 	case hwmon_temp_max:
37 		/* Chip reduces speed to 1G if threshold is exceeded */
38 		raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6;
39 		*val = rtl822x_hwmon_get_temp(raw);
40 		break;
41 	default:
42 		return -EINVAL;
43 	}
44 
45 	return 0;
46 }
47 
48 static const struct hwmon_ops rtl822x_hwmon_ops = {
49 	.visible = 0444,
50 	.read = rtl822x_hwmon_read,
51 };
52 
53 static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = {
54 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX),
55 	NULL
56 };
57 
58 static const struct hwmon_chip_info rtl822x_hwmon_chip_info = {
59 	.ops = &rtl822x_hwmon_ops,
60 	.info = rtl822x_hwmon_info,
61 };
62 
63 int rtl822x_hwmon_init(struct phy_device *phydev)
64 {
65 	struct device *hwdev, *dev = &phydev->mdio.dev;
66 	const char *name;
67 
68 	/* Ensure over-temp alarm is reset. */
69 	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3);
70 
71 	name = devm_hwmon_sanitize_name(dev, dev_name(dev));
72 	if (IS_ERR(name))
73 		return PTR_ERR(name);
74 
75 	hwdev = devm_hwmon_device_register_with_info(dev, name, phydev,
76 						     &rtl822x_hwmon_chip_info,
77 						     NULL);
78 	return PTR_ERR_OR_ZERO(hwdev);
79 }
80