GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / vdpa / solidrun / snet_hwmon.c
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 * const 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 }