File Index
Files and directories
Sign in
FILE

dasharo-acpi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/dasharo-acpi.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Dasharo ACPI Driver
  4 */
  5
  6#include <linux/acpi.h>
  7#include <linux/array_size.h>
  8#include <linux/hwmon.h>
  9#include <linux/module.h>
 10#include <linux/platform_device.h>
 11#include <linux/types.h>
 12#include <linux/units.h>
 13
 14enum dasharo_feature {
 15	DASHARO_FEATURE_TEMPERATURE = 0,
 16	DASHARO_FEATURE_FAN_PWM,
 17	DASHARO_FEATURE_FAN_TACH,
 18	DASHARO_FEATURE_MAX
 19};
 20
 21enum dasharo_temperature {
 22	DASHARO_TEMPERATURE_CPU_PACKAGE = 0,
 23	DASHARO_TEMPERATURE_CPU_CORE,
 24	DASHARO_TEMPERATURE_GPU,
 25	DASHARO_TEMPERATURE_BOARD,
 26	DASHARO_TEMPERATURE_CHASSIS,
 27	DASHARO_TEMPERATURE_MAX
 28};
 29
 30enum dasharo_fan {
 31	DASHARO_FAN_CPU = 0,
 32	DASHARO_FAN_GPU,
 33	DASHARO_FAN_CHASSIS,
 34	DASHARO_FAN_MAX
 35};
 36
 37#define MAX_GROUPS_PER_FEAT 8
 38
 39static const char * const dasharo_group_names[DASHARO_FEATURE_MAX][MAX_GROUPS_PER_FEAT] = {
 40	[DASHARO_FEATURE_TEMPERATURE] = {
 41		[DASHARO_TEMPERATURE_CPU_PACKAGE] = "CPU Package",
 42		[DASHARO_TEMPERATURE_CPU_CORE] = "CPU Core",
 43		[DASHARO_TEMPERATURE_GPU] = "GPU",
 44		[DASHARO_TEMPERATURE_BOARD] = "Board",
 45		[DASHARO_TEMPERATURE_CHASSIS] = "Chassis",
 46	},
 47	[DASHARO_FEATURE_FAN_PWM] = {
 48		[DASHARO_FAN_CPU] = "CPU",
 49		[DASHARO_FAN_GPU] = "GPU",
 50		[DASHARO_FAN_CHASSIS] = "Chassis",
 51	},
 52	[DASHARO_FEATURE_FAN_TACH] = {
 53		[DASHARO_FAN_CPU] = "CPU",
 54		[DASHARO_FAN_GPU] = "GPU",
 55		[DASHARO_FAN_CHASSIS] = "Chassis",
 56	},
 57};
 58
 59struct dasharo_capability {
 60	unsigned int group;
 61	unsigned int index;
 62	char name[16];
 63};
 64
 65#define MAX_CAPS_PER_FEAT 24
 66
 67struct dasharo_data {
 68	struct platform_device *pdev;
 69	int caps_found[DASHARO_FEATURE_MAX];
 70	struct dasharo_capability capabilities[DASHARO_FEATURE_MAX][MAX_CAPS_PER_FEAT];
 71};
 72
 73static int dasharo_get_feature_cap_count(struct dasharo_data *data, enum dasharo_feature feat, int cap)
 74{
 75	struct acpi_object_list obj_list;
 76	union acpi_object obj[2];
 77	acpi_handle handle;
 78	acpi_status status;
 79	u64 count;
 80
 81	obj[0].type = ACPI_TYPE_INTEGER;
 82	obj[0].integer.value = feat;
 83	obj[1].type = ACPI_TYPE_INTEGER;
 84	obj[1].integer.value = cap;
 85	obj_list.count = 2;
 86	obj_list.pointer = &obj[0];
 87
 88	handle = ACPI_HANDLE(&data->pdev->dev);
 89	status = acpi_evaluate_integer(handle, "GFCP", &obj_list, &count);
 90	if (ACPI_FAILURE(status))
 91		return -ENODEV;
 92
 93	return count;
 94}
 95
 96static int dasharo_read_channel(struct dasharo_data *data, char *method, enum dasharo_feature feat, int channel, long *value)
 97{
 98	struct acpi_object_list obj_list;
 99	union acpi_object obj[2];
100	acpi_handle handle;
101	acpi_status status;
102	u64 val;
103
104	if (feat >= ARRAY_SIZE(data->capabilities))
105		return -EINVAL;
106
107	if (channel >= data->caps_found[feat])
108		return -EINVAL;
109
110	obj[0].type = ACPI_TYPE_INTEGER;
111	obj[0].integer.value = data->capabilities[feat][channel].group;
112	obj[1].type = ACPI_TYPE_INTEGER;
113	obj[1].integer.value = data->capabilities[feat][channel].index;
114	obj_list.count = 2;
115	obj_list.pointer = &obj[0];
116
117	handle = ACPI_HANDLE(&data->pdev->dev);
118	status = acpi_evaluate_integer(handle, method, &obj_list, &val);
119	if (ACPI_FAILURE(status))
120		return -ENODEV;
121
122	*value = val;
123	return 0;
124}
125
126static int dasharo_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
127			      u32 attr, int channel, long *val)
128{
129	struct dasharo_data *data = dev_get_drvdata(dev);
130	long value;
131	int ret;
132
133	switch (type) {
134	case hwmon_temp:
135		ret = dasharo_read_channel(data, "GTMP", DASHARO_FEATURE_TEMPERATURE, channel, &value);
136		if (!ret)
137			*val = value * MILLIDEGREE_PER_DEGREE;
138		break;
139	case hwmon_fan:
140		ret = dasharo_read_channel(data, "GFTH", DASHARO_FEATURE_FAN_TACH, channel, &value);
141		if (!ret)
142			*val = value;
143		break;
144	case hwmon_pwm:
145		ret = dasharo_read_channel(data, "GFDC", DASHARO_FEATURE_FAN_PWM, channel, &value);
146		if (!ret)
147			*val = value;
148		break;
149	default:
150		return -ENODEV;
151		break;
152	}
153
154	return ret;
155}
156
157static int dasharo_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
158				     u32 attr, int channel, const char **str)
159{
160	struct dasharo_data *data = dev_get_drvdata(dev);
161
162	switch (type) {
163	case hwmon_temp:
164		if (channel >= data->caps_found[DASHARO_FEATURE_TEMPERATURE])
165			return -EINVAL;
166
167		*str = data->capabilities[DASHARO_FEATURE_TEMPERATURE][channel].name;
168		break;
169	case hwmon_fan:
170		if (channel >= data->caps_found[DASHARO_FEATURE_FAN_TACH])
171			return -EINVAL;
172
173		*str = data->capabilities[DASHARO_FEATURE_FAN_TACH][channel].name;
174		break;
175	default:
176		return -EOPNOTSUPP;
177	}
178
179	return 0;
180}
181
182static umode_t dasharo_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
183					u32 attr, int channel)
184{
185	const struct dasharo_data *data = drvdata;
186
187	switch (type) {
188	case hwmon_temp:
189		if (channel < data->caps_found[DASHARO_FEATURE_TEMPERATURE])
190			return 0444;
191		break;
192	case hwmon_pwm:
193		if (channel < data->caps_found[DASHARO_FEATURE_FAN_PWM])
194			return 0444;
195		break;
196	case hwmon_fan:
197		if (channel < data->caps_found[DASHARO_FEATURE_FAN_TACH])
198			return 0444;
199		break;
200	default:
201		break;
202	}
203
204	return 0;
205}
206
207static const struct hwmon_ops dasharo_hwmon_ops = {
208	.is_visible = dasharo_hwmon_is_visible,
209	.read_string = dasharo_hwmon_read_string,
210	.read = dasharo_hwmon_read,
211};
212
213// Max 24 capabilities per feature
214static const struct hwmon_channel_info * const dasharo_hwmon_info[] = {
215	HWMON_CHANNEL_INFO(fan,
216		HWMON_F_INPUT | HWMON_F_LABEL,
217		HWMON_F_INPUT | HWMON_F_LABEL,
218		HWMON_F_INPUT | HWMON_F_LABEL,
219		HWMON_F_INPUT | HWMON_F_LABEL,
220		HWMON_F_INPUT | HWMON_F_LABEL,
221		HWMON_F_INPUT | HWMON_F_LABEL,
222		HWMON_F_INPUT | HWMON_F_LABEL,
223		HWMON_F_INPUT | HWMON_F_LABEL,
224		HWMON_F_INPUT | HWMON_F_LABEL,
225		HWMON_F_INPUT | HWMON_F_LABEL,
226		HWMON_F_INPUT | HWMON_F_LABEL,
227		HWMON_F_INPUT | HWMON_F_LABEL,
228		HWMON_F_INPUT | HWMON_F_LABEL,
229		HWMON_F_INPUT | HWMON_F_LABEL,
230		HWMON_F_INPUT | HWMON_F_LABEL,
231		HWMON_F_INPUT | HWMON_F_LABEL,
232		HWMON_F_INPUT | HWMON_F_LABEL,
233		HWMON_F_INPUT | HWMON_F_LABEL,
234		HWMON_F_INPUT | HWMON_F_LABEL,
235		HWMON_F_INPUT | HWMON_F_LABEL,
236		HWMON_F_INPUT | HWMON_F_LABEL,
237		HWMON_F_INPUT | HWMON_F_LABEL,
238		HWMON_F_INPUT | HWMON_F_LABEL,
239		HWMON_F_INPUT | HWMON_F_LABEL),
240	HWMON_CHANNEL_INFO(temp,
241		HWMON_T_INPUT | HWMON_T_LABEL,
242		HWMON_T_INPUT | HWMON_T_LABEL,
243		HWMON_T_INPUT | HWMON_T_LABEL,
244		HWMON_T_INPUT | HWMON_T_LABEL,
245		HWMON_T_INPUT | HWMON_T_LABEL,
246		HWMON_T_INPUT | HWMON_T_LABEL,
247		HWMON_T_INPUT | HWMON_T_LABEL,
248		HWMON_T_INPUT | HWMON_T_LABEL,
249		HWMON_T_INPUT | HWMON_T_LABEL,
250		HWMON_T_INPUT | HWMON_T_LABEL,
251		HWMON_T_INPUT | HWMON_T_LABEL,
252		HWMON_T_INPUT | HWMON_T_LABEL,
253		HWMON_T_INPUT | HWMON_T_LABEL,
254		HWMON_T_INPUT | HWMON_T_LABEL,
255		HWMON_T_INPUT | HWMON_T_LABEL,
256		HWMON_T_INPUT | HWMON_T_LABEL,
257		HWMON_T_INPUT | HWMON_T_LABEL,
258		HWMON_T_INPUT | HWMON_T_LABEL,
259		HWMON_T_INPUT | HWMON_T_LABEL,
260		HWMON_T_INPUT | HWMON_T_LABEL,
261		HWMON_T_INPUT | HWMON_T_LABEL,
262		HWMON_T_INPUT | HWMON_T_LABEL,
263		HWMON_T_INPUT | HWMON_T_LABEL,
264		HWMON_T_INPUT | HWMON_T_LABEL),
265	HWMON_CHANNEL_INFO(pwm,
266		HWMON_PWM_INPUT,
267		HWMON_PWM_INPUT,
268		HWMON_PWM_INPUT,
269		HWMON_PWM_INPUT,
270		HWMON_PWM_INPUT,
271		HWMON_PWM_INPUT,
272		HWMON_PWM_INPUT,
273		HWMON_PWM_INPUT,
274		HWMON_PWM_INPUT,
275		HWMON_PWM_INPUT,
276		HWMON_PWM_INPUT,
277		HWMON_PWM_INPUT,
278		HWMON_PWM_INPUT,
279		HWMON_PWM_INPUT,
280		HWMON_PWM_INPUT,
281		HWMON_PWM_INPUT,
282		HWMON_PWM_INPUT,
283		HWMON_PWM_INPUT,
284		HWMON_PWM_INPUT,
285		HWMON_PWM_INPUT,
286		HWMON_PWM_INPUT,
287		HWMON_PWM_INPUT,
288		HWMON_PWM_INPUT,
289		HWMON_PWM_INPUT),
290	NULL
291};
292
293static const struct hwmon_chip_info dasharo_hwmon_chip_info = {
294	.ops = &dasharo_hwmon_ops,
295	.info = dasharo_hwmon_info,
296};
297
298static void dasharo_fill_feature_caps(struct dasharo_data *data, enum dasharo_feature feat)
299{
300	struct dasharo_capability *cap;
301	int cap_count = 0;
302	int count;
303
304	for (int group = 0; group < MAX_GROUPS_PER_FEAT; ++group) {
305		count = dasharo_get_feature_cap_count(data, feat, group);
306		if (count <= 0)
307			continue;
308
309		for (unsigned int i = 0; i < count; ++i) {
310			if (cap_count >= ARRAY_SIZE(data->capabilities[feat]))
311				break;
312
313			cap = &data->capabilities[feat][cap_count];
314			cap->group = group;
315			cap->index = i;
316			scnprintf(cap->name, sizeof(cap->name), "%s %d",
317				  dasharo_group_names[feat][group], i);
318			cap_count++;
319		}
320	}
321	data->caps_found[feat] = cap_count;
322}
323
324static int dasharo_probe(struct platform_device *pdev)
325{
326	struct dasharo_data *data;
327	struct device *hwmon;
328
329	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
330	if (!data)
331		return -ENOMEM;
332	data->pdev = pdev;
333
334	for (unsigned int i = 0; i < DASHARO_FEATURE_MAX; ++i)
335		dasharo_fill_feature_caps(data, i);
336
337	hwmon = devm_hwmon_device_register_with_info(&pdev->dev, "dasharo_acpi", data,
338						     &dasharo_hwmon_chip_info, NULL);
339
340	return PTR_ERR_OR_ZERO(hwmon);
341}
342
343static const struct acpi_device_id dasharo_device_ids[] = {
344	{"DSHR0001", 0},
345	{}
346};
347MODULE_DEVICE_TABLE(acpi, dasharo_device_ids);
348
349static struct platform_driver dasharo_driver = {
350	.driver = {
351		.name = "dasharo-acpi",
352		.acpi_match_table = dasharo_device_ids,
353	},
354	.probe = dasharo_probe,
355};
356module_platform_driver(dasharo_driver);
357
358MODULE_DESCRIPTION("Dasharo ACPI Driver");
359MODULE_AUTHOR("Michał Kopeć <michal.kopec@3mdeb.com>");
360MODULE_LICENSE("GPL");
~/ Read-only file preview.