1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AMD HSMP hwmon support
4  * Copyright (c) 2025, AMD.
5  * All Rights Reserved.
6  *
7  * This file provides hwmon implementation for HSMP interface.
8  */
9 
10 #include <asm/amd/hsmp.h>
11 
12 #include <linux/device.h>
13 #include <linux/err.h>
14 #include <linux/hwmon.h>
15 #include <linux/types.h>
16 #include <linux/units.h>
17 
18 #include "hsmp.h"
19 
20 #define HSMP_HWMON_NAME		"amd_hsmp_hwmon"
21 
22 static int hsmp_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
23 			    u32 attr, int channel, long val)
24 {
25 	u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
26 	struct hsmp_message msg = {};
27 
28 	if (type != hwmon_power)
29 		return -EOPNOTSUPP;
30 
31 	if (attr != hwmon_power_cap)
32 		return -EOPNOTSUPP;
33 
34 	msg.num_args = 1;
35 	msg.args[0] = val / MICROWATT_PER_MILLIWATT;
36 	msg.msg_id = HSMP_SET_SOCKET_POWER_LIMIT;
37 	msg.sock_ind = sock_ind;
38 	return hsmp_send_message(&msg);
39 }
40 
41 static int hsmp_hwmon_read(struct device *dev,
42 			   enum hwmon_sensor_types type,
43 			   u32 attr, int channel, long *val)
44 {
45 	u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
46 	struct hsmp_message msg = {};
47 	int ret;
48 
49 	if (type != hwmon_power)
50 		return -EOPNOTSUPP;
51 
52 	msg.sock_ind = sock_ind;
53 	msg.response_sz = 1;
54 
55 	switch (attr) {
56 	case hwmon_power_input:
57 		msg.msg_id = HSMP_GET_SOCKET_POWER;
58 		break;
59 	case hwmon_power_cap:
60 		msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT;
61 		break;
62 	case hwmon_power_cap_max:
63 		msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT_MAX;
64 		break;
65 	default:
66 		return -EOPNOTSUPP;
67 	}
68 
69 	ret = hsmp_send_message(&msg);
70 	if (!ret)
71 		*val = msg.args[0] * MICROWATT_PER_MILLIWATT;
72 
73 	return ret;
74 }
75 
76 static umode_t hsmp_hwmon_is_visble(const void *data,
77 				    enum hwmon_sensor_types type,
78 				    u32 attr, int channel)
79 {
80 	if (type != hwmon_power)
81 		return 0;
82 
83 	switch (attr) {
84 	case hwmon_power_input:
85 		return 0444;
86 	case hwmon_power_cap:
87 		return 0644;
88 	case hwmon_power_cap_max:
89 		return 0444;
90 	default:
91 		return 0;
92 	}
93 }
94 
95 static const struct hwmon_ops hsmp_hwmon_ops = {
96 	.read = hsmp_hwmon_read,
97 	.is_visible = hsmp_hwmon_is_visble,
98 	.write	= hsmp_hwmon_write,
99 };
100 
101 static const struct hwmon_channel_info * const hsmp_info[] = {
102 	HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
103 	NULL
104 };
105 
106 static const struct hwmon_chip_info hsmp_chip_info = {
107 	.ops = &hsmp_hwmon_ops,
108 	.info = hsmp_info,
109 };
110 
111 int hsmp_create_sensor(struct device *dev, u16 sock_ind)
112 {
113 	struct device *hwmon_dev;
114 
115 	hwmon_dev = devm_hwmon_device_register_with_info(dev, HSMP_HWMON_NAME,
116 							 (void *)(uintptr_t)sock_ind,
117 							 &hsmp_chip_info,
118 							 NULL);
119 	return PTR_ERR_OR_ZERO(hwmon_dev);
120 }
121 EXPORT_SYMBOL_NS(hsmp_create_sensor, "AMD_HSMP");
122