summaryrefslogtreecommitdiffstats
path: root/drivers/vdpa/solidrun/snet_hwmon.c
blob: af531a3390824f00b17fd531ecf43ec4ec7e2df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// SPDX-License-Identifier: GPL-2.0-only
/*
 * SolidRun DPU driver for control plane
 *
 * Copyright (C) 2022-2023 SolidRun
 *
 * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
 *
 */
#include <linux/hwmon.h>

#include "snet_vdpa.h"

/* Monitor offsets */
#define SNET_MON_TMP0_IN_OFF      0x00
#define SNET_MON_TMP0_MAX_OFF     0x08
#define SNET_MON_TMP0_CRIT_OFF    0x10
#define SNET_MON_TMP1_IN_OFF      0x18
#define SNET_MON_TMP1_CRIT_OFF    0x20
#define SNET_MON_CURR_IN_OFF      0x28
#define SNET_MON_CURR_MAX_OFF     0x30
#define SNET_MON_CURR_CRIT_OFF    0x38
#define SNET_MON_PWR_IN_OFF       0x40
#define SNET_MON_VOLT_IN_OFF      0x48
#define SNET_MON_VOLT_CRIT_OFF    0x50
#define SNET_MON_VOLT_LCRIT_OFF   0x58

static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)
{
	*out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);
}

static umode_t snet_howmon_is_visible(const void *data,
				      enum hwmon_sensor_types type,
				      u32 attr, int channel)
{
	return 0444;
}

static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,
			    u32 attr, int channel, long *val)
{
	struct psnet *psnet = dev_get_drvdata(dev);
	int ret = 0;

	switch (type) {
	case hwmon_in:
		switch (attr) {
		case hwmon_in_lcrit:
			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);
			break;
		case hwmon_in_crit:
			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);
			break;
		case hwmon_in_input:
			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);
			break;
		default:
			ret = -EOPNOTSUPP;
			break;
		}
		break;

	case hwmon_power:
		switch (attr) {
		case hwmon_power_input:
			snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);
			break;

		default:
			ret = -EOPNOTSUPP;
			break;
		}
		break;

	case hwmon_curr:
		switch (attr) {
		case hwmon_curr_input:
			snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);
			break;
		case hwmon_curr_max:
			snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);
			break;
		case hwmon_curr_crit:
			snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);
			break;
		default:
			ret = -EOPNOTSUPP;
			break;
		}
		break;

	case hwmon_temp:
		switch (attr) {
		case hwmon_temp_input:
			if (channel == 0)
				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);
			else
				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);
			break;
		case hwmon_temp_max:
			if (channel == 0)
				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);
			else
				ret = -EOPNOTSUPP;
			break;
		case hwmon_temp_crit:
			if (channel == 0)
				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);
			else
				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);
			break;

		default:
			ret = -EOPNOTSUPP;
			break;
		}
		break;

	default:
		ret = -EOPNOTSUPP;
		break;
	}
	return ret;
}

static int snet_hwmon_read_string(struct device *dev,
				  enum hwmon_sensor_types type, u32 attr,
				  int channel, const char **str)
{
	int ret = 0;

	switch (type) {
	case hwmon_in:
		*str = "main_vin";
		break;
	case hwmon_power:
		*str = "soc_pin";
		break;
	case hwmon_curr:
		*str = "soc_iin";
		break;
	case hwmon_temp:
		if (channel == 0)
			*str = "power_stage_temp";
		else
			*str = "ic_junction_temp";
		break;
	default:
		ret = -EOPNOTSUPP;
		break;
	}
	return ret;
}

static const struct hwmon_ops snet_hwmon_ops = {
	.is_visible = snet_howmon_is_visible,
	.read = snet_howmon_read,
	.read_string = snet_hwmon_read_string
};

static const struct hwmon_channel_info * const snet_hwmon_info[] = {
	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,
			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),
	HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),
	HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),
	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),
			   NULL
};

static const struct hwmon_chip_info snet_hwmono_info = {
	.ops = &snet_hwmon_ops,
	.info = snet_hwmon_info,
};

/* Create an HW monitor device */
void psnet_create_hwmon(struct pci_dev *pdev)
{
	struct device *hwmon;
	struct psnet *psnet = pci_get_drvdata(pdev);

	snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));
	hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,
						     &snet_hwmono_info, NULL);
	/* The monitor is not mandatory, Just alert user in case of an error */
	if (IS_ERR(hwmon))
		SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));
}