]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ACPI: platform_profile: Add profile attribute for class interface
authorMario Limonciello <mario.limonciello@amd.com>
Fri, 6 Dec 2024 03:19:09 +0000 (21:19 -0600)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Tue, 10 Dec 2024 17:18:06 +0000 (19:18 +0200)
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>
drivers/acpi/platform_profile.c

index 885f41bca6c2502822d7abc5195d3baaf7467521..d2c83cb258296dc2e713b056b3ebe97e60d65a0d 100644 (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);