forked from mirrors/linux
		
	ACPI: platform_profile: Create class for ACPI platform profile
When registering a platform profile handler create a class device that will allow changing a single platform profile handler. The class and sysfs group are no longer needed when the platform profile core is a module and unloaded, so remove them at that time as well. Reviewed-by: Armin Wolf <W_Armin@gmx.de> Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca> Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca> 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-11-mario.limonciello@amd.com Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									1f3ac55c2e
								
							
						
					
					
						commit
						77be5cacb2
					
				
					 2 changed files with 79 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
#include <linux/acpi.h>
 | 
			
		||||
#include <linux/bits.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/kdev_t.h>
 | 
			
		||||
#include <linux/mutex.h>
 | 
			
		||||
#include <linux/platform_profile.h>
 | 
			
		||||
#include <linux/sysfs.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +23,12 @@ static const char * const profile_names[] = {
 | 
			
		|||
};
 | 
			
		||||
static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST);
 | 
			
		||||
 | 
			
		||||
static DEFINE_IDA(platform_profile_ida);
 | 
			
		||||
 | 
			
		||||
static const struct class platform_profile_class = {
 | 
			
		||||
	.name = "platform-profile",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static ssize_t platform_profile_choices_show(struct device *dev,
 | 
			
		||||
					struct device_attribute *attr,
 | 
			
		||||
					char *buf)
 | 
			
		||||
| 
						 | 
				
			
			@ -101,8 +108,21 @@ static struct attribute *platform_profile_attrs[] = {
 | 
			
		|||
	NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int profile_class_registered(struct device *dev, const void *data)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static umode_t profile_class_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
 | 
			
		||||
{
 | 
			
		||||
	if (!class_find_device(&platform_profile_class, NULL, NULL, profile_class_registered))
 | 
			
		||||
		return 0;
 | 
			
		||||
	return attr->mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct attribute_group platform_profile_group = {
 | 
			
		||||
	.attrs = platform_profile_attrs
 | 
			
		||||
	.attrs = platform_profile_attrs,
 | 
			
		||||
	.is_visible = profile_class_is_visible,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void platform_profile_notify(struct platform_profile_handler *pprof)
 | 
			
		||||
| 
						 | 
				
			
			@ -160,25 +180,77 @@ int platform_profile_register(struct platform_profile_handler *pprof)
 | 
			
		|||
	if (cur_profile)
 | 
			
		||||
		return -EEXIST;
 | 
			
		||||
 | 
			
		||||
	err = sysfs_create_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
	/* create class interface for individual handler */
 | 
			
		||||
	pprof->minor = ida_alloc(&platform_profile_ida, GFP_KERNEL);
 | 
			
		||||
	if (pprof->minor < 0)
 | 
			
		||||
		return pprof->minor;
 | 
			
		||||
	pprof->class_dev = device_create(&platform_profile_class, pprof->dev,
 | 
			
		||||
					 MKDEV(0, 0), pprof, "platform-profile-%d",
 | 
			
		||||
					 pprof->minor);
 | 
			
		||||
	if (IS_ERR(pprof->class_dev)) {
 | 
			
		||||
		err = PTR_ERR(pprof->class_dev);
 | 
			
		||||
		goto cleanup_ida;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cur_profile = pprof;
 | 
			
		||||
 | 
			
		||||
	err = sysfs_update_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto cleanup_cur;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
cleanup_cur:
 | 
			
		||||
	cur_profile = NULL;
 | 
			
		||||
	device_unregister(pprof->class_dev);
 | 
			
		||||
 | 
			
		||||
cleanup_ida:
 | 
			
		||||
	ida_free(&platform_profile_ida, pprof->minor);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(platform_profile_register);
 | 
			
		||||
 | 
			
		||||
int platform_profile_remove(struct platform_profile_handler *pprof)
 | 
			
		||||
{
 | 
			
		||||
	int id;
 | 
			
		||||
	guard(mutex)(&profile_lock);
 | 
			
		||||
 | 
			
		||||
	sysfs_remove_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
	cur_profile = NULL;
 | 
			
		||||
 | 
			
		||||
	id = pprof->minor;
 | 
			
		||||
	device_unregister(pprof->class_dev);
 | 
			
		||||
	ida_free(&platform_profile_ida, id);
 | 
			
		||||
 | 
			
		||||
	sysfs_update_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(platform_profile_remove);
 | 
			
		||||
 | 
			
		||||
static int __init platform_profile_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = class_register(&platform_profile_class);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	err = sysfs_create_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
	if (err)
 | 
			
		||||
		class_unregister(&platform_profile_class);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit platform_profile_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	sysfs_remove_group(acpi_kobj, &platform_profile_group);
 | 
			
		||||
	class_unregister(&platform_profile_class);
 | 
			
		||||
}
 | 
			
		||||
module_init(platform_profile_init);
 | 
			
		||||
module_exit(platform_profile_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
 | 
			
		||||
MODULE_DESCRIPTION("ACPI platform profile sysfs interface");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,8 @@ enum platform_profile_option {
 | 
			
		|||
struct platform_profile_handler {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	struct device *class_dev;
 | 
			
		||||
	int minor;
 | 
			
		||||
	unsigned long choices[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)];
 | 
			
		||||
	int (*profile_get)(struct platform_profile_handler *pprof,
 | 
			
		||||
				enum platform_profile_option *profile);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue