162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SolidRun DPU driver for control plane 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022-2023 SolidRun 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Alvaro Karsz <alvaro.karsz@solid-run.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/hwmon.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "snet_vdpa.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* Monitor offsets */ 1562306a36Sopenharmony_ci#define SNET_MON_TMP0_IN_OFF 0x00 1662306a36Sopenharmony_ci#define SNET_MON_TMP0_MAX_OFF 0x08 1762306a36Sopenharmony_ci#define SNET_MON_TMP0_CRIT_OFF 0x10 1862306a36Sopenharmony_ci#define SNET_MON_TMP1_IN_OFF 0x18 1962306a36Sopenharmony_ci#define SNET_MON_TMP1_CRIT_OFF 0x20 2062306a36Sopenharmony_ci#define SNET_MON_CURR_IN_OFF 0x28 2162306a36Sopenharmony_ci#define SNET_MON_CURR_MAX_OFF 0x30 2262306a36Sopenharmony_ci#define SNET_MON_CURR_CRIT_OFF 0x38 2362306a36Sopenharmony_ci#define SNET_MON_PWR_IN_OFF 0x40 2462306a36Sopenharmony_ci#define SNET_MON_VOLT_IN_OFF 0x48 2562306a36Sopenharmony_ci#define SNET_MON_VOLT_CRIT_OFF 0x50 2662306a36Sopenharmony_ci#define SNET_MON_VOLT_LCRIT_OFF 0x58 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci *out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic umode_t snet_howmon_is_visible(const void *data, 3462306a36Sopenharmony_ci enum hwmon_sensor_types type, 3562306a36Sopenharmony_ci u32 attr, int channel) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return 0444; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type, 4162306a36Sopenharmony_ci u32 attr, int channel, long *val) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct psnet *psnet = dev_get_drvdata(dev); 4462306a36Sopenharmony_ci int ret = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci switch (type) { 4762306a36Sopenharmony_ci case hwmon_in: 4862306a36Sopenharmony_ci switch (attr) { 4962306a36Sopenharmony_ci case hwmon_in_lcrit: 5062306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val); 5162306a36Sopenharmony_ci break; 5262306a36Sopenharmony_ci case hwmon_in_crit: 5362306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val); 5462306a36Sopenharmony_ci break; 5562306a36Sopenharmony_ci case hwmon_in_input: 5662306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val); 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci default: 5962306a36Sopenharmony_ci ret = -EOPNOTSUPP; 6062306a36Sopenharmony_ci break; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci case hwmon_power: 6562306a36Sopenharmony_ci switch (attr) { 6662306a36Sopenharmony_ci case hwmon_power_input: 6762306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val); 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci default: 7162306a36Sopenharmony_ci ret = -EOPNOTSUPP; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci case hwmon_curr: 7762306a36Sopenharmony_ci switch (attr) { 7862306a36Sopenharmony_ci case hwmon_curr_input: 7962306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val); 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case hwmon_curr_max: 8262306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val); 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case hwmon_curr_crit: 8562306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val); 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci default: 8862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci case hwmon_temp: 9462306a36Sopenharmony_ci switch (attr) { 9562306a36Sopenharmony_ci case hwmon_temp_input: 9662306a36Sopenharmony_ci if (channel == 0) 9762306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val); 9862306a36Sopenharmony_ci else 9962306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val); 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case hwmon_temp_max: 10262306a36Sopenharmony_ci if (channel == 0) 10362306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val); 10462306a36Sopenharmony_ci else 10562306a36Sopenharmony_ci ret = -EOPNOTSUPP; 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci case hwmon_temp_crit: 10862306a36Sopenharmony_ci if (channel == 0) 10962306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val); 11062306a36Sopenharmony_ci else 11162306a36Sopenharmony_ci snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci default: 11562306a36Sopenharmony_ci ret = -EOPNOTSUPP; 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci default: 12162306a36Sopenharmony_ci ret = -EOPNOTSUPP; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int snet_hwmon_read_string(struct device *dev, 12862306a36Sopenharmony_ci enum hwmon_sensor_types type, u32 attr, 12962306a36Sopenharmony_ci int channel, const char **str) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int ret = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci switch (type) { 13462306a36Sopenharmony_ci case hwmon_in: 13562306a36Sopenharmony_ci *str = "main_vin"; 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case hwmon_power: 13862306a36Sopenharmony_ci *str = "soc_pin"; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case hwmon_curr: 14162306a36Sopenharmony_ci *str = "soc_iin"; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case hwmon_temp: 14462306a36Sopenharmony_ci if (channel == 0) 14562306a36Sopenharmony_ci *str = "power_stage_temp"; 14662306a36Sopenharmony_ci else 14762306a36Sopenharmony_ci *str = "ic_junction_temp"; 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci default: 15062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci return ret; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic const struct hwmon_ops snet_hwmon_ops = { 15762306a36Sopenharmony_ci .is_visible = snet_howmon_is_visible, 15862306a36Sopenharmony_ci .read = snet_howmon_read, 15962306a36Sopenharmony_ci .read_string = snet_hwmon_read_string 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic const struct hwmon_channel_info * const snet_hwmon_info[] = { 16362306a36Sopenharmony_ci HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL, 16462306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL), 16562306a36Sopenharmony_ci HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL), 16662306a36Sopenharmony_ci HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL), 16762306a36Sopenharmony_ci HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL), 16862306a36Sopenharmony_ci NULL 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct hwmon_chip_info snet_hwmono_info = { 17262306a36Sopenharmony_ci .ops = &snet_hwmon_ops, 17362306a36Sopenharmony_ci .info = snet_hwmon_info, 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* Create an HW monitor device */ 17762306a36Sopenharmony_civoid psnet_create_hwmon(struct pci_dev *pdev) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct device *hwmon; 18062306a36Sopenharmony_ci struct psnet *psnet = pci_get_drvdata(pdev); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev)); 18362306a36Sopenharmony_ci hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet, 18462306a36Sopenharmony_ci &snet_hwmono_info, NULL); 18562306a36Sopenharmony_ci /* The monitor is not mandatory, Just alert user in case of an error */ 18662306a36Sopenharmony_ci if (IS_ERR(hwmon)) 18762306a36Sopenharmony_ci SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon)); 18862306a36Sopenharmony_ci} 189