1*a245fecbSHeiko Stübner /* 2*a245fecbSHeiko Stübner * Copyright (c) 2014 MundoReader S.L. 3*a245fecbSHeiko Stübner * Author: Heiko Stuebner <heiko@sntech.de> 4*a245fecbSHeiko Stübner * 5*a245fecbSHeiko Stübner * based on 6*a245fecbSHeiko Stübner * 7*a245fecbSHeiko Stübner * samsung/clk.c 8*a245fecbSHeiko Stübner * Copyright (c) 2013 Samsung Electronics Co., Ltd. 9*a245fecbSHeiko Stübner * Copyright (c) 2013 Linaro Ltd. 10*a245fecbSHeiko Stübner * Author: Thomas Abraham <thomas.ab@samsung.com> 11*a245fecbSHeiko Stübner * 12*a245fecbSHeiko Stübner * This program is free software; you can redistribute it and/or modify 13*a245fecbSHeiko Stübner * it under the terms of the GNU General Public License as published by 14*a245fecbSHeiko Stübner * the Free Software Foundation; either version 2 of the License, or 15*a245fecbSHeiko Stübner * (at your option) any later version. 16*a245fecbSHeiko Stübner * 17*a245fecbSHeiko Stübner * This program is distributed in the hope that it will be useful, 18*a245fecbSHeiko Stübner * but WITHOUT ANY WARRANTY; without even the implied warranty of 19*a245fecbSHeiko Stübner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20*a245fecbSHeiko Stübner * GNU General Public License for more details. 21*a245fecbSHeiko Stübner */ 22*a245fecbSHeiko Stübner 23*a245fecbSHeiko Stübner #include <linux/slab.h> 24*a245fecbSHeiko Stübner #include <linux/clk.h> 25*a245fecbSHeiko Stübner #include <linux/clk-provider.h> 26*a245fecbSHeiko Stübner #include "clk.h" 27*a245fecbSHeiko Stübner 28*a245fecbSHeiko Stübner /** 29*a245fecbSHeiko Stübner * Register a clock branch. 30*a245fecbSHeiko Stübner * Most clock branches have a form like 31*a245fecbSHeiko Stübner * 32*a245fecbSHeiko Stübner * src1 --|--\ 33*a245fecbSHeiko Stübner * |M |--[GATE]-[DIV]- 34*a245fecbSHeiko Stübner * src2 --|--/ 35*a245fecbSHeiko Stübner * 36*a245fecbSHeiko Stübner * sometimes without one of those components. 37*a245fecbSHeiko Stübner */ 38*a245fecbSHeiko Stübner struct clk *rockchip_clk_register_branch(const char *name, 39*a245fecbSHeiko Stübner const char **parent_names, u8 num_parents, void __iomem *base, 40*a245fecbSHeiko Stübner int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, 41*a245fecbSHeiko Stübner u8 div_shift, u8 div_width, u8 div_flags, 42*a245fecbSHeiko Stübner struct clk_div_table *div_table, int gate_offset, 43*a245fecbSHeiko Stübner u8 gate_shift, u8 gate_flags, unsigned long flags, 44*a245fecbSHeiko Stübner spinlock_t *lock) 45*a245fecbSHeiko Stübner { 46*a245fecbSHeiko Stübner struct clk *clk; 47*a245fecbSHeiko Stübner struct clk_mux *mux = NULL; 48*a245fecbSHeiko Stübner struct clk_gate *gate = NULL; 49*a245fecbSHeiko Stübner struct clk_divider *div = NULL; 50*a245fecbSHeiko Stübner const struct clk_ops *mux_ops = NULL, *div_ops = NULL, 51*a245fecbSHeiko Stübner *gate_ops = NULL; 52*a245fecbSHeiko Stübner 53*a245fecbSHeiko Stübner if (num_parents > 1) { 54*a245fecbSHeiko Stübner mux = kzalloc(sizeof(*mux), GFP_KERNEL); 55*a245fecbSHeiko Stübner if (!mux) 56*a245fecbSHeiko Stübner return ERR_PTR(-ENOMEM); 57*a245fecbSHeiko Stübner 58*a245fecbSHeiko Stübner mux->reg = base + muxdiv_offset; 59*a245fecbSHeiko Stübner mux->shift = mux_shift; 60*a245fecbSHeiko Stübner mux->mask = BIT(mux_width) - 1; 61*a245fecbSHeiko Stübner mux->flags = mux_flags; 62*a245fecbSHeiko Stübner mux->lock = lock; 63*a245fecbSHeiko Stübner mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops 64*a245fecbSHeiko Stübner : &clk_mux_ops; 65*a245fecbSHeiko Stübner } 66*a245fecbSHeiko Stübner 67*a245fecbSHeiko Stübner if (gate_offset >= 0) { 68*a245fecbSHeiko Stübner gate = kzalloc(sizeof(*gate), GFP_KERNEL); 69*a245fecbSHeiko Stübner if (!gate) 70*a245fecbSHeiko Stübner return ERR_PTR(-ENOMEM); 71*a245fecbSHeiko Stübner 72*a245fecbSHeiko Stübner gate->flags = gate_flags; 73*a245fecbSHeiko Stübner gate->reg = base + gate_offset; 74*a245fecbSHeiko Stübner gate->bit_idx = gate_shift; 75*a245fecbSHeiko Stübner gate->lock = lock; 76*a245fecbSHeiko Stübner gate_ops = &clk_gate_ops; 77*a245fecbSHeiko Stübner } 78*a245fecbSHeiko Stübner 79*a245fecbSHeiko Stübner if (div_width > 0) { 80*a245fecbSHeiko Stübner div = kzalloc(sizeof(*div), GFP_KERNEL); 81*a245fecbSHeiko Stübner if (!div) 82*a245fecbSHeiko Stübner return ERR_PTR(-ENOMEM); 83*a245fecbSHeiko Stübner 84*a245fecbSHeiko Stübner div->flags = div_flags; 85*a245fecbSHeiko Stübner div->reg = base + muxdiv_offset; 86*a245fecbSHeiko Stübner div->shift = div_shift; 87*a245fecbSHeiko Stübner div->width = div_width; 88*a245fecbSHeiko Stübner div->lock = lock; 89*a245fecbSHeiko Stübner div->table = div_table; 90*a245fecbSHeiko Stübner div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) 91*a245fecbSHeiko Stübner ? &clk_divider_ro_ops 92*a245fecbSHeiko Stübner : &clk_divider_ops; 93*a245fecbSHeiko Stübner } 94*a245fecbSHeiko Stübner 95*a245fecbSHeiko Stübner clk = clk_register_composite(NULL, name, parent_names, num_parents, 96*a245fecbSHeiko Stübner mux ? &mux->hw : NULL, mux_ops, 97*a245fecbSHeiko Stübner div ? &div->hw : NULL, div_ops, 98*a245fecbSHeiko Stübner gate ? &gate->hw : NULL, gate_ops, 99*a245fecbSHeiko Stübner flags); 100*a245fecbSHeiko Stübner 101*a245fecbSHeiko Stübner return clk; 102*a245fecbSHeiko Stübner } 103*a245fecbSHeiko Stübner 104*a245fecbSHeiko Stübner static DEFINE_SPINLOCK(clk_lock); 105*a245fecbSHeiko Stübner static struct clk **clk_table; 106*a245fecbSHeiko Stübner static void __iomem *reg_base; 107*a245fecbSHeiko Stübner static struct clk_onecell_data clk_data; 108*a245fecbSHeiko Stübner 109*a245fecbSHeiko Stübner void __init rockchip_clk_init(struct device_node *np, void __iomem *base, 110*a245fecbSHeiko Stübner unsigned long nr_clks) 111*a245fecbSHeiko Stübner { 112*a245fecbSHeiko Stübner reg_base = base; 113*a245fecbSHeiko Stübner 114*a245fecbSHeiko Stübner clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); 115*a245fecbSHeiko Stübner if (!clk_table) 116*a245fecbSHeiko Stübner pr_err("%s: could not allocate clock lookup table\n", __func__); 117*a245fecbSHeiko Stübner 118*a245fecbSHeiko Stübner clk_data.clks = clk_table; 119*a245fecbSHeiko Stübner clk_data.clk_num = nr_clks; 120*a245fecbSHeiko Stübner of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 121*a245fecbSHeiko Stübner } 122*a245fecbSHeiko Stübner 123*a245fecbSHeiko Stübner void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) 124*a245fecbSHeiko Stübner { 125*a245fecbSHeiko Stübner if (clk_table && id) 126*a245fecbSHeiko Stübner clk_table[id] = clk; 127*a245fecbSHeiko Stübner } 128*a245fecbSHeiko Stübner 129*a245fecbSHeiko Stübner void __init rockchip_clk_register_branches( 130*a245fecbSHeiko Stübner struct rockchip_clk_branch *list, 131*a245fecbSHeiko Stübner unsigned int nr_clk) 132*a245fecbSHeiko Stübner { 133*a245fecbSHeiko Stübner struct clk *clk = NULL; 134*a245fecbSHeiko Stübner unsigned int idx; 135*a245fecbSHeiko Stübner unsigned long flags; 136*a245fecbSHeiko Stübner 137*a245fecbSHeiko Stübner for (idx = 0; idx < nr_clk; idx++, list++) { 138*a245fecbSHeiko Stübner flags = list->flags; 139*a245fecbSHeiko Stübner 140*a245fecbSHeiko Stübner /* catch simple muxes */ 141*a245fecbSHeiko Stübner switch (list->branch_type) { 142*a245fecbSHeiko Stübner case branch_mux: 143*a245fecbSHeiko Stübner clk = clk_register_mux(NULL, list->name, 144*a245fecbSHeiko Stübner list->parent_names, list->num_parents, 145*a245fecbSHeiko Stübner flags, reg_base + list->muxdiv_offset, 146*a245fecbSHeiko Stübner list->mux_shift, list->mux_width, 147*a245fecbSHeiko Stübner list->mux_flags, &clk_lock); 148*a245fecbSHeiko Stübner break; 149*a245fecbSHeiko Stübner case branch_divider: 150*a245fecbSHeiko Stübner if (list->div_table) 151*a245fecbSHeiko Stübner clk = clk_register_divider_table(NULL, 152*a245fecbSHeiko Stübner list->name, list->parent_names[0], 153*a245fecbSHeiko Stübner flags, reg_base + list->muxdiv_offset, 154*a245fecbSHeiko Stübner list->div_shift, list->div_width, 155*a245fecbSHeiko Stübner list->div_flags, list->div_table, 156*a245fecbSHeiko Stübner &clk_lock); 157*a245fecbSHeiko Stübner else 158*a245fecbSHeiko Stübner clk = clk_register_divider(NULL, list->name, 159*a245fecbSHeiko Stübner list->parent_names[0], flags, 160*a245fecbSHeiko Stübner reg_base + list->muxdiv_offset, 161*a245fecbSHeiko Stübner list->div_shift, list->div_width, 162*a245fecbSHeiko Stübner list->div_flags, &clk_lock); 163*a245fecbSHeiko Stübner break; 164*a245fecbSHeiko Stübner case branch_fraction_divider: 165*a245fecbSHeiko Stübner /* unimplemented */ 166*a245fecbSHeiko Stübner continue; 167*a245fecbSHeiko Stübner break; 168*a245fecbSHeiko Stübner case branch_gate: 169*a245fecbSHeiko Stübner flags |= CLK_SET_RATE_PARENT; 170*a245fecbSHeiko Stübner 171*a245fecbSHeiko Stübner /* keep all gates untouched for now */ 172*a245fecbSHeiko Stübner flags |= CLK_IGNORE_UNUSED; 173*a245fecbSHeiko Stübner 174*a245fecbSHeiko Stübner clk = clk_register_gate(NULL, list->name, 175*a245fecbSHeiko Stübner list->parent_names[0], flags, 176*a245fecbSHeiko Stübner reg_base + list->gate_offset, 177*a245fecbSHeiko Stübner list->gate_shift, list->gate_flags, &clk_lock); 178*a245fecbSHeiko Stübner break; 179*a245fecbSHeiko Stübner case branch_composite: 180*a245fecbSHeiko Stübner /* keep all gates untouched for now */ 181*a245fecbSHeiko Stübner flags |= CLK_IGNORE_UNUSED; 182*a245fecbSHeiko Stübner 183*a245fecbSHeiko Stübner clk = rockchip_clk_register_branch(list->name, 184*a245fecbSHeiko Stübner list->parent_names, list->num_parents, 185*a245fecbSHeiko Stübner reg_base, list->muxdiv_offset, list->mux_shift, 186*a245fecbSHeiko Stübner list->mux_width, list->mux_flags, 187*a245fecbSHeiko Stübner list->div_shift, list->div_width, 188*a245fecbSHeiko Stübner list->div_flags, list->div_table, 189*a245fecbSHeiko Stübner list->gate_offset, list->gate_shift, 190*a245fecbSHeiko Stübner list->gate_flags, flags, &clk_lock); 191*a245fecbSHeiko Stübner break; 192*a245fecbSHeiko Stübner } 193*a245fecbSHeiko Stübner 194*a245fecbSHeiko Stübner /* none of the cases above matched */ 195*a245fecbSHeiko Stübner if (!clk) { 196*a245fecbSHeiko Stübner pr_err("%s: unknown clock type %d\n", 197*a245fecbSHeiko Stübner __func__, list->branch_type); 198*a245fecbSHeiko Stübner continue; 199*a245fecbSHeiko Stübner } 200*a245fecbSHeiko Stübner 201*a245fecbSHeiko Stübner if (IS_ERR(clk)) { 202*a245fecbSHeiko Stübner pr_err("%s: failed to register clock %s: %ld\n", 203*a245fecbSHeiko Stübner __func__, list->name, PTR_ERR(clk)); 204*a245fecbSHeiko Stübner continue; 205*a245fecbSHeiko Stübner } 206*a245fecbSHeiko Stübner 207*a245fecbSHeiko Stübner rockchip_clk_add_lookup(clk, list->id); 208*a245fecbSHeiko Stübner } 209*a245fecbSHeiko Stübner } 210