1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * rmi-hwmon.c - hwmon sensor support for side band RMI
4 *
5 * Copyright (C) 2025 Advanced Micro Devices, Inc.
6 */
7 #include <linux/err.h>
8 #include <linux/hwmon.h>
9 #include <uapi/misc/amd-apml.h>
10 #include "rmi-core.h"
11
12 /* Do not allow setting negative power limit */
13 #define SBRMI_PWR_MIN 0
14
sbrmi_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)15 static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
16 u32 attr, int channel, long *val)
17 {
18 struct sbrmi_data *data = dev_get_drvdata(dev);
19 struct apml_mbox_msg msg = { 0 };
20 int ret;
21
22 if (!data)
23 return -ENODEV;
24
25 if (type != hwmon_power)
26 return -EINVAL;
27
28 switch (attr) {
29 case hwmon_power_input:
30 msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
31 ret = rmi_mailbox_xfer(data, &msg);
32 break;
33 case hwmon_power_cap:
34 msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
35 ret = rmi_mailbox_xfer(data, &msg);
36 break;
37 case hwmon_power_cap_max:
38 msg.mb_in_out = data->pwr_limit_max;
39 ret = 0;
40 break;
41 default:
42 return -EINVAL;
43 }
44 if (ret < 0)
45 return ret;
46 /* hwmon power attributes are in microWatt */
47 *val = (long)msg.mb_in_out * 1000;
48 return ret;
49 }
50
sbrmi_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)51 static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
52 u32 attr, int channel, long val)
53 {
54 struct sbrmi_data *data = dev_get_drvdata(dev);
55 struct apml_mbox_msg msg = { 0 };
56
57 if (!data)
58 return -ENODEV;
59
60 if (type != hwmon_power && attr != hwmon_power_cap)
61 return -EINVAL;
62 /*
63 * hwmon power attributes are in microWatt
64 * mailbox read/write is in mWatt
65 */
66 val /= 1000;
67
68 val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);
69
70 msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
71 msg.mb_in_out = val;
72
73 return rmi_mailbox_xfer(data, &msg);
74 }
75
sbrmi_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)76 static umode_t sbrmi_is_visible(const void *data,
77 enum hwmon_sensor_types type,
78 u32 attr, int channel)
79 {
80 switch (type) {
81 case hwmon_power:
82 switch (attr) {
83 case hwmon_power_input:
84 case hwmon_power_cap_max:
85 return 0444;
86 case hwmon_power_cap:
87 return 0644;
88 }
89 break;
90 default:
91 break;
92 }
93 return 0;
94 }
95
96 static const struct hwmon_channel_info * const sbrmi_info[] = {
97 HWMON_CHANNEL_INFO(power,
98 HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
99 NULL
100 };
101
102 static const struct hwmon_ops sbrmi_hwmon_ops = {
103 .is_visible = sbrmi_is_visible,
104 .read = sbrmi_read,
105 .write = sbrmi_write,
106 };
107
108 static const struct hwmon_chip_info sbrmi_chip_info = {
109 .ops = &sbrmi_hwmon_ops,
110 .info = sbrmi_info,
111 };
112
create_hwmon_sensor_device(struct device * dev,struct sbrmi_data * data)113 int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data)
114 {
115 struct device *hwmon_dev;
116
117 hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi", data,
118 &sbrmi_chip_info, NULL);
119 return PTR_ERR_OR_ZERO(hwmon_dev);
120 }
121