|
| 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 | +} |
0 commit comments