194885fafSGabriel FERNANDEZ /* 294885fafSGabriel FERNANDEZ * clkgen-mux.c: ST GEN-MUX Clock driver 394885fafSGabriel FERNANDEZ * 494885fafSGabriel FERNANDEZ * Copyright (C) 2014 STMicroelectronics (R&D) Limited 594885fafSGabriel FERNANDEZ * 694885fafSGabriel FERNANDEZ * Authors: Stephen Gallimore <stephen.gallimore@st.com> 794885fafSGabriel FERNANDEZ * Pankaj Dev <pankaj.dev@st.com> 894885fafSGabriel FERNANDEZ * 994885fafSGabriel FERNANDEZ * This program is free software; you can redistribute it and/or modify 1094885fafSGabriel FERNANDEZ * it under the terms of the GNU General Public License as published by 1194885fafSGabriel FERNANDEZ * the Free Software Foundation; either version 2 of the License, or 1294885fafSGabriel FERNANDEZ * (at your option) any later version. 1394885fafSGabriel FERNANDEZ * 1494885fafSGabriel FERNANDEZ */ 1594885fafSGabriel FERNANDEZ 1694885fafSGabriel FERNANDEZ #include <linux/slab.h> 1794885fafSGabriel FERNANDEZ #include <linux/of_address.h> 1894885fafSGabriel FERNANDEZ #include <linux/clk-provider.h> 1994885fafSGabriel FERNANDEZ 2094885fafSGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgena_divmux_lock); 21*44993d38SGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgenf_lock); 2294885fafSGabriel FERNANDEZ 2394885fafSGabriel FERNANDEZ static const char ** __init clkgen_mux_get_parents(struct device_node *np, 2494885fafSGabriel FERNANDEZ int *num_parents) 2594885fafSGabriel FERNANDEZ { 2694885fafSGabriel FERNANDEZ const char **parents; 2794885fafSGabriel FERNANDEZ int nparents, i; 2894885fafSGabriel FERNANDEZ 2994885fafSGabriel FERNANDEZ nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); 3094885fafSGabriel FERNANDEZ if (WARN_ON(nparents <= 0)) 3194885fafSGabriel FERNANDEZ return ERR_PTR(-EINVAL); 3294885fafSGabriel FERNANDEZ 3394885fafSGabriel FERNANDEZ parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL); 3494885fafSGabriel FERNANDEZ if (!parents) 3594885fafSGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 3694885fafSGabriel FERNANDEZ 3794885fafSGabriel FERNANDEZ for (i = 0; i < nparents; i++) 3894885fafSGabriel FERNANDEZ parents[i] = of_clk_get_parent_name(np, i); 3994885fafSGabriel FERNANDEZ 4094885fafSGabriel FERNANDEZ *num_parents = nparents; 4194885fafSGabriel FERNANDEZ return parents; 4294885fafSGabriel FERNANDEZ } 4394885fafSGabriel FERNANDEZ 4494885fafSGabriel FERNANDEZ /** 4594885fafSGabriel FERNANDEZ * DOC: Clock mux with a programmable divider on each of its three inputs. 4694885fafSGabriel FERNANDEZ * The mux has an input setting which effectively gates its output. 4794885fafSGabriel FERNANDEZ * 4894885fafSGabriel FERNANDEZ * Traits of this clock: 4994885fafSGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 5094885fafSGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional & control gating 5194885fafSGabriel FERNANDEZ * rate - set rate is supported 5294885fafSGabriel FERNANDEZ * parent - set/get parent 5394885fafSGabriel FERNANDEZ */ 5494885fafSGabriel FERNANDEZ 5594885fafSGabriel FERNANDEZ #define NUM_INPUTS 3 5694885fafSGabriel FERNANDEZ 5794885fafSGabriel FERNANDEZ struct clkgena_divmux { 5894885fafSGabriel FERNANDEZ struct clk_hw hw; 5994885fafSGabriel FERNANDEZ /* Subclassed mux and divider structures */ 6094885fafSGabriel FERNANDEZ struct clk_mux mux; 6194885fafSGabriel FERNANDEZ struct clk_divider div[NUM_INPUTS]; 6294885fafSGabriel FERNANDEZ /* Enable/running feedback register bits for each input */ 6394885fafSGabriel FERNANDEZ void __iomem *feedback_reg[NUM_INPUTS]; 6494885fafSGabriel FERNANDEZ int feedback_bit_idx; 6594885fafSGabriel FERNANDEZ 6694885fafSGabriel FERNANDEZ u8 muxsel; 6794885fafSGabriel FERNANDEZ }; 6894885fafSGabriel FERNANDEZ 6994885fafSGabriel FERNANDEZ #define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw) 7094885fafSGabriel FERNANDEZ 7194885fafSGabriel FERNANDEZ struct clkgena_divmux_data { 7294885fafSGabriel FERNANDEZ int num_outputs; 7394885fafSGabriel FERNANDEZ int mux_offset; 7494885fafSGabriel FERNANDEZ int mux_offset2; 7594885fafSGabriel FERNANDEZ int mux_start_bit; 7694885fafSGabriel FERNANDEZ int div_offsets[NUM_INPUTS]; 7794885fafSGabriel FERNANDEZ int fb_offsets[NUM_INPUTS]; 7894885fafSGabriel FERNANDEZ int fb_start_bit_idx; 7994885fafSGabriel FERNANDEZ }; 8094885fafSGabriel FERNANDEZ 8194885fafSGabriel FERNANDEZ #define CKGAX_CLKOPSRC_SWITCH_OFF 0x3 8294885fafSGabriel FERNANDEZ 8394885fafSGabriel FERNANDEZ static int clkgena_divmux_is_running(struct clkgena_divmux *mux) 8494885fafSGabriel FERNANDEZ { 8594885fafSGabriel FERNANDEZ u32 regval = readl(mux->feedback_reg[mux->muxsel]); 8694885fafSGabriel FERNANDEZ u32 running = regval & BIT(mux->feedback_bit_idx); 8794885fafSGabriel FERNANDEZ return !!running; 8894885fafSGabriel FERNANDEZ } 8994885fafSGabriel FERNANDEZ 9094885fafSGabriel FERNANDEZ static int clkgena_divmux_enable(struct clk_hw *hw) 9194885fafSGabriel FERNANDEZ { 9294885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 9394885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 9494885fafSGabriel FERNANDEZ unsigned long timeout; 9594885fafSGabriel FERNANDEZ int ret = 0; 9694885fafSGabriel FERNANDEZ 9794885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 9894885fafSGabriel FERNANDEZ 9994885fafSGabriel FERNANDEZ ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel); 10094885fafSGabriel FERNANDEZ if (ret) 10194885fafSGabriel FERNANDEZ return ret; 10294885fafSGabriel FERNANDEZ 10394885fafSGabriel FERNANDEZ timeout = jiffies + msecs_to_jiffies(10); 10494885fafSGabriel FERNANDEZ 10594885fafSGabriel FERNANDEZ while (!clkgena_divmux_is_running(genamux)) { 10694885fafSGabriel FERNANDEZ if (time_after(jiffies, timeout)) 10794885fafSGabriel FERNANDEZ return -ETIMEDOUT; 10894885fafSGabriel FERNANDEZ cpu_relax(); 10994885fafSGabriel FERNANDEZ } 11094885fafSGabriel FERNANDEZ 11194885fafSGabriel FERNANDEZ return 0; 11294885fafSGabriel FERNANDEZ } 11394885fafSGabriel FERNANDEZ 11494885fafSGabriel FERNANDEZ static void clkgena_divmux_disable(struct clk_hw *hw) 11594885fafSGabriel FERNANDEZ { 11694885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 11794885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 11894885fafSGabriel FERNANDEZ 11994885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 12094885fafSGabriel FERNANDEZ 12194885fafSGabriel FERNANDEZ clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF); 12294885fafSGabriel FERNANDEZ } 12394885fafSGabriel FERNANDEZ 12494885fafSGabriel FERNANDEZ static int clkgena_divmux_is_enabled(struct clk_hw *hw) 12594885fafSGabriel FERNANDEZ { 12694885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 12794885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 12894885fafSGabriel FERNANDEZ 12994885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 13094885fafSGabriel FERNANDEZ 13194885fafSGabriel FERNANDEZ return (s8)clk_mux_ops.get_parent(mux_hw) > 0; 13294885fafSGabriel FERNANDEZ } 13394885fafSGabriel FERNANDEZ 13494885fafSGabriel FERNANDEZ u8 clkgena_divmux_get_parent(struct clk_hw *hw) 13594885fafSGabriel FERNANDEZ { 13694885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 13794885fafSGabriel FERNANDEZ struct clk_hw *mux_hw = &genamux->mux.hw; 13894885fafSGabriel FERNANDEZ 13994885fafSGabriel FERNANDEZ mux_hw->clk = hw->clk; 14094885fafSGabriel FERNANDEZ 14194885fafSGabriel FERNANDEZ genamux->muxsel = clk_mux_ops.get_parent(mux_hw); 14294885fafSGabriel FERNANDEZ if ((s8)genamux->muxsel < 0) { 14394885fafSGabriel FERNANDEZ pr_debug("%s: %s: Invalid parent, setting to default.\n", 14494885fafSGabriel FERNANDEZ __func__, __clk_get_name(hw->clk)); 14594885fafSGabriel FERNANDEZ genamux->muxsel = 0; 14694885fafSGabriel FERNANDEZ } 14794885fafSGabriel FERNANDEZ 14894885fafSGabriel FERNANDEZ return genamux->muxsel; 14994885fafSGabriel FERNANDEZ } 15094885fafSGabriel FERNANDEZ 15194885fafSGabriel FERNANDEZ static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index) 15294885fafSGabriel FERNANDEZ { 15394885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 15494885fafSGabriel FERNANDEZ 15594885fafSGabriel FERNANDEZ if (index >= CKGAX_CLKOPSRC_SWITCH_OFF) 15694885fafSGabriel FERNANDEZ return -EINVAL; 15794885fafSGabriel FERNANDEZ 15894885fafSGabriel FERNANDEZ genamux->muxsel = index; 15994885fafSGabriel FERNANDEZ 16094885fafSGabriel FERNANDEZ /* 16194885fafSGabriel FERNANDEZ * If the mux is already enabled, call enable directly to set the 16294885fafSGabriel FERNANDEZ * new mux position and wait for it to start running again. Otherwise 16394885fafSGabriel FERNANDEZ * do nothing. 16494885fafSGabriel FERNANDEZ */ 16594885fafSGabriel FERNANDEZ if (clkgena_divmux_is_enabled(hw)) 16694885fafSGabriel FERNANDEZ clkgena_divmux_enable(hw); 16794885fafSGabriel FERNANDEZ 16894885fafSGabriel FERNANDEZ return 0; 16994885fafSGabriel FERNANDEZ } 17094885fafSGabriel FERNANDEZ 17194885fafSGabriel FERNANDEZ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw, 17294885fafSGabriel FERNANDEZ unsigned long parent_rate) 17394885fafSGabriel FERNANDEZ { 17494885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 17594885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 17694885fafSGabriel FERNANDEZ 17794885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 17894885fafSGabriel FERNANDEZ 17994885fafSGabriel FERNANDEZ return clk_divider_ops.recalc_rate(div_hw, parent_rate); 18094885fafSGabriel FERNANDEZ } 18194885fafSGabriel FERNANDEZ 18294885fafSGabriel FERNANDEZ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate, 18394885fafSGabriel FERNANDEZ unsigned long parent_rate) 18494885fafSGabriel FERNANDEZ { 18594885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 18694885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 18794885fafSGabriel FERNANDEZ 18894885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 18994885fafSGabriel FERNANDEZ 19094885fafSGabriel FERNANDEZ return clk_divider_ops.set_rate(div_hw, rate, parent_rate); 19194885fafSGabriel FERNANDEZ } 19294885fafSGabriel FERNANDEZ 19394885fafSGabriel FERNANDEZ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate, 19494885fafSGabriel FERNANDEZ unsigned long *prate) 19594885fafSGabriel FERNANDEZ { 19694885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux = to_clkgena_divmux(hw); 19794885fafSGabriel FERNANDEZ struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; 19894885fafSGabriel FERNANDEZ 19994885fafSGabriel FERNANDEZ div_hw->clk = hw->clk; 20094885fafSGabriel FERNANDEZ 20194885fafSGabriel FERNANDEZ return clk_divider_ops.round_rate(div_hw, rate, prate); 20294885fafSGabriel FERNANDEZ } 20394885fafSGabriel FERNANDEZ 20494885fafSGabriel FERNANDEZ static const struct clk_ops clkgena_divmux_ops = { 20594885fafSGabriel FERNANDEZ .enable = clkgena_divmux_enable, 20694885fafSGabriel FERNANDEZ .disable = clkgena_divmux_disable, 20794885fafSGabriel FERNANDEZ .is_enabled = clkgena_divmux_is_enabled, 20894885fafSGabriel FERNANDEZ .get_parent = clkgena_divmux_get_parent, 20994885fafSGabriel FERNANDEZ .set_parent = clkgena_divmux_set_parent, 21094885fafSGabriel FERNANDEZ .round_rate = clkgena_divmux_round_rate, 21194885fafSGabriel FERNANDEZ .recalc_rate = clkgena_divmux_recalc_rate, 21294885fafSGabriel FERNANDEZ .set_rate = clkgena_divmux_set_rate, 21394885fafSGabriel FERNANDEZ }; 21494885fafSGabriel FERNANDEZ 21594885fafSGabriel FERNANDEZ /** 21694885fafSGabriel FERNANDEZ * clk_register_genamux - register a genamux clock with the clock framework 21794885fafSGabriel FERNANDEZ */ 21894885fafSGabriel FERNANDEZ struct clk *clk_register_genamux(const char *name, 21994885fafSGabriel FERNANDEZ const char **parent_names, u8 num_parents, 22094885fafSGabriel FERNANDEZ void __iomem *reg, 22194885fafSGabriel FERNANDEZ const struct clkgena_divmux_data *muxdata, 22294885fafSGabriel FERNANDEZ u32 idx) 22394885fafSGabriel FERNANDEZ { 22494885fafSGabriel FERNANDEZ /* 22594885fafSGabriel FERNANDEZ * Fixed constants across all ClockgenA variants 22694885fafSGabriel FERNANDEZ */ 22794885fafSGabriel FERNANDEZ const int mux_width = 2; 22894885fafSGabriel FERNANDEZ const int divider_width = 5; 22994885fafSGabriel FERNANDEZ struct clkgena_divmux *genamux; 23094885fafSGabriel FERNANDEZ struct clk *clk; 23194885fafSGabriel FERNANDEZ struct clk_init_data init; 23294885fafSGabriel FERNANDEZ int i; 23394885fafSGabriel FERNANDEZ 23494885fafSGabriel FERNANDEZ genamux = kzalloc(sizeof(*genamux), GFP_KERNEL); 23594885fafSGabriel FERNANDEZ if (!genamux) 23694885fafSGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 23794885fafSGabriel FERNANDEZ 23894885fafSGabriel FERNANDEZ init.name = name; 23994885fafSGabriel FERNANDEZ init.ops = &clkgena_divmux_ops; 24094885fafSGabriel FERNANDEZ init.flags = CLK_IS_BASIC; 24194885fafSGabriel FERNANDEZ init.parent_names = parent_names; 24294885fafSGabriel FERNANDEZ init.num_parents = num_parents; 24394885fafSGabriel FERNANDEZ 24494885fafSGabriel FERNANDEZ genamux->mux.lock = &clkgena_divmux_lock; 24594885fafSGabriel FERNANDEZ genamux->mux.mask = BIT(mux_width) - 1; 24694885fafSGabriel FERNANDEZ genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width); 24794885fafSGabriel FERNANDEZ if (genamux->mux.shift > 31) { 24894885fafSGabriel FERNANDEZ /* 24994885fafSGabriel FERNANDEZ * We have spilled into the second mux register so 25094885fafSGabriel FERNANDEZ * adjust the register address and the bit shift accordingly 25194885fafSGabriel FERNANDEZ */ 25294885fafSGabriel FERNANDEZ genamux->mux.reg = reg + muxdata->mux_offset2; 25394885fafSGabriel FERNANDEZ genamux->mux.shift -= 32; 25494885fafSGabriel FERNANDEZ } else { 25594885fafSGabriel FERNANDEZ genamux->mux.reg = reg + muxdata->mux_offset; 25694885fafSGabriel FERNANDEZ } 25794885fafSGabriel FERNANDEZ 25894885fafSGabriel FERNANDEZ for (i = 0; i < NUM_INPUTS; i++) { 25994885fafSGabriel FERNANDEZ /* 26094885fafSGabriel FERNANDEZ * Divider config for each input 26194885fafSGabriel FERNANDEZ */ 26294885fafSGabriel FERNANDEZ void __iomem *divbase = reg + muxdata->div_offsets[i]; 26394885fafSGabriel FERNANDEZ genamux->div[i].width = divider_width; 26494885fafSGabriel FERNANDEZ genamux->div[i].reg = divbase + (idx * sizeof(u32)); 26594885fafSGabriel FERNANDEZ 26694885fafSGabriel FERNANDEZ /* 26794885fafSGabriel FERNANDEZ * Mux enabled/running feedback register for each input. 26894885fafSGabriel FERNANDEZ */ 26994885fafSGabriel FERNANDEZ genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i]; 27094885fafSGabriel FERNANDEZ } 27194885fafSGabriel FERNANDEZ 27294885fafSGabriel FERNANDEZ genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx; 27394885fafSGabriel FERNANDEZ genamux->hw.init = &init; 27494885fafSGabriel FERNANDEZ 27594885fafSGabriel FERNANDEZ clk = clk_register(NULL, &genamux->hw); 27694885fafSGabriel FERNANDEZ if (IS_ERR(clk)) { 27794885fafSGabriel FERNANDEZ kfree(genamux); 27894885fafSGabriel FERNANDEZ goto err; 27994885fafSGabriel FERNANDEZ } 28094885fafSGabriel FERNANDEZ 28194885fafSGabriel FERNANDEZ pr_debug("%s: parent %s rate %lu\n", 28294885fafSGabriel FERNANDEZ __clk_get_name(clk), 28394885fafSGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 28494885fafSGabriel FERNANDEZ clk_get_rate(clk)); 28594885fafSGabriel FERNANDEZ err: 28694885fafSGabriel FERNANDEZ return clk; 28794885fafSGabriel FERNANDEZ } 28894885fafSGabriel FERNANDEZ 28994885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65hs = { 29094885fafSGabriel FERNANDEZ .num_outputs = 4, 29194885fafSGabriel FERNANDEZ .mux_offset = 0x14, 29294885fafSGabriel FERNANDEZ .mux_start_bit = 0, 29394885fafSGabriel FERNANDEZ .div_offsets = { 0x800, 0x900, 0xb00 }, 29494885fafSGabriel FERNANDEZ .fb_offsets = { 0x18, 0x1c, 0x20 }, 29594885fafSGabriel FERNANDEZ .fb_start_bit_idx = 0, 29694885fafSGabriel FERNANDEZ }; 29794885fafSGabriel FERNANDEZ 29894885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65ls = { 29994885fafSGabriel FERNANDEZ .num_outputs = 14, 30094885fafSGabriel FERNANDEZ .mux_offset = 0x14, 30194885fafSGabriel FERNANDEZ .mux_offset2 = 0x24, 30294885fafSGabriel FERNANDEZ .mux_start_bit = 8, 30394885fafSGabriel FERNANDEZ .div_offsets = { 0x810, 0xa10, 0xb10 }, 30494885fafSGabriel FERNANDEZ .fb_offsets = { 0x18, 0x1c, 0x20 }, 30594885fafSGabriel FERNANDEZ .fb_start_bit_idx = 4, 30694885fafSGabriel FERNANDEZ }; 30794885fafSGabriel FERNANDEZ 30894885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf0 = { 30994885fafSGabriel FERNANDEZ .num_outputs = 8, 31094885fafSGabriel FERNANDEZ .mux_offset = 0x1c, 31194885fafSGabriel FERNANDEZ .mux_start_bit = 0, 31294885fafSGabriel FERNANDEZ .div_offsets = { 0x800, 0x900, 0xa60 }, 31394885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 31494885fafSGabriel FERNANDEZ .fb_start_bit_idx = 0, 31594885fafSGabriel FERNANDEZ }; 31694885fafSGabriel FERNANDEZ 31794885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf1 = { 31894885fafSGabriel FERNANDEZ .num_outputs = 8, 31994885fafSGabriel FERNANDEZ .mux_offset = 0x1c, 32094885fafSGabriel FERNANDEZ .mux_start_bit = 16, 32194885fafSGabriel FERNANDEZ .div_offsets = { 0x820, 0x980, 0xa80 }, 32294885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 32394885fafSGabriel FERNANDEZ .fb_start_bit_idx = 8, 32494885fafSGabriel FERNANDEZ }; 32594885fafSGabriel FERNANDEZ 32694885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf2 = { 32794885fafSGabriel FERNANDEZ .num_outputs = 8, 32894885fafSGabriel FERNANDEZ .mux_offset = 0x20, 32994885fafSGabriel FERNANDEZ .mux_start_bit = 0, 33094885fafSGabriel FERNANDEZ .div_offsets = { 0x840, 0xa20, 0xb10 }, 33194885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 33294885fafSGabriel FERNANDEZ .fb_start_bit_idx = 16, 33394885fafSGabriel FERNANDEZ }; 33494885fafSGabriel FERNANDEZ 33594885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf3 = { 33694885fafSGabriel FERNANDEZ .num_outputs = 8, 33794885fafSGabriel FERNANDEZ .mux_offset = 0x20, 33894885fafSGabriel FERNANDEZ .mux_start_bit = 16, 33994885fafSGabriel FERNANDEZ .div_offsets = { 0x860, 0xa40, 0xb30 }, 34094885fafSGabriel FERNANDEZ .fb_offsets = { 0x2c, 0x24, 0x28 }, 34194885fafSGabriel FERNANDEZ .fb_start_bit_idx = 24, 34294885fafSGabriel FERNANDEZ }; 34394885fafSGabriel FERNANDEZ 34494885fafSGabriel FERNANDEZ static struct of_device_id clkgena_divmux_of_match[] = { 34594885fafSGabriel FERNANDEZ { 34694885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c65-hs", 34794885fafSGabriel FERNANDEZ .data = &st_divmux_c65hs, 34894885fafSGabriel FERNANDEZ }, 34994885fafSGabriel FERNANDEZ { 35094885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c65-ls", 35194885fafSGabriel FERNANDEZ .data = &st_divmux_c65ls, 35294885fafSGabriel FERNANDEZ }, 35394885fafSGabriel FERNANDEZ { 35494885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf0", 35594885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf0, 35694885fafSGabriel FERNANDEZ }, 35794885fafSGabriel FERNANDEZ { 35894885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf1", 35994885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf1, 36094885fafSGabriel FERNANDEZ }, 36194885fafSGabriel FERNANDEZ { 36294885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf2", 36394885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf2, 36494885fafSGabriel FERNANDEZ }, 36594885fafSGabriel FERNANDEZ { 36694885fafSGabriel FERNANDEZ .compatible = "st,clkgena-divmux-c32-odf3", 36794885fafSGabriel FERNANDEZ .data = &st_divmux_c32odf3, 36894885fafSGabriel FERNANDEZ }, 36994885fafSGabriel FERNANDEZ {} 37094885fafSGabriel FERNANDEZ }; 37194885fafSGabriel FERNANDEZ 37294885fafSGabriel FERNANDEZ static void __iomem * __init clkgen_get_register_base( 37394885fafSGabriel FERNANDEZ struct device_node *np) 37494885fafSGabriel FERNANDEZ { 37594885fafSGabriel FERNANDEZ struct device_node *pnode; 37694885fafSGabriel FERNANDEZ void __iomem *reg = NULL; 37794885fafSGabriel FERNANDEZ 37894885fafSGabriel FERNANDEZ pnode = of_get_parent(np); 37994885fafSGabriel FERNANDEZ if (!pnode) 38094885fafSGabriel FERNANDEZ return NULL; 38194885fafSGabriel FERNANDEZ 38294885fafSGabriel FERNANDEZ reg = of_iomap(pnode, 0); 38394885fafSGabriel FERNANDEZ 38494885fafSGabriel FERNANDEZ of_node_put(pnode); 38594885fafSGabriel FERNANDEZ return reg; 38694885fafSGabriel FERNANDEZ } 38794885fafSGabriel FERNANDEZ 38894885fafSGabriel FERNANDEZ void __init st_of_clkgena_divmux_setup(struct device_node *np) 38994885fafSGabriel FERNANDEZ { 39094885fafSGabriel FERNANDEZ const struct of_device_id *match; 39194885fafSGabriel FERNANDEZ const struct clkgena_divmux_data *data; 39294885fafSGabriel FERNANDEZ struct clk_onecell_data *clk_data; 39394885fafSGabriel FERNANDEZ void __iomem *reg; 39494885fafSGabriel FERNANDEZ const char **parents; 39594885fafSGabriel FERNANDEZ int num_parents = 0, i; 39694885fafSGabriel FERNANDEZ 39794885fafSGabriel FERNANDEZ match = of_match_node(clkgena_divmux_of_match, np); 39894885fafSGabriel FERNANDEZ if (WARN_ON(!match)) 39994885fafSGabriel FERNANDEZ return; 40094885fafSGabriel FERNANDEZ 40194885fafSGabriel FERNANDEZ data = (struct clkgena_divmux_data *)match->data; 40294885fafSGabriel FERNANDEZ 40394885fafSGabriel FERNANDEZ reg = clkgen_get_register_base(np); 40494885fafSGabriel FERNANDEZ if (!reg) 40594885fafSGabriel FERNANDEZ return; 40694885fafSGabriel FERNANDEZ 40794885fafSGabriel FERNANDEZ parents = clkgen_mux_get_parents(np, &num_parents); 40894885fafSGabriel FERNANDEZ if (IS_ERR(parents)) 40994885fafSGabriel FERNANDEZ return; 41094885fafSGabriel FERNANDEZ 41194885fafSGabriel FERNANDEZ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 41294885fafSGabriel FERNANDEZ if (!clk_data) 41394885fafSGabriel FERNANDEZ goto err; 41494885fafSGabriel FERNANDEZ 41594885fafSGabriel FERNANDEZ clk_data->clk_num = data->num_outputs; 41694885fafSGabriel FERNANDEZ clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), 41794885fafSGabriel FERNANDEZ GFP_KERNEL); 41894885fafSGabriel FERNANDEZ 41994885fafSGabriel FERNANDEZ if (!clk_data->clks) 42094885fafSGabriel FERNANDEZ goto err; 42194885fafSGabriel FERNANDEZ 42294885fafSGabriel FERNANDEZ for (i = 0; i < clk_data->clk_num; i++) { 42394885fafSGabriel FERNANDEZ struct clk *clk; 42494885fafSGabriel FERNANDEZ const char *clk_name; 42594885fafSGabriel FERNANDEZ 42694885fafSGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 42794885fafSGabriel FERNANDEZ i, &clk_name)) 42894885fafSGabriel FERNANDEZ break; 42994885fafSGabriel FERNANDEZ 43094885fafSGabriel FERNANDEZ /* 43194885fafSGabriel FERNANDEZ * If we read an empty clock name then the output is unused 43294885fafSGabriel FERNANDEZ */ 43394885fafSGabriel FERNANDEZ if (*clk_name == '\0') 43494885fafSGabriel FERNANDEZ continue; 43594885fafSGabriel FERNANDEZ 43694885fafSGabriel FERNANDEZ clk = clk_register_genamux(clk_name, parents, num_parents, 43794885fafSGabriel FERNANDEZ reg, data, i); 43894885fafSGabriel FERNANDEZ 43994885fafSGabriel FERNANDEZ if (IS_ERR(clk)) 44094885fafSGabriel FERNANDEZ goto err; 44194885fafSGabriel FERNANDEZ 44294885fafSGabriel FERNANDEZ clk_data->clks[i] = clk; 44394885fafSGabriel FERNANDEZ } 44494885fafSGabriel FERNANDEZ 44594885fafSGabriel FERNANDEZ kfree(parents); 44694885fafSGabriel FERNANDEZ 44794885fafSGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 44894885fafSGabriel FERNANDEZ return; 44994885fafSGabriel FERNANDEZ err: 45094885fafSGabriel FERNANDEZ if (clk_data) 45194885fafSGabriel FERNANDEZ kfree(clk_data->clks); 45294885fafSGabriel FERNANDEZ 45394885fafSGabriel FERNANDEZ kfree(clk_data); 45494885fafSGabriel FERNANDEZ kfree(parents); 45594885fafSGabriel FERNANDEZ } 45694885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); 45794885fafSGabriel FERNANDEZ 45894885fafSGabriel FERNANDEZ struct clkgena_prediv_data { 45994885fafSGabriel FERNANDEZ u32 offset; 46094885fafSGabriel FERNANDEZ u8 shift; 46194885fafSGabriel FERNANDEZ struct clk_div_table *table; 46294885fafSGabriel FERNANDEZ }; 46394885fafSGabriel FERNANDEZ 46494885fafSGabriel FERNANDEZ static struct clk_div_table prediv_table16[] = { 46594885fafSGabriel FERNANDEZ { .val = 0, .div = 1 }, 46694885fafSGabriel FERNANDEZ { .val = 1, .div = 16 }, 46794885fafSGabriel FERNANDEZ { .div = 0 }, 46894885fafSGabriel FERNANDEZ }; 46994885fafSGabriel FERNANDEZ 47094885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c65_data = { 47194885fafSGabriel FERNANDEZ .offset = 0x4c, 47294885fafSGabriel FERNANDEZ .shift = 31, 47394885fafSGabriel FERNANDEZ .table = prediv_table16, 47494885fafSGabriel FERNANDEZ }; 47594885fafSGabriel FERNANDEZ 47694885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c32_data = { 47794885fafSGabriel FERNANDEZ .offset = 0x50, 47894885fafSGabriel FERNANDEZ .shift = 1, 47994885fafSGabriel FERNANDEZ .table = prediv_table16, 48094885fafSGabriel FERNANDEZ }; 48194885fafSGabriel FERNANDEZ 48294885fafSGabriel FERNANDEZ static struct of_device_id clkgena_prediv_of_match[] = { 48394885fafSGabriel FERNANDEZ { .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data }, 48494885fafSGabriel FERNANDEZ { .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data }, 48594885fafSGabriel FERNANDEZ {} 48694885fafSGabriel FERNANDEZ }; 48794885fafSGabriel FERNANDEZ 48894885fafSGabriel FERNANDEZ void __init st_of_clkgena_prediv_setup(struct device_node *np) 48994885fafSGabriel FERNANDEZ { 49094885fafSGabriel FERNANDEZ const struct of_device_id *match; 49194885fafSGabriel FERNANDEZ void __iomem *reg; 49294885fafSGabriel FERNANDEZ const char *parent_name, *clk_name; 49394885fafSGabriel FERNANDEZ struct clk *clk; 49494885fafSGabriel FERNANDEZ struct clkgena_prediv_data *data; 49594885fafSGabriel FERNANDEZ 49694885fafSGabriel FERNANDEZ match = of_match_node(clkgena_prediv_of_match, np); 49794885fafSGabriel FERNANDEZ if (!match) { 49894885fafSGabriel FERNANDEZ pr_err("%s: No matching data\n", __func__); 49994885fafSGabriel FERNANDEZ return; 50094885fafSGabriel FERNANDEZ } 50194885fafSGabriel FERNANDEZ 50294885fafSGabriel FERNANDEZ data = (struct clkgena_prediv_data *)match->data; 50394885fafSGabriel FERNANDEZ 50494885fafSGabriel FERNANDEZ reg = clkgen_get_register_base(np); 50594885fafSGabriel FERNANDEZ if (!reg) 50694885fafSGabriel FERNANDEZ return; 50794885fafSGabriel FERNANDEZ 50894885fafSGabriel FERNANDEZ parent_name = of_clk_get_parent_name(np, 0); 50994885fafSGabriel FERNANDEZ if (!parent_name) 51094885fafSGabriel FERNANDEZ return; 51194885fafSGabriel FERNANDEZ 51294885fafSGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 51394885fafSGabriel FERNANDEZ 0, &clk_name)) 51494885fafSGabriel FERNANDEZ return; 51594885fafSGabriel FERNANDEZ 51694885fafSGabriel FERNANDEZ clk = clk_register_divider_table(NULL, clk_name, parent_name, 0, 51794885fafSGabriel FERNANDEZ reg + data->offset, data->shift, 1, 51894885fafSGabriel FERNANDEZ 0, data->table, NULL); 51994885fafSGabriel FERNANDEZ if (IS_ERR(clk)) 52094885fafSGabriel FERNANDEZ return; 52194885fafSGabriel FERNANDEZ 52294885fafSGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_simple_get, clk); 52394885fafSGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 52494885fafSGabriel FERNANDEZ __clk_get_name(clk), 52594885fafSGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 52694885fafSGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 52794885fafSGabriel FERNANDEZ 52894885fafSGabriel FERNANDEZ return; 52994885fafSGabriel FERNANDEZ } 53094885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); 531*44993d38SGabriel FERNANDEZ 532*44993d38SGabriel FERNANDEZ struct clkgen_mux_data { 533*44993d38SGabriel FERNANDEZ u32 offset; 534*44993d38SGabriel FERNANDEZ u8 shift; 535*44993d38SGabriel FERNANDEZ u8 width; 536*44993d38SGabriel FERNANDEZ spinlock_t *lock; 537*44993d38SGabriel FERNANDEZ unsigned long clk_flags; 538*44993d38SGabriel FERNANDEZ u8 mux_flags; 539*44993d38SGabriel FERNANDEZ }; 540*44993d38SGabriel FERNANDEZ 541*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_c_vcc_hd_416 = { 542*44993d38SGabriel FERNANDEZ .offset = 0, 543*44993d38SGabriel FERNANDEZ .shift = 0, 544*44993d38SGabriel FERNANDEZ .width = 1, 545*44993d38SGabriel FERNANDEZ }; 546*44993d38SGabriel FERNANDEZ 547*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_fvdp_416 = { 548*44993d38SGabriel FERNANDEZ .offset = 0, 549*44993d38SGabriel FERNANDEZ .shift = 0, 550*44993d38SGabriel FERNANDEZ .width = 1, 551*44993d38SGabriel FERNANDEZ }; 552*44993d38SGabriel FERNANDEZ 553*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_hva_416 = { 554*44993d38SGabriel FERNANDEZ .offset = 0, 555*44993d38SGabriel FERNANDEZ .shift = 0, 556*44993d38SGabriel FERNANDEZ .width = 1, 557*44993d38SGabriel FERNANDEZ }; 558*44993d38SGabriel FERNANDEZ 559*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_hd_416 = { 560*44993d38SGabriel FERNANDEZ .offset = 0, 561*44993d38SGabriel FERNANDEZ .shift = 16, 562*44993d38SGabriel FERNANDEZ .width = 1, 563*44993d38SGabriel FERNANDEZ .lock = &clkgenf_lock, 564*44993d38SGabriel FERNANDEZ }; 565*44993d38SGabriel FERNANDEZ 566*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_c_vcc_sd_416 = { 567*44993d38SGabriel FERNANDEZ .offset = 0, 568*44993d38SGabriel FERNANDEZ .shift = 17, 569*44993d38SGabriel FERNANDEZ .width = 1, 570*44993d38SGabriel FERNANDEZ .lock = &clkgenf_lock, 571*44993d38SGabriel FERNANDEZ }; 572*44993d38SGabriel FERNANDEZ 573*44993d38SGabriel FERNANDEZ static struct of_device_id mux_of_match[] = { 574*44993d38SGabriel FERNANDEZ { 575*44993d38SGabriel FERNANDEZ .compatible = "st,stih416-clkgenc-vcc-hd", 576*44993d38SGabriel FERNANDEZ .data = &clkgen_mux_c_vcc_hd_416, 577*44993d38SGabriel FERNANDEZ }, 578*44993d38SGabriel FERNANDEZ { 579*44993d38SGabriel FERNANDEZ .compatible = "st,stih416-clkgenf-vcc-fvdp", 580*44993d38SGabriel FERNANDEZ .data = &clkgen_mux_f_vcc_fvdp_416, 581*44993d38SGabriel FERNANDEZ }, 582*44993d38SGabriel FERNANDEZ { 583*44993d38SGabriel FERNANDEZ .compatible = "st,stih416-clkgenf-vcc-hva", 584*44993d38SGabriel FERNANDEZ .data = &clkgen_mux_f_vcc_hva_416, 585*44993d38SGabriel FERNANDEZ }, 586*44993d38SGabriel FERNANDEZ { 587*44993d38SGabriel FERNANDEZ .compatible = "st,stih416-clkgenf-vcc-hd", 588*44993d38SGabriel FERNANDEZ .data = &clkgen_mux_f_vcc_hd_416, 589*44993d38SGabriel FERNANDEZ }, 590*44993d38SGabriel FERNANDEZ { 591*44993d38SGabriel FERNANDEZ .compatible = "st,stih416-clkgenf-vcc-sd", 592*44993d38SGabriel FERNANDEZ .data = &clkgen_mux_c_vcc_sd_416, 593*44993d38SGabriel FERNANDEZ }, 594*44993d38SGabriel FERNANDEZ {} 595*44993d38SGabriel FERNANDEZ }; 596*44993d38SGabriel FERNANDEZ 597*44993d38SGabriel FERNANDEZ void __init st_of_clkgen_mux_setup(struct device_node *np) 598*44993d38SGabriel FERNANDEZ { 599*44993d38SGabriel FERNANDEZ const struct of_device_id *match; 600*44993d38SGabriel FERNANDEZ struct clk *clk; 601*44993d38SGabriel FERNANDEZ void __iomem *reg; 602*44993d38SGabriel FERNANDEZ const char **parents; 603*44993d38SGabriel FERNANDEZ int num_parents; 604*44993d38SGabriel FERNANDEZ struct clkgen_mux_data *data; 605*44993d38SGabriel FERNANDEZ 606*44993d38SGabriel FERNANDEZ match = of_match_node(mux_of_match, np); 607*44993d38SGabriel FERNANDEZ if (!match) { 608*44993d38SGabriel FERNANDEZ pr_err("%s: No matching data\n", __func__); 609*44993d38SGabriel FERNANDEZ return; 610*44993d38SGabriel FERNANDEZ } 611*44993d38SGabriel FERNANDEZ 612*44993d38SGabriel FERNANDEZ data = (struct clkgen_mux_data *)match->data; 613*44993d38SGabriel FERNANDEZ 614*44993d38SGabriel FERNANDEZ reg = of_iomap(np, 0); 615*44993d38SGabriel FERNANDEZ if (!reg) { 616*44993d38SGabriel FERNANDEZ pr_err("%s: Failed to get base address\n", __func__); 617*44993d38SGabriel FERNANDEZ return; 618*44993d38SGabriel FERNANDEZ } 619*44993d38SGabriel FERNANDEZ 620*44993d38SGabriel FERNANDEZ parents = clkgen_mux_get_parents(np, &num_parents); 621*44993d38SGabriel FERNANDEZ if (IS_ERR(parents)) { 622*44993d38SGabriel FERNANDEZ pr_err("%s: Failed to get parents (%ld)\n", 623*44993d38SGabriel FERNANDEZ __func__, PTR_ERR(parents)); 624*44993d38SGabriel FERNANDEZ return; 625*44993d38SGabriel FERNANDEZ } 626*44993d38SGabriel FERNANDEZ 627*44993d38SGabriel FERNANDEZ clk = clk_register_mux(NULL, np->name, parents, num_parents, 628*44993d38SGabriel FERNANDEZ data->clk_flags | CLK_SET_RATE_PARENT, 629*44993d38SGabriel FERNANDEZ reg + data->offset, 630*44993d38SGabriel FERNANDEZ data->shift, data->width, data->mux_flags, 631*44993d38SGabriel FERNANDEZ data->lock); 632*44993d38SGabriel FERNANDEZ if (IS_ERR(clk)) 633*44993d38SGabriel FERNANDEZ goto err; 634*44993d38SGabriel FERNANDEZ 635*44993d38SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 636*44993d38SGabriel FERNANDEZ __clk_get_name(clk), 637*44993d38SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 638*44993d38SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 639*44993d38SGabriel FERNANDEZ 640*44993d38SGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_simple_get, clk); 641*44993d38SGabriel FERNANDEZ 642*44993d38SGabriel FERNANDEZ err: 643*44993d38SGabriel FERNANDEZ kfree(parents); 644*44993d38SGabriel FERNANDEZ 645*44993d38SGabriel FERNANDEZ return; 646*44993d38SGabriel FERNANDEZ } 647*44993d38SGabriel FERNANDEZ CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); 648*44993d38SGabriel FERNANDEZ 649*44993d38SGabriel FERNANDEZ #define VCC_MAX_CHANNELS 16 650*44993d38SGabriel FERNANDEZ 651*44993d38SGabriel FERNANDEZ #define VCC_GATE_OFFSET 0x0 652*44993d38SGabriel FERNANDEZ #define VCC_MUX_OFFSET 0x4 653*44993d38SGabriel FERNANDEZ #define VCC_DIV_OFFSET 0x8 654*44993d38SGabriel FERNANDEZ 655*44993d38SGabriel FERNANDEZ struct clkgen_vcc_data { 656*44993d38SGabriel FERNANDEZ spinlock_t *lock; 657*44993d38SGabriel FERNANDEZ unsigned long clk_flags; 658*44993d38SGabriel FERNANDEZ }; 659*44993d38SGabriel FERNANDEZ 660*44993d38SGabriel FERNANDEZ static struct clkgen_vcc_data st_clkgenc_vcc_416 = { 661*44993d38SGabriel FERNANDEZ .clk_flags = CLK_SET_RATE_PARENT, 662*44993d38SGabriel FERNANDEZ }; 663*44993d38SGabriel FERNANDEZ 664*44993d38SGabriel FERNANDEZ static struct clkgen_vcc_data st_clkgenf_vcc_416 = { 665*44993d38SGabriel FERNANDEZ .lock = &clkgenf_lock, 666*44993d38SGabriel FERNANDEZ }; 667*44993d38SGabriel FERNANDEZ 668*44993d38SGabriel FERNANDEZ static struct of_device_id vcc_of_match[] = { 669*44993d38SGabriel FERNANDEZ { .compatible = "st,stih416-clkgenc", .data = &st_clkgenc_vcc_416 }, 670*44993d38SGabriel FERNANDEZ { .compatible = "st,stih416-clkgenf", .data = &st_clkgenf_vcc_416 }, 671*44993d38SGabriel FERNANDEZ {} 672*44993d38SGabriel FERNANDEZ }; 673*44993d38SGabriel FERNANDEZ 674*44993d38SGabriel FERNANDEZ void __init st_of_clkgen_vcc_setup(struct device_node *np) 675*44993d38SGabriel FERNANDEZ { 676*44993d38SGabriel FERNANDEZ const struct of_device_id *match; 677*44993d38SGabriel FERNANDEZ void __iomem *reg; 678*44993d38SGabriel FERNANDEZ const char **parents; 679*44993d38SGabriel FERNANDEZ int num_parents, i; 680*44993d38SGabriel FERNANDEZ struct clk_onecell_data *clk_data; 681*44993d38SGabriel FERNANDEZ struct clkgen_vcc_data *data; 682*44993d38SGabriel FERNANDEZ 683*44993d38SGabriel FERNANDEZ match = of_match_node(vcc_of_match, np); 684*44993d38SGabriel FERNANDEZ if (WARN_ON(!match)) 685*44993d38SGabriel FERNANDEZ return; 686*44993d38SGabriel FERNANDEZ data = (struct clkgen_vcc_data *)match->data; 687*44993d38SGabriel FERNANDEZ 688*44993d38SGabriel FERNANDEZ reg = of_iomap(np, 0); 689*44993d38SGabriel FERNANDEZ if (!reg) 690*44993d38SGabriel FERNANDEZ return; 691*44993d38SGabriel FERNANDEZ 692*44993d38SGabriel FERNANDEZ parents = clkgen_mux_get_parents(np, &num_parents); 693*44993d38SGabriel FERNANDEZ if (IS_ERR(parents)) 694*44993d38SGabriel FERNANDEZ return; 695*44993d38SGabriel FERNANDEZ 696*44993d38SGabriel FERNANDEZ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 697*44993d38SGabriel FERNANDEZ if (!clk_data) 698*44993d38SGabriel FERNANDEZ goto err; 699*44993d38SGabriel FERNANDEZ 700*44993d38SGabriel FERNANDEZ clk_data->clk_num = VCC_MAX_CHANNELS; 701*44993d38SGabriel FERNANDEZ clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), 702*44993d38SGabriel FERNANDEZ GFP_KERNEL); 703*44993d38SGabriel FERNANDEZ 704*44993d38SGabriel FERNANDEZ if (!clk_data->clks) 705*44993d38SGabriel FERNANDEZ goto err; 706*44993d38SGabriel FERNANDEZ 707*44993d38SGabriel FERNANDEZ for (i = 0; i < clk_data->clk_num; i++) { 708*44993d38SGabriel FERNANDEZ struct clk *clk; 709*44993d38SGabriel FERNANDEZ const char *clk_name; 710*44993d38SGabriel FERNANDEZ struct clk_gate *gate; 711*44993d38SGabriel FERNANDEZ struct clk_divider *div; 712*44993d38SGabriel FERNANDEZ struct clk_mux *mux; 713*44993d38SGabriel FERNANDEZ 714*44993d38SGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 715*44993d38SGabriel FERNANDEZ i, &clk_name)) 716*44993d38SGabriel FERNANDEZ break; 717*44993d38SGabriel FERNANDEZ 718*44993d38SGabriel FERNANDEZ /* 719*44993d38SGabriel FERNANDEZ * If we read an empty clock name then the output is unused 720*44993d38SGabriel FERNANDEZ */ 721*44993d38SGabriel FERNANDEZ if (*clk_name == '\0') 722*44993d38SGabriel FERNANDEZ continue; 723*44993d38SGabriel FERNANDEZ 724*44993d38SGabriel FERNANDEZ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); 725*44993d38SGabriel FERNANDEZ if (!gate) 726*44993d38SGabriel FERNANDEZ break; 727*44993d38SGabriel FERNANDEZ 728*44993d38SGabriel FERNANDEZ div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); 729*44993d38SGabriel FERNANDEZ if (!div) { 730*44993d38SGabriel FERNANDEZ kfree(gate); 731*44993d38SGabriel FERNANDEZ break; 732*44993d38SGabriel FERNANDEZ } 733*44993d38SGabriel FERNANDEZ 734*44993d38SGabriel FERNANDEZ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); 735*44993d38SGabriel FERNANDEZ if (!mux) { 736*44993d38SGabriel FERNANDEZ kfree(gate); 737*44993d38SGabriel FERNANDEZ kfree(div); 738*44993d38SGabriel FERNANDEZ break; 739*44993d38SGabriel FERNANDEZ } 740*44993d38SGabriel FERNANDEZ 741*44993d38SGabriel FERNANDEZ gate->reg = reg + VCC_GATE_OFFSET; 742*44993d38SGabriel FERNANDEZ gate->bit_idx = i; 743*44993d38SGabriel FERNANDEZ gate->flags = CLK_GATE_SET_TO_DISABLE; 744*44993d38SGabriel FERNANDEZ gate->lock = data->lock; 745*44993d38SGabriel FERNANDEZ 746*44993d38SGabriel FERNANDEZ div->reg = reg + VCC_DIV_OFFSET; 747*44993d38SGabriel FERNANDEZ div->shift = 2 * i; 748*44993d38SGabriel FERNANDEZ div->width = 2; 749*44993d38SGabriel FERNANDEZ div->flags = CLK_DIVIDER_POWER_OF_TWO; 750*44993d38SGabriel FERNANDEZ 751*44993d38SGabriel FERNANDEZ mux->reg = reg + VCC_MUX_OFFSET; 752*44993d38SGabriel FERNANDEZ mux->shift = 2 * i; 753*44993d38SGabriel FERNANDEZ mux->mask = 0x3; 754*44993d38SGabriel FERNANDEZ 755*44993d38SGabriel FERNANDEZ clk = clk_register_composite(NULL, clk_name, parents, 756*44993d38SGabriel FERNANDEZ num_parents, 757*44993d38SGabriel FERNANDEZ &mux->hw, &clk_mux_ops, 758*44993d38SGabriel FERNANDEZ &div->hw, &clk_divider_ops, 759*44993d38SGabriel FERNANDEZ &gate->hw, &clk_gate_ops, 760*44993d38SGabriel FERNANDEZ data->clk_flags); 761*44993d38SGabriel FERNANDEZ if (IS_ERR(clk)) { 762*44993d38SGabriel FERNANDEZ kfree(gate); 763*44993d38SGabriel FERNANDEZ kfree(div); 764*44993d38SGabriel FERNANDEZ kfree(mux); 765*44993d38SGabriel FERNANDEZ goto err; 766*44993d38SGabriel FERNANDEZ } 767*44993d38SGabriel FERNANDEZ 768*44993d38SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 769*44993d38SGabriel FERNANDEZ __clk_get_name(clk), 770*44993d38SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 771*44993d38SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 772*44993d38SGabriel FERNANDEZ 773*44993d38SGabriel FERNANDEZ clk_data->clks[i] = clk; 774*44993d38SGabriel FERNANDEZ } 775*44993d38SGabriel FERNANDEZ 776*44993d38SGabriel FERNANDEZ kfree(parents); 777*44993d38SGabriel FERNANDEZ 778*44993d38SGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 779*44993d38SGabriel FERNANDEZ return; 780*44993d38SGabriel FERNANDEZ 781*44993d38SGabriel FERNANDEZ err: 782*44993d38SGabriel FERNANDEZ for (i = 0; i < clk_data->clk_num; i++) { 783*44993d38SGabriel FERNANDEZ struct clk_composite *composite; 784*44993d38SGabriel FERNANDEZ 785*44993d38SGabriel FERNANDEZ if (!clk_data->clks[i]) 786*44993d38SGabriel FERNANDEZ continue; 787*44993d38SGabriel FERNANDEZ 788*44993d38SGabriel FERNANDEZ composite = container_of(__clk_get_hw(clk_data->clks[i]), 789*44993d38SGabriel FERNANDEZ struct clk_composite, hw); 790*44993d38SGabriel FERNANDEZ kfree(container_of(composite->gate_hw, struct clk_gate, hw)); 791*44993d38SGabriel FERNANDEZ kfree(container_of(composite->rate_hw, struct clk_divider, hw)); 792*44993d38SGabriel FERNANDEZ kfree(container_of(composite->mux_hw, struct clk_mux, hw)); 793*44993d38SGabriel FERNANDEZ } 794*44993d38SGabriel FERNANDEZ 795*44993d38SGabriel FERNANDEZ if (clk_data) 796*44993d38SGabriel FERNANDEZ kfree(clk_data->clks); 797*44993d38SGabriel FERNANDEZ 798*44993d38SGabriel FERNANDEZ kfree(clk_data); 799*44993d38SGabriel FERNANDEZ kfree(parents); 800*44993d38SGabriel FERNANDEZ } 801*44993d38SGabriel FERNANDEZ CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup); 802