1 /* 2 * Marvell PXA family clocks 3 * 4 * Copyright (C) 2014 Robert Jarzmik 5 * 6 * Common clock code for PXA clocks ("CKEN" type clocks + DT) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 */ 13 #include <linux/clk.h> 14 #include <linux/clk-provider.h> 15 #include <linux/clkdev.h> 16 #include <linux/of.h> 17 18 #include <dt-bindings/clock/pxa-clock.h> 19 #include "clk-pxa.h" 20 21 DEFINE_SPINLOCK(lock); 22 23 static struct clk *pxa_clocks[CLK_MAX]; 24 static struct clk_onecell_data onecell_data = { 25 .clks = pxa_clocks, 26 .clk_num = CLK_MAX, 27 }; 28 29 #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk_cken, hw) 30 31 static unsigned long cken_recalc_rate(struct clk_hw *hw, 32 unsigned long parent_rate) 33 { 34 struct pxa_clk_cken *pclk = to_pxa_clk(hw); 35 struct clk_fixed_factor *fix; 36 37 if (!pclk->is_in_low_power || pclk->is_in_low_power()) 38 fix = &pclk->lp; 39 else 40 fix = &pclk->hp; 41 fix->hw.clk = hw->clk; 42 return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); 43 } 44 45 static struct clk_ops cken_rate_ops = { 46 .recalc_rate = cken_recalc_rate, 47 }; 48 49 static u8 cken_get_parent(struct clk_hw *hw) 50 { 51 struct pxa_clk_cken *pclk = to_pxa_clk(hw); 52 53 if (!pclk->is_in_low_power) 54 return 0; 55 return pclk->is_in_low_power() ? 0 : 1; 56 } 57 58 static struct clk_ops cken_mux_ops = { 59 .get_parent = cken_get_parent, 60 .set_parent = dummy_clk_set_parent, 61 }; 62 63 void __init clkdev_pxa_register(int ckid, const char *con_id, 64 const char *dev_id, struct clk *clk) 65 { 66 if (!IS_ERR(clk) && (ckid != CLK_NONE)) 67 pxa_clocks[ckid] = clk; 68 if (!IS_ERR(clk)) 69 clk_register_clkdev(clk, con_id, dev_id); 70 } 71 72 int __init clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks) 73 { 74 int i; 75 struct pxa_clk_cken *pclk; 76 struct clk *clk; 77 78 for (i = 0; i < nb_clks; i++) { 79 pclk = clks + i; 80 pclk->gate.lock = &lock; 81 clk = clk_register_composite(NULL, pclk->name, 82 pclk->parent_names, 2, 83 &pclk->hw, &cken_mux_ops, 84 &pclk->hw, &cken_rate_ops, 85 &pclk->gate.hw, &clk_gate_ops, 86 pclk->flags); 87 clkdev_pxa_register(pclk->ckid, pclk->con_id, pclk->dev_id, 88 clk); 89 } 90 return 0; 91 } 92 93 static void __init pxa_dt_clocks_init(struct device_node *np) 94 { 95 of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); 96 } 97 CLK_OF_DECLARE(pxa_clks, "marvell,pxa-clocks", pxa_dt_clocks_init); 98