1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * SolidRun DPU driver for control plane
4  *
5  * Copyright (C) 2022-2023 SolidRun
6  *
7  * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
8  *
9  */
10 #include <linux/hwmon.h>
11 
12 #include "snet_vdpa.h"
13 
14 /* Monitor offsets */
15 #define SNET_MON_TMP0_IN_OFF      0x00
16 #define SNET_MON_TMP0_MAX_OFF     0x08
17 #define SNET_MON_TMP0_CRIT_OFF    0x10
18 #define SNET_MON_TMP1_IN_OFF      0x18
19 #define SNET_MON_TMP1_CRIT_OFF    0x20
20 #define SNET_MON_CURR_IN_OFF      0x28
21 #define SNET_MON_CURR_MAX_OFF     0x30
22 #define SNET_MON_CURR_CRIT_OFF    0x38
23 #define SNET_MON_PWR_IN_OFF       0x40
24 #define SNET_MON_VOLT_IN_OFF      0x48
25 #define SNET_MON_VOLT_CRIT_OFF    0x50
26 #define SNET_MON_VOLT_LCRIT_OFF   0x58
27 
28 static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)
29 {
30 	*out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);
31 }
32 
33 static umode_t snet_howmon_is_visible(const void *data,
34 				      enum hwmon_sensor_types type,
35 				      u32 attr, int channel)
36 {
37 	return 0444;
38 }
39 
40 static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,
41 			    u32 attr, int channel, long *val)
42 {
43 	struct psnet *psnet = dev_get_drvdata(dev);
44 	int ret = 0;
45 
46 	switch (type) {
47 	case hwmon_in:
48 		switch (attr) {
49 		case hwmon_in_lcrit:
50 			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);
51 			break;
52 		case hwmon_in_crit:
53 			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);
54 			break;
55 		case hwmon_in_input:
56 			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);
57 			break;
58 		default:
59 			ret = -EOPNOTSUPP;
60 			break;
61 		}
62 		break;
63 
64 	case hwmon_power:
65 		switch (attr) {
66 		case hwmon_power_input:
67 			snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);
68 			break;
69 
70 		default:
71 			ret = -EOPNOTSUPP;
72 			break;
73 		}
74 		break;
75 
76 	case hwmon_curr:
77 		switch (attr) {
78 		case hwmon_curr_input:
79 			snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);
80 			break;
81 		case hwmon_curr_max:
82 			snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);
83 			break;
84 		case hwmon_curr_crit:
85 			snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);
86 			break;
87 		default:
88 			ret = -EOPNOTSUPP;
89 			break;
90 		}
91 		break;
92 
93 	case hwmon_temp:
94 		switch (attr) {
95 		case hwmon_temp_input:
96 			if (channel == 0)
97 				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);
98 			else
99 				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);
100 			break;
101 		case hwmon_temp_max:
102 			if (channel == 0)
103 				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);
104 			else
105 				ret = -EOPNOTSUPP;
106 			break;
107 		case hwmon_temp_crit:
108 			if (channel == 0)
109 				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);
110 			else
111 				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);
112 			break;
113 
114 		default:
115 			ret = -EOPNOTSUPP;
116 			break;
117 		}
118 		break;
119 
120 	default:
121 		ret = -EOPNOTSUPP;
122 		break;
123 	}
124 	return ret;
125 }
126 
127 static int snet_hwmon_read_string(struct device *dev,
128 				  enum hwmon_sensor_types type, u32 attr,
129 				  int channel, const char **str)
130 {
131 	int ret = 0;
132 
133 	switch (type) {
134 	case hwmon_in:
135 		*str = "main_vin";
136 		break;
137 	case hwmon_power:
138 		*str = "soc_pin";
139 		break;
140 	case hwmon_curr:
141 		*str = "soc_iin";
142 		break;
143 	case hwmon_temp:
144 		if (channel == 0)
145 			*str = "power_stage_temp";
146 		else
147 			*str = "ic_junction_temp";
148 		break;
149 	default:
150 		ret = -EOPNOTSUPP;
151 		break;
152 	}
153 	return ret;
154 }
155 
156 static const struct hwmon_ops snet_hwmon_ops = {
157 	.is_visible = snet_howmon_is_visible,
158 	.read = snet_howmon_read,
159 	.read_string = snet_hwmon_read_string
160 };
161 
162 static const struct hwmon_channel_info *snet_hwmon_info[] = {
163 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,
164 			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),
165 	HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),
166 	HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),
167 	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),
168 			   NULL
169 };
170 
171 static const struct hwmon_chip_info snet_hwmono_info = {
172 	.ops = &snet_hwmon_ops,
173 	.info = snet_hwmon_info,
174 };
175 
176 /* Create an HW monitor device */
177 void psnet_create_hwmon(struct pci_dev *pdev)
178 {
179 	struct device *hwmon;
180 	struct psnet *psnet = pci_get_drvdata(pdev);
181 
182 	snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));
183 	hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,
184 						     &snet_hwmono_info, NULL);
185 	/* The monitor is not mandatory, Just alert user in case of an error */
186 	if (IS_ERR(hwmon))
187 		SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));
188 }
189