1 /* 2 * System Control and Power Interface (SCPI) based CPUFreq Interface driver 3 * 4 * It provides necessary ops to arm_big_little cpufreq driver. 5 * 6 * Copyright (C) 2015 ARM Ltd. 7 * Sudeep Holla <sudeep.holla@arm.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 14 * kind, whether express or implied; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21 #include <linux/cpu.h> 22 #include <linux/cpufreq.h> 23 #include <linux/module.h> 24 #include <linux/platform_device.h> 25 #include <linux/pm_opp.h> 26 #include <linux/scpi_protocol.h> 27 #include <linux/types.h> 28 29 #include "arm_big_little.h" 30 31 static struct scpi_ops *scpi_ops; 32 33 static int scpi_get_transition_latency(struct device *cpu_dev) 34 { 35 return scpi_ops->get_transition_latency(cpu_dev); 36 } 37 38 static int scpi_init_opp_table(const struct cpumask *cpumask) 39 { 40 int ret; 41 struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask)); 42 43 ret = scpi_ops->add_opps_to_device(cpu_dev); 44 if (ret) { 45 dev_warn(cpu_dev, "failed to add opps to the device\n"); 46 return ret; 47 } 48 49 ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask); 50 if (ret) 51 dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", 52 __func__, ret); 53 return ret; 54 } 55 56 static const struct cpufreq_arm_bL_ops scpi_cpufreq_ops = { 57 .name = "scpi", 58 .get_transition_latency = scpi_get_transition_latency, 59 .init_opp_table = scpi_init_opp_table, 60 .free_opp_table = dev_pm_opp_cpumask_remove_table, 61 }; 62 63 static int scpi_cpufreq_probe(struct platform_device *pdev) 64 { 65 scpi_ops = get_scpi_ops(); 66 if (!scpi_ops) 67 return -EIO; 68 69 return bL_cpufreq_register(&scpi_cpufreq_ops); 70 } 71 72 static int scpi_cpufreq_remove(struct platform_device *pdev) 73 { 74 bL_cpufreq_unregister(&scpi_cpufreq_ops); 75 scpi_ops = NULL; 76 return 0; 77 } 78 79 static struct platform_driver scpi_cpufreq_platdrv = { 80 .driver = { 81 .name = "scpi-cpufreq", 82 }, 83 .probe = scpi_cpufreq_probe, 84 .remove = scpi_cpufreq_remove, 85 }; 86 module_platform_driver(scpi_cpufreq_platdrv); 87 88 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 89 MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver"); 90 MODULE_LICENSE("GPL v2"); 91