Commit f4dc6406 authored by Akshay Gupta's avatar Akshay Gupta Committed by Greg Kroah-Hartman
Browse files

misc: amd-sbi: Move hwmon device sensor as separate entity



- Move hwmon device sensor to misc as only power is reported through
  hwmon sensor.

Reviewed-by: default avatarNaveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
Signed-off-by: default avatarAkshay Gupta <akshay.gupta@amd.com>
Link: https://lore.kernel.org/r/20250428063034.2145566-4-akshay.gupta@amd.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 43470595
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -2,9 +2,17 @@
config AMD_SBRMI_I2C
	tristate "AMD side band RMI support"
	depends on I2C
	depends on HWMON
	help
	  Side band RMI over I2C support for AMD out of band management.

	  This driver can also be built as a module. If so, the module will
	  be called sbrmi-i2c.

config AMD_SBRMI_HWMON
	bool "SBRMI hardware monitoring"
	depends on AMD_SBRMI_I2C && HWMON
	depends on !(AMD_SBRMI_I2C=y && HWMON=m)
	help
	  This provides support for RMI device hardware monitoring. If enabled,
	  a hardware monitoring device will be created for each socket in
	  the system.
+2 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
sbrmi-i2c-objs  		:= rmi-i2c.o rmi-core.o
sbrmi-i2c-objs  		+= rmi-i2c.o rmi-core.o
sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON)	+= rmi-hwmon.o
obj-$(CONFIG_AMD_SBRMI_I2C)	+= sbrmi-i2c.o
+8 −0
Original line number Diff line number Diff line
@@ -60,4 +60,12 @@ struct sbrmi_mailbox_msg {
};

int rmi_mailbox_xfer(struct sbrmi_data *data, struct sbrmi_mailbox_msg *msg);
#ifdef CONFIG_AMD_SBRMI_HWMON
int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data);
#else
static inline int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data)
{
	return 0;
}
#endif
#endif /*_SBRMI_CORE_H_*/
+121 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * rmi-hwmon.c - hwmon sensor support for side band RMI
 *
 * Copyright (C) 2025 Advanced Micro Devices, Inc.
 */
#include <linux/err.h>
#include <linux/hwmon.h>
#include "rmi-core.h"

/* Do not allow setting negative power limit */
#define SBRMI_PWR_MIN  0

static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
		      u32 attr, int channel, long *val)
{
	struct sbrmi_data *data = dev_get_drvdata(dev);
	struct sbrmi_mailbox_msg msg = { 0 };
	int ret;

	if (!data)
		return -ENODEV;

	if (type != hwmon_power)
		return -EINVAL;

	msg.read = true;
	switch (attr) {
	case hwmon_power_input:
		msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
		ret = rmi_mailbox_xfer(data, &msg);
		break;
	case hwmon_power_cap:
		msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
		ret = rmi_mailbox_xfer(data, &msg);
		break;
	case hwmon_power_cap_max:
		msg.data_out = data->pwr_limit_max;
		ret = 0;
		break;
	default:
		return -EINVAL;
	}
	if (ret < 0)
		return ret;
	/* hwmon power attributes are in microWatt */
	*val = (long)msg.data_out * 1000;
	return ret;
}

static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
		       u32 attr, int channel, long val)
{
	struct sbrmi_data *data = dev_get_drvdata(dev);
	struct sbrmi_mailbox_msg msg = { 0 };

	if (!data)
		return -ENODEV;

	if (type != hwmon_power && attr != hwmon_power_cap)
		return -EINVAL;
	/*
	 * hwmon power attributes are in microWatt
	 * mailbox read/write is in mWatt
	 */
	val /= 1000;

	val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);

	msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
	msg.data_in = val;
	msg.read = false;

	return rmi_mailbox_xfer(data, &msg);
}

static umode_t sbrmi_is_visible(const void *data,
				enum hwmon_sensor_types type,
				u32 attr, int channel)
{
	switch (type) {
	case hwmon_power:
		switch (attr) {
		case hwmon_power_input:
		case hwmon_power_cap_max:
			return 0444;
		case hwmon_power_cap:
			return 0644;
		}
		break;
	default:
		break;
	}
	return 0;
}

