ACPI: platform_profile: Add profile attribute for class interface

Reading and writing the `profile` sysfs file will use the callbacks for
the platform profile handler to read or set the given profile.

Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20241206031918.1537-14-mario.limonciello@amd.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
Mario Limonciello
2024-12-05 21:19:09 -06:00
committed by Ilpo Järvinen
parent 52a67be8ee
commit d2785e3942

View File

@@ -47,6 +47,55 @@ static ssize_t _commmon_choices_show(unsigned long *choices, char *buf)
return len;
}
/**
* _store_class_profile - Set the profile for a class device
* @dev: The class device
* @data: The profile to set
*
* Return: 0 on success, -errno on failure
*/
static int _store_class_profile(struct device *dev, void *data)
{
struct platform_profile_handler *handler;
int *bit = (int *)data;
lockdep_assert_held(&profile_lock);
handler = dev_get_drvdata(dev);
if (!test_bit(*bit, handler->choices))
return -EOPNOTSUPP;
return handler->profile_set(handler, *bit);
}
/**
* get_class_profile - Show the current profile for a class device
* @dev: The class device
* @profile: The profile to return
*
* Return: 0 on success, -errno on failure
*/
static int get_class_profile(struct device *dev,
enum platform_profile_option *profile)
{
struct platform_profile_handler *handler;
enum platform_profile_option val;
int err;
lockdep_assert_held(&profile_lock);
handler = dev_get_drvdata(dev);
err = handler->profile_get(handler, &val);
if (err) {
pr_err("Failed to get profile for handler %s\n", handler->name);
return err;
}
if (WARN_ON(val >= PLATFORM_PROFILE_LAST))
return -EINVAL;
*profile = val;
return 0;
}
/**
* name_show - Show the name of the profile handler
* @dev: The device
@@ -81,9 +130,65 @@ static ssize_t choices_show(struct device *dev,
}
static DEVICE_ATTR_RO(choices);
/**
* profile_show - Show the current profile for a class device
* @dev: The device
* @attr: The attribute
* @buf: The buffer to write to
*
* Return: The number of bytes written
*/
static ssize_t profile_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
enum platform_profile_option profile = PLATFORM_PROFILE_LAST;
int err;
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) {
err = get_class_profile(dev, &profile);
if (err)
return err;
}
return sysfs_emit(buf, "%s\n", profile_names[profile]);
}
/**
* profile_store - Set the profile for a class device
* @dev: The device
* @attr: The attribute
* @buf: The buffer to read from
* @count: The number of bytes to read
*
* Return: The number of bytes read
*/
static ssize_t profile_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int index, ret;
index = sysfs_match_string(profile_names, buf);
if (index < 0)
return -EINVAL;
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) {
ret = _store_class_profile(dev, &index);
if (ret)
return ret;
}
sysfs_notify(acpi_kobj, NULL, "platform_profile");
return count;
}
static DEVICE_ATTR_RW(profile);
static struct attribute *profile_attrs[] = {
&dev_attr_name.attr,
&dev_attr_choices.attr,
&dev_attr_profile.attr,
NULL
};
ATTRIBUTE_GROUPS(profile);