aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-vexpress/spc.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c
index de0ca3615c36..3532e26c9117 100644
--- a/arch/arm/mach-vexpress/spc.c
+++ b/arch/arm/mach-vexpress/spc.c
@@ -17,6 +17,9 @@
17 * GNU General Public License for more details. 17 * GNU General Public License for more details.
18 */ 18 */
19 19
20#include <linux/clk-provider.h>
21#include <linux/clkdev.h>
22#include <linux/cpu.h>
20#include <linux/delay.h> 23#include <linux/delay.h>
21#include <linux/err.h> 24#include <linux/err.h>
22#include <linux/interrupt.h> 25#include <linux/interrupt.h>
@@ -438,3 +441,102 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq)
438 441
439 return 0; 442 return 0;
440} 443}
444
445struct clk_spc {
446 struct clk_hw hw;
447 int cluster;
448};
449
450#define to_clk_spc(spc) container_of(spc, struct clk_spc, hw)
451static unsigned long spc_recalc_rate(struct clk_hw *hw,
452 unsigned long parent_rate)
453{
454 struct clk_spc *spc = to_clk_spc(hw);
455 u32 freq;
456
457 if (ve_spc_get_performance(spc->cluster, &freq))
458 return -EIO;
459
460 return freq * 1000;
461}
462
463static long spc_round_rate(struct clk_hw *hw, unsigned long drate,
464 unsigned long *parent_rate)
465{
466 struct clk_spc *spc = to_clk_spc(hw);
467
468 return ve_spc_round_performance(spc->cluster, drate);
469}
470
471static int spc_set_rate(struct clk_hw *hw, unsigned long rate,
472 unsigned long parent_rate)
473{
474 struct clk_spc *spc = to_clk_spc(hw);
475
476 return ve_spc_set_performance(spc->cluster, rate / 1000);
477}
478
479static struct clk_ops clk_spc_ops = {
480 .recalc_rate = spc_recalc_rate,
481 .round_rate = spc_round_rate,
482 .set_rate = spc_set_rate,
483};
484
485static struct clk *ve_spc_clk_register(struct device *cpu_dev)
486{
487 struct clk_init_data init;
488 struct clk_spc *spc;
489
490 spc = kzalloc(sizeof(*spc), GFP_KERNEL);
491 if (!spc) {
492 pr_err("could not allocate spc clk\n");
493 return ERR_PTR(-ENOMEM);
494 }
495
496 spc->hw.init = &init;
497 spc->cluster = topology_physical_package_id(cpu_dev->id);
498
499 init.name = dev_name(cpu_dev);
500 init.ops = &clk_spc_ops;
501 init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE;
502 init.num_parents = 0;
503
504 return devm_clk_register(cpu_dev, &spc->hw);
505}
506
507static int __init ve_spc_clk_init(void)
508{
509 int cpu;
510 struct clk *clk;
511
512 if (!info)
513 return 0; /* Continue only if SPC is initialised */
514
515 if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) {
516 pr_err("failed to build OPP table\n");
517 return -ENODEV;
518 }
519
520 for_each_possible_cpu(cpu) {
521 struct device *cpu_dev = get_cpu_device(cpu);
522 if (!cpu_dev) {
523 pr_warn("failed to get cpu%d device\n", cpu);
524 continue;
525 }
526 clk = ve_spc_clk_register(cpu_dev);
527 if (IS_ERR(clk)) {
528 pr_warn("failed to register cpu%d clock\n", cpu);
529 continue;
530 }
531 if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) {
532 pr_warn("failed to register cpu%d clock lookup\n", cpu);
533 continue;
534 }
535
536 if (ve_init_opp_table(cpu_dev))
537 pr_warn("failed to initialise cpu%d opp table\n", cpu);
538 }
539
540 return 0;
541}
542module_init(ve_spc_clk_init);