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 struct pxa_clk { 30 struct clk_hw hw; 31 struct clk_fixed_factor lp; 32 struct clk_fixed_factor hp; 33 struct clk_gate gate; 34 bool (*is_in_low_power)(void); 35 }; 36 37 #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk, hw) 38 39 static unsigned long cken_recalc_rate(struct clk_hw *hw, 40 unsigned long parent_rate) 41 { 42 struct pxa_clk *pclk = to_pxa_clk(hw); 43 struct clk_fixed_factor *fix; 44 45 if (!pclk->is_in_low_power || pclk->is_in_low_power()) 46 fix = &pclk->lp; 47 else 48 fix = &pclk->hp; 49 __clk_hw_set_clk(&fix->hw, hw); 50 return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); 51 } 52 53 static struct clk_ops cken_rate_ops = { 54 .recalc_rate = cken_recalc_rate, 55 }; 56 57 static u8 cken_get_parent(struct clk_hw *hw) 58 { 59 struct pxa_clk *pclk = to_pxa_clk(hw); 60 61 if (!pclk->is_in_low_power) 62 return 0; 63 return pclk->is_in_low_power() ? 0 : 1; 64 } 65 66 static struct clk_ops cken_mux_ops = { 67 .get_parent = cken_get_parent, 68 .set_parent = dummy_clk_set_parent, 69 }; 70 71 void __init clkdev_pxa_register(int ckid, const char *con_id, 72 const char *dev_id, struct clk *clk) 73 { 74 if (!IS_ERR(clk) && (ckid != CLK_NONE)) 75 pxa_clocks[ckid] = clk; 76 if (!IS_ERR(clk)) 77 clk_register_clkdev(clk, con_id, dev_id); 78 } 79 80 int __init clk_pxa_cken_init(const struct desc_clk_cken *clks, int nb_clks) 81 { 82 int i; 83 struct pxa_clk *pxa_clk; 84 struct clk *clk; 85 86 for (i = 0; i < nb_clks; i++) { 87 pxa_clk = kzalloc(sizeof(*pxa_clk), GFP_KERNEL); 88 pxa_clk->is_in_low_power = clks[i].is_in_low_power; 89 pxa_clk->lp = clks[i].lp; 90 pxa_clk->hp = clks[i].hp; 91 pxa_clk->gate = clks[i].gate; 92 pxa_clk->gate.lock = &lock; 93 clk = clk_register_composite(NULL, clks[i].name, 94 clks[i].parent_names, 2, 95 &pxa_clk->hw, &cken_mux_ops, 96 &pxa_clk->hw, &cken_rate_ops, 97 &pxa_clk->gate.hw, &clk_gate_ops, 98 clks[i].flags); 99 clkdev_pxa_register(clks[i].ckid, clks[i].con_id, 100 clks[i].dev_id, clk); 101 } 102 return 0; 103 } 104 105 void __init clk_pxa_dt_common_init(struct device_node *np) 106 { 107 of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); 108 } 109