File Index
Files and directories
Sign in
FILE

rmi-hwmon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/misc/amd-sbi/rmi-hwmon.c C
  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
 15static 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
 51static 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
 76static 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
 96static 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
102static const struct hwmon_ops sbrmi_hwmon_ops = {
103	.is_visible = sbrmi_is_visible,
104	.read = sbrmi_read,
105	.write = sbrmi_write,
106};
107
108static const struct hwmon_chip_info sbrmi_chip_info = {
109	.ops = &sbrmi_hwmon_ops,
110	.info = sbrmi_info,
111};
112
113int 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}
~/ Read-only file preview.