diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2015-07-28 11:58:26 -0700 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2015-07-28 11:58:26 -0700 |
commit | 4d341056202a4725777ed99897f6456405819cd4 (patch) | |
tree | 45fb9d229bacf995aabcad282937568e5201b5a7 /drivers/clk/ti/clk.c | |
parent | e306479ac252928b84cc563c6e790f9b7e7ae427 (diff) | |
parent | 989feafb84118a840ff21250a1e5f516f43e3dbb (diff) | |
download | linux-stable-4d341056202a4725777ed99897f6456405819cd4.tar.gz linux-stable-4d341056202a4725777ed99897f6456405819cd4.tar.bz2 linux-stable-4d341056202a4725777ed99897f6456405819cd4.zip |
Merge branch 'for-4.2/ti-clk-move' of https://github.com/t-kristo/linux-pm into clk-next
From Tero Kristo:
"This pull request contains the TI clock driver set to move the
clock implementations under clock driver. Some small portions of
the clock driver code still remain under mach-omap2 after this,
it should be decided whether this code is now obsolete and should
be deleted or should someone try to fix it."
Slight merge conflicts with determine_rate prototype changes.
Diffstat (limited to 'drivers/clk/ti/clk.c')
-rw-r--r-- | drivers/clk/ti/clk.c | 145 |
1 files changed, 142 insertions, 3 deletions
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 64bb5e8a3b8c..3343bde47fe4 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -21,6 +21,8 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/list.h> +#include <linux/regmap.h> +#include <linux/bootmem.h> #include "clock.h" @@ -30,6 +32,63 @@ struct ti_clk_ll_ops *ti_clk_ll_ops; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; +struct ti_clk_features ti_clk_features; + +struct clk_iomap { + struct regmap *regmap; + void __iomem *mem; +}; + +static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; + +static void clk_memmap_writel(u32 val, void __iomem *reg) +{ + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_write(io->regmap, r->offset, val); + else + writel_relaxed(val, io->mem + r->offset); +} + +static u32 clk_memmap_readl(void __iomem *reg) +{ + u32 val; + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_read(io->regmap, r->offset, &val); + else + val = readl_relaxed(io->mem + r->offset); + + return val; +} + +/** + * ti_clk_setup_ll_ops - setup low level clock operations + * @ops: low level clock ops descriptor + * + * Sets up low level clock operations for TI clock driver. This is used + * to provide various callbacks for the clock driver towards platform + * specific code. Returns 0 on success, -EBUSY if ll_ops have been + * registered already. + */ +int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) +{ + if (ti_clk_ll_ops) { + pr_err("Attempt to register ll_ops multiple times.\n"); + return -EBUSY; + } + + ti_clk_ll_ops = ops; + ops->clk_readl = clk_memmap_readl; + ops->clk_writel = clk_memmap_writel; + + return 0; +} + /** * ti_dt_clocks_register - register DT alias clocks during boot * @oclks: list of clocks to register @@ -138,28 +197,61 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) } /** - * ti_dt_clk_init_provider - init master clock provider + * omap2_clk_provider_init - init master clock provider * @parent: master node * @index: internal index for clk_reg_ops + * @syscon: syscon regmap pointer for accessing clock registers + * @mem: iomem pointer for the clock provider memory area, only used if + * syscon is not provided * * Initializes a master clock IP block. This basically sets up the * mapping from clocks node to the memory map index. All the clocks * are then initialized through the common of_clk_init call, and the * clocks will access their memory maps based on the node layout. + * Returns 0 in success. */ -void ti_dt_clk_init_provider(struct device_node *parent, int index) +int __init omap2_clk_provider_init(struct device_node *parent, int index, + struct regmap *syscon, void __iomem *mem) { struct device_node *clocks; + struct clk_iomap *io; /* get clocks for this parent */ clocks = of_get_child_by_name(parent, "clocks"); if (!clocks) { pr_err("%s missing 'clocks' child node.\n", parent->name); - return; + return -EINVAL; } /* add clocks node info */ clocks_node_ptr[index] = clocks; + + io = kzalloc(sizeof(*io), GFP_KERNEL); + + io->regmap = syscon; + io->mem = mem; + + clk_memmaps[index] = io; + + return 0; +} + +/** + * omap2_clk_legacy_provider_init - initialize a legacy clock provider + * @index: index for the clock provider + * @mem: iomem pointer for the clock provider memory area + * + * Initializes a legacy clock provider memory mapping. + */ +void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) +{ + struct clk_iomap *io; + + io = memblock_virt_alloc(sizeof(*io), 0); + + io->mem = mem; + + clk_memmaps[index] = io; } /** @@ -311,3 +403,50 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks) return 0; } #endif + +/** + * ti_clk_setup_features - setup clock features flags + * @features: features definition to use + * + * Initializes the clock driver features flags based on platform + * provided data. No return value. + */ +void __init ti_clk_setup_features(struct ti_clk_features *features) +{ + memcpy(&ti_clk_features, features, sizeof(*features)); +} + +/** + * ti_clk_get_features - get clock driver features flags + * + * Get TI clock driver features description. Returns a pointer + * to the current feature setup. + */ +const struct ti_clk_features *ti_clk_get_features(void) +{ + return &ti_clk_features; +} + +/** + * omap2_clk_enable_init_clocks - prepare & enable a list of clocks + * @clk_names: ptr to an array of strings of clock names to enable + * @num_clocks: number of clock names in @clk_names + * + * Prepare and enable a list of clocks, named by @clk_names. No + * return value. XXX Deprecated; only needed until these clocks are + * properly claimed and enabled by the drivers or core code that uses + * them. XXX What code disables & calls clk_put on these clocks? + */ +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) +{ + struct clk *init_clk; + int i; + + for (i = 0; i < num_clocks; i++) { + init_clk = clk_get(NULL, clk_names[i]); + if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", + clk_names[i])) + continue; + clk_prepare_enable(init_clk); + } +} |