23
23
#include <linux/nvmem-consumer.h>
24
24
#include <linux/of.h>
25
25
#include <linux/platform_device.h>
26
+ #include <linux/pm.h>
26
27
#include <linux/pm_domain.h>
27
28
#include <linux/pm_opp.h>
29
+ #include <linux/pm_runtime.h>
28
30
#include <linux/slab.h>
29
31
#include <linux/soc/qcom/smem.h>
30
32
@@ -55,6 +57,7 @@ struct qcom_cpufreq_match_data {
55
57
56
58
struct qcom_cpufreq_drv_cpu {
57
59
int opp_token ;
60
+ struct device * * virt_devs ;
58
61
};
59
62
60
63
struct qcom_cpufreq_drv {
@@ -424,6 +427,30 @@ static const struct qcom_cpufreq_match_data match_data_ipq8074 = {
424
427
.get_version = qcom_cpufreq_ipq8074_name_version ,
425
428
};
426
429
430
+ static void qcom_cpufreq_suspend_virt_devs (struct qcom_cpufreq_drv * drv , unsigned int cpu )
431
+ {
432
+ const char * const * name = drv -> data -> genpd_names ;
433
+ int i ;
434
+
435
+ if (!drv -> cpus [cpu ].virt_devs )
436
+ return ;
437
+
438
+ for (i = 0 ; * name ; i ++ , name ++ )
439
+ device_set_awake_path (drv -> cpus [cpu ].virt_devs [i ]);
440
+ }
441
+
442
+ static void qcom_cpufreq_put_virt_devs (struct qcom_cpufreq_drv * drv , unsigned int cpu )
443
+ {
444
+ const char * const * name = drv -> data -> genpd_names ;
445
+ int i ;
446
+
447
+ if (!drv -> cpus [cpu ].virt_devs )
448
+ return ;
449
+
450
+ for (i = 0 ; * name ; i ++ , name ++ )
451
+ pm_runtime_put (drv -> cpus [cpu ].virt_devs [i ]);
452
+ }
453
+
427
454
static int qcom_cpufreq_probe (struct platform_device * pdev )
428
455
{
429
456
struct qcom_cpufreq_drv * drv ;
@@ -478,6 +505,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
478
505
of_node_put (np );
479
506
480
507
for_each_possible_cpu (cpu ) {
508
+ struct device * * virt_devs = NULL ;
481
509
struct dev_pm_opp_config config = {
482
510
.supported_hw = NULL ,
483
511
};
@@ -498,7 +526,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
498
526
499
527
if (drv -> data -> genpd_names ) {
500
528
config .genpd_names = drv -> data -> genpd_names ;
501
- config .virt_devs = NULL ;
529
+ config .virt_devs = & virt_devs ;
502
530
}
503
531
504
532
if (config .supported_hw || config .genpd_names ) {
@@ -509,6 +537,27 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
509
537
goto free_opp ;
510
538
}
511
539
}
540
+
541
+ if (virt_devs ) {
542
+ const char * const * name = config .genpd_names ;
543
+ int i , j ;
544
+
545
+ for (i = 0 ; * name ; i ++ , name ++ ) {
546
+ ret = pm_runtime_resume_and_get (virt_devs [i ]);
547
+ if (ret ) {
548
+ dev_err (cpu_dev , "failed to resume %s: %d\n" ,
549
+ * name , ret );
550
+
551
+ /* Rollback previous PM runtime calls */
552
+ name = config .genpd_names ;
553
+ for (j = 0 ; * name && j < i ; j ++ , name ++ )
554
+ pm_runtime_put (virt_devs [j ]);
555
+
556
+ goto free_opp ;
557
+ }
558
+ }
559
+ drv -> cpus [cpu ].virt_devs = virt_devs ;
560
+ }
512
561
}
513
562
514
563
cpufreq_dt_pdev = platform_device_register_simple ("cpufreq-dt" , -1 ,
@@ -522,8 +571,10 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
522
571
dev_err (cpu_dev , "Failed to register platform device\n" );
523
572
524
573
free_opp :
525
- for_each_possible_cpu (cpu )
574
+ for_each_possible_cpu (cpu ) {
575
+ qcom_cpufreq_put_virt_devs (drv , cpu );
526
576
dev_pm_opp_clear_config (drv -> cpus [cpu ].opp_token );
577
+ }
527
578
return ret ;
528
579
}
529
580
@@ -534,15 +585,31 @@ static void qcom_cpufreq_remove(struct platform_device *pdev)
534
585
535
586
platform_device_unregister (cpufreq_dt_pdev );
536
587
537
- for_each_possible_cpu (cpu )
588
+ for_each_possible_cpu (cpu ) {
589
+ qcom_cpufreq_put_virt_devs (drv , cpu );
538
590
dev_pm_opp_clear_config (drv -> cpus [cpu ].opp_token );
591
+ }
539
592
}
540
593
594
+ static int qcom_cpufreq_suspend (struct device * dev )
595
+ {
596
+ struct qcom_cpufreq_drv * drv = dev_get_drvdata (dev );
597
+ unsigned int cpu ;
598
+
599
+ for_each_possible_cpu (cpu )
600
+ qcom_cpufreq_suspend_virt_devs (drv , cpu );
601
+
602
+ return 0 ;
603
+ }
604
+
605
+ static DEFINE_SIMPLE_DEV_PM_OPS (qcom_cpufreq_pm_ops , qcom_cpufreq_suspend , NULL) ;
606
+
541
607
static struct platform_driver qcom_cpufreq_driver = {
542
608
.probe = qcom_cpufreq_probe ,
543
609
.remove_new = qcom_cpufreq_remove ,
544
610
.driver = {
545
611
.name = "qcom-cpufreq-nvmem" ,
612
+ .pm = pm_sleep_ptr (& qcom_cpufreq_pm_ops ),
546
613
},
547
614
};
548
615
0 commit comments