1*94885fafSGabriel FERNANDEZ /* 2*94885fafSGabriel FERNANDEZ * clkgen-mux.c: ST GEN-MUX Clock driver 3*94885fafSGabriel FERNANDEZ * 4*94885fafSGabriel FERNANDEZ * Copyright (C) 2014 STMicroelectronics (R&D) Limited 5*94885fafSGabriel FERNANDEZ * 6*94885fafSGabriel FERNANDEZ * Authors: Stephen Gallimore <stephen.gallimore@st.com> 7*94885fafSGabriel FERNANDEZ * Pankaj Dev <pankaj.dev@st.com> 8*94885fafSGabriel FERNANDEZ * 9*94885fafSGabriel FERNANDEZ * This program is free software; you can redistribute it and/or modify 10*94885fafSGabriel FERNANDEZ * it under the terms of the GNU General Public License as published by 11*94885fafSGabriel FERNANDEZ * the Free Software Foundation; either version 2 of the License, or 12*94885fafSGabriel FERNANDEZ * (at your option) any later version. 13*94885fafSGabriel FERNANDEZ * 14*94885fafSGabriel FERNANDEZ */ 15*94885fafSGabriel FERNANDEZ 16*94885fafSGabriel FERNANDEZ #include <linux/slab.h> 17*94885fafSGabriel FERNANDEZ #include <linux/of_address.h> 18*94885fafSGabriel FERNANDEZ #include <linux/clk-provider.h> 19*94885fafSGabriel FERNANDEZ 20*94885fafSGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgena_divmux_lock); 21*94885fafSGabriel FERNANDEZ 22*94885fafSGabriel FERNANDEZ static const char ** __init clkgen_mux_get_parents(struct device_node *np, 23*94885fafSGabriel FERNANDEZ int *num_parents) 24*94885fafSGabriel FERNANDEZ { 25*94885fafSGabriel FERNANDEZ const char **parents; 26*94885fafSGabriel FERNANDEZ int nparents, i; 27*94885fafSGabriel FERNANDEZ 28*94885fafSGabriel FERNANDEZ nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); 29*94885fafSGabriel FERNANDEZ if (WARN_ON(nparents <= 0)) 30*94885fafSGabriel FERNANDEZ return ERR_PTR(-EINVAL); 31*94885fafSGabriel FERNANDEZ 32*94885fafSGabriel FERNANDEZ parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL); 33*94885fafSGabriel FERNANDEZ if (!parents) 34*94885fafSGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 35*94885fafSGabriel FERNANDEZ 36*94885fafSGabriel FERNANDEZ for (i = 0; i < nparents; i++) 37*94885fafSGabriel FERNANDEZ parents[i] = of_clk_get_parent_name(np, i); 38*94885fafSGabriel FERNANDEZ 39*94885fafSGabriel FERNANDEZ *num_parents = nparents; 40*94885fafSGabriel FERNANDEZ return parents; 41*94885fafSGabriel FERNANDEZ } 42*94885fafSGabriel FERNANDEZ 43*94885fafSGabriel FERNANDEZ /** 44*94885fafSGabriel FERNANDEZ * DOC: Clock mux with a programmable divider on each of its three inputs. 45*94885fafSGabriel FERNANDEZ * The mux has an input setting which effectively gates its output. 46*94885fafSGabriel FERNANDEZ * 47*94885fafSGabriel FERNANDEZ * Traits of this clock: 48*94885fafSGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 49*94885fafSGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional & control gating 50*94885fafSGabriel FERNANDEZ * rate - set rate is supported 51*94885fafSGabriel FERNANDEZ * parent - set/get parent 52*94885fafSGabriel FERNANDEZ */ 53*94885fafSGabriel FERNANDEZ 54*94885fafSGabriel FERNANDEZ #define NUM_INPUTS 3 55*94885fafSGabriel FERNANDEZ 56*94885fafSGabriel FERNANDEZ struct clkgena_divmux { 57*94885fafSGabriel FERNANDEZ struct clk_hw hw; 58*94885fafSGabriel FERNANDEZ /* Subclassed mux and divider structures */ 59*94885fafSGabriel FERNANDEZ struct clk_mux mux; 60*94885fafSGabriel FERNANDEZ struct clk_divider div[NUM_INPUTS]; 61*94885fafSGabriel FERNANDEZ /* Enable/running feedback register bits for each input */ 62*94885fafSGabriel FERNANDEZ void __iomem *feedback_reg[NUM_INPUTS]; 63*94885fafSGabriel FERNANDEZ int feedback_bit_idx; 64*94885fafSGabriel FERNANDEZ 65*94885fafSGabriel FERNANDEZ u8 muxsel; 66*94885fafSGabriel FERNANDEZ }; 67*94885fafSGabriel FERNANDEZ 68*94885fafSGabriel FERNANDEZ #define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw) 69*94885fafSGabriel FERNANDEZ 70*94885fafSGabriel FERNANDEZ struct clkgena_divmux_data { 71*94885fafSGabriel FERNANDEZ int num_outputs; 72*94885fafSGabriel FERNANDEZ int mux_offset; 73*94885fafSGabriel FERNANDEZ int mux_offset2; 74*94885fafSGabriel FERNANDEZ int mux_start_bit; 75*94885fafSGabriel FERNANDEZ int div_offsets[NUM_INPUTS]; 76*94885fafSGabriel FERNANDEZ int fb_offsets[NUM_INPUTS]; 77*94885fafSGabriel FERNANDEZ int fb_start_bit_idx; 78*94885fafSGabriel FERNANDEZ }; 79*94885fafSGabriel FERNANDEZ 80*94885fafSGabriel FERNANDEZ #define CKGAX_CLKOPSRC_SWITCH_OFF 0x3 81*94885fafSGabriel FERNANDEZ 82*94885fafSGabriel FERNANDEZ static int clkgena_divmux_is_running(struct clkgena_divmux *mux) 83*94885fafSGabriel FERNANDEZ { 84*94885fafSGabriel FERNANDEZ u32 regval = readl(mux->feedback_reg[mux->muxsel]); 85*94885fafSGabriel FERNANDEZ u32 running = regval & BIT(mux->feedback_bit_idx); 86*94885fafSGabriel FERNANDEZ return !!running; 87*94885fafSGabriel FERNANDEZ } 88*94885fafSGabriel FERNANDEZ 89*94885fafSGabriel FERNANDEZ static int clkgena_divmux_enable(struct clk_hw *hw) 90*94885fafSGabriel FERNANDEZ { 91*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 92*94885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 93*94885fafSGabriel FERNANDEZ unsigned long timeout; 94*94885fafSGabriel FERNANDEZ int ret = 0; 95*94885fafSGabriel FERNANDEZ 96*94885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 97*94885fafSGabriel FERNANDEZ 98*94885fafSGabriel FERNANDEZ ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel); 99*94885fafSGabriel FERNANDEZ if (ret) 100*94885fafSGabriel FERNANDEZ return ret; 101*94885fafSGabriel FERNANDEZ 102*94885fafSGabriel FERNANDEZ timeout = jiffies + msecs_to_jiffies(10); 103*94885fafSGabriel FERNANDEZ 104*94885fafSGabriel FERNANDEZ while (!clkgena_divmux_is_running(genamux)) { 105*94885fafSGabriel FERNANDEZ if (time_after(jiffies, timeout)) 106*94885fafSGabriel FERNANDEZ return -ETIMEDOUT; 107*94885fafSGabriel FERNANDEZ cpu_relax(); 108*94885fafSGabriel FERNANDEZ } 109*94885fafSGabriel FERNANDEZ 110*94885fafSGabriel FERNANDEZ return 0; 111*94885fafSGabriel FERNANDEZ } 112*94885fafSGabriel FERNANDEZ 113*94885fafSGabriel FERNANDEZ static void clkgena_divmux_disable(struct clk_hw *hw) 114*94885fafSGabriel FERNANDEZ { 115*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 116*94885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 117*94885fafSGabriel FERNANDEZ 118*94885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 119*94885fafSGabriel FERNANDEZ 120*94885fafSGabriel FERNANDEZ clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF); 121*94885fafSGabriel FERNANDEZ } 122*94885fafSGabriel FERNANDEZ 123*94885fafSGabriel FERNANDEZ static int clkgena_divmux_is_enabled(struct clk_hw *hw) 124*94885fafSGabriel FERNANDEZ { 125*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 126*94885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 127*94885fafSGabriel FERNANDEZ 128*94885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 129*94885fafSGabriel FERNANDEZ 130*94885fafSGabriel FERNANDEZ return (s8)clk_mux_ops.get_parent(mux_hw) > 0; 131*94885fafSGabriel FERNANDEZ } 132*94885fafSGabriel FERNANDEZ 133*94885fafSGabriel FERNANDEZ u8 clkgena_divmux_get_parent(struct clk_hw *hw) 134*94885fafSGabriel FERNANDEZ { 135*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 136*94885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 137*94885fafSGabriel FERNANDEZ 138*94885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 139*94885fafSGabriel FERNANDEZ 140*94885fafSGabriel FERNANDEZ genamux->muxsel = clk_mux_ops.get_parent(mux_hw); 141*94885fafSGabriel FERNANDEZ if ((s8)genamux->muxsel < 0) { 142*94885fafSGabriel FERNANDEZ pr_debug("%s: %s: Invalid parent, setting to default.\n", 143*94885fafSGabriel FERNANDEZ __func__, __clk_get_name(hw->clk)); 144*94885fafSGabriel FERNANDEZ genamux->muxsel = 0; 145*94885fafSGabriel FERNANDEZ } 146*94885fafSGabriel FERNANDEZ 147*94885fafSGabriel FERNANDEZ return genamux->muxsel; 148*94885fafSGabriel FERNANDEZ } 149*94885fafSGabriel FERNANDEZ 150*94885fafSGabriel FERNANDEZ static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index) 151*94885fafSGabriel FERNANDEZ { 152*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 153*94885fafSGabriel FERNANDEZ 154*94885fafSGabriel FERNANDEZ if (index >= CKGAX_CLKOPSRC_SWITCH_OFF) 155*94885fafSGabriel FERNANDEZ return -EINVAL; 156*94885fafSGabriel FERNANDEZ 157*94885fafSGabriel FERNANDEZ genamux->muxsel = index; 158*94885fafSGabriel FERNANDEZ 159*94885fafSGabriel FERNANDEZ /* 160*94885fafSGabriel FERNANDEZ * If the mux is already enabled, call enable directly to set the 161*94885fafSGabriel FERNANDEZ * new mux position and wait for it to start running again. Otherwise 162*94885fafSGabriel FERNANDEZ * do nothing. 163*94885fafSGabriel FERNANDEZ */ 164*94885fafSGabriel FERNANDEZ if (clkgena_divmux_is_enabled(hw)) 165*94885fafSGabriel FERNANDEZ clkgena_divmux_enable(hw); 166*94885fafSGabriel FERNANDEZ 167*94885fafSGabriel FERNANDEZ return 0; 168*94885fafSGabriel FERNANDEZ } 169*94885fafSGabriel FERNANDEZ 170*94885fafSGabriel FERNANDEZ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw, 171*94885fafSGabriel FERNANDEZ unsigned long parent_rate) 172*94885fafSGabriel FERNANDEZ { 173*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 174*94885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 175*94885fafSGabriel FERNANDEZ 176*94885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 177*94885fafSGabriel FERNANDEZ 178*94885fafSGabriel FERNANDEZ return clk_divider_ops.recalc_rate(div_hw, parent_rate); 179*94885fafSGabriel FERNANDEZ } 180*94885fafSGabriel FERNANDEZ 181*94885fafSGabriel FERNANDEZ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate, 182*94885fafSGabriel FERNANDEZ unsigned long parent_rate) 183*94885fafSGabriel FERNANDEZ { 184*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 185*94885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 186*94885fafSGabriel FERNANDEZ 187*94885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 188*94885fafSGabriel FERNANDEZ 189*94885fafSGabriel FERNANDEZ return clk_divider_ops.set_rate(div_hw, rate, parent_rate); 190*94885fafSGabriel FERNANDEZ } 191*94885fafSGabriel FERNANDEZ 192*94885fafSGabriel FERNANDEZ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate, 193*94885fafSGabriel FERNANDEZ unsigned long *prate) 194*94885fafSGabriel FERNANDEZ { 195*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 196*94885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 197*94885fafSGabriel FERNANDEZ 198*94885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 199*94885fafSGabriel FERNANDEZ 200*94885fafSGabriel FERNANDEZ return clk_divider_ops.round_rate(div_hw, rate, prate); 201*94885fafSGabriel FERNANDEZ } 202*94885fafSGabriel FERNANDEZ 203*94885fafSGabriel FERNANDEZ static const struct clk_ops clkgena_divmux_ops = { 204*94885fafSGabriel FERNANDEZ .enable = clkgena_divmux_enable, 205*94885fafSGabriel FERNANDEZ .disable = clkgena_divmux_disable, 206*94885fafSGabriel FERNANDEZ .is_enabled = clkgena_divmux_is_enabled, 207*94885fafSGabriel FERNANDEZ .get_parent = clkgena_divmux_get_parent, 208*94885fafSGabriel FERNANDEZ .set_parent = clkgena_divmux_set_parent, 209*94885fafSGabriel FERNANDEZ .round_rate = clkgena_divmux_round_rate, 210*94885fafSGabriel FERNANDEZ .recalc_rate = clkgena_divmux_recalc_rate, 211*94885fafSGabriel FERNANDEZ .set_rate = clkgena_divmux_set_rate, 212*94885fafSGabriel FERNANDEZ }; 213*94885fafSGabriel FERNANDEZ 214*94885fafSGabriel FERNANDEZ /** 215*94885fafSGabriel FERNANDEZ * clk_register_genamux - register a genamux clock with the clock framework 216*94885fafSGabriel FERNANDEZ */ 217*94885fafSGabriel FERNANDEZ struct clk *clk_register_genamux(const char *name, 218*94885fafSGabriel FERNANDEZ const char **parent_names, u8 num_parents, 219*94885fafSGabriel FERNANDEZ void __iomem *reg, 220*94885fafSGabriel FERNANDEZ const struct clkgena_divmux_data *muxdata, 221*94885fafSGabriel FERNANDEZ u32 idx) 222*94885fafSGabriel FERNANDEZ { 223*94885fafSGabriel FERNANDEZ /* 224*94885fafSGabriel FERNANDEZ * Fixed constants across all ClockgenA variants 225*94885fafSGabriel FERNANDEZ */ 226*94885fafSGabriel FERNANDEZ const int mux_width = 2; 227*94885fafSGabriel FERNANDEZ const int divider_width = 5; 228*94885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux; 229*94885fafSGabriel FERNANDEZ struct clk *clk; 230*94885fafSGabriel FERNANDEZ struct clk_init_data init; 231*94885fafSGabriel FERNANDEZ int i; 232*94885fafSGabriel FERNANDEZ 233*94885fafSGabriel FERNANDEZ genamux = kzalloc(sizeof(*genamux), GFP_KERNEL); 234*94885fafSGabriel FERNANDEZ if (!genamux) 235*94885fafSGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 236*94885fafSGabriel FERNANDEZ 237*94885fafSGabriel FERNANDEZ init.name = name; 238*94885fafSGabriel FERNANDEZ init.ops = &clkgena_divmux_ops; 239*94885fafSGabriel FERNANDEZ init.flags = CLK_IS_BASIC; 240*94885fafSGabriel FERNANDEZ init.parent_names = parent_names; 241*94885fafSGabriel FERNANDEZ init.num_parents = num_parents; 242*94885fafSGabriel FERNANDEZ 243*94885fafSGabriel FERNANDEZ genamux->mux.lock = &clkgena_divmux_lock; 244*94885fafSGabriel FERNANDEZ genamux->mux.mask = BIT(mux_width) - 1; 245*94885fafSGabriel FERNANDEZ genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width); 246*94885fafSGabriel FERNANDEZ if (genamux->mux.shift > 31) { 247*94885fafSGabriel FERNANDEZ /* 248*94885fafSGabriel FERNANDEZ * We have spilled into the second mux register so 249*94885fafSGabriel FERNANDEZ * adjust the register address and the bit shift accordingly 250*94885fafSGabriel FERNANDEZ */ 251*94885fafSGabriel FERNANDEZ genamux->mux.reg = reg + muxdata->mux_offset2; 252*94885fafSGabriel FERNANDEZ genamux->mux.shift -= 32; 253*94885fafSGabriel FERNANDEZ } else { 254*94885fafSGabriel FERNANDEZ genamux->mux.reg = reg + muxdata->mux_offset; 255*94885fafSGabriel FERNANDEZ } 256*94885fafSGabriel FERNANDEZ 257*94885fafSGabriel FERNANDEZ for (i = 0; i < NUM_INPUTS; i++) { 258*94885fafSGabriel FERNANDEZ /* 259*94885fafSGabriel FERNANDEZ * Divider config for each input 260*94885fafSGabriel FERNANDEZ */ 261*94885fafSGabriel FERNANDEZ void __iomem *divbase = reg + muxdata->div_offsets[i]; 262*94885fafSGabriel FERNANDEZ genamux->div[i].width = divider_width; 263*94885fafSGabriel FERNANDEZ genamux->div[i].reg = divbase + (idx * sizeof(u32)); 264*94885fafSGabriel FERNANDEZ 265*94885fafSGabriel FERNANDEZ /* 266*94885fafSGabriel FERNANDEZ * Mux enabled/running feedback register for each input. 267*94885fafSGabriel FERNANDEZ */ 268*94885fafSGabriel FERNANDEZ genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i]; 269*94885fafSGabriel FERNANDEZ } 270*94885fafSGabriel FERNANDEZ 271*94885fafSGabriel FERNANDEZ genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx; 272*94885fafSGabriel FERNANDEZ genamux->hw.init = &init; 273*94885fafSGabriel FERNANDEZ 274*94885fafSGabriel FERNANDEZ clk = clk_register(NULL, &genamux->hw); 275*94885fafSGabriel FERNANDEZ if (IS_ERR(clk)) { 276*94885fafSGabriel FERNANDEZ kfree(genamux); 277*94885fafSGabriel FERNANDEZ goto err; 278*94885fafSGabriel FERNANDEZ } 279*94885fafSGabriel FERNANDEZ 280*94885fafSGabriel FERNANDEZ pr_debug("%s: parent %s rate %lu\n", 281*94885fafSGabriel FERNANDEZ __clk_get_name(clk), 282*94885fafSGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 283*94885fafSGabriel FERNANDEZ clk_get_rate(clk)); 284*94885fafSGabriel FERNANDEZ err: 285*94885fafSGabriel FERNANDEZ return clk; 286*94885fafSGabriel FERNANDEZ } 287*94885fafSGabriel FERNANDEZ 288*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65hs = { 289*94885fafSGabriel FERNANDEZ .num_outputs = 4, 290*94885fafSGabriel FERNANDEZ .mux_offset = 0x14, 291*94885fafSGabriel FERNANDEZ .mux_start_bit = 0, 292*94885fafSGabriel FERNANDEZ .div_offsets = { 0x800, 0x900, 0xb00 }, 293*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x18, 0x1c, 0x20 }, 294*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 0, 295*94885fafSGabriel FERNANDEZ }; 296*94885fafSGabriel FERNANDEZ 297*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65ls = { 298*94885fafSGabriel FERNANDEZ .num_outputs = 14, 299*94885fafSGabriel FERNANDEZ .mux_offset = 0x14, 300*94885fafSGabriel FERNANDEZ .mux_offset2 = 0x24, 301*94885fafSGabriel FERNANDEZ .mux_start_bit = 8, 302*94885fafSGabriel FERNANDEZ .div_offsets = { 0x810, 0xa10, 0xb10 }, 303*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x18, 0x1c, 0x20 }, 304*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 4, 305*94885fafSGabriel FERNANDEZ }; 306*94885fafSGabriel FERNANDEZ 307*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf0 = { 308*94885fafSGabriel FERNANDEZ .num_outputs = 8, 309*94885fafSGabriel FERNANDEZ .mux_offset = 0x1c, 310*94885fafSGabriel FERNANDEZ .mux_start_bit = 0, 311*94885fafSGabriel FERNANDEZ .div_offsets = { 0x800, 0x900, 0xa60 }, 312*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 313*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 0, 314*94885fafSGabriel FERNANDEZ }; 315*94885fafSGabriel FERNANDEZ 316*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf1 = { 317*94885fafSGabriel FERNANDEZ .num_outputs = 8, 318*94885fafSGabriel FERNANDEZ .mux_offset = 0x1c, 319*94885fafSGabriel FERNANDEZ .mux_start_bit = 16, 320*94885fafSGabriel FERNANDEZ .div_offsets = { 0x820, 0x980, 0xa80 }, 321*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 322*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 8, 323*94885fafSGabriel FERNANDEZ }; 324*94885fafSGabriel FERNANDEZ 325*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf2 = { 326*94885fafSGabriel FERNANDEZ .num_outputs = 8, 327*94885fafSGabriel FERNANDEZ .mux_offset = 0x20, 328*94885fafSGabriel FERNANDEZ .mux_start_bit = 0, 329*94885fafSGabriel FERNANDEZ .div_offsets = { 0x840, 0xa20, 0xb10 }, 330*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 331*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 16, 332*94885fafSGabriel FERNANDEZ }; 333*94885fafSGabriel FERNANDEZ 334*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf3 = { 335*94885fafSGabriel FERNANDEZ .num_outputs = 8, 336*94885fafSGabriel FERNANDEZ .mux_offset = 0x20, 337*94885fafSGabriel FERNANDEZ .mux_start_bit = 16, 338*94885fafSGabriel FERNANDEZ .div_offsets = { 0x860, 0xa40, 0xb30 }, 339*94885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 340*94885fafSGabriel FERNANDEZ .fb_start_bit_idx = 24, 341*94885fafSGabriel FERNANDEZ }; 342*94885fafSGabriel FERNANDEZ 343*94885fafSGabriel FERNANDEZ static struct of_device_id clkgena_divmux_of_match[] = { 344*94885fafSGabriel FERNANDEZ { 345*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c65-hs", 346*94885fafSGabriel FERNANDEZ .data = &st_divmux_c65hs, 347*94885fafSGabriel FERNANDEZ }, 348*94885fafSGabriel FERNANDEZ { 349*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c65-ls", 350*94885fafSGabriel FERNANDEZ .data = &st_divmux_c65ls, 351*94885fafSGabriel FERNANDEZ }, 352*94885fafSGabriel FERNANDEZ { 353*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf0", 354*94885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf0, 355*94885fafSGabriel FERNANDEZ }, 356*94885fafSGabriel FERNANDEZ { 357*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf1", 358*94885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf1, 359*94885fafSGabriel FERNANDEZ }, 360*94885fafSGabriel FERNANDEZ { 361*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf2", 362*94885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf2, 363*94885fafSGabriel FERNANDEZ }, 364*94885fafSGabriel FERNANDEZ { 365*94885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf3", 366*94885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf3, 367*94885fafSGabriel FERNANDEZ }, 368*94885fafSGabriel FERNANDEZ {} 369*94885fafSGabriel FERNANDEZ }; 370*94885fafSGabriel FERNANDEZ 371*94885fafSGabriel FERNANDEZ static void __iomem * __init clkgen_get_register_base( 372*94885fafSGabriel FERNANDEZ struct device_node *np) 373*94885fafSGabriel FERNANDEZ { 374*94885fafSGabriel FERNANDEZ struct device_node *pnode; 375*94885fafSGabriel FERNANDEZ void __iomem *reg = NULL; 376*94885fafSGabriel FERNANDEZ 377*94885fafSGabriel FERNANDEZ pnode = of_get_parent(np); 378*94885fafSGabriel FERNANDEZ if (!pnode) 379*94885fafSGabriel FERNANDEZ return NULL; 380*94885fafSGabriel FERNANDEZ 381*94885fafSGabriel FERNANDEZ reg = of_iomap(pnode, 0); 382*94885fafSGabriel FERNANDEZ 383*94885fafSGabriel FERNANDEZ of_node_put(pnode); 384*94885fafSGabriel FERNANDEZ return reg; 385*94885fafSGabriel FERNANDEZ } 386*94885fafSGabriel FERNANDEZ 387*94885fafSGabriel FERNANDEZ void __init st_of_clkgena_divmux_setup(struct device_node *np) 388*94885fafSGabriel FERNANDEZ { 389*94885fafSGabriel FERNANDEZ const struct of_device_id *match; 390*94885fafSGabriel FERNANDEZ const struct clkgena_divmux_data *data; 391*94885fafSGabriel FERNANDEZ struct clk_onecell_data *clk_data; 392*94885fafSGabriel FERNANDEZ void __iomem *reg; 393*94885fafSGabriel FERNANDEZ const char **parents; 394*94885fafSGabriel FERNANDEZ int num_parents = 0, i; 395*94885fafSGabriel FERNANDEZ 396*94885fafSGabriel FERNANDEZ match = of_match_node(clkgena_divmux_of_match, np); 397*94885fafSGabriel FERNANDEZ if (WARN_ON(!match)) 398*94885fafSGabriel FERNANDEZ return; 399*94885fafSGabriel FERNANDEZ 400*94885fafSGabriel FERNANDEZ data = (struct clkgena_divmux_data *)match->data; 401*94885fafSGabriel FERNANDEZ 402*94885fafSGabriel FERNANDEZ reg = clkgen_get_register_base(np); 403*94885fafSGabriel FERNANDEZ if (!reg) 404*94885fafSGabriel FERNANDEZ return; 405*94885fafSGabriel FERNANDEZ 406*94885fafSGabriel FERNANDEZ parents = clkgen_mux_get_parents(np, &num_parents); 407*94885fafSGabriel FERNANDEZ if (IS_ERR(parents)) 408*94885fafSGabriel FERNANDEZ return; 409*94885fafSGabriel FERNANDEZ 410*94885fafSGabriel FERNANDEZ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 411*94885fafSGabriel FERNANDEZ if (!clk_data) 412*94885fafSGabriel FERNANDEZ goto err; 413*94885fafSGabriel FERNANDEZ 414*94885fafSGabriel FERNANDEZ clk_data->clk_num = data->num_outputs; 415*94885fafSGabriel FERNANDEZ clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), 416*94885fafSGabriel FERNANDEZ GFP_KERNEL); 417*94885fafSGabriel FERNANDEZ 418*94885fafSGabriel FERNANDEZ if (!clk_data->clks) 419*94885fafSGabriel FERNANDEZ goto err; 420*94885fafSGabriel FERNANDEZ 421*94885fafSGabriel FERNANDEZ for (i = 0; i < clk_data->clk_num; i++) { 422*94885fafSGabriel FERNANDEZ struct clk *clk; 423*94885fafSGabriel FERNANDEZ const char *clk_name; 424*94885fafSGabriel FERNANDEZ 425*94885fafSGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 426*94885fafSGabriel FERNANDEZ i, &clk_name)) 427*94885fafSGabriel FERNANDEZ break; 428*94885fafSGabriel FERNANDEZ 429*94885fafSGabriel FERNANDEZ /* 430*94885fafSGabriel FERNANDEZ * If we read an empty clock name then the output is unused 431*94885fafSGabriel FERNANDEZ */ 432*94885fafSGabriel FERNANDEZ if (*clk_name == '\0') 433*94885fafSGabriel FERNANDEZ continue; 434*94885fafSGabriel FERNANDEZ 435*94885fafSGabriel FERNANDEZ clk = clk_register_genamux(clk_name, parents, num_parents, 436*94885fafSGabriel FERNANDEZ reg, data, i); 437*94885fafSGabriel FERNANDEZ 438*94885fafSGabriel FERNANDEZ if (IS_ERR(clk)) 439*94885fafSGabriel FERNANDEZ goto err; 440*94885fafSGabriel FERNANDEZ 441*94885fafSGabriel FERNANDEZ clk_data->clks[i] = clk; 442*94885fafSGabriel FERNANDEZ } 443*94885fafSGabriel FERNANDEZ 444*94885fafSGabriel FERNANDEZ kfree(parents); 445*94885fafSGabriel FERNANDEZ 446*94885fafSGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 447*94885fafSGabriel FERNANDEZ return; 448*94885fafSGabriel FERNANDEZ err: 449*94885fafSGabriel FERNANDEZ if (clk_data) 450*94885fafSGabriel FERNANDEZ kfree(clk_data->clks); 451*94885fafSGabriel FERNANDEZ 452*94885fafSGabriel FERNANDEZ kfree(clk_data); 453*94885fafSGabriel FERNANDEZ kfree(parents); 454*94885fafSGabriel FERNANDEZ } 455*94885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); 456*94885fafSGabriel FERNANDEZ 457*94885fafSGabriel FERNANDEZ struct clkgena_prediv_data { 458*94885fafSGabriel FERNANDEZ u32 offset; 459*94885fafSGabriel FERNANDEZ u8 shift; 460*94885fafSGabriel FERNANDEZ struct clk_div_table *table; 461*94885fafSGabriel FERNANDEZ }; 462*94885fafSGabriel FERNANDEZ 463*94885fafSGabriel FERNANDEZ static struct clk_div_table prediv_table16[] = { 464*94885fafSGabriel FERNANDEZ { .val = 0, .div = 1 }, 465*94885fafSGabriel FERNANDEZ { .val = 1, .div = 16 }, 466*94885fafSGabriel FERNANDEZ { .div = 0 }, 467*94885fafSGabriel FERNANDEZ }; 468*94885fafSGabriel FERNANDEZ 469*94885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c65_data = { 470*94885fafSGabriel FERNANDEZ .offset = 0x4c, 471*94885fafSGabriel FERNANDEZ .shift = 31, 472*94885fafSGabriel FERNANDEZ .table = prediv_table16, 473*94885fafSGabriel FERNANDEZ }; 474*94885fafSGabriel FERNANDEZ 475*94885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c32_data = { 476*94885fafSGabriel FERNANDEZ .offset = 0x50, 477*94885fafSGabriel FERNANDEZ .shift = 1, 478*94885fafSGabriel FERNANDEZ .table = prediv_table16, 479*94885fafSGabriel FERNANDEZ }; 480*94885fafSGabriel FERNANDEZ 481*94885fafSGabriel FERNANDEZ static struct of_device_id clkgena_prediv_of_match[] = { 482*94885fafSGabriel FERNANDEZ { .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data }, 483*94885fafSGabriel FERNANDEZ { .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data }, 484*94885fafSGabriel FERNANDEZ {} 485*94885fafSGabriel FERNANDEZ }; 486*94885fafSGabriel FERNANDEZ 487*94885fafSGabriel FERNANDEZ void __init st_of_clkgena_prediv_setup(struct device_node *np) 488*94885fafSGabriel FERNANDEZ { 489*94885fafSGabriel FERNANDEZ const struct of_device_id *match; 490*94885fafSGabriel FERNANDEZ void __iomem *reg; 491*94885fafSGabriel FERNANDEZ const char *parent_name, *clk_name; 492*94885fafSGabriel FERNANDEZ struct clk *clk; 493*94885fafSGabriel FERNANDEZ struct clkgena_prediv_data *data; 494*94885fafSGabriel FERNANDEZ 495*94885fafSGabriel FERNANDEZ match = of_match_node(clkgena_prediv_of_match, np); 496*94885fafSGabriel FERNANDEZ if (!match) { 497*94885fafSGabriel FERNANDEZ pr_err("%s: No matching data\n", __func__); 498*94885fafSGabriel FERNANDEZ return; 499*94885fafSGabriel FERNANDEZ } 500*94885fafSGabriel FERNANDEZ 501*94885fafSGabriel FERNANDEZ data = (struct clkgena_prediv_data *)match->data; 502*94885fafSGabriel FERNANDEZ 503*94885fafSGabriel FERNANDEZ reg = clkgen_get_register_base(np); 504*94885fafSGabriel FERNANDEZ if (!reg) 505*94885fafSGabriel FERNANDEZ return; 506*94885fafSGabriel FERNANDEZ 507*94885fafSGabriel FERNANDEZ parent_name = of_clk_get_parent_name(np, 0); 508*94885fafSGabriel FERNANDEZ if (!parent_name) 509*94885fafSGabriel FERNANDEZ return; 510*94885fafSGabriel FERNANDEZ 511*94885fafSGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 512*94885fafSGabriel FERNANDEZ 0, &clk_name)) 513*94885fafSGabriel FERNANDEZ return; 514*94885fafSGabriel FERNANDEZ 515*94885fafSGabriel FERNANDEZ clk = clk_register_divider_table(NULL, clk_name, parent_name, 0, 516*94885fafSGabriel FERNANDEZ reg + data->offset, data->shift, 1, 517*94885fafSGabriel FERNANDEZ 0, data->table, NULL); 518*94885fafSGabriel FERNANDEZ if (IS_ERR(clk)) 519*94885fafSGabriel FERNANDEZ return; 520*94885fafSGabriel FERNANDEZ 521*94885fafSGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_simple_get, clk); 522*94885fafSGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 523*94885fafSGabriel FERNANDEZ __clk_get_name(clk), 524*94885fafSGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 525*94885fafSGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 526*94885fafSGabriel FERNANDEZ 527*94885fafSGabriel FERNANDEZ return; 528*94885fafSGabriel FERNANDEZ } 529*94885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); 530