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 21DEFINE_SPINLOCK(lock); 22 23static struct clk *pxa_clocks[CLK_MAX]; 24static struct clk_onecell_data onecell_data = { 25 .clks = pxa_clocks, 26 .clk_num = CLK_MAX, 27}; 28 29struct 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 39static 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 53static struct clk_ops cken_rate_ops = { 54 .recalc_rate = cken_recalc_rate, 55}; 56 57static 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 66static struct clk_ops cken_mux_ops = { 67 .get_parent = cken_get_parent, 68 .set_parent = dummy_clk_set_parent, 69}; 70 71void __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 80int __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 105void __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