static const struct hwmon_channel_info * const sbrmi_info[] = {
	HWMON_CHANNEL_INFO(power,
			   HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
	NULL
};

static const struct hwmon_ops sbrmi_hwmon_ops = {
	.is_visible = sbrmi_is_visible,
	.read = sbrmi_read,
	.write = sbrmi_write,
};

static const struct hwmon_chip_info sbrmi_chip_info = {
	.ops = &sbrmi_hwmon_ops,
	.info = sbrmi_info,
};

int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data)
{
	struct device *hwmon_dev;

	hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi", data,
							 &sbrmi_chip_info, NULL);
	return PTR_ERR_OR_ZERO(hwmon_dev);
}
+2 −102
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@

#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -16,9 +15,6 @@
#include <linux/of.h>
#include "rmi-core.h"

/* Do not allow setting negative power limit */
#define SBRMI_PWR_MIN	0

static int sbrmi_enable_alert(struct i2c_client *client)
{
	int ctrl;
@@ -40,100 +36,6 @@ static int sbrmi_enable_alert(struct i2c_client *client)
	return 0;
}

static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
		      u32 attr, int channel, long *val)
{
	struct sbrmi_data *data = dev_get_drvdata(dev);
	struct sbrmi_mailbox_msg msg = { 0 };
	int ret;

	if (type != hwmon_power)
		return -EINVAL;

	msg.read = true;
	switch (attr) {
	case hwmon_power_input:
		msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
		ret = rmi_mailbox_xfer(data, &msg);
		break;
	case hwmon_power_cap:
		msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
		ret = rmi_mailbox_xfer(data, &msg);
		break;
	case hwmon_power_cap_max:
		msg.data_out = data->pwr_limit_max;
		ret = 0;
		break;
	default:
		return -EINVAL;
	}
	if (ret < 0)
		return ret;
	/* hwmon power attributes are in microWatt */
	*val = (long)msg.data_out * 1000;
	return ret;
}

static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
		       u32 attr, int channel, long val)
{
	struct sbrmi_data *data = dev_get_drvdata(dev);
	struct sbrmi_mailbox_msg msg = { 0 };

	if (type != hwmon_power && attr != hwmon_power_cap)
		return -EINVAL;
	/*
	 * hwmon power attributes are in microWatt
	 * mailbox read/write is in mWatt
	 */
	val /= 1000;

	val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);

	msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
	msg.data_in = val;
	msg.read = false;

	return rmi_mailbox_xfer(data, &msg);
}

static umode_t sbrmi_is_visible(const void *data,
				enum hwmon_sensor_types type,
				u32 attr, int channel)
{
	switch (type) {
	case hwmon_power:
		switch (attr) {
		case hwmon_power_input:
		case hwmon_power_cap_max:
			return 0444;
		case hwmon_power_cap:
			return 0644;
		}
		break;
	default:
		break;
	}
	return 0;
}

static const struct hwmon_channel_info * const sbrmi_info[] = {
	HWMON_CHANNEL_INFO(power,
			   HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
	NULL
};

static const struct hwmon_ops sbrmi_hwmon_ops = {
	.is_visible = sbrmi_is_visible,
	.read = sbrmi_read,
	.write = sbrmi_write,
};

static const struct hwmon_chip_info sbrmi_chip_info = {
	.ops = &sbrmi_hwmon_ops,
	.info = sbrmi_info,
};

static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
{
	struct sbrmi_mailbox_msg msg = { 0 };
@@ -152,7 +54,6 @@ static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
static int sbrmi_i2c_probe(struct i2c_client *client)
{
	struct device *dev = &client->dev;
	struct device *hwmon_dev;
	struct sbrmi_data *data;
	int ret;

@@ -173,9 +74,8 @@ static int sbrmi_i2c_probe(struct i2c_client *client)
	if (ret < 0)
		return ret;

	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
							 &sbrmi_chip_info, NULL);
	return PTR_ERR_OR_ZERO(hwmon_dev);
	dev_set_drvdata(dev, data);
	return create_hwmon_sensor_device(dev, data);
}

static const struct i2c_device_id sbrmi_id[] = {