diff options
Diffstat (limited to 'drivers/clk/ti/clk.c')
| -rw-r--r-- | drivers/clk/ti/clk.c | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 3d636938a739..693a4459a01b 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -7,6 +7,7 @@ * Tero Kristo <t-kristo@ti.com> */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> @@ -15,7 +16,9 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/list.h> +#include <linux/minmax.h> #include <linux/regmap.h> +#include <linux/string_helpers.h> #include <linux/memblock.h> #include <linux/device.h> @@ -113,42 +116,31 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) /* * Eventually we could standardize to using '_' for clk-*.c files to follow the - * TRM naming and leave out the tmp name here. + * TRM naming. */ -static struct device_node *ti_find_clock_provider(struct device_node *from, - const char *name) +static struct device_node *ti_find_clock_provider(const char *name) { + char *tmp __free(kfree) = NULL; struct device_node *np; - bool found = false; - const char *n; - char *tmp; + char *p; - tmp = kstrdup(name, GFP_KERNEL); + tmp = kstrdup_and_replace(name, '-', '_', GFP_KERNEL); if (!tmp) return NULL; - strreplace(tmp, '-', '_'); - /* Node named "clock" with "clock-output-names" */ - for_each_of_allnodes_from(from, np) { - if (of_property_read_string_index(np, "clock-output-names", - 0, &n)) - continue; + /* Ignore a possible address for the node name */ + p = strchr(tmp, '@'); + if (p) + *p = '\0'; - if (!strncmp(n, tmp, strlen(tmp))) { - of_node_get(np); - found = true; - break; - } - } - kfree(tmp); - - if (found) { - of_node_put(from); - return np; + /* Node named "clock" with "clock-output-names" */ + for_each_node_with_property(np, "clock-output-names") { + if (of_property_match_string(np, "clock-output-names", tmp) == 0) + return np; } /* Fall back to using old node name base provider name */ - return of_find_node_by_name(from, name); + return of_find_node_by_name(NULL, tmp); } /** @@ -201,7 +193,7 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) if (num_args && clkctrl_nodes_missing) continue; - node = ti_find_clock_provider(NULL, buf); + node = ti_find_clock_provider(buf); if (num_args && compat_mode) { parent = node; child = of_get_child_by_name(parent, "clock"); @@ -301,8 +293,9 @@ int __init ti_clk_retry_init(struct device_node *node, void *user, int ti_clk_get_reg_addr(struct device_node *node, int index, struct clk_omap_reg *reg) { - u32 val; - int i; + u32 clksel_addr, val; + bool is_clksel = false; + int i, err; for (i = 0; i < CLK_MAX_MEMMAPS; i++) { if (clocks_node_ptr[i] == node->parent) @@ -318,21 +311,62 @@ int ti_clk_get_reg_addr(struct device_node *node, int index, reg->index = i; - if (of_property_read_u32_index(node, "reg", index, &val)) { - if (of_property_read_u32_index(node->parent, "reg", - index, &val)) { - pr_err("%pOFn or parent must have reg[%d]!\n", - node, index); + if (of_device_is_compatible(node->parent, "ti,clksel")) { + err = of_property_read_u32_index(node->parent, "reg", index, &clksel_addr); + if (err) { + pr_err("%pOFn parent clksel must have reg[%d]!\n", node, index); return -EINVAL; } + is_clksel = true; + } + + err = of_property_read_u32_index(node, "reg", index, &val); + if (err && is_clksel) { + /* Legacy clksel with no reg and a possible ti,bit-shift property */ + reg->offset = clksel_addr; + reg->bit = ti_clk_get_legacy_bit_shift(node); + reg->ptr = NULL; + + return 0; + } + + /* Updated clksel clock with a proper reg property */ + if (is_clksel) { + reg->offset = clksel_addr; + reg->bit = val; + reg->ptr = NULL; + return 0; } + /* Other clocks that may or may not have ti,bit-shift property */ reg->offset = val; + reg->bit = ti_clk_get_legacy_bit_shift(node); reg->ptr = NULL; return 0; } +/** + * ti_clk_get_legacy_bit_shift - get bit shift for a clock register + * @node: device node for the clock + * + * Gets the clock register bit shift using the legacy ti,bit-shift + * property. Only needed for legacy clock, and can be eventually + * dropped once all the composite clocks use a clksel node with a + * proper reg property. + */ +int ti_clk_get_legacy_bit_shift(struct device_node *node) +{ + int err; + u32 val; + + err = of_property_read_u32(node, "ti,bit-shift", &val); + if (!err && in_range(val, 0, 32)) + return val; + + return 0; +} + void ti_clk_latch(struct clk_omap_reg *reg, s8 shift) { u32 latch; @@ -400,10 +434,7 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) { struct clk_iomap *io; - io = memblock_alloc(sizeof(*io), SMP_CACHE_BYTES); - if (!io) - panic("%s: Failed to allocate %zu bytes\n", __func__, - sizeof(*io)); + io = memblock_alloc_or_panic(sizeof(*io), SMP_CACHE_BYTES); io->mem = mem; |
