44
55#include <linux/acpi.h>
66#include <linux/bits.h>
7+ #include <linux/cleanup.h>
78#include <linux/init.h>
89#include <linux/mutex.h>
910#include <linux/platform_profile.h>
@@ -212,9 +213,17 @@ static struct attribute *profile_attrs[] = {
212213};
213214ATTRIBUTE_GROUPS (profile );
214215
216+ static void pprof_device_release (struct device * dev )
217+ {
218+ struct platform_profile_handler * pprof = to_pprof_handler (dev );
219+
220+ kfree (pprof );
221+ }
222+
215223static const struct class platform_profile_class = {
216224 .name = "platform-profile" ,
217225 .dev_groups = profile_groups ,
226+ .dev_release = pprof_device_release ,
218227};
219228
220229/**
@@ -408,10 +417,10 @@ static const struct attribute_group platform_profile_group = {
408417 .is_visible = profile_class_is_visible ,
409418};
410419
411- void platform_profile_notify (struct platform_profile_handler * pprof )
420+ void platform_profile_notify (struct device * dev )
412421{
413422 scoped_cond_guard (mutex_intr , return , & profile_lock ) {
414- _notify_class_profile (& pprof -> class_dev , NULL );
423+ _notify_class_profile (dev , NULL );
415424 }
416425 sysfs_notify (acpi_kobj , NULL , "platform_profile" );
417426}
@@ -460,42 +469,54 @@ int platform_profile_cycle(void)
460469}
461470EXPORT_SYMBOL_GPL (platform_profile_cycle );
462471
463- int platform_profile_register (struct platform_profile_handler * pprof , void * drvdata )
472+ struct device * platform_profile_register (struct device * dev , const char * name ,
473+ void * drvdata ,
474+ const struct platform_profile_ops * ops )
464475{
476+ struct device * ppdev ;
477+ int minor ;
465478 int err ;
466479
467- /* Sanity check the profile handler */
468- if (!pprof || !pprof -> ops -> profile_set || !pprof -> ops -> profile_get ||
469- !pprof -> ops -> probe ) {
470- pr_err ("platform_profile: handler is invalid\n" );
471- return - EINVAL ;
472- }
480+ /* Sanity check */
481+ if (WARN_ON_ONCE (!dev || !name || !ops || !ops -> profile_get ||
482+ !ops -> profile_set || !ops -> probe ))
483+ return ERR_PTR (- EINVAL );
484+
485+ struct platform_profile_handler * pprof __free (kfree ) = kzalloc (
486+ sizeof (* pprof ), GFP_KERNEL );
487+ if (!pprof )
488+ return ERR_PTR (- ENOMEM );
473489
474- err = pprof -> ops -> probe (drvdata , pprof -> choices );
490+ err = ops -> probe (drvdata , pprof -> choices );
475491 if (err ) {
476- dev_err (pprof -> dev , "platform_profile probe failed\n" );
477- return err ;
492+ dev_err (dev , "platform_profile probe failed\n" );
493+ return ERR_PTR ( err ) ;
478494 }
479495
480496 if (bitmap_empty (pprof -> choices , PLATFORM_PROFILE_LAST )) {
481- dev_err (pprof -> dev , "Failed to register a platform_profile class device with empty choices\n" );
482- return - EINVAL ;
497+ dev_err (dev , "Failed to register platform_profile class device with empty choices\n" );
498+ return ERR_PTR ( - EINVAL ) ;
483499 }
484500
485501 guard (mutex )(& profile_lock );
486502
487503 /* create class interface for individual handler */
488- pprof -> minor = ida_alloc (& platform_profile_ida , GFP_KERNEL );
489- if (pprof -> minor < 0 )
490- return pprof -> minor ;
504+ minor = ida_alloc (& platform_profile_ida , GFP_KERNEL );
505+ if (minor < 0 )
506+ return ERR_PTR ( minor ) ;
491507
508+ pprof -> name = name ;
509+ pprof -> ops = ops ;
510+ pprof -> minor = minor ;
492511 pprof -> class_dev .class = & platform_profile_class ;
493- pprof -> class_dev .parent = pprof -> dev ;
512+ pprof -> class_dev .parent = dev ;
494513 dev_set_drvdata (& pprof -> class_dev , drvdata );
495514 dev_set_name (& pprof -> class_dev , "platform-profile-%d" , pprof -> minor );
496- err = device_register (& pprof -> class_dev );
515+ /* device_register() takes ownership of pprof/ppdev */
516+ ppdev = & no_free_ptr (pprof )-> class_dev ;
517+ err = device_register (ppdev );
497518 if (err ) {
498- put_device (& pprof -> class_dev );
519+ put_device (ppdev );
499520 goto cleanup_ida ;
500521 }
501522
@@ -505,20 +526,21 @@ int platform_profile_register(struct platform_profile_handler *pprof, void *drvd
505526 if (err )
506527 goto cleanup_cur ;
507528
508- return 0 ;
529+ return ppdev ;
509530
510531cleanup_cur :
511- device_unregister (& pprof -> class_dev );
532+ device_unregister (ppdev );
512533
513534cleanup_ida :
514- ida_free (& platform_profile_ida , pprof -> minor );
535+ ida_free (& platform_profile_ida , minor );
515536
516- return err ;
537+ return ERR_PTR ( err ) ;
517538}
518539EXPORT_SYMBOL_GPL (platform_profile_register );
519540
520- int platform_profile_remove (struct platform_profile_handler * pprof )
541+ int platform_profile_remove (struct device * dev )
521542{
543+ struct platform_profile_handler * pprof = to_pprof_handler (dev );
522544 int id ;
523545 guard (mutex )(& profile_lock );
524546
@@ -536,30 +558,32 @@ EXPORT_SYMBOL_GPL(platform_profile_remove);
536558
537559static void devm_platform_profile_release (struct device * dev , void * res )
538560{
539- struct platform_profile_handler * * pprof = res ;
561+ struct device * * ppdev = res ;
540562
541- platform_profile_remove (* pprof );
563+ platform_profile_remove (* ppdev );
542564}
543565
544- int devm_platform_profile_register (struct platform_profile_handler * pprof , void * drvdata )
566+ struct device * devm_platform_profile_register (struct device * dev , const char * name ,
567+ void * drvdata ,
568+ const struct platform_profile_ops * ops )
545569{
546- struct platform_profile_handler * * dr ;
547- int ret ;
570+ struct device * ppdev ;
571+ struct device * * dr ;
548572
549573 dr = devres_alloc (devm_platform_profile_release , sizeof (* dr ), GFP_KERNEL );
550574 if (!dr )
551- return - ENOMEM ;
575+ return ERR_PTR ( - ENOMEM ) ;
552576
553- ret = platform_profile_register (pprof , drvdata );
554- if (ret ) {
577+ ppdev = platform_profile_register (dev , name , drvdata , ops );
578+ if (IS_ERR ( ppdev ) ) {
555579 devres_free (dr );
556- return ret ;
580+ return ppdev ;
557581 }
558582
559- * dr = pprof ;
560- devres_add (pprof -> dev , dr );
583+ * dr = ppdev ;
584+ devres_add (dev , dr );
561585
562- return 0 ;
586+ return ppdev ;
563587}
564588EXPORT_SYMBOL_GPL (devm_platform_profile_register );
565589
0 commit comments