Unverified Commit d2785e39 authored by Mario Limonciello's avatar Mario Limonciello Committed by Ilpo Järvinen
Browse files

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: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: default avatarArmin Wolf <W_Armin@gmx.de>
Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarMario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20241206031918.1537-14-mario.limonciello@amd.com


Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent 52a67be8
Loading
Loading
Loading
Loading
+105 −0
Original line number Diff line number Diff line
@@ -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);