diff options
Diffstat (limited to 'drivers/clk')
99 files changed, 5541 insertions, 1207 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e2d9bd760c84..bf7d540d6965 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -31,22 +31,12 @@ config COMMON_CLK_WM831X source "drivers/clk/versatile/Kconfig" -config COMMON_CLK_MAX_GEN - bool - config COMMON_CLK_MAX77686 - tristate "Clock driver for Maxim 77686 MFD" - depends on MFD_MAX77686 - select COMMON_CLK_MAX_GEN - ---help--- - This driver supports Maxim 77686 crystal oscillator clock. - -config COMMON_CLK_MAX77802 - tristate "Clock driver for Maxim 77802 PMIC" - depends on MFD_MAX77686 - select COMMON_CLK_MAX_GEN + tristate "Clock driver for Maxim 77620/77686/77802 MFD" + depends on MFD_MAX77686 || MFD_MAX77620 ---help--- - This driver supports Maxim 77802 crystal oscillator clock. + This driver supports Maxim 77620/77686/77802 crystal oscillator + clock. config COMMON_CLK_RK808 tristate "Clock driver for RK808/RK818" @@ -210,6 +200,7 @@ config COMMON_CLK_OXNAS source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" +source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 3b6f9cf3464a..e775a836247c 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,9 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o -obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o -obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c index ffc988b098e4..da1a073c2236 100644 --- a/drivers/clk/axis/clk-artpec6.c +++ b/drivers/clk/axis/clk-artpec6.c @@ -113,8 +113,8 @@ static void of_artpec6_clkctrl_setup(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data); } -CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl", - of_artpec6_clkctrl_setup); +CLK_OF_DECLARE_DRIVER(artpec6_clkctrl, "axis,artpec6-clkctrl", + of_artpec6_clkctrl_setup); static int artpec6_clkctrl_probe(struct platform_device *pdev) { diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 7a7970865c2d..e8a9646afd6d 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -36,6 +36,7 @@ #include <linux/clk-provider.h> #include <linux/clkdev.h> +#include <linux/clk.h> #include <linux/clk/bcm2835.h> #include <linux/debugfs.h> #include <linux/module.h> @@ -443,6 +444,8 @@ struct bcm2835_clock_data { /* Number of fractional bits in the divider */ u32 frac_bits; + u32 flags; + bool is_vpu_clock; bool is_mash_clock; }; @@ -1006,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, return 0; } +static bool +bcm2835_clk_is_pllc(struct clk_hw *hw) +{ + if (!hw) + return false; + + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; +} + static int bcm2835_clock_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct clk_hw *parent, *best_parent = NULL; + bool current_parent_is_pllc; unsigned long rate, best_rate = 0; unsigned long prate, best_prate = 0; size_t i; u32 div; + current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw)); + /* * Select parent clock that results in the closest but lower rate */ @@ -1023,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, parent = clk_hw_get_parent_by_index(hw, i); if (!parent) continue; + + /* + * Don't choose a PLLC-derived clock as our parent + * unless it had been manually set that way. PLLC's + * frequency gets adjusted by the firmware due to + * over-temp or under-voltage conditions, without + * prior notification to our clock consumer. + */ + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) + continue; + prate = clk_hw_get_rate(parent); div = bcm2835_clock_choose_div(hw, req->rate, prate, true); rate = bcm2835_clock_rate_from_divisor(clock, prate, div); @@ -1230,13 +1256,19 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.parent_names = parents; init.num_parents = data->num_mux_parents; init.name = data->name; - init.flags = CLK_IGNORE_UNUSED; + init.flags = data->flags | CLK_IGNORE_UNUSED; if (data->is_vpu_clock) { init.ops = &bcm2835_vpu_clock_clk_ops; } else { init.ops = &bcm2835_clock_clk_ops; init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + /* If the clock wasn't actually enabled at boot, it's not + * critical. + */ + if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE)) + init.flags &= ~CLK_IS_CRITICAL; } clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL); @@ -1649,6 +1681,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_VPUDIV, .int_bits = 12, .frac_bits = 8, + .flags = CLK_IS_CRITICAL, .is_vpu_clock = true), /* clocks with per parent mux */ @@ -1705,13 +1738,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_GP1DIV, .int_bits = 12, .frac_bits = 12, + .flags = CLK_IS_CRITICAL, .is_mash_clock = true), [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( .name = "gp2", .ctl_reg = CM_GP2CTL, .div_reg = CM_GP2DIV, .int_bits = 12, - .frac_bits = 12), + .frac_bits = 12, + .flags = CLK_IS_CRITICAL), /* HDMI state machine */ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK( @@ -1790,6 +1825,25 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_PERIICTL), }; +/* + * Permanently take a reference on the parent of the SDRAM clock. + * + * While the SDRAM is being driven by its dedicated PLL most of the + * time, there is a little loop running in the firmware that + * periodically switches the SDRAM to using our CM clock to do PVT + * recalibration, with the assumption that the previously configured + * SDRAM parent is still enabled and running. + */ +static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) +{ + struct clk *parent = clk_get_parent(sdc); + + if (IS_ERR(parent)) + return PTR_ERR(parent); + + return clk_prepare_enable(parent); +} + static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1799,6 +1853,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) const struct bcm2835_clk_desc *desc; const size_t asize = ARRAY_SIZE(clk_desc_array); size_t i; + int ret; cprman = devm_kzalloc(dev, sizeof(*cprman) + asize * sizeof(*clks), @@ -1829,6 +1884,10 @@ static int bcm2835_clk_probe(struct platform_device *pdev) clks[i] = desc->clk_register(cprman, desc->data); } + ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]); + if (ret) + return ret; + return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, &cprman->onecell); } diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 526b0b0e9a9f..f2359b3b73bc 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -696,77 +696,69 @@ static void bcm_clk_teardown(struct kona_clk *bcm_clk) bcm_clk->type = bcm_clk_none; } -static void kona_clk_teardown(struct clk *clk) +static void kona_clk_teardown(struct clk_hw *hw) { - struct clk_hw *hw; struct kona_clk *bcm_clk; - if (!clk) + if (!hw) return; - hw = __clk_get_hw(clk); - if (!hw) { - pr_err("%s: clk %p has null hw pointer\n", __func__, clk); - return; - } - clk_unregister(clk); + clk_hw_unregister(hw); bcm_clk = to_kona_clk(hw); bcm_clk_teardown(bcm_clk); } -struct clk *kona_clk_setup(struct kona_clk *bcm_clk) +static int kona_clk_setup(struct kona_clk *bcm_clk) { + int ret; struct clk_init_data *init_data = &bcm_clk->init_data; - struct clk *clk = NULL; switch (bcm_clk->type) { case bcm_clk_peri: - if (peri_clk_setup(bcm_clk->u.data, init_data)) - return NULL; + ret = peri_clk_setup(bcm_clk->u.data, init_data); + if (ret) + return ret; break; default: pr_err("%s: clock type %d invalid for %s\n", __func__, (int)bcm_clk->type, init_data->name); - return NULL; + return -EINVAL; } /* Make sure everything makes sense before we set it up */ if (!kona_clk_valid(bcm_clk)) { pr_err("%s: clock data invalid for %s\n", __func__, init_data->name); + ret = -EINVAL; goto out_teardown; } bcm_clk->hw.init = init_data; - clk = clk_register(NULL, &bcm_clk->hw); - if (IS_ERR(clk)) { - pr_err("%s: error registering clock %s (%ld)\n", __func__, - init_data->name, PTR_ERR(clk)); + ret = clk_hw_register(NULL, &bcm_clk->hw); + if (ret) { + pr_err("%s: error registering clock %s (%d)\n", __func__, + init_data->name, ret); goto out_teardown; } - BUG_ON(!clk); - return clk; + return 0; out_teardown: bcm_clk_teardown(bcm_clk); - return NULL; + return ret; } static void ccu_clks_teardown(struct ccu_data *ccu) { u32 i; - for (i = 0; i < ccu->clk_data.clk_num; i++) - kona_clk_teardown(ccu->clk_data.clks[i]); - kfree(ccu->clk_data.clks); + for (i = 0; i < ccu->clk_num; i++) + kona_clk_teardown(&ccu->kona_clks[i].hw); } static void kona_ccu_teardown(struct ccu_data *ccu) { - kfree(ccu->clk_data.clks); - ccu->clk_data.clks = NULL; if (!ccu->base) return; @@ -793,6 +785,20 @@ static bool ccu_data_valid(struct ccu_data *ccu) return true; } +static struct clk_hw * +of_clk_kona_onecell_get(struct of_phandle_args *clkspec, void *data) +{ + struct ccu_data *ccu = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ccu->clk_num) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &ccu->kona_clks[idx].hw; +} + /* * Set up a CCU. Call the provided ccu_clks_setup callback to * initialize the array of clocks provided by the CCU. @@ -805,18 +811,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, unsigned int i; int ret; - if (ccu->clk_data.clk_num) { - size_t size; - - size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks); - ccu->clk_data.clks = kzalloc(size, GFP_KERNEL); - if (!ccu->clk_data.clks) { - pr_err("%s: unable to allocate %u clocks for %s\n", - __func__, ccu->clk_data.clk_num, node->name); - return; - } - } - ret = of_address_to_resource(node, 0, &res); if (ret) { pr_err("%s: no valid CCU registers found for %s\n", __func__, @@ -851,13 +845,13 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, * the clock framework clock array (in ccu->data). Then * register as a provider for these clocks. */ - for (i = 0; i < ccu->clk_data.clk_num; i++) { + for (i = 0; i < ccu->clk_num; i++) { if (!ccu->kona_clks[i].ccu) continue; - ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]); + kona_clk_setup(&ccu->kona_clks[i]); } - ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data); + ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu); if (ret) { pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, node->name, ret); diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 3a15347b4233..eee64b9e5d10 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1256,19 +1256,18 @@ bool __init kona_ccu_init(struct ccu_data *ccu) { unsigned long flags; unsigned int which; - struct clk **clks = ccu->clk_data.clks; struct kona_clk *kona_clks = ccu->kona_clks; bool success = true; flags = ccu_lock(ccu); __ccu_write_enable(ccu); - for (which = 0; which < ccu->clk_data.clk_num; which++) { - struct kona_clk *bcm_clk; + for (which = 0; which < ccu->clk_num; which++) { + struct kona_clk *bcm_clk = &kona_clks[which]; - if (!clks[which]) + if (!bcm_clk->ccu) continue; - bcm_clk = &kona_clks[which]; + success &= __kona_clk_init(bcm_clk); } diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index 906576ec97b6..f4b39bb5558a 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h @@ -481,7 +481,7 @@ struct ccu_data { bool write_enabled; /* write access is currently enabled */ struct ccu_policy policy; struct device_node *node; - struct clk_onecell_data clk_data; + size_t clk_num; const char *name; u32 range; /* byte range of address space */ struct kona_clk kona_clks[]; /* must be last */ @@ -491,9 +491,7 @@ struct ccu_data { #define KONA_CCU_COMMON(_prefix, _name, _ccuname) \ .name = #_name "_ccu", \ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \ - .clk_data = { \ - .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \ - } + .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT /* Exported globals */ @@ -505,7 +503,6 @@ extern u64 scaled_div_max(struct bcm_clk_div *div); extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths); -extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk); extern void __init kona_dt_ccu_setup(struct ccu_data *ccu, struct device_node *node); extern bool __init kona_ccu_init(struct ccu_data *ccu); diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c index fd0f26c38465..cfcae468e989 100644 --- a/drivers/clk/berlin/berlin2-avpll.c +++ b/drivers/clk/berlin/berlin2-avpll.c @@ -188,7 +188,7 @@ static const struct clk_ops berlin2_avpll_vco_ops = { .recalc_rate = berlin2_avpll_vco_recalc_rate, }; -struct clk * __init berlin2_avpll_vco_register(void __iomem *base, +int __init berlin2_avpll_vco_register(void __iomem *base, const char *name, const char *parent_name, u8 vco_flags, unsigned long flags) { @@ -197,7 +197,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base, vco = kzalloc(sizeof(*vco), GFP_KERNEL); if (!vco) - return ERR_PTR(-ENOMEM); + return -ENOMEM; vco->base = base; vco->flags = vco_flags; @@ -208,7 +208,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &vco->hw); + return clk_hw_register(NULL, &vco->hw); } struct berlin2_avpll_channel { @@ -364,7 +364,7 @@ static const struct clk_ops berlin2_avpll_channel_ops = { */ static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 }; -struct clk * __init berlin2_avpll_channel_register(void __iomem *base, +int __init berlin2_avpll_channel_register(void __iomem *base, const char *name, u8 index, const char *parent_name, u8 ch_flags, unsigned long flags) { @@ -373,7 +373,7 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base, ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (!ch) - return ERR_PTR(-ENOMEM); + return -ENOMEM; ch->base = base; if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK) @@ -389,5 +389,5 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &ch->hw); + return clk_hw_register(NULL, &ch->hw); } diff --git a/drivers/clk/berlin/berlin2-avpll.h b/drivers/clk/berlin/berlin2-avpll.h index a37f5068d299..17e311153b42 100644 --- a/drivers/clk/berlin/berlin2-avpll.h +++ b/drivers/clk/berlin/berlin2-avpll.h @@ -19,17 +19,13 @@ #ifndef __BERLIN2_AVPLL_H #define __BERLIN2_AVPLL_H -struct clk; - #define BERLIN2_AVPLL_BIT_QUIRK BIT(0) #define BERLIN2_AVPLL_SCRAMBLE_QUIRK BIT(1) -struct clk * __init -berlin2_avpll_vco_register(void __iomem *base, const char *name, +int berlin2_avpll_vco_register(void __iomem *base, const char *name, const char *parent_name, u8 vco_flags, unsigned long flags); -struct clk * __init -berlin2_avpll_channel_register(void __iomem *base, const char *name, +int berlin2_avpll_channel_register(void __iomem *base, const char *name, u8 index, const char *parent_name, u8 ch_flags, unsigned long flags); diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c index 81ff97f8aa0b..41ab2d392c57 100644 --- a/drivers/clk/berlin/berlin2-div.c +++ b/drivers/clk/berlin/berlin2-div.c @@ -234,7 +234,7 @@ static const struct clk_ops berlin2_div_mux_ops = { .get_parent = berlin2_div_get_parent, }; -struct clk * __init +struct clk_hw * __init berlin2_div_register(const struct berlin2_div_map *map, void __iomem *base, const char *name, u8 div_flags, const char **parent_names, int num_parents, @@ -259,7 +259,7 @@ berlin2_div_register(const struct berlin2_div_map *map, if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0) mux_ops = NULL; - return clk_register_composite(NULL, name, parent_names, num_parents, + return clk_hw_register_composite(NULL, name, parent_names, num_parents, &div->hw, mux_ops, &div->hw, rate_ops, &div->hw, gate_ops, flags); } diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h index 15e3384f3116..e835ddf8374a 100644 --- a/drivers/clk/berlin/berlin2-div.h +++ b/drivers/clk/berlin/berlin2-div.h @@ -19,7 +19,7 @@ #ifndef __BERLIN2_DIV_H #define __BERLIN2_DIV_H -struct clk; +struct clk_hw; #define BERLIN2_DIV_HAS_GATE BIT(0) #define BERLIN2_DIV_HAS_MUX BIT(1) @@ -80,7 +80,7 @@ struct berlin2_div_data { u8 div_flags; }; -struct clk * __init +struct clk_hw * berlin2_div_register(const struct berlin2_div_map *map, void __iomem *base, const char *name, u8 div_flags, const char **parent_names, int num_parents, diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c index 1c2294d3ba85..4ffbe80f6323 100644 --- a/drivers/clk/berlin/berlin2-pll.c +++ b/drivers/clk/berlin/berlin2-pll.c @@ -84,7 +84,7 @@ static const struct clk_ops berlin2_pll_ops = { .recalc_rate = berlin2_pll_recalc_rate, }; -struct clk * __init +int __init berlin2_pll_register(const struct berlin2_pll_map *map, void __iomem *base, const char *name, const char *parent_name, unsigned long flags) @@ -94,7 +94,7 @@ berlin2_pll_register(const struct berlin2_pll_map *map, pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) - return ERR_PTR(-ENOMEM); + return -ENOMEM; /* copy pll_map to allow __initconst */ memcpy(&pll->map, map, sizeof(*map)); @@ -106,5 +106,5 @@ berlin2_pll_register(const struct berlin2_pll_map *map, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &pll->hw); + return clk_hw_register(NULL, &pll->hw); } diff --git a/drivers/clk/berlin/berlin2-pll.h b/drivers/clk/berlin/berlin2-pll.h index 8831ce27ac1e..583e024b9bed 100644 --- a/drivers/clk/berlin/berlin2-pll.h +++ b/drivers/clk/berlin/berlin2-pll.h @@ -19,8 +19,6 @@ #ifndef __BERLIN2_PLL_H #define __BERLIN2_PLL_H -struct clk; - struct berlin2_pll_map { const u8 vcodiv[16]; u8 mult; @@ -29,9 +27,8 @@ struct berlin2_pll_map { u8 divsel_shift; }; -struct clk * __init -berlin2_pll_register(const struct berlin2_pll_map *map, - void __iomem *base, const char *name, - const char *parent_name, unsigned long flags); +int berlin2_pll_register(const struct berlin2_pll_map *map, + void __iomem *base, const char *name, + const char *parent_name, unsigned long flags); #endif /* __BERLIN2_PLL_H */ diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c index 23e0e3be6c37..edf3b96b3b73 100644 --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -92,8 +92,7 @@ */ #define MAX_CLKS 41 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(lock); static void __iomem *gbase; @@ -505,8 +504,17 @@ static void __init berlin2_clock_setup(struct device_node *np) struct device_node *parent_np = of_get_parent(np); const char *parent_names[9]; struct clk *clk; + struct clk_hw *hw; + struct clk_hw **hws; u8 avpll_flags = 0; - int n; + int n, ret; + + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; gbase = of_iomap(parent_np, 0); if (!gbase) @@ -526,118 +534,118 @@ static void __init berlin2_clock_setup(struct device_node *np) } /* simple register PLLs */ - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, clk_names[MEMPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, clk_names[CPUPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; if (of_device_is_compatible(np, "marvell,berlin2-global-register")) avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; /* audio/video VCOs */ - clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", + ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", clk_names[REFCLK], avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { - clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, + ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, clk_names[AVPLL_A1 + n], n, "avpll_vcoA", avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; } - clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", + ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { - clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, + ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, clk_names[AVPLL_B1 + n], n, "avpll_vcoB", BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; } /* reference clock bypass switches */ parent_names[0] = clk_names[SYSPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[SYSPLL] = __clk_get_name(clk); + clk_names[SYSPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[MEMPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[MEMPLL] = __clk_get_name(clk); + clk_names[MEMPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[CPUPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[CPUPLL] = __clk_get_name(clk); + clk_names[CPUPLL] = clk_hw_get_name(hw); /* clock muxes */ parent_names[0] = clk_names[AVPLL_B3]; parent_names[1] = clk_names[AVPLL_A3]; - clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO0_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO1_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_A2]; parent_names[1] = clk_names[AVPLL_B2]; - clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO2_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_B1]; parent_names[1] = clk_names[AVPLL_A5]; - clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; /* clock divider cells */ @@ -648,7 +656,7 @@ static void __init berlin2_clock_setup(struct device_node *np) for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; - clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, + hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } @@ -657,18 +665,18 @@ static void __init berlin2_clock_setup(struct device_node *np) for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { const struct berlin2_gate_data *gd = &bg2_gates[n]; - clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name, + hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* twdclk is derived from cpu/3 */ - clks[CLKID_TWD] = - clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); + hws[CLKID_TWD] = + clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -677,9 +685,7 @@ static void __init berlin2_clock_setup(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); return; diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c index f144547cf76c..0718e831475f 100644 --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -46,8 +46,7 @@ #define REG_SDIO1XIN_CLKCTL 0x015c #define MAX_CLKS 28 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(lock); static void __iomem *gbase; static void __iomem *cpupll_base; @@ -293,7 +292,15 @@ static void __init berlin2q_clock_setup(struct device_node *np) struct device_node *parent_np = of_get_parent(np); const char *parent_names[9]; struct clk *clk; - int n; + struct clk_hw **hws; + int n, ret; + + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; gbase = of_iomap(parent_np, 0); if (!gbase) { @@ -317,14 +324,14 @@ static void __init berlin2q_clock_setup(struct device_node *np) } /* simple register PLLs */ - clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, + ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2q_fail; - clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base, + ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base, clk_names[CPUPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2q_fail; /* TODO: add BG2Q AVPLL */ @@ -342,7 +349,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; - clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, + hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } @@ -351,22 +358,22 @@ static void __init berlin2q_clock_setup(struct device_node *np) for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { const struct berlin2_gate_data *gd = &bg2q_gates[n]; - clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name, + hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* cpuclk divider is fixed to 1 */ - clks[CLKID_CPU] = - clk_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], + hws[CLKID_CPU] = + clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], 0, 1, 1); /* twdclk is derived from cpu/3 */ - clks[CLKID_TWD] = - clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); + hws[CLKID_TWD] = + clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -375,9 +382,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); return; diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c index 90897af8d9f7..ea8568536193 100644 --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -68,8 +68,7 @@ #define HW_LCDCLKDIV 0x01fc #define HW_ADCANACLKDIV 0x0200 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(asm9260_clk_lock); struct asm9260_div_clk { @@ -267,12 +266,20 @@ static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = { static void __init asm9260_acc_init(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; + struct clk_hw **hws; const char *ref_clk, *pll_clk = "pll"; u32 rate; int n; u32 accuracy = 0; + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; + base = of_io_request_and_map(np, 0, np->name); if (IS_ERR(base)) panic("%s: unable to map resource", np->name); @@ -282,10 +289,10 @@ static void __init asm9260_acc_init(struct device_node *np) ref_clk = of_clk_get_parent_name(np, 0); accuracy = clk_get_accuracy(__clk_lookup(ref_clk)); - clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk, + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, pll_clk, ref_clk, 0, rate, accuracy); - if (IS_ERR(clk)) + if (IS_ERR(hw)) panic("%s: can't register REFCLK. Check DT!", np->name); for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) { @@ -293,7 +300,7 @@ static void __init asm9260_acc_init(struct device_node *np) mc->parent_names[0] = ref_clk; mc->parent_names[1] = pll_clk; - clk = clk_register_mux_table(NULL, mc->name, mc->parent_names, + hw = clk_hw_register_mux_table(NULL, mc->name, mc->parent_names, mc->num_parents, mc->flags, base + mc->offset, 0, mc->mask, 0, mc->table, &asm9260_clk_lock); } @@ -302,7 +309,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) { const struct asm9260_gate_data *gd = &asm9260_mux_gates[n]; - clk = clk_register_gate(NULL, gd->name, + hw = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags | CLK_SET_RATE_PARENT, base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock); } @@ -311,7 +318,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) { const struct asm9260_div_clk *dc = &asm9260_div_clks[n]; - clks[dc->idx] = clk_register_divider(NULL, dc->name, + hws[dc->idx] = clk_hw_register_divider(NULL, dc->name, dc->parent_name, CLK_SET_RATE_PARENT, base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED, &asm9260_clk_lock); @@ -321,14 +328,14 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) { const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n]; - clks[gd->idx] = clk_register_gate(NULL, gd->name, + hws[gd->idx] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock); } /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -337,9 +344,7 @@ static void __init asm9260_acc_init(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); return; fail: iounmap(base); diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 3294db3b4e4e..5e918e7afaba 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -392,8 +392,8 @@ static int axi_clkgen_probe(struct platform_device *pdev) const char *parent_names[2]; const char *clk_name; struct resource *mem; - struct clk *clk; unsigned int i; + int ret; if (!pdev->dev.of_node) return -ENODEV; @@ -433,12 +433,12 @@ static int axi_clkgen_probe(struct platform_device *pdev) axi_clkgen_mmcm_enable(axi_clkgen, false); axi_clkgen->clk_hw.init = &init; - clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw); + if (ret) + return ret; - return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, - clk); + return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get, + &axi_clkgen->clk_hw); } static int axi_clkgen_remove(struct platform_device *pdev) diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c index c7c91a5ecf8b..5d7ae333257e 100644 --- a/drivers/clk/clk-axm5516.c +++ b/drivers/clk/clk-axm5516.c @@ -516,6 +516,19 @@ static struct axxia_clk *axmclk_clocks[] = { [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk, }; +static struct clk_hw * +of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused) +{ + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(axmclk_clocks)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &axmclk_clocks[idx]->hw; +} + static const struct regmap_config axmclk_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -530,21 +543,14 @@ static const struct of_device_id axmclk_match_table[] = { }; MODULE_DEVICE_TABLE(of, axmclk_match_table); -struct axmclk_priv { - struct clk_onecell_data onecell; - struct clk *clks[]; -}; - static int axmclk_probe(struct platform_device *pdev) { void __iomem *base; struct resource *res; int i, ret; struct device *dev = &pdev->dev; - struct clk *clk; struct regmap *regmap; size_t num_clks; - struct axmclk_priv *priv; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); @@ -557,29 +563,18 @@ static int axmclk_probe(struct platform_device *pdev) num_clks = ARRAY_SIZE(axmclk_clocks); pr_info("axmclk: supporting %zu clocks\n", num_clks); - priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks, - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->onecell.clks = priv->clks; - priv->onecell.clk_num = num_clks; /* Update each entry with the allocated regmap and register the clock * with the common clock framework */ for (i = 0; i < num_clks; i++) { axmclk_clocks[i]->regmap = regmap; - clk = devm_clk_register(dev, &axmclk_clocks[i]->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); - priv->clks[i] = clk; + ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw); + if (ret) + return ret; } - ret = of_clk_add_provider(dev->of_node, - of_clk_src_onecell_get, &priv->onecell); - - return ret; + return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL); } static int axmclk_remove(struct platform_device *pdev) diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index 01877f64eff6..f21d9092564f 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -71,7 +71,6 @@ struct cdce706_hw_data { struct cdce706_dev_data *dev_data; unsigned idx; unsigned parent; - struct clk *clk; struct clk_hw hw; unsigned div; unsigned mul; @@ -81,8 +80,6 @@ struct cdce706_hw_data { struct cdce706_dev_data { struct i2c_client *client; struct regmap *regmap; - struct clk_onecell_data onecell; - struct clk *clks[6]; struct clk *clkin_clk[2]; const char *clkin_name[2]; struct cdce706_hw_data clkin[1]; @@ -455,18 +452,19 @@ static int cdce706_register_hw(struct cdce706_dev_data *cdce, struct clk_init_data *init) { unsigned i; + int ret; for (i = 0; i < num_hw; ++i, ++hw) { init->name = clk_names[i]; hw->dev_data = cdce; hw->idx = i; hw->hw.init = init; - hw->clk = devm_clk_register(&cdce->client->dev, + ret = devm_clk_hw_register(&cdce->client->dev, &hw->hw); - if (IS_ERR(hw->clk)) { + if (ret) { dev_err(&cdce->client->dev, "Failed to register %s\n", clk_names[i]); - return PTR_ERR(hw->clk); + return ret; } } return 0; @@ -613,13 +611,23 @@ static int cdce706_register_clkouts(struct cdce706_dev_data *cdce) cdce->clkout[i].parent); } - ret = cdce706_register_hw(cdce, cdce->clkout, - ARRAY_SIZE(cdce->clkout), - cdce706_clkout_name, &init); - for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) - cdce->clks[i] = cdce->clkout[i].clk; + return cdce706_register_hw(cdce, cdce->clkout, + ARRAY_SIZE(cdce->clkout), + cdce706_clkout_name, &init); +} - return ret; +static struct clk_hw * +of_clk_cdce_get(struct of_phandle_args *clkspec, void *data) +{ + struct cdce706_dev_data *cdce = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(cdce->clkout)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &cdce->clkout[idx].hw; } static int cdce706_probe(struct i2c_client *client, @@ -657,12 +665,8 @@ static int cdce706_probe(struct i2c_client *client, ret = cdce706_register_clkouts(cdce); if (ret < 0) return ret; - cdce->onecell.clks = cdce->clks; - cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks); - ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &cdce->onecell); - - return ret; + return of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce_get, + cdce); } static int cdce706_remove(struct i2c_client *client) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index 089bf88ffa8d..b8459c14a1b7 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -62,8 +62,6 @@ struct clk_cdce925_chip { struct i2c_client *i2c_client; struct clk_cdce925_pll pll[NUMBER_OF_PLLS]; struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS]; - struct clk *dt_clk[NUMBER_OF_OUTPUTS]; - struct clk_onecell_data onecell; }; /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ @@ -557,6 +555,20 @@ static int cdce925_regmap_i2c_read(void *context, return -EIO; } +static struct clk_hw * +of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data) +{ + struct clk_cdce925_chip *data = _data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(data->clk)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &data->clk[idx].hw; +} + /* The CDCE925 uses a funky way to read/write registers. Bulk mode is * just weird, so just use the single byte mode exclusively. */ static struct regmap_bus regmap_cdce925_bus = { @@ -572,7 +584,6 @@ static int cdce925_probe(struct i2c_client *client, const char *parent_name; const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,}; struct clk_init_data init; - struct clk *clk; u32 value; int i; int err; @@ -622,10 +633,9 @@ static int cdce925_probe(struct i2c_client *client, data->pll[i].chip = data; data->pll[i].hw.init = &init; data->pll[i].index = i; - clk = devm_clk_register(&client->dev, &data->pll[i].hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->pll[i].hw); + if (err) { dev_err(&client->dev, "Failed register PLL %d\n", i); - err = PTR_ERR(clk); goto error; } sprintf(child_name, "PLL%d", i+1); @@ -634,7 +644,7 @@ static int cdce925_probe(struct i2c_client *client, continue; if (!of_property_read_u32(np_output, "clock-frequency", &value)) { - err = clk_set_rate(clk, value); + err = clk_set_rate(data->pll[i].hw.clk, value); if (err) dev_err(&client->dev, "unable to set PLL frequency %ud\n", @@ -663,14 +673,12 @@ static int cdce925_probe(struct i2c_client *client, data->clk[0].hw.init = &init; data->clk[0].index = 0; data->clk[0].pdiv = 1; - clk = devm_clk_register(&client->dev, &data->clk[0].hw); + err = devm_clk_hw_register(&client->dev, &data->clk[0].hw); kfree(init.name); /* clock framework made a copy of the name */ - if (IS_ERR(clk)) { + if (err) { dev_err(&client->dev, "clock registration Y1 failed\n"); - err = PTR_ERR(clk); goto error; } - data->dt_clk[0] = clk; /* Register output clocks Y2 .. Y5*/ init.ops = &cdce925_clk_ops; @@ -695,21 +703,17 @@ static int cdce925_probe(struct i2c_client *client, init.parent_names = &pll_clk_name[1]; break; } - clk = devm_clk_register(&client->dev, &data->clk[i].hw); + err = devm_clk_hw_register(&client->dev, &data->clk[i].hw); kfree(init.name); /* clock framework made a copy of the name */ - if (IS_ERR(clk)) { + if (err) { dev_err(&client->dev, "clock registration failed\n"); - err = PTR_ERR(clk); goto error; } - data->dt_clk[i] = clk; } /* Register the output clocks */ - data->onecell.clk_num = NUMBER_OF_OUTPUTS; - data->onecell.clks = data->dt_clk; - err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &data->onecell); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce925_get, + data); if (err) dev_err(&client->dev, "unable to add OF clock provider\n"); diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index adaf109f2fe2..9193f64561f6 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -40,9 +40,8 @@ static const struct clk_div_table timer_div_table[] = { }; struct clps711x_clk { - struct clk_onecell_data clk_data; - spinlock_t lock; - struct clk *clks[CLPS711X_CLK_MAX]; + spinlock_t lock; + struct clk_hw_onecell_data clk_data; }; static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, @@ -55,7 +54,9 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, if (!base) return ERR_PTR(-ENOMEM); - clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL); + clps711x_clk = kzalloc(sizeof(*clps711x_clk) + + sizeof(*clps711x_clk->clk_data.hws) * CLPS711X_CLK_MAX, + GFP_KERNEL); if (!clps711x_clk) return ERR_PTR(-ENOMEM); @@ -106,40 +107,40 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, tmp |= SYSCON1_TC2M | SYSCON1_TC2S; writel(tmp, base + CLPS711X_SYSCON1); - clps711x_clk->clks[CLPS711X_CLK_DUMMY] = - clk_register_fixed_rate(NULL, "dummy", NULL, 0, 0); - clps711x_clk->clks[CLPS711X_CLK_CPU] = - clk_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu); - clps711x_clk->clks[CLPS711X_CLK_BUS] = - clk_register_fixed_rate(NULL, "bus", NULL, 0, f_bus); - clps711x_clk->clks[CLPS711X_CLK_PLL] = - clk_register_fixed_rate(NULL, "pll", NULL, 0, f_pll); - clps711x_clk->clks[CLPS711X_CLK_TIMERREF] = - clk_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim); - clps711x_clk->clks[CLPS711X_CLK_TIMER1] = - clk_register_divider_table(NULL, "timer1", "timer_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_DUMMY] = + clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0); + clps711x_clk->clk_data.hws[CLPS711X_CLK_CPU] = + clk_hw_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu); + clps711x_clk->clk_data.hws[CLPS711X_CLK_BUS] = + clk_hw_register_fixed_rate(NULL, "bus", NULL, 0, f_bus); + clps711x_clk->clk_data.hws[CLPS711X_CLK_PLL] = + clk_hw_register_fixed_rate(NULL, "pll", NULL, 0, f_pll); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMERREF] = + clk_hw_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1] = + clk_hw_register_divider_table(NULL, "timer1", "timer_ref", 0, base + CLPS711X_SYSCON1, 5, 1, 0, timer_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_TIMER2] = - clk_register_divider_table(NULL, "timer2", "timer_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2] = + clk_hw_register_divider_table(NULL, "timer2", "timer_ref", 0, base + CLPS711X_SYSCON1, 7, 1, 0, timer_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_PWM] = - clk_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm); - clps711x_clk->clks[CLPS711X_CLK_SPIREF] = - clk_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi); - clps711x_clk->clks[CLPS711X_CLK_SPI] = - clk_register_divider_table(NULL, "spi", "spi_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM] = + clk_hw_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm); + clps711x_clk->clk_data.hws[CLPS711X_CLK_SPIREF] = + clk_hw_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi); + clps711x_clk->clk_data.hws[CLPS711X_CLK_SPI] = + clk_hw_register_divider_table(NULL, "spi", "spi_ref", 0, base + CLPS711X_SYSCON1, 16, 2, 0, spi_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_UART] = - clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); - clps711x_clk->clks[CLPS711X_CLK_TICK] = - clk_register_fixed_rate(NULL, "tick", NULL, 0, 64); + clps711x_clk->clk_data.hws[CLPS711X_CLK_UART] = + clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] = + clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64); for (i = 0; i < CLPS711X_CLK_MAX; i++) - if (IS_ERR(clps711x_clk->clks[i])) + if (IS_ERR(clps711x_clk->clk_data.hws[i])) pr_err("clk %i: register failed with %ld\n", - i, PTR_ERR(clps711x_clk->clks[i])); + i, PTR_ERR(clps711x_clk->clk_data.hws[i])); return clps711x_clk; } @@ -153,17 +154,17 @@ void __init clps711x_clk_init(void __iomem *base) BUG_ON(IS_ERR(clps711x_clk)); /* Clocksource */ - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER1], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1], NULL, "clps711x-timer.0"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER2], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2], NULL, "clps711x-timer.1"); /* Drivers */ - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_PWM], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM], NULL, "clps711x-pwm"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], NULL, "clps711x-uart.0"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], NULL, "clps711x-uart.1"); } @@ -179,10 +180,9 @@ static void __init clps711x_clk_init_dt(struct device_node *np) clps711x_clk = _clps711x_clk_init(base, fref); BUG_ON(IS_ERR(clps711x_clk)); - clps711x_clk->clk_data.clks = clps711x_clk->clks; - clps711x_clk->clk_data.clk_num = CLPS711X_CLK_MAX; - of_clk_add_provider(np, of_clk_src_onecell_get, - &clps711x_clk->clk_data); + clps711x_clk->clk_data.num = CLPS711X_CLK_MAX; + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &clps711x_clk->clk_data); } CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt); #endif diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 7379de8dc894..021f3daf34e1 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -59,7 +59,6 @@ struct cs2000_priv { struct i2c_client *client; struct clk *clk_in; struct clk *ref_clk; - struct clk *clk_out; }; static const struct of_device_id cs2000_of_match[] = { @@ -371,7 +370,6 @@ static int cs2000_clk_register(struct cs2000_priv *priv) struct device_node *np = dev->of_node; struct clk_init_data init; const char *name = np->name; - struct clk *clk; static const char *parent_names[CLK_MAX]; int ch = 0; /* it uses ch0 only at this point */ int rate; @@ -400,18 +398,16 @@ static int cs2000_clk_register(struct cs2000_priv *priv) priv->hw.init = &init; - clk = clk_register(dev, &priv->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = clk_hw_register(dev, &priv->hw); + if (ret) + return ret; - ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw); if (ret < 0) { - clk_unregister(clk); + clk_hw_unregister(&priv->hw); return ret; } - priv->clk_out = clk; - return 0; } @@ -454,7 +450,7 @@ static int cs2000_remove(struct i2c_client *client) of_clk_del_provider(np); - clk_unregister(priv->clk_out); + clk_hw_unregister(&priv->hw); return 0; } diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a0f55bc1ad3d..96386ffc8483 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -352,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = readl(divider->reg) >> divider->shift; + bestdiv = clk_readl(divider->reg) >> divider->shift; bestdiv &= div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index 22e4c659704e..8802a2dd56ac 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -10,24 +10,31 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/slab.h> #include <dt-bindings/clock/efm32-cmu.h> #define CMU_HFPERCLKEN0 0x44 +#define CMU_MAX_CLKS 37 -static struct clk *clk[37]; -static struct clk_onecell_data clk_data = { - .clks = clk, - .clk_num = ARRAY_SIZE(clk), -}; +static struct clk_hw_onecell_data *clk_data; static void __init efm32gg_cmu_init(struct device_node *np) { int i; void __iomem *base; + struct clk_hw **hws; - for (i = 0; i < ARRAY_SIZE(clk); ++i) - clk[i] = ERR_PTR(-ENOENT); + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * CMU_MAX_CLKS, GFP_KERNEL); + + if (!clk_data) + return; + + hws = clk_data->hws; + + for (i = 0; i < CMU_MAX_CLKS; ++i) + hws[i] = ERR_PTR(-ENOENT); base = of_iomap(np, 0); if (!base) { @@ -35,46 +42,46 @@ static void __init efm32gg_cmu_init(struct device_node *np) return; } - clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL, - 0, 48000000); + hws[clk_HFXO] = clk_hw_register_fixed_rate(NULL, "HFXO", NULL, 0, + 48000000); - clk[clk_HFPERCLKUSART0] = clk_register_gate(NULL, "HFPERCLK.USART0", + hws[clk_HFPERCLKUSART0] = clk_hw_register_gate(NULL, "HFPERCLK.USART0", "HFXO", 0, base + CMU_HFPERCLKEN0, 0, 0, NULL); - clk[clk_HFPERCLKUSART1] = clk_register_gate(NULL, "HFPERCLK.USART1", + hws[clk_HFPERCLKUSART1] = clk_hw_register_gate(NULL, "HFPERCLK.USART1", "HFXO", 0, base + CMU_HFPERCLKEN0, 1, 0, NULL); - clk[clk_HFPERCLKUSART2] = clk_register_gate(NULL, "HFPERCLK.USART2", + hws[clk_HFPERCLKUSART2] = clk_hw_register_gate(NULL, "HFPERCLK.USART2", "HFXO", 0, base + CMU_HFPERCLKEN0, 2, 0, NULL); - clk[clk_HFPERCLKUART0] = clk_register_gate(NULL, "HFPERCLK.UART0", + hws[clk_HFPERCLKUART0] = clk_hw_register_gate(NULL, "HFPERCLK.UART0", "HFXO", 0, base + CMU_HFPERCLKEN0, 3, 0, NULL); - clk[clk_HFPERCLKUART1] = clk_register_gate(NULL, "HFPERCLK.UART1", + hws[clk_HFPERCLKUART1] = clk_hw_register_gate(NULL, "HFPERCLK.UART1", "HFXO", 0, base + CMU_HFPERCLKEN0, 4, 0, NULL); - clk[clk_HFPERCLKTIMER0] = clk_register_gate(NULL, "HFPERCLK.TIMER0", + hws[clk_HFPERCLKTIMER0] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER0", "HFXO", 0, base + CMU_HFPERCLKEN0, 5, 0, NULL); - clk[clk_HFPERCLKTIMER1] = clk_register_gate(NULL, "HFPERCLK.TIMER1", + hws[clk_HFPERCLKTIMER1] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER1", "HFXO", 0, base + CMU_HFPERCLKEN0, 6, 0, NULL); - clk[clk_HFPERCLKTIMER2] = clk_register_gate(NULL, "HFPERCLK.TIMER2", + hws[clk_HFPERCLKTIMER2] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER2", "HFXO", 0, base + CMU_HFPERCLKEN0, 7, 0, NULL); - clk[clk_HFPERCLKTIMER3] = clk_register_gate(NULL, "HFPERCLK.TIMER3", + hws[clk_HFPERCLKTIMER3] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER3", "HFXO", 0, base + CMU_HFPERCLKEN0, 8, 0, NULL); - clk[clk_HFPERCLKACMP0] = clk_register_gate(NULL, "HFPERCLK.ACMP0", + hws[clk_HFPERCLKACMP0] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP0", "HFXO", 0, base + CMU_HFPERCLKEN0, 9, 0, NULL); - clk[clk_HFPERCLKACMP1] = clk_register_gate(NULL, "HFPERCLK.ACMP1", + hws[clk_HFPERCLKACMP1] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP1", "HFXO", 0, base + CMU_HFPERCLKEN0, 10, 0, NULL); - clk[clk_HFPERCLKI2C0] = clk_register_gate(NULL, "HFPERCLK.I2C0", + hws[clk_HFPERCLKI2C0] = clk_hw_register_gate(NULL, "HFPERCLK.I2C0", "HFXO", 0, base + CMU_HFPERCLKEN0, 11, 0, NULL); - clk[clk_HFPERCLKI2C1] = clk_register_gate(NULL, "HFPERCLK.I2C1", + hws[clk_HFPERCLKI2C1] = clk_hw_register_gate(NULL, "HFPERCLK.I2C1", "HFXO", 0, base + CMU_HFPERCLKEN0, 12, 0, NULL); - clk[clk_HFPERCLKGPIO] = clk_register_gate(NULL, "HFPERCLK.GPIO", + hws[clk_HFPERCLKGPIO] = clk_hw_register_gate(NULL, "HFPERCLK.GPIO", "HFXO", 0, base + CMU_HFPERCLKEN0, 13, 0, NULL); - clk[clk_HFPERCLKVCMP] = clk_register_gate(NULL, "HFPERCLK.VCMP", + hws[clk_HFPERCLKVCMP] = clk_hw_register_gate(NULL, "HFPERCLK.VCMP", "HFXO", 0, base + CMU_HFPERCLKEN0, 14, 0, NULL); - clk[clk_HFPERCLKPRS] = clk_register_gate(NULL, "HFPERCLK.PRS", + hws[clk_HFPERCLKPRS] = clk_hw_register_gate(NULL, "HFPERCLK.PRS", "HFXO", 0, base + CMU_HFPERCLKEN0, 15, 0, NULL); - clk[clk_HFPERCLKADC0] = clk_register_gate(NULL, "HFPERCLK.ADC0", + hws[clk_HFPERCLKADC0] = clk_hw_register_gate(NULL, "HFPERCLK.ADC0", "HFXO", 0, base + CMU_HFPERCLKEN0, 16, 0, NULL); - clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0", + hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0", "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); } CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 4db3be214077..a5d402de5584 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/of.h> +#include <linux/platform_device.h> /* * DOC: basic fixed multiplier and divider clock that cannot gate @@ -147,27 +148,25 @@ static const struct of_device_id set_rate_parent_matches[] = { { /* Sentinel */ }, }; -/** - * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock - */ -void __init of_fixed_factor_clk_setup(struct device_node *node) +static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = node->name; const char *parent_name; unsigned long flags = 0; u32 div, mult; + int ret; if (of_property_read_u32(node, "clock-div", &div)) { pr_err("%s Fixed factor clock <%s> must have a clock-div property\n", __func__, node->name); - return; + return ERR_PTR(-EIO); } if (of_property_read_u32(node, "clock-mult", &mult)) { pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n", __func__, node->name); - return; + return ERR_PTR(-EIO); } of_property_read_string(node, "clock-output-names", &clk_name); @@ -178,10 +177,67 @@ void __init of_fixed_factor_clk_setup(struct device_node *node) clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, mult, div); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (IS_ERR(clk)) + return clk; + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + clk_unregister(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock + */ +void __init of_fixed_factor_clk_setup(struct device_node *node) +{ + _of_fixed_factor_clk_setup(node); } -EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup); CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", of_fixed_factor_clk_setup); + +static int of_fixed_factor_clk_remove(struct platform_device *pdev) +{ + struct clk *clk = platform_get_drvdata(pdev); + + clk_unregister_fixed_factor(clk); + + return 0; +} + +static int of_fixed_factor_clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + + /* + * This function is not executed when of_fixed_factor_clk_setup + * succeeded. + */ + clk = _of_fixed_factor_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static const struct of_device_id of_fixed_factor_clk_ids[] = { + { .compatible = "fixed-factor-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids); + +static struct platform_driver of_fixed_factor_clk_driver = { + .driver = { + .name = "of_fixed_factor_clk", + .of_match_table = of_fixed_factor_clk_ids, + }, + .probe = of_fixed_factor_clk_probe, + .remove = of_fixed_factor_clk_remove, +}; +builtin_platform_driver(of_fixed_factor_clk_driver); #endif diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 2edb39342a02..b5c46b3f8764 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/of.h> +#include <linux/platform_device.h> /* * DOC: basic fixed-rate clock that cannot gate @@ -157,18 +158,16 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw) EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate); #ifdef CONFIG_OF -/** - * of_fixed_clk_setup() - Setup function for simple fixed rate clock - */ -void of_fixed_clk_setup(struct device_node *node) +static struct clk *_of_fixed_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = node->name; u32 rate; u32 accuracy = 0; + int ret; if (of_property_read_u32(node, "clock-frequency", &rate)) - return; + return ERR_PTR(-EIO); of_property_read_u32(node, "clock-accuracy", &accuracy); @@ -176,9 +175,66 @@ void of_fixed_clk_setup(struct device_node *node) clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL, 0, rate, accuracy); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (IS_ERR(clk)) + return clk; + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + clk_unregister(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * of_fixed_clk_setup() - Setup function for simple fixed rate clock + */ +void __init of_fixed_clk_setup(struct device_node *node) +{ + _of_fixed_clk_setup(node); } -EXPORT_SYMBOL_GPL(of_fixed_clk_setup); CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); + +static int of_fixed_clk_remove(struct platform_device *pdev) +{ + struct clk *clk = platform_get_drvdata(pdev); + + clk_unregister_fixed_rate(clk); + + return 0; +} + +static int of_fixed_clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + + /* + * This function is not executed when of_fixed_clk_setup + * succeeded. + */ + clk = _of_fixed_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static const struct of_device_id of_fixed_clk_ids[] = { + { .compatible = "fixed-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_clk_ids); + +static struct platform_driver of_fixed_clk_driver = { + .driver = { + .name = "of_fixed_clk", + .of_match_table = of_fixed_clk_ids, + }, + .probe = of_fixed_clk_probe, + .remove = of_fixed_clk_remove, +}; +builtin_platform_driver(of_fixed_clk_driver); #endif diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c index 5097831387ff..8430e45427f4 100644 --- a/drivers/clk/clk-ls1x.c +++ b/drivers/clk/clk-ls1x.c @@ -48,13 +48,13 @@ static const struct clk_ops ls1x_pll_clk_ops = { .recalc_rate = ls1x_pll_recalc_rate, }; -static struct clk *__init clk_register_pll(struct device *dev, - const char *name, - const char *parent_name, - unsigned long flags) +static struct clk_hw *__init clk_hw_register_pll(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags) { + int ret; struct clk_hw *hw; - struct clk *clk; struct clk_init_data init; /* allocate the divider */ @@ -72,12 +72,13 @@ static struct clk *__init clk_register_pll(struct device *dev, hw->init = &init; /* register the clock */ - clk = clk_register(dev, hw); - - if (IS_ERR(clk)) + ret = clk_hw_register(dev, hw); + if (ret) { kfree(hw); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; @@ -86,14 +87,14 @@ static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; void __init ls1x_clk_init(void) { - struct clk *clk; + struct clk_hw *hw; - clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); - clk_register_clkdev(clk, "osc_33m_clk", NULL); + hw = clk_hw_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); + clk_hw_register_clkdev(hw, "osc_33m_clk", NULL); /* clock derived from 33 MHz OSC clk */ - clk = clk_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); - clk_register_clkdev(clk, "pll_clk", NULL); + hw = clk_hw_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); + clk_hw_register_clkdev(hw, "pll_clk", NULL); /* clock derived from PLL clk */ /* _____ @@ -102,17 +103,17 @@ void __init ls1x_clk_init(void) * \___ PLL ___ CPU DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "cpu_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST, &_lock); - clk_register_clkdev(clk, "cpu_clk_div", NULL); - clk = clk_register_mux(NULL, "cpu_clk", cpu_parents, + clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, ARRAY_SIZE(cpu_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "cpu_clk", NULL); + clk_hw_register_clkdev(hw, "cpu_clk", NULL); /* _____ * _______________________| | @@ -120,15 +121,15 @@ void __init ls1x_clk_init(void) * \___ PLL ___ DC DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "dc_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_register_clkdev(clk, "dc_clk_div", NULL); - clk = clk_register_mux(NULL, "dc_clk", dc_parents, + clk_hw_register_clkdev(hw, "dc_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, ARRAY_SIZE(dc_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "dc_clk", NULL); + clk_hw_register_clkdev(hw, "dc_clk", NULL); /* _____ * _______________________| | @@ -136,26 +137,26 @@ void __init ls1x_clk_init(void) * \___ PLL ___ DDR DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "ahb_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_register_clkdev(clk, "ahb_clk_div", NULL); - clk = clk_register_mux(NULL, "ahb_clk", ahb_parents, + clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, ARRAY_SIZE(ahb_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "ahb_clk", NULL); - clk_register_clkdev(clk, "stmmaceth", NULL); + clk_hw_register_clkdev(hw, "ahb_clk", NULL); + clk_hw_register_clkdev(hw, "stmmaceth", NULL); /* clock derived from AHB clk */ /* APB clk is always half of the AHB clk */ - clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, + hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, DIV_APB); - clk_register_clkdev(clk, "apb_clk", NULL); - clk_register_clkdev(clk, "ls1x_i2c", NULL); - clk_register_clkdev(clk, "ls1x_pwmtimer", NULL); - clk_register_clkdev(clk, "ls1x_spi", NULL); - clk_register_clkdev(clk, "ls1x_wdt", NULL); - clk_register_clkdev(clk, "serial8250", NULL); + clk_hw_register_clkdev(hw, "apb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x_i2c", NULL); + clk_hw_register_clkdev(hw, "ls1x_pwmtimer", NULL); + clk_hw_register_clkdev(hw, "ls1x_spi", NULL); + clk_hw_register_clkdev(hw, "ls1x_wdt", NULL); + clk_hw_register_clkdev(hw, "serial8250", NULL); } diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c deleted file mode 100644 index 35af9cb6da4f..000000000000 --- a/drivers/clk/clk-max-gen.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks - * - * Copyright (C) 2014 Google, Inc - * - * Copyright (C) 2012 Samsung Electornics - * Jonghwa Lee <jonghwa3.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on clk-max77686.c - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/regmap.h> -#include <linux/platform_device.h> -#include <linux/clk-provider.h> -#include <linux/mutex.h> -#include <linux/clkdev.h> -#include <linux/of.h> -#include <linux/export.h> - -#include "clk-max-gen.h" - -struct max_gen_clk { - struct regmap *regmap; - u32 mask; - u32 reg; - struct clk_hw hw; -}; - -static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw) -{ - return container_of(hw, struct max_gen_clk, hw); -} - -static int max_gen_clk_prepare(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - - return regmap_update_bits(max_gen->regmap, max_gen->reg, - max_gen->mask, max_gen->mask); -} - -static void max_gen_clk_unprepare(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - - regmap_update_bits(max_gen->regmap, max_gen->reg, - max_gen->mask, ~max_gen->mask); -} - -static int max_gen_clk_is_prepared(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - int ret; - u32 val; - - ret = regmap_read(max_gen->regmap, max_gen->reg, &val); - - if (ret < 0) - return -EINVAL; - - return val & max_gen->mask; -} - -static unsigned long max_gen_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return 32768; -} - -struct clk_ops max_gen_clk_ops = { - .prepare = max_gen_clk_prepare, - .unprepare = max_gen_clk_unprepare, - .is_prepared = max_gen_clk_is_prepared, - .recalc_rate = max_gen_recalc_rate, -}; -EXPORT_SYMBOL_GPL(max_gen_clk_ops); - -static struct clk *max_gen_clk_register(struct device *dev, - struct max_gen_clk *max_gen) -{ - struct clk *clk; - struct clk_hw *hw = &max_gen->hw; - int ret; - - clk = devm_clk_register(dev, hw); - if (IS_ERR(clk)) - return clk; - - ret = clk_register_clkdev(clk, hw->init->name, NULL); - - if (ret) - return ERR_PTR(ret); - - return clk; -} - -int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, - u32 reg, struct clk_init_data *clks_init, int num_init) -{ - int i, ret; - struct max_gen_clk *max_gen_clks; - struct clk **clocks; - struct device *dev = pdev->dev.parent; - const char *clk_name; - struct clk_init_data *init; - - clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); - if (!clocks) - return -ENOMEM; - - max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) - * num_init, GFP_KERNEL); - if (!max_gen_clks) - return -ENOMEM; - - for (i = 0; i < num_init; i++) { - max_gen_clks[i].regmap = regmap; - max_gen_clks[i].mask = 1 << i; - max_gen_clks[i].reg = reg; - - init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL); - if (!init) - return -ENOMEM; - - if (dev->of_node && - !of_property_read_string_index(dev->of_node, - "clock-output-names", - i, &clk_name)) - init->name = clk_name; - else - init->name = clks_init[i].name; - - init->ops = clks_init[i].ops; - init->flags = clks_init[i].flags; - - max_gen_clks[i].hw.init = init; - - clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]); - if (IS_ERR(clocks[i])) { - ret = PTR_ERR(clocks[i]); - dev_err(dev, "failed to register %s\n", - max_gen_clks[i].hw.init->name); - return ret; - } - } - - platform_set_drvdata(pdev, clocks); - - if (dev->of_node) { - struct clk_onecell_data *of_data; - - of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); - if (!of_data) - return -ENOMEM; - - of_data->clks = clocks; - of_data->clk_num = num_init; - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, - of_data); - - if (ret) { - dev_err(dev, "failed to register OF clock provider\n"); - return ret; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(max_gen_clk_probe); - -int max_gen_clk_remove(struct platform_device *pdev, int num_init) -{ - struct device *dev = pdev->dev.parent; - - if (dev->of_node) - of_clk_del_provider(dev->of_node); - - return 0; -} -EXPORT_SYMBOL_GPL(max_gen_clk_remove); diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h deleted file mode 100644 index 997e86fc3f4d..000000000000 --- a/drivers/clk/clk-max-gen.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks - * - * Copyright (C) 2014 Google, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __CLK_MAX_GEN_H__ -#define __CLK_MAX_GEN_H__ - -#include <linux/types.h> -#include <linux/device.h> -#include <linux/clkdev.h> -#include <linux/regmap.h> -#include <linux/platform_device.h> - -int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, - u32 reg, struct clk_init_data *clks_init, int num_init); -int max_gen_clk_remove(struct platform_device *pdev, int num_init); -extern struct clk_ops max_gen_clk_ops; - -#endif /* __CLK_MAX_GEN_H__ */ diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 9b6f2772e948..b637f5979023 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -1,5 +1,5 @@ /* - * clk-max77686.c - Clock driver for Maxim 77686 + * clk-max77686.c - Clock driver for Maxim 77686/MAX77802 * * Copyright (C) 2012 Samsung Electornics * Jonghwa Lee <jonghwa3.lee@samsung.com> @@ -25,46 +25,284 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/mfd/max77620.h> #include <linux/mfd/max77686.h> #include <linux/mfd/max77686-private.h> #include <linux/clk-provider.h> #include <linux/mutex.h> #include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/regmap.h> #include <dt-bindings/clock/maxim,max77686.h> -#include "clk-max-gen.h" +#include <dt-bindings/clock/maxim,max77802.h> +#include <dt-bindings/clock/maxim,max77620.h> -static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { +#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 + +enum max77686_chip_name { + CHIP_MAX77686, + CHIP_MAX77802, + CHIP_MAX77620, +}; + +struct max77686_hw_clk_info { + const char *name; + u32 clk_reg; + u32 clk_enable_mask; + u32 flags; +}; + +struct max77686_clk_init_data { + struct regmap *regmap; + struct clk_hw hw; + struct clk_init_data clk_idata; + const struct max77686_hw_clk_info *clk_info; +}; + +struct max77686_clk_driver_data { + enum max77686_chip_name chip; + struct max77686_clk_init_data *max_clk_data; + size_t num_clks; +}; + +static const struct +max77686_hw_clk_info max77686_hw_clks_info[MAX77686_CLKS_NUM] = { [MAX77686_CLK_AP] = { .name = "32khz_ap", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_AP), }, [MAX77686_CLK_CP] = { .name = "32khz_cp", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_CP), }, [MAX77686_CLK_PMIC] = { .name = "32khz_pmic", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_PMIC), + }, +}; + +static const struct +max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = { + [MAX77802_CLK_32K_AP] = { + .name = "32khz_ap", + .clk_reg = MAX77802_REG_32KHZ, + .clk_enable_mask = BIT(MAX77802_CLK_32K_AP), + }, + [MAX77802_CLK_32K_CP] = { + .name = "32khz_cp", + .clk_reg = MAX77802_REG_32KHZ, + .clk_enable_mask = BIT(MAX77802_CLK_32K_CP), + }, +}; + +static const struct +max77686_hw_clk_info max77620_hw_clks_info[MAX77620_CLKS_NUM] = { + [MAX77620_CLK_32K_OUT0] = { + .name = "32khz_out0", + .clk_reg = MAX77620_REG_CNFG1_32K, + .clk_enable_mask = MAX77620_CNFG1_32K_OUT0_EN, }, }; +static struct max77686_clk_init_data *to_max77686_clk_init_data( + struct clk_hw *hw) +{ + return container_of(hw, struct max77686_clk_init_data, hw); +} + +static int max77686_clk_prepare(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + + return regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg, + max77686->clk_info->clk_enable_mask, + max77686->clk_info->clk_enable_mask); +} + +static void max77686_clk_unprepare(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + + regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg, + max77686->clk_info->clk_enable_mask, + ~max77686->clk_info->clk_enable_mask); +} + +static int max77686_clk_is_prepared(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + int ret; + u32 val; + + ret = regmap_read(max77686->regmap, max77686->clk_info->clk_reg, &val); + + if (ret < 0) + return -EINVAL; + + return val & max77686->clk_info->clk_enable_mask; +} + +static unsigned long max77686_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 32768; +} + +static struct clk_ops max77686_clk_ops = { + .prepare = max77686_clk_prepare, + .unprepare = max77686_clk_unprepare, + .is_prepared = max77686_clk_is_prepared, + .recalc_rate = max77686_recalc_rate, +}; + +static struct clk_hw * +of_clk_max77686_get(struct of_phandle_args *clkspec, void *data) +{ + struct max77686_clk_driver_data *drv_data = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= drv_data->num_clks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &drv_data->max_clk_data[idx].hw; +} + static int max77686_clk_probe(struct platform_device *pdev) { - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + const struct platform_device_id *id = platform_get_device_id(pdev); + struct max77686_clk_driver_data *drv_data; + const struct max77686_hw_clk_info *hw_clks; + struct regmap *regmap; + int i, ret, num_clks; + + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + regmap = dev_get_regmap(parent, NULL); + if (!regmap) { + dev_err(dev, "Failed to get rtc regmap\n"); + return -ENODEV; + } + + drv_data->chip = id->driver_data; + + switch (drv_data->chip) { + case CHIP_MAX77686: + num_clks = MAX77686_CLKS_NUM; + hw_clks = max77686_hw_clks_info; + break; + + case CHIP_MAX77802: + num_clks = MAX77802_CLKS_NUM; + hw_clks = max77802_hw_clks_info; + break; + + case CHIP_MAX77620: + num_clks = MAX77620_CLKS_NUM; + hw_clks = max77620_hw_clks_info; + break; - return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ, - max77686_clks_init, MAX77686_CLKS_NUM); + default: + dev_err(dev, "Unknown Chip ID\n"); + return -EINVAL; + } + + drv_data->max_clk_data = devm_kcalloc(dev, num_clks, + sizeof(*drv_data->max_clk_data), + GFP_KERNEL); + if (!drv_data->max_clk_data) + return -ENOMEM; + + for (i = 0; i < num_clks; i++) { + struct max77686_clk_init_data *max_clk_data; + const char *clk_name; + + max_clk_data = &drv_data->max_clk_data[i]; + + max_clk_data->regmap = regmap; + max_clk_data->clk_info = &hw_clks[i]; + max_clk_data->clk_idata.flags = hw_clks[i].flags; + max_clk_data->clk_idata.ops = &max77686_clk_ops; + + if (parent->of_node && + !of_property_read_string_index(parent->of_node, + "clock-output-names", + i, &clk_name)) + max_clk_data->clk_idata.name = clk_name; + else + max_clk_data->clk_idata.name = hw_clks[i].name; + + max_clk_data->hw.init = &max_clk_data->clk_idata; + + ret = devm_clk_hw_register(dev, &max_clk_data->hw); + if (ret) { + dev_err(dev, "Failed to clock register: %d\n", ret); + return ret; + } + + ret = clk_hw_register_clkdev(&max_clk_data->hw, + max_clk_data->clk_idata.name, NULL); + if (ret < 0) { + dev_err(dev, "Failed to clkdev register: %d\n", ret); + return ret; + } + } + + if (parent->of_node) { + ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get, + drv_data); + + if (ret < 0) { + dev_err(dev, "Failed to register OF clock provider: %d\n", + ret); + return ret; + } + } + + /* MAX77802: Enable low-jitter mode on the 32khz clocks. */ + if (drv_data->chip == CHIP_MAX77802) { + ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ, + 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, + 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); + if (ret < 0) { + dev_err(dev, "Failed to config low-jitter: %d\n", ret); + goto remove_of_clk_provider; + } + } + + return 0; + +remove_of_clk_provider: + if (parent->of_node) + of_clk_del_provider(parent->of_node); + + return ret; } static int max77686_clk_remove(struct platform_device *pdev) { - return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM); + struct device *parent = pdev->dev.parent; + + if (parent->of_node) + of_clk_del_provider(parent->of_node); + + return 0; } static const struct platform_device_id max77686_clk_id[] = { - { "max77686-clk", 0}, - { }, + { "max77686-clk", .driver_data = CHIP_MAX77686, }, + { "max77802-clk", .driver_data = CHIP_MAX77802, }, + { "max77620-clock", .driver_data = CHIP_MAX77620, }, + {}, }; MODULE_DEVICE_TABLE(platform, max77686_clk_id); diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c deleted file mode 100644 index 355dd2e522c3..000000000000 --- a/drivers/clk/clk-max77802.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * clk-max77802.c - Clock driver for Maxim 77802 - * - * Copyright (C) 2014 Google, Inc - * - * Copyright (C) 2012 Samsung Electornics - * Jonghwa Lee <jonghwa3.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on clk-max77686.c - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mfd/max77686-private.h> -#include <linux/clk-provider.h> -#include <linux/mutex.h> -#include <linux/clkdev.h> - -#include <dt-bindings/clock/maxim,max77802.h> -#include "clk-max-gen.h" - -#define MAX77802_CLOCK_OPMODE_MASK 0x1 -#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 - -static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = { - [MAX77802_CLK_32K_AP] = { - .name = "32khz_ap", - .ops = &max_gen_clk_ops, - }, - [MAX77802_CLK_32K_CP] = { - .name = "32khz_cp", - .ops = &max_gen_clk_ops, - }, -}; - -static int max77802_clk_probe(struct platform_device *pdev) -{ - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - int ret; - - ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ, - max77802_clks_init, MAX77802_CLKS_NUM); - - if (ret) { - dev_err(&pdev->dev, "generic probe failed %d\n", ret); - return ret; - } - - /* Enable low-jitter mode on the 32khz clocks. */ - ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ, - 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, - 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); - if (ret < 0) - dev_err(&pdev->dev, "failed to enable low-jitter mode\n"); - - return ret; -} - -static int max77802_clk_remove(struct platform_device *pdev) -{ - return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM); -} - -static const struct platform_device_id max77802_clk_id[] = { - { "max77802-clk", 0}, - { }, -}; -MODULE_DEVICE_TABLE(platform, max77802_clk_id); - -static struct platform_driver max77802_clk_driver = { - .driver = { - .name = "max77802-clk", - }, - .probe = max77802_clk_probe, - .remove = max77802_clk_remove, - .id_table = max77802_clk_id, -}; - -module_platform_driver(max77802_clk_driver); - -MODULE_DESCRIPTION("MAXIM 77802 Clock Driver"); -MODULE_AUTHOR("Javier Martinez Canillas <javier@osg.samsung.com"); -MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-mb86s7x.c b/drivers/clk/clk-mb86s7x.c index e0817754ca3e..2a83a3ff1d09 100644 --- a/drivers/clk/clk-mb86s7x.c +++ b/drivers/clk/clk-mb86s7x.c @@ -327,10 +327,11 @@ static struct clk_ops clk_clc_ops = { .set_rate = clc_set_rate, }; -struct clk *mb86s7x_clclk_register(struct device *cpu_dev) +static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev) { struct clk_init_data init; struct cl_clk *clc; + int ret; clc = kzalloc(sizeof(*clc), GFP_KERNEL); if (!clc) @@ -344,14 +345,17 @@ struct clk *mb86s7x_clclk_register(struct device *cpu_dev) init.flags = CLK_GET_RATE_NOCACHE; init.num_parents = 0; - return devm_clk_register(cpu_dev, &clc->hw); + ret = devm_clk_hw_register(cpu_dev, &clc->hw); + if (ret) + return ERR_PTR(ret); + return &clc->hw; } static int mb86s7x_clclk_of_init(void) { int cpu, ret = -ENODEV; struct device_node *np; - struct clk *clk; + struct clk_hw *hw; np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0"); if (!np || !of_device_is_available(np)) @@ -365,12 +369,12 @@ static int mb86s7x_clclk_of_init(void) continue; } - clk = mb86s7x_clclk_register(cpu_dev); - if (IS_ERR(clk)) { + hw = mb86s7x_clclk_register(cpu_dev); + if (IS_ERR(hw)) { pr_err("failed to register cpu%d clock\n", cpu); continue; } - if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { + if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) { pr_err("failed to register cpu%d clock lookup\n", cpu); continue; } diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c index f37f719643ec..b86dac851116 100644 --- a/drivers/clk/clk-moxart.c +++ b/drivers/clk/clk-moxart.c @@ -19,7 +19,8 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) { static void __iomem *base; - struct clk *clk, *ref_clk; + struct clk_hw *hw; + struct clk *ref_clk; unsigned int mul; const char *name = node->name; const char *parent_name; @@ -42,14 +43,14 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) return; } - clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); - if (IS_ERR(clk)) { + hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); + if (IS_ERR(hw)) { pr_err("%s: failed to register clock\n", node->full_name); return; } - clk_register_clkdev(clk, NULL, name); - of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_hw_register_clkdev(hw, NULL, name); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", moxart_of_pll_clk_init); @@ -57,7 +58,8 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", static void __init moxart_of_apb_clk_init(struct device_node *node) { static void __iomem *base; - struct clk *clk, *pll_clk; + struct clk_hw *hw; + struct clk *pll_clk; unsigned int div, val; unsigned int div_idx[] = { 2, 3, 4, 6, 8}; const char *name = node->name; @@ -85,14 +87,14 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) return; } - clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div); - if (IS_ERR(clk)) { + hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div); + if (IS_ERR(hw)) { pr_err("%s: failed to register clock\n", node->full_name); return; } - clk_register_clkdev(clk, NULL, name); - of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_hw_register_clkdev(hw, NULL, name); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", moxart_of_apb_clk_init); diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c index 64f196a90816..f861011d5d21 100644 --- a/drivers/clk/clk-nspire.c +++ b/drivers/clk/clk-nspire.c @@ -69,7 +69,7 @@ static void __init nspire_ahbdiv_setup(struct device_node *node, { u32 val; void __iomem *io; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; const char *parent_name; struct nspire_clk_info info; @@ -85,10 +85,10 @@ static void __init nspire_ahbdiv_setup(struct device_node *node, of_property_read_string(node, "clock-output-names", &clk_name); parent_name = of_clk_get_parent_name(node, 0); - clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, - 1, info.base_ahb_ratio); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + hw = clk_hw_register_fixed_factor(NULL, clk_name, parent_name, 0, + 1, info.base_ahb_ratio); + if (!IS_ERR(hw)) + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } static void __init nspire_ahbdiv_setup_cx(struct device_node *node) @@ -111,7 +111,7 @@ static void __init nspire_clk_setup(struct device_node *node, { u32 val; void __iomem *io; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; struct nspire_clk_info info; @@ -125,9 +125,10 @@ static void __init nspire_clk_setup(struct device_node *node, of_property_read_string(node, "clock-output-names", &clk_name); - clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, info.base_clock); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + hw = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, + info.base_clock); + if (!IS_ERR(hw)) + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); else return; diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 8328863cb0e0..31f590cea493 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -41,7 +41,6 @@ struct palmas_clk32k_desc { struct palmas_clock_info { struct device *dev; - struct clk *clk; struct clk_hw hw; struct palmas *palmas; const struct palmas_clk32k_desc *clk_desc; @@ -218,7 +217,7 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) } if (cinfo->ext_control_pin) { - ret = clk_prepare(cinfo->clk); + ret = clk_prepare(cinfo->hw.clk); if (ret < 0) { dev_err(cinfo->dev, "Clock prep failed, %d\n", ret); return ret; @@ -242,7 +241,6 @@ static int palmas_clks_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const struct palmas_clks_of_match_data *match_data; struct palmas_clock_info *cinfo; - struct clk *clk; int ret; match_data = of_device_get_match_data(&pdev->dev); @@ -261,22 +259,20 @@ static int palmas_clks_probe(struct platform_device *pdev) cinfo->clk_desc = &match_data->desc; cinfo->hw.init = &match_data->init; - clk = devm_clk_register(&pdev->dev, &cinfo->hw); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &cinfo->hw); + if (ret) { dev_err(&pdev->dev, "Fail to register clock %s, %d\n", match_data->desc.clk_name, ret); return ret; } - cinfo->clk = clk; ret = palmas_clks_init_configure(cinfo); if (ret < 0) { dev_err(&pdev->dev, "Clock config failed, %d\n", ret); return ret; } - ret = of_clk_add_provider(node, of_clk_src_simple_get, cinfo->clk); + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &cinfo->hw); if (ret < 0) dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret); return ret; diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 1630a1f085f7..8cb9d117fdbf 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -61,7 +61,6 @@ static int clk_pwm_probe(struct platform_device *pdev) struct pwm_device *pwm; struct pwm_args pargs; const char *clk_name; - struct clk *clk; int ret; clk_pwm = devm_kzalloc(&pdev->dev, sizeof(*clk_pwm), GFP_KERNEL); @@ -107,11 +106,11 @@ static int clk_pwm_probe(struct platform_device *pdev) clk_pwm->pwm = pwm; clk_pwm->hw.init = &init; - clk = devm_clk_register(&pdev->dev, &clk_pwm->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &clk_pwm->hw); + if (ret) + return ret; - return of_clk_add_provider(node, of_clk_src_simple_get, clk); + return of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clk_pwm->hw); } static int clk_pwm_remove(struct platform_device *pdev) diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 58566a17944a..20b105584f82 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -766,7 +766,11 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) if (!hwc) return NULL; - hwc->reg = cg->regs + 0x20 * idx; + if (cg->info.flags & CG_VER3) + hwc->reg = cg->regs + 0x70000 + 0x20 * idx; + else + hwc->reg = cg->regs + 0x20 * idx; + hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]]; /* diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c index 74383039761e..6461f2820a5b 100644 --- a/drivers/clk/clk-rk808.c +++ b/drivers/clk/clk-rk808.c @@ -22,11 +22,8 @@ #include <linux/mfd/rk808.h> #include <linux/i2c.h> -#define RK808_NR_OUTPUT 2 - struct rk808_clkout { struct rk808 *rk808; - struct clk_onecell_data clk_data; struct clk_hw clkout1_hw; struct clk_hw clkout2_hw; }; @@ -85,14 +82,28 @@ static const struct clk_ops rk808_clkout2_ops = { .recalc_rate = rk808_clkout_recalc_rate, }; +static struct clk_hw * +of_clk_rk808_get(struct of_phandle_args *clkspec, void *data) +{ + struct rk808_clkout *rk808_clkout = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= 2) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw; +} + static int rk808_clkout_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); struct i2c_client *client = rk808->i2c; struct device_node *node = client->dev.of_node; struct clk_init_data init = {}; - struct clk **clk_table; struct rk808_clkout *rk808_clkout; + int ret; rk808_clkout = devm_kzalloc(&client->dev, sizeof(*rk808_clkout), GFP_KERNEL); @@ -101,11 +112,6 @@ static int rk808_clkout_probe(struct platform_device *pdev) rk808_clkout->rk808 = rk808; - clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT, - sizeof(struct clk *), GFP_KERNEL); - if (!clk_table) - return -ENOMEM; - init.parent_names = NULL; init.num_parents = 0; init.name = "rk808-clkout1"; @@ -116,10 +122,9 @@ static int rk808_clkout_probe(struct platform_device *pdev) of_property_read_string_index(node, "clock-output-names", 0, &init.name); - clk_table[0] = devm_clk_register(&client->dev, - &rk808_clkout->clkout1_hw); - if (IS_ERR(clk_table[0])) - return PTR_ERR(clk_table[0]); + ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw); + if (ret) + return ret; init.name = "rk808-clkout2"; init.ops = &rk808_clkout2_ops; @@ -129,16 +134,11 @@ static int rk808_clkout_probe(struct platform_device *pdev) of_property_read_string_index(node, "clock-output-names", 1, &init.name); - clk_table[1] = devm_clk_register(&client->dev, - &rk808_clkout->clkout2_hw); - if (IS_ERR(clk_table[1])) - return PTR_ERR(clk_table[1]); - - rk808_clkout->clk_data.clks = clk_table; - rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT; + ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw); + if (ret) + return ret; - return of_clk_add_provider(node, of_clk_src_onecell_get, - &rk808_clkout->clk_data); + return of_clk_add_hw_provider(node, of_clk_rk808_get, rk808_clkout); } static int rk808_clkout_remove(struct platform_device *pdev) diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 6962ee5d1e9a..2a3e9d8e88b0 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -146,13 +146,13 @@ static const struct of_device_id scpi_clk_match[] = { {} }; -static struct clk * +static int scpi_clk_ops_init(struct device *dev, const struct of_device_id *match, struct scpi_clk *sclk, const char *name) { struct clk_init_data init; - struct clk *clk; unsigned long min = 0, max = 0; + int ret; init.name = name; init.flags = 0; @@ -164,18 +164,18 @@ scpi_clk_ops_init(struct device *dev, const struct of_device_id *match, if (init.ops == &scpi_dvfs_ops) { sclk->info = sclk->scpi_ops->dvfs_get_info(sclk->id); if (IS_ERR(sclk->info)) - return NULL; + return PTR_ERR(sclk->info); } else if (init.ops == &scpi_clk_ops) { if (sclk->scpi_ops->clk_get_range(sclk->id, &min, &max) || !max) - return NULL; + return -EINVAL; } else { - return NULL; + return -EINVAL; } - clk = devm_clk_register(dev, &sclk->hw); - if (!IS_ERR(clk) && max) + ret = devm_clk_hw_register(dev, &sclk->hw); + if (!ret && max) clk_hw_set_rate_range(&sclk->hw, min, max); - return clk; + return ret; } struct scpi_clk_data { @@ -183,7 +183,7 @@ struct scpi_clk_data { unsigned int clk_num; }; -static struct clk * +static struct clk_hw * scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) { struct scpi_clk *sclk; @@ -193,7 +193,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) for (count = 0; count < clk_data->clk_num; count++) { sclk = clk_data->clk[count]; if (idx == sclk->id) - return sclk->hw.clk; + return &sclk->hw; } return ERR_PTR(-EINVAL); @@ -202,8 +202,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) static int scpi_clk_add(struct device *dev, struct device_node *np, const struct of_device_id *match) { - struct clk **clks; - int idx, count; + int idx, count, err; struct scpi_clk_data *clk_data; count = of_property_count_strings(np, "clock-output-names"); @@ -222,10 +221,6 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, if (!clk_data->clk) return -ENOMEM; - clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL); - if (!clks) - return -ENOMEM; - for (idx = 0; idx < count; idx++) { struct scpi_clk *sclk; const char *name; @@ -249,15 +244,15 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, sclk->id = val; - clks[idx] = scpi_clk_ops_init(dev, match, sclk, name); - if (IS_ERR_OR_NULL(clks[idx])) + err = scpi_clk_ops_init(dev, match, sclk, name); + if (err) dev_err(dev, "failed to register clock '%s'\n", name); else dev_dbg(dev, "Registered clock '%s'\n", name); clk_data->clk[idx] = sclk; } - return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data); + return of_clk_add_hw_provider(np, scpi_of_clk_src_get, clk_data); } static int scpi_clocks_remove(struct platform_device *pdev) diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index ceef25b0990b..09b6718956bd 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -305,7 +305,6 @@ static int si514_probe(struct i2c_client *client, { struct clk_si514 *data; struct clk_init_data init; - struct clk *clk; int err; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); @@ -330,13 +329,13 @@ static int si514_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - clk = devm_clk_register(&client->dev, &data->hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->hw); + if (err) { dev_err(&client->dev, "clock registration failed\n"); - return PTR_ERR(clk); + return err; } - err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, - clk); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index b1bc12c045d3..b051db43fae1 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -54,7 +54,6 @@ struct si5351_driver_data { enum si5351_variant variant; struct i2c_client *client; struct regmap *regmap; - struct clk_onecell_data onecell; struct clk *pxtal; const char *pxtal_name; @@ -66,6 +65,7 @@ struct si5351_driver_data { struct si5351_hw_data pll[2]; struct si5351_hw_data *msynth; struct si5351_hw_data *clkout; + size_t num_clkout; }; static const char * const si5351_input_names[] = { @@ -1307,11 +1307,31 @@ put_child: of_node_put(child); return -EINVAL; } + +static struct clk_hw * +si53351_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct si5351_driver_data *drvdata = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= drvdata->num_clkout) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &drvdata->clkout[idx].hw; +} #else static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant) { return 0; } + +static struct clk_hw * +si53351_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + return NULL; +} #endif /* CONFIG_OF */ static int si5351_i2c_probe(struct i2c_client *client, @@ -1321,7 +1341,6 @@ static int si5351_i2c_probe(struct i2c_client *client, struct si5351_platform_data *pdata; struct si5351_driver_data *drvdata; struct clk_init_data init; - struct clk *clk; const char *parent_names[4]; u8 num_parents, num_clocks; int ret, n; @@ -1438,10 +1457,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.num_parents = 1; } drvdata->xtal.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->xtal); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->xtal); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1456,11 +1474,10 @@ static int si5351_i2c_probe(struct i2c_client *client, init.num_parents = 1; } drvdata->clkin.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->clkin); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->clkin); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } } @@ -1480,10 +1497,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags = 0; init.parent_names = parent_names; init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1505,10 +1521,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.parent_names = parent_names; init.num_parents = num_parents; } - clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1524,13 +1539,9 @@ static int si5351_i2c_probe(struct i2c_client *client, sizeof(*drvdata->msynth), GFP_KERNEL); drvdata->clkout = devm_kzalloc(&client->dev, num_clocks * sizeof(*drvdata->clkout), GFP_KERNEL); + drvdata->num_clkout = num_clocks; - drvdata->onecell.clk_num = num_clocks; - drvdata->onecell.clks = devm_kzalloc(&client->dev, - num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); - - if (WARN_ON(!drvdata->msynth || !drvdata->clkout || - !drvdata->onecell.clks)) { + if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) { ret = -ENOMEM; goto err_clk; } @@ -1547,11 +1558,11 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags |= CLK_SET_RATE_PARENT; init.parent_names = parent_names; init.num_parents = 2; - clk = devm_clk_register(&client->dev, &drvdata->msynth[n].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, + &drvdata->msynth[n].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } } @@ -1575,19 +1586,19 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags |= CLK_SET_RATE_PARENT; init.parent_names = parent_names; init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->clkout[n].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, + &drvdata->clkout[n].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } - drvdata->onecell.clks[n] = clk; /* set initial clkout rate */ if (pdata->clkout[n].rate != 0) { int ret; - ret = clk_set_rate(clk, pdata->clkout[n].rate); + ret = clk_set_rate(drvdata->clkout[n].hw.clk, + pdata->clkout[n].rate); if (ret != 0) { dev_err(&client->dev, "Cannot set rate : %d\n", ret); @@ -1595,8 +1606,8 @@ static int si5351_i2c_probe(struct i2c_client *client, } } - ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &drvdata->onecell); + ret = of_clk_add_hw_provider(client->dev.of_node, si53351_of_clk_get, + drvdata); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); goto err_clk; diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index d56648521a95..646af1d1898d 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -408,7 +408,6 @@ static int si570_probe(struct i2c_client *client, { struct clk_si570 *data; struct clk_init_data init; - struct clk *clk; u32 initial_fout, factory_fout, stability; int err; enum clk_si570_variant variant = id->driver_data; @@ -462,13 +461,13 @@ static int si570_probe(struct i2c_client *client, if (err) return err; - clk = devm_clk_register(&client->dev, &data->hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->hw); + if (err) { dev_err(&client->dev, "clock registration failed\n"); - return PTR_ERR(clk); + return err; } - err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, - clk); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; @@ -477,7 +476,7 @@ static int si570_probe(struct i2c_client *client, /* Read the requested initial output frequency from device tree */ if (!of_property_read_u32(client->dev.of_node, "clock-frequency", &initial_fout)) { - err = clk_set_rate(clk, initial_fout); + err = clk_set_rate(data->hw.clk, initial_fout); if (err) { of_clk_del_provider(client->dev.of_node); return err; diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 697c66757400..7b222a5db931 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -26,60 +26,73 @@ #include <linux/mfd/twl6040.h> #include <linux/clk-provider.h> -struct twl6040_clk { +struct twl6040_pdmclk { struct twl6040 *twl6040; struct device *dev; - struct clk_hw mcpdm_fclk; - struct clk *clk; + struct clk_hw pdmclk_hw; int enabled; }; -static int twl6040_bitclk_is_enabled(struct clk_hw *hw) +static int twl6040_pdmclk_is_prepared(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); - return twl6040_clk->enabled; + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); + + return pdmclk->enabled; } -static int twl6040_bitclk_prepare(struct clk_hw *hw) +static int twl6040_pdmclk_prepare(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); int ret; - ret = twl6040_power(twl6040_clk->twl6040, 1); + ret = twl6040_power(pdmclk->twl6040, 1); if (!ret) - twl6040_clk->enabled = 1; + pdmclk->enabled = 1; return ret; } -static void twl6040_bitclk_unprepare(struct clk_hw *hw) +static void twl6040_pdmclk_unprepare(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); int ret; - ret = twl6040_power(twl6040_clk->twl6040, 0); + ret = twl6040_power(pdmclk->twl6040, 0); if (!ret) - twl6040_clk->enabled = 0; + pdmclk->enabled = 0; + } -static const struct clk_ops twl6040_mcpdm_ops = { - .is_enabled = twl6040_bitclk_is_enabled, - .prepare = twl6040_bitclk_prepare, - .unprepare = twl6040_bitclk_unprepare, +static unsigned long twl6040_pdmclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); + + return twl6040_get_sysclk(pdmclk->twl6040); +} + +static const struct clk_ops twl6040_pdmclk_ops = { + .is_prepared = twl6040_pdmclk_is_prepared, + .prepare = twl6040_pdmclk_prepare, + .unprepare = twl6040_pdmclk_unprepare, + .recalc_rate = twl6040_pdmclk_recalc_rate, }; -static struct clk_init_data wm831x_clkout_init = { - .name = "mcpdm_fclk", - .ops = &twl6040_mcpdm_ops, +static struct clk_init_data twl6040_pdmclk_init = { + .name = "pdmclk", + .ops = &twl6040_pdmclk_ops, + .flags = CLK_GET_RATE_NOCACHE, }; -static int twl6040_clk_probe(struct platform_device *pdev) +static int twl6040_pdmclk_probe(struct platform_device *pdev) { struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent); - struct twl6040_clk *clkdata; + struct twl6040_pdmclk *clkdata; + int ret; clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); if (!clkdata) @@ -88,26 +101,28 @@ static int twl6040_clk_probe(struct platform_device *pdev) clkdata->dev = &pdev->dev; clkdata->twl6040 = twl6040; - clkdata->mcpdm_fclk.init = &wm831x_clkout_init; - clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk); - if (IS_ERR(clkdata->clk)) - return PTR_ERR(clkdata->clk); + clkdata->pdmclk_hw.init = &twl6040_pdmclk_init; + ret = devm_clk_hw_register(&pdev->dev, &clkdata->pdmclk_hw); + if (ret) + return ret; platform_set_drvdata(pdev, clkdata); - return 0; + return of_clk_add_hw_provider(pdev->dev.parent->of_node, + of_clk_hw_simple_get, + &clkdata->pdmclk_hw); } -static struct platform_driver twl6040_clk_driver = { +static struct platform_driver twl6040_pdmclk_driver = { .driver = { - .name = "twl6040-clk", + .name = "twl6040-pdmclk", }, - .probe = twl6040_clk_probe, + .probe = twl6040_pdmclk_probe, }; -module_platform_driver(twl6040_clk_driver); +module_platform_driver(twl6040_pdmclk_driver); MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock"); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_ALIAS("platform:twl6040-clk"); +MODULE_ALIAS("platform:twl6040-pdmclk"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 37368a399ff9..4161a6f25741 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -232,7 +232,7 @@ static const struct clk_ops vt8500_gated_divisor_clk_ops = { static __init void vtwm_device_clk_init(struct device_node *node) { u32 en_reg, div_reg; - struct clk *clk; + struct clk_hw *hw; struct clk_device *dev_clk; const char *clk_name = node->name; const char *parent_name; @@ -301,13 +301,14 @@ static __init void vtwm_device_clk_init(struct device_node *node) dev_clk->hw.init = &init; - clk = clk_register(NULL, &dev_clk->hw); - if (WARN_ON(IS_ERR(clk))) { + hw = &dev_clk->hw; + rc = clk_hw_register(NULL, hw); + if (WARN_ON(rc)) { kfree(dev_clk); return; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); + clk_hw_register_clkdev(hw, clk_name, NULL); } CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init); @@ -681,7 +682,7 @@ static const struct clk_ops vtwm_pll_ops = { static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) { u32 reg; - struct clk *clk; + struct clk_hw *hw; struct clk_pll *pll_clk; const char *clk_name = node->name; const char *parent_name; @@ -714,13 +715,14 @@ static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) pll_clk->hw.init = &init; - clk = clk_register(NULL, &pll_clk->hw); - if (WARN_ON(IS_ERR(clk))) { + hw = &pll_clk->hw; + rc = clk_hw_register(NULL, &pll_clk->hw); + if (WARN_ON(rc)) { kfree(pll_clk); return; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); + clk_hw_register_clkdev(hw, clk_name, NULL); } diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 88def4b2761c..f4fdac55727c 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -24,9 +24,6 @@ struct wm831x_clk { struct clk_hw xtal_hw; struct clk_hw fll_hw; struct clk_hw clkout_hw; - struct clk *xtal; - struct clk *fll; - struct clk *clkout; bool xtal_ena; }; @@ -370,19 +367,19 @@ static int wm831x_clk_probe(struct platform_device *pdev) clkdata->xtal_ena = ret & WM831X_XTAL_ENA; clkdata->xtal_hw.init = &wm831x_xtal_init; - clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw); - if (IS_ERR(clkdata->xtal)) - return PTR_ERR(clkdata->xtal); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw); + if (ret) + return ret; clkdata->fll_hw.init = &wm831x_fll_init; - clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw); - if (IS_ERR(clkdata->fll)) - return PTR_ERR(clkdata->fll); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw); + if (ret) + return ret; clkdata->clkout_hw.init = &wm831x_clkout_init; - clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw); - if (IS_ERR(clkdata->clkout)) - return PTR_ERR(clkdata->clkout); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw); + if (ret) + return ret; platform_set_drvdata(pdev, clkdata); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 820a939fb6bb..0fb39fe217d1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1908,10 +1908,6 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); - /* bail early if nothing to do */ - if (degrees == clk->core->phase) - goto out; - trace_clk_set_phase(clk->core, degrees); if (clk->core->ops->set_phase) @@ -1922,7 +1918,6 @@ int clk_set_phase(struct clk *clk, int degrees) if (!ret) clk->core->phase = degrees; -out: clk_prepare_unlock(); return ret; @@ -2449,8 +2444,16 @@ static int __clk_core_init(struct clk_core *core) hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); - if (parent) - clk_core_reparent(orphan, parent); + /* + * we could call __clk_set_parent, but that would result in a + * redundant call to the .set_rate op, if it exists + */ + if (parent) { + __clk_set_parent_before(orphan, parent); + __clk_set_parent_after(orphan, parent, NULL); + __clk_recalc_accuracies(orphan); + __clk_recalc_rates(orphan, 0); + } } /* @@ -2491,7 +2494,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, /* This is to allow this function to be chained to others */ if (IS_ERR_OR_NULL(hw)) - return (struct clk *) hw; + return ERR_CAST(hw); clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) @@ -3166,19 +3169,14 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider, struct of_phandle_args *clkspec) { struct clk *clk; - struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); - if (provider->get_hw) { - hw = provider->get_hw(clkspec, provider->data); - } else if (provider->get) { - clk = provider->get(clkspec, provider->data); - if (!IS_ERR(clk)) - hw = __clk_get_hw(clk); - else - hw = ERR_CAST(clk); - } + if (provider->get_hw) + return provider->get_hw(clkspec, provider->data); - return hw; + clk = provider->get(clkspec, provider->data); + if (IS_ERR(clk)) + return ERR_CAST(clk); + return __clk_get_hw(clk); } struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, @@ -3186,7 +3184,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); - struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); + struct clk_hw *hw; if (!clkspec) return ERR_PTR(-EINVAL); @@ -3194,12 +3192,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, /* Check if we have such a provider in our array */ mutex_lock(&of_clk_mutex); list_for_each_entry(provider, &of_clk_providers, link) { - if (provider->node == clkspec->np) + if (provider->node == clkspec->np) { hw = __of_clk_get_hw_from_provider(provider, clkspec); - if (!IS_ERR(hw)) { clk = __clk_create_clk(hw, dev_id, con_id); + } - if (!IS_ERR(clk) && !__clk_get(clk)) { + if (!IS_ERR(clk)) { + if (!__clk_get(clk)) { __clk_free_clk(clk); clk = ERR_PTR(-ENOENT); } @@ -3451,6 +3450,10 @@ void __init of_clk_init(const struct of_device_id *matches) &clk_provider_list, node) { if (force || parent_ready(clk_provider->np)) { + /* Don't populate platform devices */ + of_node_set_flag(clk_provider->np, + OF_POPULATED); + clk_provider->clk_init_cb(clk_provider->np); of_clk_set_defaults(clk_provider->np, true); diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 4bf44a25d950..715b882205a8 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -14,7 +14,7 @@ static DEFINE_SPINLOCK(clklock); static void __init h8300_div_clk_setup(struct device_node *node) { unsigned int num_parents; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; const char *parent_name; void __iomem *divcr = NULL; @@ -38,15 +38,15 @@ static void __init h8300_div_clk_setup(struct device_node *node) parent_name = of_clk_get_parent_name(node, 0); of_property_read_u32(node, "renesas,width", &width); - clk = clk_register_divider(NULL, clk_name, parent_name, + hw = clk_hw_register_divider(NULL, clk_name, parent_name, CLK_SET_RATE_GATE, divcr, offset, width, CLK_DIVIDER_POWER_OF_TWO, &clklock); - if (!IS_ERR(clk)) { - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (!IS_ERR(hw)) { + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); return; } pr_err("%s: failed to register %s div clock (%ld)\n", - __func__, clk_name, PTR_ERR(clk)); + __func__, clk_name, PTR_ERR(hw)); error: if (divcr) iounmap(divcr); diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index c9c2fd575ef7..a26312460621 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -84,11 +84,11 @@ static const struct clk_ops pll_ops = { static void __init h8s2678_pll_clk_setup(struct device_node *node) { unsigned int num_parents; - struct clk *clk; const char *clk_name = node->name; const char *parent_name; struct pll_clock *pll_clock; struct clk_init_data init; + int ret; num_parents = of_clk_get_parent_count(node); if (!num_parents) { @@ -121,14 +121,14 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) init.num_parents = 1; pll_clock->hw.init = &init; - clk = clk_register(NULL, &pll_clock->hw); - if (IS_ERR(clk)) { - pr_err("%s: failed to register %s div clock (%ld)\n", - __func__, clk_name, PTR_ERR(clk)); + ret = clk_hw_register(NULL, &pll_clock->hw); + if (ret) { + pr_err("%s: failed to register %s div clock (%d)\n", + __func__, clk_name, ret); goto unmap_pllcr; } - of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clock->hw); return; unmap_pllcr: diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 6ed4f8fa0667..e7c7353a86fc 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -22,43 +22,63 @@ #include "clk.h" +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; + +static struct clk_div_table test_div_table[] = { + { .val = 3, .div = 1, }, + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { } +}; + +static struct clk_div_table post_div_table[] = { + { .val = 3, .div = 4, }, + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 1, }, + { } +}; + static struct clk *clks[IMX7D_CLK_END]; static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk", "pll_enet_500m_clk", "pll_dram_main_clk", - "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_main_clk", + "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_post_div", "pll_usb_main_clk", }; static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_enet_250m_clk", "pll_sys_pfd2_270m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *arm_m0_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_125m_clk", "pll_sys_pfd2_135m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_sys_pfd7_clk", }; + "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", }; static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk", - "pll_sys_pfd7_clk", "pll_audio_main_clk", "pll_video_main_clk", }; + "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", - "pll_sys_main_240m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd4_clk", }; static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_main_240m_clk", "pll_sys_pfd2_135m_clk", "pll_sys_pfd6_clk", "pll_enet_250m_clk", - "pll_audio_main_clk", }; + "pll_audio_post_div", }; static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", - "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_main_clk", + "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", @@ -69,13 +89,13 @@ static const char *dram_sel[] = { "pll_dram_main_clk", static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", - "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_main_clk", + "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", "pll_enet_250m_clk", "pll_sys_pfd0_392m_clk", - "pll_audio_main_clk", "pll_sys_pfd2_270m_clk", }; + "pll_audio_post_div", "pll_sys_pfd2_270m_clk", }; static const char *usb_hsic_sel[] = { "osc", "pll_sys_main_clk", "pll_usb_main_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk", @@ -101,53 +121,53 @@ static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk", static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", }; + "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", }; + "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; static const char *mipi_dphy_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_dram_533m_clk", "pll_sys_pfd5_clk", "ref_1m_clk", "ext_clk_2", "pll_video_main_clk", "ext_clk_3", }; static const char *sai1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai3_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_3", }; static const char *spdif_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_3_clk", }; static const char *enet1_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", "ext_clk_4", }; static const char *enet1_time_sel[] = { "osc", "pll_enet_100m_clk", - "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3", + "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", "ext_clk_4", "pll_video_main_clk", }; static const char *enet2_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", "ext_clk_4", }; static const char *enet2_time_sel[] = { "osc", "pll_enet_100m_clk", - "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3", + "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", "ext_clk_4", "pll_video_main_clk", }; static const char *enet_phy_ref_sel[] = { "osc", "pll_enet_25m_clk", "pll_enet_50m_clk", "pll_enet_125m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd3_clk", }; static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -188,22 +208,22 @@ static const char *can2_sel[] = { "osc", "pll_sys_main_120m_clk", static const char *i2c1_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c2_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c3_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c4_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *uart1_sel[] = { "osc", "pll_sys_main_240m_clk", @@ -262,32 +282,32 @@ static const char *ecspi4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_usb_main_clk", }; static const char *pwm1_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm2_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm3_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm4_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; static const char *flextimer1_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; static const char *flextimer2_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_usb_main_clk", "pll_audio_main_clk", "pll_enet_125m_clk", + "pll_usb_main_clk", "pll_audio_post_div", "pll_enet_125m_clk", "pll_sys_pfd7_clk", }; static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -297,19 +317,19 @@ static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *gpt1_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_1", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_1", }; static const char *gpt2_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_2", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_2", }; static const char *gpt3_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_3", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_3", }; static const char *gpt4_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_4", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_4", }; static const char *trace_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", @@ -323,12 +343,12 @@ static const char *wdog_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *csi_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *audio_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *wrclk_sel[] = { "osc", "pll_enet_40m_clk", @@ -342,13 +362,13 @@ static const char *clko1_sel[] = { "osc", "pll_sys_main_clk", static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk", - "pll_audio_main_clk", "pll_video_main_clk", "ckil", }; + "pll_audio_post_div", "pll_video_main_clk", "ckil", }; static const char *lvds1_sel[] = { "pll_arm_main_clk", "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk", "pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk", "pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_enet_500m_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_enet_500m_clk", "pll_enet_250m_clk", "pll_enet_125m_clk", "pll_enet_100m_clk", "pll_enet_50m_clk", "pll_enet_40m_clk", "pll_enet_25m_clk", "pll_dram_main_clk", }; @@ -430,6 +450,11 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13); clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13); + clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0); clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1); clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2); @@ -779,6 +804,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0); clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0); clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0); + clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0); clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0); clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0); @@ -786,9 +812,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0); clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0); clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0); - clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate4("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0); - clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate4("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0); - clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate4("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0); + clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1); + clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1); + clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2); + clks[IMX7D_SAI2_IPG_CLK] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root_clk", base + 0x48d0, 0, &share_count_sai2); + clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3); + clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3); clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0); clks[IMX7D_ENET1_REF_ROOT_CLK] = imx_clk_gate4("enet1_ref_root_clk", "enet1_ref_post_div", base + 0x44e0, 0); clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base + 0x44f0, 0); @@ -860,8 +889,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */ clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); - clk_set_parent(clks[IMX7D_ENET_AXI_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_250M_CLK]); - /* set uart module clock's parent clock source that must be great then 80MHz */ clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a81c0385ed64..3799ff82a9b4 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -134,6 +134,15 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, shift, 0x3, 0, &imx_ccm_lock, share_count); } +static inline struct clk *imx_clk_gate2_shared2(const char *name, + const char *parent, void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | + CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, + &imx_ccm_lock, share_count); +} + static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 cgr_val) { diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig new file mode 100644 index 000000000000..380c372d528e --- /dev/null +++ b/drivers/clk/mediatek/Kconfig @@ -0,0 +1,21 @@ +# +# MediaTek SoC drivers +# +config COMMON_CLK_MEDIATEK + bool + ---help--- + Mediatek SoCs' clock support. + +config COMMON_CLK_MT8135 + bool "Clock driver for Mediatek MT8135" + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports Mediatek MT8135 clocks. + +config COMMON_CLK_MT8173 + bool "Clock driver for Mediatek MT8173" + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports Mediatek MT8173 clocks. diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 95fdfacb2ebf..32e7222e7305 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,4 +1,4 @@ -obj-y += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o +obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o -obj-y += clk-mt8135.o -obj-y += clk-mt8173.o +obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o +obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 2a76901bf04b..d8787bf444eb 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -97,7 +97,7 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = { .disable = mtk_cg_disable_inv, }; -struct clk * __init mtk_clk_register_gate( +struct clk *mtk_clk_register_gate( const char *name, const char *parent_name, struct regmap *regmap, diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 5ada644e6200..bb30f7063569 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -24,7 +24,7 @@ #include "clk-mtk.h" #include "clk-gate.h" -struct clk_onecell_data * __init mtk_alloc_clk_data(unsigned int clk_num) +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num) { int i; struct clk_onecell_data *clk_data; @@ -49,7 +49,7 @@ err_out: return NULL; } -void __init mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, +void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, struct clk_onecell_data *clk_data) { int i; @@ -72,7 +72,7 @@ void __init mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, } } -void __init mtk_clk_register_factors(const struct mtk_fixed_factor *clks, +void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, struct clk_onecell_data *clk_data) { int i; @@ -95,7 +95,7 @@ void __init mtk_clk_register_factors(const struct mtk_fixed_factor *clks, } } -int __init mtk_clk_register_gates(struct device_node *node, +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, int num, struct clk_onecell_data *clk_data) { @@ -135,7 +135,7 @@ int __init mtk_clk_register_gates(struct device_node *node, return 0; } -struct clk * __init mtk_clk_register_composite(const struct mtk_composite *mc, +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock) { struct clk *clk; @@ -222,7 +222,7 @@ err_out: return ERR_PTR(ret); } -void __init mtk_clk_register_composites(const struct mtk_composite *mcs, +void mtk_clk_register_composites(const struct mtk_composite *mcs, int num, void __iomem *base, spinlock_t *lock, struct clk_onecell_data *clk_data) { diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 966cab1348da..0c2deac17ce9 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -313,7 +313,7 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, return clk; } -void __init mtk_clk_register_plls(struct device_node *node, +void mtk_clk_register_plls(struct device_node *node, const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data) { void __iomem *base; diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 197e40175166..349583405b7c 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,5 +3,5 @@ # obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o -obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b-clkc.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o +obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 53326c32e853..9bb70e7a7d6a 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -98,7 +98,7 @@ struct meson_clk_mpll { }; #define MESON_GATE(_name, _reg, _bit) \ -struct clk_gate gxbb_##_name = { \ +struct clk_gate _name = { \ .reg = (void __iomem *) _reg, \ .bit_idx = (_bit), \ .lock = &clk_lock, \ diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c new file mode 100644 index 000000000000..b45c5fba7e35 --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -0,0 +1,191 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/init.h> +#include <dt-bindings/clock/gxbb-aoclkc.h> +#include <dt-bindings/reset/gxbb-aoclkc.h> + +static DEFINE_SPINLOCK(gxbb_aoclk_lock); + +struct gxbb_aoclk_reset_controller { + struct reset_controller_dev reset; + unsigned int *data; + void __iomem *base; +}; + +static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct gxbb_aoclk_reset_controller *reset = + container_of(rcdev, struct gxbb_aoclk_reset_controller, reset); + + writel(BIT(reset->data[id]), reset->base); + + return 0; +} + +static const struct reset_control_ops gxbb_aoclk_reset_ops = { + .reset = gxbb_aoclk_do_reset, +}; + +#define GXBB_AO_GATE(_name, _bit) \ +static struct clk_gate _name##_ao = { \ + .reg = (void __iomem *)0, \ + .bit_idx = (_bit), \ + .lock = &gxbb_aoclk_lock, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_ao", \ + .ops = &clk_gate_ops, \ + .parent_names = (const char *[]){ "clk81" }, \ + .num_parents = 1, \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ +} + +GXBB_AO_GATE(remote, 0); +GXBB_AO_GATE(i2c_master, 1); +GXBB_AO_GATE(i2c_slave, 2); +GXBB_AO_GATE(uart1, 3); +GXBB_AO_GATE(uart2, 5); +GXBB_AO_GATE(ir_blaster, 6); + +static unsigned int gxbb_aoclk_reset[] = { + [RESET_AO_REMOTE] = 16, + [RESET_AO_I2C_MASTER] = 18, + [RESET_AO_I2C_SLAVE] = 19, + [RESET_AO_UART1] = 17, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_BLASTER] = 23, +}; + +static struct clk_gate *gxbb_aoclk_gate[] = { + [CLKID_AO_REMOTE] = &remote_ao, + [CLKID_AO_I2C_MASTER] = &i2c_master_ao, + [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, + [CLKID_AO_UART1] = &uart1_ao, + [CLKID_AO_UART2] = &uart2_ao, + [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, +}; + +static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { + .hws = { + [CLKID_AO_REMOTE] = &remote_ao.hw, + [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, + [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, + [CLKID_AO_UART1] = &uart1_ao.hw, + [CLKID_AO_UART2] = &uart2_ao.hw, + [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, + }, + .num = ARRAY_SIZE(gxbb_aoclk_gate), +}; + +static int gxbb_aoclkc_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + int ret, clkid; + struct device *dev = &pdev->dev; + struct gxbb_aoclk_reset_controller *rstc; + + rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return -ENOMEM; + + /* Generic clocks */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Reset Controller */ + rstc->base = base; + rstc->data = gxbb_aoclk_reset; + rstc->reset.ops = &gxbb_aoclk_reset_ops; + rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset); + rstc->reset.of_node = dev->of_node; + ret = devm_reset_controller_register(dev, &rstc->reset); + + /* + * Populate base address and register all clks + */ + for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) { + gxbb_aoclk_gate[clkid]->reg = base; + + ret = devm_clk_hw_register(dev, + gxbb_aoclk_onecell_data.hws[clkid]); + if (ret) + return ret; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + &gxbb_aoclk_onecell_data); +} + +static const struct of_device_id gxbb_aoclkc_match_table[] = { + { .compatible = "amlogic,gxbb-aoclkc" }, + { } +}; + +static struct platform_driver gxbb_aoclkc_driver = { + .probe = gxbb_aoclkc_probe, + .driver = { + .name = "gxbb-aoclkc", + .of_match_table = gxbb_aoclkc_match_table, + }, +}; +builtin_platform_driver(gxbb_aoclkc_driver); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index a4c6684b3019..9d9af446bafc 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -565,90 +565,93 @@ static struct clk_gate gxbb_clk81 = { }; /* Everything Else (EE) domain gates */ -static MESON_GATE(ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(dos, HHI_GCLK_MPEG0, 1); -static MESON_GATE(isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(spicc, HHI_GCLK_MPEG0, 8); -static MESON_GATE(i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(sar_adc, HHI_GCLK_MPEG0, 10); -static MESON_GATE(smart_card, HHI_GCLK_MPEG0, 11); -static MESON_GATE(rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(sdhc, HHI_GCLK_MPEG0, 14); -static MESON_GATE(stream, HHI_GCLK_MPEG0, 15); -static MESON_GATE(async_fifo, HHI_GCLK_MPEG0, 16); -static MESON_GATE(sdio, HHI_GCLK_MPEG0, 17); -static MESON_GATE(abuf, HHI_GCLK_MPEG0, 18); -static MESON_GATE(hiu_iface, HHI_GCLK_MPEG0, 19); -static MESON_GATE(assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(spi, HHI_GCLK_MPEG0, 30); - -static MESON_GATE(i2s_spdif, HHI_GCLK_MPEG1, 2); -static MESON_GATE(eth, HHI_GCLK_MPEG1, 3); -static MESON_GATE(demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(aiu_glue, HHI_GCLK_MPEG1, 6); -static MESON_GATE(iec958, HHI_GCLK_MPEG1, 7); -static MESON_GATE(i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_GATE(amclk, HHI_GCLK_MPEG1, 9); -static MESON_GATE(aififo2, HHI_GCLK_MPEG1, 10); -static MESON_GATE(mixer, HHI_GCLK_MPEG1, 11); -static MESON_GATE(mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_GATE(adc, HHI_GCLK_MPEG1, 13); -static MESON_GATE(blkmv, HHI_GCLK_MPEG1, 14); -static MESON_GATE(aiu, HHI_GCLK_MPEG1, 15); -static MESON_GATE(uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(usb0, HHI_GCLK_MPEG1, 21); -static MESON_GATE(usb1, HHI_GCLK_MPEG1, 22); -static MESON_GATE(reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(nand, HHI_GCLK_MPEG1, 24); -static MESON_GATE(dos_parser, HHI_GCLK_MPEG1, 25); -static MESON_GATE(usb, HHI_GCLK_MPEG1, 26); -static MESON_GATE(vdin1, HHI_GCLK_MPEG1, 28); -static MESON_GATE(ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(efuse, HHI_GCLK_MPEG1, 30); -static MESON_GATE(boot_rom, HHI_GCLK_MPEG1, 31); - -static MESON_GATE(ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static MESON_GATE(hdmi_pclk, HHI_GCLK_MPEG2, 4); -static MESON_GATE(usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static MESON_GATE(usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static MESON_GATE(mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(dvin, HHI_GCLK_MPEG2, 12); -static MESON_GATE(uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(sana, HHI_GCLK_MPEG2, 22); -static MESON_GATE(vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON_GATE(clk81_a53, HHI_GCLK_MPEG2, 29); - -static MESON_GATE(vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON_GATE(vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON_GATE(vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON_GATE(vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON_GATE(gclk_venci_int0, HHI_GCLK_OTHER, 8); -static MESON_GATE(gclk_vencp_int, HHI_GCLK_OTHER, 9); -static MESON_GATE(dac_clk, HHI_GCLK_OTHER, 10); -static MESON_GATE(aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON_GATE(iec958_gate, HHI_GCLK_OTHER, 16); -static MESON_GATE(enc480p, HHI_GCLK_OTHER, 20); -static MESON_GATE(rng1, HHI_GCLK_OTHER, 21); -static MESON_GATE(gclk_venci_int1, HHI_GCLK_OTHER, 22); -static MESON_GATE(vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static MESON_GATE(vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON_GATE(vclk_other, HHI_GCLK_OTHER, 26); -static MESON_GATE(edp, HHI_GCLK_OTHER, 31); +static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE(gxbb_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(gxbb_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(gxbb_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(gxbb_spicc, HHI_GCLK_MPEG0, 8); +static MESON_GATE(gxbb_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(gxbb_smart_card, HHI_GCLK_MPEG0, 11); +static MESON_GATE(gxbb_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(gxbb_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(gxbb_sdhc, HHI_GCLK_MPEG0, 14); +static MESON_GATE(gxbb_stream, HHI_GCLK_MPEG0, 15); +static MESON_GATE(gxbb_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON_GATE(gxbb_sdio, HHI_GCLK_MPEG0, 17); +static MESON_GATE(gxbb_abuf, HHI_GCLK_MPEG0, 18); +static MESON_GATE(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19); +static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); +static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30); + +static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); +static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3); +static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6); +static MESON_GATE(gxbb_iec958, HHI_GCLK_MPEG1, 7); +static MESON_GATE(gxbb_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_GATE(gxbb_amclk, HHI_GCLK_MPEG1, 9); +static MESON_GATE(gxbb_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_GATE(gxbb_mixer, HHI_GCLK_MPEG1, 11); +static MESON_GATE(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_GATE(gxbb_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14); +static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15); +static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(gxbb_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(gxbb_usb0, HHI_GCLK_MPEG1, 21); +static MESON_GATE(gxbb_usb1, HHI_GCLK_MPEG1, 22); +static MESON_GATE(gxbb_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(gxbb_nand, HHI_GCLK_MPEG1, 24); +static MESON_GATE(gxbb_dos_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE(gxbb_usb, HHI_GCLK_MPEG1, 26); +static MESON_GATE(gxbb_vdin1, HHI_GCLK_MPEG1, 28); +static MESON_GATE(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON_GATE(gxbb_efuse, HHI_GCLK_MPEG1, 30); +static MESON_GATE(gxbb_boot_rom, HHI_GCLK_MPEG1, 31); + +static MESON_GATE(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static MESON_GATE(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static MESON_GATE(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static MESON_GATE(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static MESON_GATE(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(gxbb_dvin, HHI_GCLK_MPEG2, 12); +static MESON_GATE(gxbb_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON_GATE(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); + +static MESON_GATE(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8); +static MESON_GATE(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static MESON_GATE(gxbb_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON_GATE(gxbb_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON_GATE(gxbb_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE(gxbb_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22); +static MESON_GATE(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static MESON_GATE(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE(gxbb_vclk_other, HHI_GCLK_OTHER, 26); +static MESON_GATE(gxbb_edp, HHI_GCLK_OTHER, 31); /* Always On (AO) domain gates */ -static MESON_GATE(ao_media_cpu, HHI_GCLK_AO, 0); -static MESON_GATE(ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON_GATE(ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON_GATE(ao_iface, HHI_GCLK_AO, 3); -static MESON_GATE(ao_i2c, HHI_GCLK_AO, 4); +static MESON_GATE(gxbb_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON_GATE(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3); +static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4); /* Array of all clocks provided by this provider */ @@ -748,6 +751,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, + [CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw, + [CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw, + [CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw, }, .num = NR_CLKS, }; @@ -847,6 +853,9 @@ static struct clk_gate *gxbb_clk_gates[] = { &gxbb_ao_ahb_bus, &gxbb_ao_iface, &gxbb_ao_i2c, + &gxbb_emmc_a, + &gxbb_emmc_b, + &gxbb_emmc_c, }; static int gxbb_clkc_probe(struct platform_device *pdev) @@ -937,8 +946,4 @@ static struct platform_driver gxbb_driver = { }, }; -static int __init gxbb_clkc_init(void) -{ - return platform_driver_register(&gxbb_driver); -} -device_initcall(gxbb_clkc_init); +builtin_platform_driver(gxbb_driver); diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index a2adf3448b59..ae461b16af75 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -170,11 +170,11 @@ */ #define CLKID_SYS_PLL 0 /* CLKID_CPUCLK */ -#define CLKID_HDMI_PLL 2 +/* CLKID_HDMI_PLL */ #define CLKID_FIXED_PLL 3 -#define CLKID_FCLK_DIV2 4 -#define CLKID_FCLK_DIV3 5 -#define CLKID_FCLK_DIV4 6 +/* CLKID_FCLK_DIV2 */ +/* CLKID_FCLK_DIV3 */ +/* CLKID_FCLK_DIV4 */ #define CLKID_FCLK_DIV5 7 #define CLKID_FCLK_DIV7 8 #define CLKID_GP0_PLL 9 @@ -262,8 +262,11 @@ #define CLKID_AO_AHB_BUS 91 #define CLKID_AO_IFACE 92 #define CLKID_AO_I2C 93 +/* CLKID_SD_EMMC_A */ +/* CLKID_SD_EMMC_B */ +/* CLKID_SD_EMMC_C */ -#define NR_CLKS 94 +#define NR_CLKS 97 /* include the CLKIDs that have been made part of the stable DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b.c index 4c9413cdf373..e1d4aa145a03 100644 --- a/drivers/clk/meson/meson8b-clkc.c +++ b/drivers/clk/meson/meson8b.c @@ -23,27 +23,11 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/of_address.h> -#include <dt-bindings/clock/meson8b-clkc.h> #include <linux/platform_device.h> #include <linux/init.h> #include "clkc.h" - -/* - * Clock controller register offsets - * - * Register offsets from the HardKernel[0] data sheet are listed in comment - * blocks below. Those offsets must be multiplied by 4 before adding them to - * the base address to get the right value - * - * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf - */ -#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ -#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ -#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ -#define MESON8B_REG_PLL_FIXED 0x0280 -#define MESON8B_REG_PLL_SYS 0x0300 -#define MESON8B_REG_PLL_VID 0x0320 +#include "meson8b.h" static DEFINE_SPINLOCK(clk_lock); @@ -128,17 +112,17 @@ static struct clk_fixed_rate meson8b_xtal = { static struct meson_clk_pll meson8b_fixed_pll = { .m = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 16, .width = 2, }, @@ -154,17 +138,17 @@ static struct meson_clk_pll meson8b_fixed_pll = { static struct meson_clk_pll meson8b_vid_pll = { .m = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 16, .width = 2, }, @@ -180,17 +164,17 @@ static struct meson_clk_pll meson8b_vid_pll = { static struct meson_clk_pll meson8b_sys_pll = { .m = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 16, .width = 2, }, @@ -267,7 +251,7 @@ static struct clk_fixed_factor meson8b_fclk_div7 = { * forthcoming coordinated clock rates feature */ static struct meson_clk_cpu meson8b_cpu_clk = { - .reg_off = MESON8B_REG_SYS_CPU_CNTL1, + .reg_off = HHI_SYS_CPU_CLK_CNTL1, .div_table = cpu_div_table, .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, .hw.init = &(struct clk_init_data){ @@ -281,7 +265,7 @@ static struct meson_clk_cpu meson8b_cpu_clk = { static u32 mux_table_clk81[] = { 6, 5, 7 }; struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, .flags = CLK_MUX_READ_ONLY, @@ -303,7 +287,7 @@ struct clk_mux meson8b_mpeg_clk_sel = { }; struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, .lock = &clk_lock, @@ -317,7 +301,7 @@ struct clk_divider meson8b_mpeg_clk_div = { }; struct clk_gate meson8b_clk81 = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .bit_idx = 7, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ @@ -329,6 +313,92 @@ struct clk_gate meson8b_clk81 = { }, }; +/* Everything Else (EE) domain gates */ + +static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(meson8b_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE(meson8b_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(meson8b_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(meson8b_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(meson8b_spicc, HHI_GCLK_MPEG0, 8); +static MESON_GATE(meson8b_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(meson8b_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(meson8b_smart_card, HHI_GCLK_MPEG0, 11); +static MESON_GATE(meson8b_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(meson8b_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(meson8b_sdhc, HHI_GCLK_MPEG0, 14); +static MESON_GATE(meson8b_stream, HHI_GCLK_MPEG0, 15); +static MESON_GATE(meson8b_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON_GATE(meson8b_sdio, HHI_GCLK_MPEG0, 17); +static MESON_GATE(meson8b_abuf, HHI_GCLK_MPEG0, 18); +static MESON_GATE(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19); +static MESON_GATE(meson8b_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(meson8b_spi, HHI_GCLK_MPEG0, 30); + +static MESON_GATE(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); +static MESON_GATE(meson8b_eth, HHI_GCLK_MPEG1, 3); +static MESON_GATE(meson8b_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6); +static MESON_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7); +static MESON_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9); +static MESON_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11); +static MESON_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE(meson8b_blkmv, HHI_GCLK_MPEG1, 14); +static MESON_GATE(meson8b_aiu, HHI_GCLK_MPEG1, 15); +static MESON_GATE(meson8b_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(meson8b_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(meson8b_usb0, HHI_GCLK_MPEG1, 21); +static MESON_GATE(meson8b_usb1, HHI_GCLK_MPEG1, 22); +static MESON_GATE(meson8b_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(meson8b_nand, HHI_GCLK_MPEG1, 24); +static MESON_GATE(meson8b_dos_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE(meson8b_usb, HHI_GCLK_MPEG1, 26); +static MESON_GATE(meson8b_vdin1, HHI_GCLK_MPEG1, 28); +static MESON_GATE(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON_GATE(meson8b_efuse, HHI_GCLK_MPEG1, 30); +static MESON_GATE(meson8b_boot_rom, HHI_GCLK_MPEG1, 31); + +static MESON_GATE(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static MESON_GATE(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static MESON_GATE(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static MESON_GATE(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static MESON_GATE(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(meson8b_dvin, HHI_GCLK_MPEG2, 12); +static MESON_GATE(meson8b_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE(meson8b_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON_GATE(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29); + +static MESON_GATE(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8); +static MESON_GATE(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static MESON_GATE(meson8b_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON_GATE(meson8b_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON_GATE(meson8b_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE(meson8b_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22); +static MESON_GATE(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static MESON_GATE(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); +static MESON_GATE(meson8b_edp, HHI_GCLK_OTHER, 31); + +/* Always On (AO) domain gates */ + +static MESON_GATE(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3); + static struct clk_hw_onecell_data meson8b_hw_onecell_data = { .hws = { [CLKID_XTAL] = &meson8b_xtal.hw, @@ -344,6 +414,83 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, }, .num = CLK_NR_CLKS, }; @@ -354,6 +501,87 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = { &meson8b_sys_pll, }; +static struct clk_gate *meson8b_clk_gates[] = { + &meson8b_clk81, + &meson8b_ddr, + &meson8b_dos, + &meson8b_isa, + &meson8b_pl301, + &meson8b_periphs, + &meson8b_spicc, + &meson8b_i2c, + &meson8b_sar_adc, + &meson8b_smart_card, + &meson8b_rng0, + &meson8b_uart0, + &meson8b_sdhc, + &meson8b_stream, + &meson8b_async_fifo, + &meson8b_sdio, + &meson8b_abuf, + &meson8b_hiu_iface, + &meson8b_assist_misc, + &meson8b_spi, + &meson8b_i2s_spdif, + &meson8b_eth, + &meson8b_demux, + &meson8b_aiu_glue, + &meson8b_iec958, + &meson8b_i2s_out, + &meson8b_amclk, + &meson8b_aififo2, + &meson8b_mixer, + &meson8b_mixer_iface, + &meson8b_adc, + &meson8b_blkmv, + &meson8b_aiu, + &meson8b_uart1, + &meson8b_g2d, + &meson8b_usb0, + &meson8b_usb1, + &meson8b_reset, + &meson8b_nand, + &meson8b_dos_parser, + &meson8b_usb, + &meson8b_vdin1, + &meson8b_ahb_arb0, + &meson8b_efuse, + &meson8b_boot_rom, + &meson8b_ahb_data_bus, + &meson8b_ahb_ctrl_bus, + &meson8b_hdmi_intr_sync, + &meson8b_hdmi_pclk, + &meson8b_usb1_ddr_bridge, + &meson8b_usb0_ddr_bridge, + &meson8b_mmc_pclk, + &meson8b_dvin, + &meson8b_uart2, + &meson8b_sana, + &meson8b_vpu_intr, + &meson8b_sec_ahb_ahb3_bridge, + &meson8b_clk81_a9, + &meson8b_vclk2_venci0, + &meson8b_vclk2_venci1, + &meson8b_vclk2_vencp0, + &meson8b_vclk2_vencp1, + &meson8b_gclk_venci_int, + &meson8b_gclk_vencp_int, + &meson8b_dac_clk, + &meson8b_aoclk_gate, + &meson8b_iec958_gate, + &meson8b_enc480p, + &meson8b_rng1, + &meson8b_gclk_vencl_int, + &meson8b_vclk2_venclmcc, + &meson8b_vclk2_vencl, + &meson8b_vclk2_other, + &meson8b_edp, + &meson8b_ao_media_cpu, + &meson8b_ao_ahb_sram, + &meson8b_ao_ahb_bus, + &meson8b_ao_iface, +}; + static int meson8b_clkc_probe(struct platform_device *pdev) { void __iomem *clk_base; @@ -381,6 +609,11 @@ static int meson8b_clkc_probe(struct platform_device *pdev) meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; + /* Populate base address for gates */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) + meson8b_clk_gates[i]->reg = clk_base + + (u32)meson8b_clk_gates[i]->reg; + /* * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h new file mode 100644 index 000000000000..010e9582888d --- /dev/null +++ b/drivers/clk/meson/meson8b.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione <carlo@endlessm.com> + * + * Copyright (c) 2016 BayLibre, Inc. + * Michael Turquette <mturquette@baylibre.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MESON8B_H +#define __MESON8B_H + +/* + * Clock controller register offsets + * + * Register offsets from the HardKernel[0] data sheet are listed in comment + * blocks below. Those offsets must be multiplied by 4 before adding them to + * the base address to get the right value + * + * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf + */ +#define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ +#define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ +#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ +#define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ +#define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ +#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ +#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ +#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ +#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ +#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ + +/* + * CLKID index values + * + * These indices are entirely contrived and do not map onto the hardware. + * Migrate them out of this header and into the DT header file when they need + * to be exposed to client nodes in DT: include/dt-bindings/clock/meson8b-clkc.h + */ + +/* CLKID_UNUSED */ +/* CLKID_XTAL */ +/* CLKID_PLL_FIXED */ +/* CLKID_PLL_VID */ +/* CLKID_PLL_SYS */ +/* CLKID_FCLK_DIV2 */ +/* CLKID_FCLK_DIV3 */ +/* CLKID_FCLK_DIV4 */ +/* CLKID_FCLK_DIV5 */ +/* CLKID_FCLK_DIV7 */ +/* CLKID_CLK81 */ +/* CLKID_MALI */ +/* CLKID_CPUCLK */ +/* CLKID_ZERO */ +/* CLKID_MPEG_SEL */ +/* CLKID_MPEG_DIV */ +#define CLKID_DDR 16 +#define CLKID_DOS 17 +#define CLKID_ISA 18 +#define CLKID_PL301 19 +#define CLKID_PERIPHS 20 +#define CLKID_SPICC 21 +#define CLKID_I2C 22 +#define CLKID_SAR_ADC 23 +#define CLKID_SMART_CARD 24 +#define CLKID_RNG0 25 +#define CLKID_UART0 26 +#define CLKID_SDHC 27 +#define CLKID_STREAM 28 +#define CLKID_ASYNC_FIFO 29 +#define CLKID_SDIO 30 +#define CLKID_ABUF 31 +#define CLKID_HIU_IFACE 32 +#define CLKID_ASSIST_MISC 33 +#define CLKID_SPI 34 +#define CLKID_I2S_SPDIF 35 +#define CLKID_ETH 36 +#define CLKID_DEMUX 37 +#define CLKID_AIU_GLUE 38 +#define CLKID_IEC958 39 +#define CLKID_I2S_OUT 40 +#define CLKID_AMCLK 41 +#define CLKID_AIFIFO2 42 +#define CLKID_MIXER 43 +#define CLKID_MIXER_IFACE 44 +#define CLKID_ADC 45 +#define CLKID_BLKMV 46 +#define CLKID_AIU 47 +#define CLKID_UART1 48 +#define CLKID_G2D 49 +#define CLKID_USB0 50 +#define CLKID_USB1 51 +#define CLKID_RESET 52 +#define CLKID_NAND 53 +#define CLKID_DOS_PARSER 54 +#define CLKID_USB 55 +#define CLKID_VDIN1 56 +#define CLKID_AHB_ARB0 57 +#define CLKID_EFUSE 58 +#define CLKID_BOOT_ROM 59 +#define CLKID_AHB_DATA_BUS 60 +#define CLKID_AHB_CTRL_BUS 61 +#define CLKID_HDMI_INTR_SYNC 62 +#define CLKID_HDMI_PCLK 63 +#define CLKID_USB1_DDR_BRIDGE 64 +#define CLKID_USB0_DDR_BRIDGE 65 +#define CLKID_MMC_PCLK 66 +#define CLKID_DVIN 67 +#define CLKID_UART2 68 +#define CLKID_SANA 69 +#define CLKID_VPU_INTR 70 +#define CLKID_SEC_AHB_AHB3_BRIDGE 71 +#define CLKID_CLK81_A9 72 +#define CLKID_VCLK2_VENCI0 73 +#define CLKID_VCLK2_VENCI1 74 +#define CLKID_VCLK2_VENCP0 75 +#define CLKID_VCLK2_VENCP1 76 +#define CLKID_GCLK_VENCI_INT 77 +#define CLKID_GCLK_VENCP_INT 78 +#define CLKID_DAC_CLK 79 +#define CLKID_AOCLK_GATE 80 +#define CLKID_IEC958_GATE 81 +#define CLKID_ENC480P 82 +#define CLKID_RNG1 83 +#define CLKID_GCLK_VENCL_INT 84 +#define CLKID_VCLK2_VENCLMCC 85 +#define CLKID_VCLK2_VENCL 86 +#define CLKID_VCLK2_OTHER 87 +#define CLKID_EDP 88 +#define CLKID_AO_MEDIA_CPU 89 +#define CLKID_AO_AHB_SRAM 90 +#define CLKID_AO_AHB_BUS 91 +#define CLKID_AO_IFACE 92 + +#define CLK_NR_CLKS 93 + +/* include the CLKIDs that have been made part of the stable DT binding */ +#include <dt-bindings/clock/meson8b-clkc.h> + +#endif /* __MESON8B_H */ diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c index ca85cea17839..c3b301463425 100644 --- a/drivers/clk/microchip/clk-core.c +++ b/drivers/clk/microchip/clk-core.c @@ -199,9 +199,9 @@ static int pbclk_set_rate(struct clk_hw *hw, unsigned long rate, spin_unlock_irqrestore(&pb->core->reg_lock, flags); - /* wait again, for pbdivready */ - err = readl_poll_timeout_atomic(pb->ctrl_reg, v, v & PB_DIV_READY, - 1, LOCK_TIMEOUT_US); + /* wait again for DIV_READY */ + err = readl_poll_timeout(pb->ctrl_reg, v, v & PB_DIV_READY, + 1, LOCK_TIMEOUT_US); if (err) return err; diff --git a/drivers/clk/microchip/clk-pic32mzda.c b/drivers/clk/microchip/clk-pic32mzda.c index 51f54380474b..9f734779be92 100644 --- a/drivers/clk/microchip/clk-pic32mzda.c +++ b/drivers/clk/microchip/clk-pic32mzda.c @@ -118,6 +118,7 @@ static const struct pic32_sec_osc_data sosc_clk = { .status_reg = 0x1d0, .enable_mask = BIT(1), .status_mask = BIT(4), + .fixed_rate = 32768, .init_data = { .name = "sosc_clk", .parent_names = NULL, diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 3165da77d525..fddc8ac5faff 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -24,6 +24,9 @@ config ARMADA_39X_CLK bool select MVEBU_CLK_COMMON +config ARMADA_37XX_CLK + bool + config ARMADA_XP_CLK bool select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 7172ef65693d..d9ae97fb43c4 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -6,6 +6,9 @@ obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-periph.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c new file mode 100644 index 000000000000..45905fc0d75b --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -0,0 +1,447 @@ +/* + * Marvell Armada 37xx SoC Peripheral clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + * + * Most of the peripheral clocks can be modelled like this: + * _____ _______ _______ + * TBG-A-P --| | | | | | ______ + * TBG-B-P --| Mux |--| /div1 |--| /div2 |--| Gate |--> perip_clk + * TBG-A-S --| | | | | | |______| + * TBG-B-S --|_____| |_______| |_______| + * + * However some clocks may use only one or two block or and use the + * xtal clock as parent. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TBG_SEL 0x0 +#define DIV_SEL0 0x4 +#define DIV_SEL1 0x8 +#define DIV_SEL2 0xC +#define CLK_SEL 0x10 +#define CLK_DIS 0x14 + +struct clk_periph_driver_data { + struct clk_hw_onecell_data *hw_data; + spinlock_t lock; +}; + +struct clk_double_div { + struct clk_hw hw; + void __iomem *reg1; + u8 shift1; + void __iomem *reg2; + u8 shift2; +}; + +#define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) + +struct clk_periph_data { + const char *name; + const char * const *parent_names; + int num_parents; + struct clk_hw *mux_hw; + struct clk_hw *rate_hw; + struct clk_hw *gate_hw; + bool is_double_div; +}; + +static const struct clk_div_table clk_table6[] = { + { .val = 1, .div = 1, }, + { .val = 2, .div = 2, }, + { .val = 3, .div = 3, }, + { .val = 4, .div = 4, }, + { .val = 5, .div = 5, }, + { .val = 6, .div = 6, }, + { .val = 0, .div = 0, }, /* last entry */ +}; + +static const struct clk_div_table clk_table1[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 0, }, /* last entry */ +}; + +static const struct clk_div_table clk_table2[] = { + { .val = 0, .div = 2, }, + { .val = 1, .div = 4, }, + { .val = 0, .div = 0, }, /* last entry */ +}; +static const struct clk_ops clk_double_div_ops; + +#define PERIPH_GATE(_name, _bit) \ +struct clk_gate gate_##_name = { \ + .reg = (void *)CLK_DIS, \ + .bit_idx = _bit, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_gate_ops, \ + } \ +}; + +#define PERIPH_MUX(_name, _shift) \ +struct clk_mux mux_##_name = { \ + .reg = (void *)TBG_SEL, \ + .shift = _shift, \ + .mask = 3, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_mux_ro_ops, \ + } \ +}; + +#define PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2) \ +struct clk_double_div rate_##_name = { \ + .reg1 = (void *)_reg1, \ + .reg2 = (void *)_reg2, \ + .shift1 = _shift1, \ + .shift2 = _shift2, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_double_div_ops, \ + } \ +}; + +#define PERIPH_DIV(_name, _reg, _shift, _table) \ +struct clk_divider rate_##_name = { \ + .reg = (void *)_reg, \ + .table = _table, \ + .shift = _shift, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_divider_ro_ops, \ + } \ +}; + +#define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); + +#define PERIPH_CLK_FULL(_name, _bit, _shift, _reg, _shift1, _table) \ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DIV(_name, _reg, _shift1, _table); + +#define PERIPH_CLK_GATE_DIV(_name, _bit, _reg, _shift, _table) \ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_DIV(_name, _reg, _shift, _table); + +#define PERIPH_CLK_MUX_DIV(_name, _shift, _reg, _shift_div, _table) \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DIV(_name, _reg, _shift_div, _table); + +#define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); + +#define REF_CLK_FULL(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_FULL_DD(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + .is_double_div = true, \ + } + +#define REF_CLK_GATE(_name, _parent_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ _parent_name}, \ + .num_parents = 1, \ + .gate_hw = &gate_##_name.hw, \ + } + +#define REF_CLK_GATE_DIV(_name, _parent_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ _parent_name}, \ + .num_parents = 1, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_MUX_DIV(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_MUX_DD(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + .is_double_div = true, \ + } + +/* NB periph clocks */ +PERIPH_CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13); +PERIPH_CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7); +PERIPH_CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0); +PERIPH_CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6); +PERIPH_CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12); +PERIPH_CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, clk_table6); +static PERIPH_GATE(avs, 11); +PERIPH_CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0); +PERIPH_CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24); +static PERIPH_GATE(i2c_2, 16); +static PERIPH_GATE(i2c_1, 17); +PERIPH_CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, clk_table2); +PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12); +PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6); +PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6); +PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19); +PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6); + +static struct clk_periph_data data_nb[] ={ + REF_CLK_FULL_DD(mmc), + REF_CLK_FULL_DD(sata_host), + REF_CLK_FULL_DD(sec_at), + REF_CLK_FULL_DD(sec_dap), + REF_CLK_FULL_DD(tscem), + REF_CLK_FULL(tscem_tmx), + REF_CLK_GATE(avs, "xtal"), + REF_CLK_FULL_DD(sqf), + REF_CLK_FULL_DD(pwm), + REF_CLK_GATE(i2c_2, "xtal"), + REF_CLK_GATE(i2c_1, "xtal"), + REF_CLK_GATE_DIV(ddr_phy, "TBG-A-S"), + REF_CLK_FULL_DD(ddr_fclk), + REF_CLK_FULL(trace), + REF_CLK_FULL(counter), + REF_CLK_FULL_DD(eip97), + REF_CLK_MUX_DIV(cpu), + { }, +}; + +/* SB periph clocks */ +PERIPH_CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9); +PERIPH_CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21); +PERIPH_CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9); +static PERIPH_GATE(gbe1_50, 0); +static PERIPH_GATE(gbe0_50, 1); +static PERIPH_GATE(gbe1_125, 2); +static PERIPH_GATE(gbe0_125, 3); +PERIPH_CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, clk_table1); +PERIPH_CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, clk_table1); +PERIPH_CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, clk_table1); +PERIPH_CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6); +PERIPH_CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12); +PERIPH_CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18); + +static struct clk_periph_data data_sb[] = { + REF_CLK_MUX_DD(gbe_50), + REF_CLK_MUX_DD(gbe_core), + REF_CLK_MUX_DD(gbe_125), + REF_CLK_GATE(gbe1_50, "gbe_50"), + REF_CLK_GATE(gbe0_50, "gbe_50"), + REF_CLK_GATE(gbe1_125, "gbe_125"), + REF_CLK_GATE(gbe0_125, "gbe_125"), + REF_CLK_GATE_DIV(gbe1_core, "gbe_core"), + REF_CLK_GATE_DIV(gbe0_core, "gbe_core"), + REF_CLK_GATE_DIV(gbe_bm, "gbe_core"), + REF_CLK_FULL_DD(sdio), + REF_CLK_FULL_DD(usb32_usb2_sys), + REF_CLK_FULL_DD(usb32_ss_sys), + { }, +}; + +static unsigned int get_div(void __iomem *reg, int shift) +{ + u32 val; + + val = (readl(reg) >> shift) & 0x7; + if (val > 6) + return 0; + return val; +} + +static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_double_div *double_div = to_clk_double_div(hw); + unsigned int div; + + div = get_div(double_div->reg1, double_div->shift1); + div *= get_div(double_div->reg2, double_div->shift2); + + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + +static const struct clk_ops clk_double_div_ops = { + .recalc_rate = clk_double_div_recalc_rate, +}; + +static const struct of_device_id armada_3700_periph_clock_of_match[] = { + { .compatible = "marvell,armada-3700-periph-clock-nb", + .data = data_nb, }, + { .compatible = "marvell,armada-3700-periph-clock-sb", + .data = data_sb, }, + { } +}; +static int armada_3700_add_composite_clk(const struct clk_periph_data *data, + void __iomem *reg, spinlock_t *lock, + struct device *dev, struct clk_hw *hw) +{ + const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, + *rate_ops = NULL; + struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL; + + if (data->mux_hw) { + struct clk_mux *mux; + + mux_hw = data->mux_hw; + mux = to_clk_mux(mux_hw); + mux->lock = lock; + mux_ops = mux_hw->init->ops; + mux->reg = reg + (u64)mux->reg; + } + + if (data->gate_hw) { + struct clk_gate *gate; + + gate_hw = data->gate_hw; + gate = to_clk_gate(gate_hw); + gate->lock = lock; + gate_ops = gate_hw->init->ops; + gate->reg = reg + (u64)gate->reg; + } + + if (data->rate_hw) { + rate_hw = data->rate_hw; + rate_ops = rate_hw->init->ops; + if (data->is_double_div) { + struct clk_double_div *rate; + + rate = to_clk_double_div(rate_hw); + rate->reg1 = reg + (u64)rate->reg1; + rate->reg2 = reg + (u64)rate->reg2; + } else { + struct clk_divider *rate = to_clk_divider(rate_hw); + const struct clk_div_table *clkt; + int table_size = 0; + + rate->reg = reg + (u64)rate->reg; + for (clkt = rate->table; clkt->div; clkt++) + table_size++; + rate->width = order_base_2(table_size); + rate->lock = lock; + } + } + + hw = clk_hw_register_composite(dev, data->name, data->parent_names, + data->num_parents, mux_hw, + mux_ops, rate_hw, rate_ops, + gate_hw, gate_ops, CLK_IGNORE_UNUSED); + + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return 0; +} + +static int armada_3700_periph_clock_probe(struct platform_device *pdev) +{ + struct clk_periph_driver_data *driver_data; + struct device_node *np = pdev->dev.of_node; + const struct clk_periph_data *data; + struct device *dev = &pdev->dev; + int num_periph = 0, i, ret; + struct resource *res; + void __iomem *reg; + + data = of_device_get_match_data(dev); + if (!data) + return -ENODEV; + + while (data[num_periph].name) + num_periph++; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); + if (!driver_data) + return -ENOMEM; + + driver_data->hw_data = devm_kzalloc(dev, sizeof(*driver_data->hw_data) + + sizeof(*driver_data->hw_data->hws) * num_periph, + GFP_KERNEL); + if (!driver_data->hw_data) + return -ENOMEM; + driver_data->hw_data->num = num_periph; + + spin_lock_init(&driver_data->lock); + + for (i = 0; i < num_periph; i++) { + struct clk_hw *hw = driver_data->hw_data->hws[i]; + + if (armada_3700_add_composite_clk(&data[i], reg, + &driver_data->lock, dev, hw)) + dev_err(dev, "Can't register periph clock %s\n", + data[i].name); + + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + driver_data->hw_data); + if (ret) { + for (i = 0; i < num_periph; i++) + clk_hw_unregister(driver_data->hw_data->hws[i]); + return ret; + } + + platform_set_drvdata(pdev, driver_data); + return 0; +} + +static int armada_3700_periph_clock_remove(struct platform_device *pdev) +{ + struct clk_periph_driver_data *data = platform_get_drvdata(pdev); + struct clk_hw_onecell_data *hw_data = data->hw_data; + int i; + + of_clk_del_provider(pdev->dev.of_node); + + for (i = 0; i < hw_data->num; i++) + clk_hw_unregister(hw_data->hws[i]); + + return 0; +} + +static struct platform_driver armada_3700_periph_clock_driver = { + .probe = armada_3700_periph_clock_probe, + .remove = armada_3700_periph_clock_remove, + .driver = { + .name = "marvell-armada-3700-periph-clock", + .of_match_table = armada_3700_periph_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_periph_clock_driver); diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c new file mode 100644 index 000000000000..aa80db11f543 --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -0,0 +1,158 @@ +/* + * Marvell Armada 37xx SoC Time Base Generator clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + */ + +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define NUM_TBG 4 + +#define TBG_CTRL0 0x4 +#define TBG_CTRL1 0x8 +#define TBG_CTRL7 0x20 +#define TBG_CTRL8 0x30 + +#define TBG_DIV_MASK 0x1FF + +#define TBG_A_REFDIV 0 +#define TBG_B_REFDIV 16 + +#define TBG_A_FBDIV 2 +#define TBG_B_FBDIV 18 + +#define TBG_A_VCODIV_SE 0 +#define TBG_B_VCODIV_SE 16 + +#define TBG_A_VCODIV_DIFF 1 +#define TBG_B_VCODIV_DIFF 17 + +struct tbg_def { + char *name; + u32 refdiv_offset; + u32 fbdiv_offset; + u32 vcodiv_reg; + u32 vcodiv_offset; +}; + +static const struct tbg_def tbg[NUM_TBG] = { + {"TBG-A-P", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL8, TBG_A_VCODIV_DIFF}, + {"TBG-B-P", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL8, TBG_B_VCODIV_DIFF}, + {"TBG-A-S", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL1, TBG_A_VCODIV_SE}, + {"TBG-B-S", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL1, TBG_B_VCODIV_SE}, +}; + +static unsigned int tbg_get_mult(void __iomem *reg, const struct tbg_def *ptbg) +{ + u32 val; + + val = readl(reg + TBG_CTRL0); + + return ((val >> ptbg->fbdiv_offset) & TBG_DIV_MASK) << 2; +} + +static unsigned int tbg_get_div(void __iomem *reg, const struct tbg_def *ptbg) +{ + u32 val; + unsigned int div; + + val = readl(reg + TBG_CTRL7); + + div = (val >> ptbg->refdiv_offset) & TBG_DIV_MASK; + if (div == 0) + div = 1; + val = readl(reg + ptbg->vcodiv_reg); + + div *= 1 << ((val >> ptbg->vcodiv_offset) & TBG_DIV_MASK); + + return div; +} + + +static int armada_3700_tbg_clock_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_hw_onecell_data *hw_tbg_data; + struct device *dev = &pdev->dev; + const char *parent_name; + struct resource *res; + struct clk *parent; + void __iomem *reg; + int i, ret; + + hw_tbg_data = devm_kzalloc(&pdev->dev, sizeof(*hw_tbg_data) + + sizeof(*hw_tbg_data->hws) * NUM_TBG, + GFP_KERNEL); + if (!hw_tbg_data) + return -ENOMEM; + hw_tbg_data->num = NUM_TBG; + platform_set_drvdata(pdev, hw_tbg_data); + + parent = devm_clk_get(dev, NULL); + if (IS_ERR(parent)) { + dev_err(dev, "Could get the clock parent\n"); + return -EINVAL; + } + parent_name = __clk_get_name(parent); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + for (i = 0; i < NUM_TBG; i++) { + const char *name; + unsigned int mult, div; + + name = tbg[i].name; + mult = tbg_get_mult(reg, &tbg[i]); + div = tbg_get_div(reg, &tbg[i]); + hw_tbg_data->hws[i] = clk_hw_register_fixed_factor(NULL, name, + parent_name, 0, mult, div); + if (IS_ERR(hw_tbg_data->hws[i])) + dev_err(dev, "Can't register TBG clock %s\n", name); + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, hw_tbg_data); + + return ret; +} + +static int armada_3700_tbg_clock_remove(struct platform_device *pdev) +{ + int i; + struct clk_hw_onecell_data *hw_tbg_data = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + for (i = 0; i < hw_tbg_data->num; i++) + clk_hw_unregister_fixed_factor(hw_tbg_data->hws[i]); + + return 0; +} + +static const struct of_device_id armada_3700_tbg_clock_of_match[] = { + { .compatible = "marvell,armada-3700-tbg-clock", }, + { } +}; + +static struct platform_driver armada_3700_tbg_clock_driver = { + .probe = armada_3700_tbg_clock_probe, + .remove = armada_3700_tbg_clock_remove, + .driver = { + .name = "marvell-armada-3700-tbg-clock", + .of_match_table = armada_3700_tbg_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_tbg_clock_driver); diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c new file mode 100644 index 000000000000..612d65ede10a --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-xtal.c @@ -0,0 +1,91 @@ +/* + * Marvell Armada 37xx SoC xtal clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define NB_GPIO1_LATCH 0xC +#define XTAL_MODE BIT(31) + +static int armada_3700_xtal_clock_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const char *xtal_name = "xtal"; + struct device_node *parent; + struct regmap *regmap; + struct clk_hw *xtal_hw; + unsigned int rate; + u32 reg; + int ret; + + xtal_hw = devm_kzalloc(&pdev->dev, sizeof(*xtal_hw), GFP_KERNEL); + if (!xtal_hw) + return -ENOMEM; + + platform_set_drvdata(pdev, xtal_hw); + + parent = np->parent; + if (!parent) { + dev_err(&pdev->dev, "no parent\n"); + return -ENODEV; + } + + regmap = syscon_node_to_regmap(parent); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "cannot get regmap\n"); + return PTR_ERR(regmap); + } + + ret = regmap_read(regmap, NB_GPIO1_LATCH, ®); + if (ret) { + dev_err(&pdev->dev, "cannot read from regmap\n"); + return ret; + } + + if (reg & XTAL_MODE) + rate = 40000000; + else + rate = 25000000; + + of_property_read_string_index(np, "clock-output-names", 0, &xtal_name); + xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate); + if (IS_ERR(xtal_hw)) + return PTR_ERR(xtal_hw); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, xtal_hw); + + return ret; +} + +static int armada_3700_xtal_clock_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id armada_3700_xtal_clock_of_match[] = { + { .compatible = "marvell,armada-3700-xtal-clock", }, + { } +}; + +static struct platform_driver armada_3700_xtal_clock_driver = { + .probe = armada_3700_xtal_clock_probe, + .remove = armada_3700_xtal_clock_remove, + .driver = { + .name = "marvell-armada-3700-xtal-clock", + .of_match_table = armada_3700_xtal_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_xtal_clock_driver); diff --git a/drivers/clk/mvebu/armada-39x.c b/drivers/clk/mvebu/armada-39x.c index efb974df9822..4fdfd32247a9 100644 --- a/drivers/clk/mvebu/armada-39x.c +++ b/drivers/clk/mvebu/armada-39x.c @@ -142,6 +142,8 @@ static const struct clk_gating_soc_desc armada_39x_gating_desc[] __initconst = { { "pex3", NULL, 7 }, { "pex0", NULL, 8 }, { "usb3h0", NULL, 9 }, + { "usb3h1", NULL, 10 }, + { "sata0", NULL, 15 }, { "sdio", NULL, 17 }, { "xor0", NULL, 22 }, { "xor1", NULL, 28 }, diff --git a/drivers/clk/nxp/clk-lpc18xx-creg.c b/drivers/clk/nxp/clk-lpc18xx-creg.c index 9e35749dafdf..c6e802e7e6ec 100644 --- a/drivers/clk/nxp/clk-lpc18xx-creg.c +++ b/drivers/clk/nxp/clk-lpc18xx-creg.c @@ -184,7 +184,8 @@ static void __init lpc18xx_creg_clk_init(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_early_data); } -CLK_OF_DECLARE(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk", lpc18xx_creg_clk_init); +CLK_OF_DECLARE_DRIVER(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk", + lpc18xx_creg_clk_init); static struct clk *clk_creg[CREG_CLK_MAX]; static struct clk_onecell_data clk_creg_data = { diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 95e3b3e0fa1c..0146d3c2547f 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -87,6 +87,23 @@ config MSM_LCC_8960 Say Y if you want to use audio devices such as i2s, pcm, SLIMBus, etc. +config MDM_GCC_9615 + tristate "MDM9615 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on mdm9615 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. + +config MDM_LCC_9615 + tristate "MDM9615 LPASS Clock Controller" + select MDM_GCC_9615 + depends on COMMON_CLK_QCOM + help + Support for the LPASS clock controller on mdm9615 devices. + Say Y if you want to use audio devices such as i2s, pcm, + SLIMBus, etc. + config MSM_MMCC_8960 tristate "MSM8960 Multimedia Clock Controller" select MSM_GCC_8960 @@ -117,6 +134,7 @@ config MSM_MMCC_8974 config MSM_GCC_8996 tristate "MSM8996 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on msm8996 devices. @@ -126,6 +144,7 @@ config MSM_GCC_8996 config MSM_MMCC_8996 tristate "MSM8996 Multimedia Clock Controller" select MSM_GCC_8996 + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the multimedia clock controller on msm8996 devices. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 2a25f4e75f49..1fb1f5476cb0 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -12,17 +12,20 @@ clk-qcom-y += clk-regmap-mux.o clk-qcom-y += reset.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o +# Keep alphabetically sorted by config obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o +obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o +obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o -obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o +obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c index a58ba39a900c..1c856d330733 100644 --- a/drivers/clk/qcom/clk-regmap.c +++ b/drivers/clk/qcom/clk-regmap.c @@ -101,14 +101,13 @@ EXPORT_SYMBOL_GPL(clk_disable_regmap); * clk_regmap struct via this function so that the regmap is initialized * and so that the clock is registered with the common clock framework. */ -struct clk *devm_clk_register_regmap(struct device *dev, - struct clk_regmap *rclk) +int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk) { if (dev && dev_get_regmap(dev, NULL)) rclk->regmap = dev_get_regmap(dev, NULL); else if (dev && dev->parent) rclk->regmap = dev_get_regmap(dev->parent, NULL); - return devm_clk_register(dev, &rclk->hw); + return devm_clk_hw_register(dev, &rclk->hw); } EXPORT_SYMBOL_GPL(devm_clk_register_regmap); diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 491a63d537df..90d95cd11ec6 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -39,7 +39,6 @@ struct clk_regmap { int clk_is_enabled_regmap(struct clk_hw *hw); int clk_enable_regmap(struct clk_hw *hw); void clk_disable_regmap(struct clk_hw *hw); -struct clk * -devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk); +int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk); #endif diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index f7c226ab4307..fffcbaf0fba7 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -27,8 +27,8 @@ struct qcom_cc { struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; + struct clk_regmap **rclks; + size_t num_rclks; }; const @@ -102,8 +102,8 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, struct device_node *clocks_node; struct clk_fixed_factor *factor; struct clk_fixed_rate *fixed; - struct clk *clk; struct clk_init_data init_data = { }; + int ret; clocks_node = of_find_node_by_path("/clocks"); if (clocks_node) @@ -121,9 +121,9 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, init_data.name = path; init_data.ops = &clk_fixed_rate_ops; - clk = devm_clk_register(dev, &fixed->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &fixed->hw); + if (ret) + return ret; } of_node_put(node); @@ -141,9 +141,9 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, init_data.flags = 0; init_data.ops = &clk_fixed_factor_ops; - clk = devm_clk_register(dev, &factor->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &factor->hw); + if (ret) + return ret; } return 0; @@ -174,42 +174,48 @@ int qcom_cc_register_sleep_clk(struct device *dev) } EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk); +static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, + void *data) +{ + struct qcom_cc *cc = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= cc->num_rclks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return cc->rclks[idx] ? &cc->rclks[idx]->hw : ERR_PTR(-ENOENT); +} + int qcom_cc_really_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc, struct regmap *regmap) { int i, ret; struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; struct qcom_reset_controller *reset; struct qcom_cc *cc; struct gdsc_desc *scd; size_t num_clks = desc->num_clks; struct clk_regmap **rclks = desc->clks; - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); + cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); if (!cc) return -ENOMEM; - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + cc->rclks = rclks; + cc->num_rclks = num_clks; for (i = 0; i < num_clks; i++) { - if (!rclks[i]) { - clks[i] = ERR_PTR(-ENOENT); + if (!rclks[i]) continue; - } - clk = devm_clk_register_regmap(dev, rclks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; + + ret = devm_clk_register_regmap(dev, rclks[i]); + if (ret) + return ret; } - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + ret = of_clk_add_hw_provider(dev->of_node, qcom_cc_clk_hw_get, cc); if (ret) return ret; diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 3cd1af0af0d9..b593065de8db 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -1332,7 +1332,6 @@ static struct platform_driver gcc_ipq4019_driver = { .probe = gcc_ipq4019_probe, .driver = { .name = "qcom,gcc-ipq4019", - .owner = THIS_MODULE, .of_match_table = gcc_ipq4019_match_table, }, }; diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c new file mode 100644 index 000000000000..581a17f67379 --- /dev/null +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -0,0 +1,1727 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong <narmstrong@baylibre.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk-provider.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#include <dt-bindings/clock/qcom,gcc-mdm9615.h> +#include <dt-bindings/reset/qcom,gcc-mdm9615.h> + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +static struct clk_fixed_factor cxo = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "cxo", + .parent_names = (const char *[]){ "cxo_board" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_pll pll0 = { + .l_reg = 0x30c4, + .m_reg = 0x30c8, + .n_reg = 0x30cc, + .config_reg = 0x30d4, + .mode_reg = 0x30c0, + .status_reg = 0x30d8, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll0", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll0_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "pll0_vote", + .parent_names = (const char *[]){ "pll8" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_regmap pll4_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "pll4_vote", + .parent_names = (const char *[]){ "pll4" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_pll pll8 = { + .l_reg = 0x3144, + .m_reg = 0x3148, + .n_reg = 0x314c, + .config_reg = 0x3154, + .mode_reg = 0x3140, + .status_reg = 0x3158, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll8", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll8_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "pll8_vote", + .parent_names = (const char *[]){ "pll8" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_pll pll14 = { + .l_reg = 0x31c4, + .m_reg = 0x31c8, + .n_reg = 0x31cc, + .config_reg = 0x31d4, + .mode_reg = 0x31c0, + .status_reg = 0x31d8, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll14", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll14_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pll14_vote", + .parent_names = (const char *[]){ "pll14" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +enum { + P_CXO, + P_PLL8, + P_PLL14, +}; + +static const struct parent_map gcc_cxo_pll8_map[] = { + { P_CXO, 0 }, + { P_PLL8, 3 } +}; + +static const char * const gcc_cxo_pll8[] = { + "cxo", + "pll8_vote", +}; + +static const struct parent_map gcc_cxo_pll14_map[] = { + { P_CXO, 0 }, + { P_PLL14, 4 } +}; + +static const char * const gcc_cxo_pll14[] = { + "cxo", + "pll14_vote", +}; + +static const struct parent_map gcc_cxo_map[] = { + { P_CXO, 0 }, +}; + +static const char * const gcc_cxo[] = { + "cxo", +}; + +static struct freq_tbl clk_tbl_gsbi_uart[] = { + { 1843200, P_PLL8, 2, 6, 625 }, + { 3686400, P_PLL8, 2, 12, 625 }, + { 7372800, P_PLL8, 2, 24, 625 }, + { 14745600, P_PLL8, 2, 48, 625 }, + { 16000000, P_PLL8, 4, 1, 6 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 32000000, P_PLL8, 4, 1, 3 }, + { 40000000, P_PLL8, 1, 5, 48 }, + { 46400000, P_PLL8, 1, 29, 240 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 51200000, P_PLL8, 1, 2, 15 }, + { 56000000, P_PLL8, 1, 7, 48 }, + { 58982400, P_PLL8, 1, 96, 625 }, + { 64000000, P_PLL8, 2, 1, 3 }, + { } +}; + +static struct clk_rcg gsbi1_uart_src = { + .ns_reg = 0x29d4, + .md_reg = 0x29d0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x29d4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi1_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x29d4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_clk", + .parent_names = (const char *[]){ + "gsbi1_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi2_uart_src = { + .ns_reg = 0x29f4, + .md_reg = 0x29f0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x29f4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi2_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x29f4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_clk", + .parent_names = (const char *[]){ + "gsbi2_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi3_uart_src = { + .ns_reg = 0x2a14, + .md_reg = 0x2a10, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a14, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi3_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 2, + .clkr = { + .enable_reg = 0x2a14, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_uart_clk", + .parent_names = (const char *[]){ + "gsbi3_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi4_uart_src = { + .ns_reg = 0x2a34, + .md_reg = 0x2a30, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a34, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi4_uart_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 26, + .clkr = { + .enable_reg = 0x2a34, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_clk", + .parent_names = (const char *[]){ + "gsbi4_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi5_uart_src = { + .ns_reg = 0x2a54, + .md_reg = 0x2a50, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a54, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi5_uart_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 22, + .clkr = { + .enable_reg = 0x2a54, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_clk", + .parent_names = (const char *[]){ + "gsbi5_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_gsbi_qup[] = { + { 960000, P_CXO, 4, 1, 5 }, + { 4800000, P_CXO, 4, 0, 1 }, + { 9600000, P_CXO, 2, 0, 1 }, + { 15060000, P_PLL8, 1, 2, 51 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 25600000, P_PLL8, 1, 1, 15 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 51200000, P_PLL8, 1, 2, 15 }, + { } +}; + +static struct clk_rcg gsbi1_qup_src = { + .ns_reg = 0x29cc, + .md_reg = 0x29c8, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x29cc, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi1_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x29cc, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_clk", + .parent_names = (const char *[]){ "gsbi1_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi2_qup_src = { + .ns_reg = 0x29ec, + .md_reg = 0x29e8, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x29ec, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi2_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 4, + .clkr = { + .enable_reg = 0x29ec, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_clk", + .parent_names = (const char *[]){ "gsbi2_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi3_qup_src = { + .ns_reg = 0x2a0c, + .md_reg = 0x2a08, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a0c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi3_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 0, + .clkr = { + .enable_reg = 0x2a0c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_qup_clk", + .parent_names = (const char *[]){ "gsbi3_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi4_qup_src = { + .ns_reg = 0x2a2c, + .md_reg = 0x2a28, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a2c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi4_qup_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 24, + .clkr = { + .enable_reg = 0x2a2c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_clk", + .parent_names = (const char *[]){ "gsbi4_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi5_qup_src = { + .ns_reg = 0x2a4c, + .md_reg = 0x2a48, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a4c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi5_qup_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x2a4c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_clk", + .parent_names = (const char *[]){ "gsbi5_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_gp[] = { + { 9600000, P_CXO, 2, 0, 0 }, + { 19200000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg gp0_src = { + .ns_reg = 0x2d24, + .md_reg = 0x2d00, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d24, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp0_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + } +}; + +static struct clk_branch gp0_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x2d24, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp0_clk", + .parent_names = (const char *[]){ "gp0_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gp1_src = { + .ns_reg = 0x2d44, + .md_reg = 0x2d40, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d44, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp1_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch gp1_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x2d44, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp1_clk", + .parent_names = (const char *[]){ "gp1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gp2_src = { + .ns_reg = 0x2d64, + .md_reg = 0x2d60, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d64, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp2_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch gp2_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 5, + .clkr = { + .enable_reg = 0x2d64, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp2_clk", + .parent_names = (const char *[]){ "gp2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch pmem_clk = { + .hwcg_reg = 0x25a0, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x25a0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "pmem_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_rcg prng_src = { + .ns_reg = 0x2e80, + .p = { + .pre_div_shift = 3, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "prng_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch prng_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "prng_clk", + .parent_names = (const char *[]){ "prng_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, + }, +}; + +static const struct freq_tbl clk_tbl_sdc[] = { + { 144000, P_CXO, 1, 1, 133 }, + { 400000, P_PLL8, 4, 1, 240 }, + { 16000000, P_PLL8, 4, 1, 6 }, + { 17070000, P_PLL8, 1, 2, 45 }, + { 20210000, P_PLL8, 1, 1, 19 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 38400000, P_PLL8, 2, 1, 5 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 64000000, P_PLL8, 3, 1, 2 }, + { 76800000, P_PLL8, 1, 1, 5 }, + { } +}; + +static struct clk_rcg sdc1_src = { + .ns_reg = 0x282c, + .md_reg = 0x2828, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_sdc, + .clkr = { + .enable_reg = 0x282c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch sdc1_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x282c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_clk", + .parent_names = (const char *[]){ "sdc1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg sdc2_src = { + .ns_reg = 0x284c, + .md_reg = 0x2848, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_sdc, + .clkr = { + .enable_reg = 0x284c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch sdc2_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 5, + .clkr = { + .enable_reg = 0x284c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_clk", + .parent_names = (const char *[]){ "sdc2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb[] = { + { 60000000, P_PLL8, 1, 5, 32 }, + { } +}; + +static struct clk_rcg usb_hs1_xcvr_src = { + .ns_reg = 0x290c, + .md_reg = 0x2908, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { + .enable_reg = 0x290c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hs1_xcvr_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 0, + .clkr = { + .enable_reg = 0x290c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_clk", + .parent_names = (const char *[]){ "usb_hs1_xcvr_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg usb_hsic_xcvr_fs_src = { + .ns_reg = 0x2928, + .md_reg = 0x2924, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { + .enable_reg = 0x2928, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_xcvr_fs_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_xcvr_fs_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x2928, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_xcvr_fs_clk", + .parent_names = + (const char *[]){ "usb_hsic_xcvr_fs_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hs1_system[] = { + { 60000000, P_PLL8, 1, 5, 32 }, + { } +}; + +static struct clk_rcg usb_hs1_system_src = { + .ns_reg = 0x36a4, + .md_reg = 0x36a0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb_hs1_system, + .clkr = { + .enable_reg = 0x36a4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_system_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hs1_system_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 4, + .clkr = { + .enable_reg = 0x36a4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = + (const char *[]){ "usb_hs1_system_src" }, + .num_parents = 1, + .name = "usb_hs1_system_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hsic_system[] = { + { 64000000, P_PLL8, 1, 1, 6 }, + { } +}; + +static struct clk_rcg usb_hsic_system_src = { + .ns_reg = 0x2b58, + .md_reg = 0x2b54, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb_hsic_system, + .clkr = { + .enable_reg = 0x2b58, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_system_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_system_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x2b58, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = + (const char *[]){ "usb_hsic_system_src" }, + .num_parents = 1, + .name = "usb_hsic_system_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hsic_hsic[] = { + { 48000000, P_PLL14, 1, 0, 0 }, + { } +}; + +static struct clk_rcg usb_hsic_hsic_src = { + .ns_reg = 0x2b50, + .md_reg = 0x2b4c, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll14_map, + }, + .freq_tbl = clk_tbl_usb_hsic_hsic, + .clkr = { + .enable_reg = 0x2b50, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_hsic_src", + .parent_names = gcc_cxo_pll14, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_hsic_clk = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2b50, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "usb_hsic_hsic_src" }, + .num_parents = 1, + .name = "usb_hsic_hsic_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch usb_hsic_hsio_cal_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 8, + .clkr = { + .enable_reg = 0x2b48, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .name = "usb_hsic_hsio_cal_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch ce1_core_clk = { + .hwcg_reg = 0x2724, + .hwcg_bit = 6, + .halt_reg = 0x2fd4, + .halt_bit = 27, + .clkr = { + .enable_reg = 0x2724, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ce1_core_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch ce1_h_clk = { + .halt_reg = 0x2fd4, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x2720, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ce1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch dma_bam_h_clk = { + .hwcg_reg = 0x25c0, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 12, + .clkr = { + .enable_reg = 0x25c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "dma_bam_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi1_h_clk = { + .hwcg_reg = 0x29c0, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 11, + .clkr = { + .enable_reg = 0x29c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi2_h_clk = { + .hwcg_reg = 0x29e0, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x29e0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi3_h_clk = { + .hwcg_reg = 0x2a00, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 3, + .clkr = { + .enable_reg = 0x2a00, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi4_h_clk = { + .hwcg_reg = 0x2a20, + .hwcg_bit = 6, + .halt_reg = 0x2fd0, + .halt_bit = 27, + .clkr = { + .enable_reg = 0x2a20, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi5_h_clk = { + .hwcg_reg = 0x2a40, + .hwcg_bit = 6, + .halt_reg = 0x2fd0, + .halt_bit = 23, + .clkr = { + .enable_reg = 0x2a40, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch usb_hs1_h_clk = { + .hwcg_reg = 0x2900, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x2900, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch usb_hsic_h_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 28, + .clkr = { + .enable_reg = 0x2920, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch sdc1_h_clk = { + .hwcg_reg = 0x2820, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 11, + .clkr = { + .enable_reg = 0x2820, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch sdc2_h_clk = { + .hwcg_reg = 0x2840, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x2840, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch adm0_clk = { + .halt_reg = 0x2fdc, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 14, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "adm0_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch adm0_pbus_clk = { + .hwcg_reg = 0x2208, + .hwcg_bit = 6, + .halt_reg = 0x2fdc, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 13, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "adm0_pbus_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_arb0_h_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 22, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "pmic_arb0_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_arb1_h_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 21, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pmic_arb1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_ssbi2_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 23, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "pmic_ssbi2_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch rpm_msg_ram_h_clk = { + .hwcg_reg = 0x27e0, + .hwcg_bit = 6, + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 12, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "rpm_msg_ram_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_hw *gcc_mdm9615_hws[] = { + &cxo.hw, +}; + +static struct clk_regmap *gcc_mdm9615_clks[] = { + [PLL0] = &pll0.clkr, + [PLL0_VOTE] = &pll0_vote, + [PLL4_VOTE] = &pll4_vote, + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, + [PLL14] = &pll14.clkr, + [PLL14_VOTE] = &pll14_vote, + [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr, + [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr, + [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr, + [GSBI2_UART_CLK] = &gsbi2_uart_clk.clkr, + [GSBI3_UART_SRC] = &gsbi3_uart_src.clkr, + [GSBI3_UART_CLK] = &gsbi3_uart_clk.clkr, + [GSBI4_UART_SRC] = &gsbi4_uart_src.clkr, + [GSBI4_UART_CLK] = &gsbi4_uart_clk.clkr, + [GSBI5_UART_SRC] = &gsbi5_uart_src.clkr, + [GSBI5_UART_CLK] = &gsbi5_uart_clk.clkr, + [GSBI1_QUP_SRC] = &gsbi1_qup_src.clkr, + [GSBI1_QUP_CLK] = &gsbi1_qup_clk.clkr, + [GSBI2_QUP_SRC] = &gsbi2_qup_src.clkr, + [GSBI2_QUP_CLK] = &gsbi2_qup_clk.clkr, + [GSBI3_QUP_SRC] = &gsbi3_qup_src.clkr, + [GSBI3_QUP_CLK] = &gsbi3_qup_clk.clkr, + [GSBI4_QUP_SRC] = &gsbi4_qup_src.clkr, + [GSBI4_QUP_CLK] = &gsbi4_qup_clk.clkr, + [GSBI5_QUP_SRC] = &gsbi5_qup_src.clkr, + [GSBI5_QUP_CLK] = &gsbi5_qup_clk.clkr, + [GP0_SRC] = &gp0_src.clkr, + [GP0_CLK] = &gp0_clk.clkr, + [GP1_SRC] = &gp1_src.clkr, + [GP1_CLK] = &gp1_clk.clkr, + [GP2_SRC] = &gp2_src.clkr, + [GP2_CLK] = &gp2_clk.clkr, + [PMEM_A_CLK] = &pmem_clk.clkr, + [PRNG_SRC] = &prng_src.clkr, + [PRNG_CLK] = &prng_clk.clkr, + [SDC1_SRC] = &sdc1_src.clkr, + [SDC1_CLK] = &sdc1_clk.clkr, + [SDC2_SRC] = &sdc2_src.clkr, + [SDC2_CLK] = &sdc2_clk.clkr, + [USB_HS1_XCVR_SRC] = &usb_hs1_xcvr_src.clkr, + [USB_HS1_XCVR_CLK] = &usb_hs1_xcvr_clk.clkr, + [USB_HS1_SYSTEM_CLK_SRC] = &usb_hs1_system_src.clkr, + [USB_HS1_SYSTEM_CLK] = &usb_hs1_system_clk.clkr, + [USB_HSIC_XCVR_FS_SRC] = &usb_hsic_xcvr_fs_src.clkr, + [USB_HSIC_XCVR_FS_CLK] = &usb_hsic_xcvr_fs_clk.clkr, + [USB_HSIC_SYSTEM_CLK_SRC] = &usb_hsic_system_src.clkr, + [USB_HSIC_SYSTEM_CLK] = &usb_hsic_system_clk.clkr, + [USB_HSIC_HSIC_CLK_SRC] = &usb_hsic_hsic_src.clkr, + [USB_HSIC_HSIC_CLK] = &usb_hsic_hsic_clk.clkr, + [USB_HSIC_HSIO_CAL_CLK] = &usb_hsic_hsio_cal_clk.clkr, + [CE1_CORE_CLK] = &ce1_core_clk.clkr, + [CE1_H_CLK] = &ce1_h_clk.clkr, + [DMA_BAM_H_CLK] = &dma_bam_h_clk.clkr, + [GSBI1_H_CLK] = &gsbi1_h_clk.clkr, + [GSBI2_H_CLK] = &gsbi2_h_clk.clkr, + [GSBI3_H_CLK] = &gsbi3_h_clk.clkr, + [GSBI4_H_CLK] = &gsbi4_h_clk.clkr, + [GSBI5_H_CLK] = &gsbi5_h_clk.clkr, + [USB_HS1_H_CLK] = &usb_hs1_h_clk.clkr, + [USB_HSIC_H_CLK] = &usb_hsic_h_clk.clkr, + [SDC1_H_CLK] = &sdc1_h_clk.clkr, + [SDC2_H_CLK] = &sdc2_h_clk.clkr, + [ADM0_CLK] = &adm0_clk.clkr, + [ADM0_PBUS_CLK] = &adm0_pbus_clk.clkr, + [PMIC_ARB0_H_CLK] = &pmic_arb0_h_clk.clkr, + [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr, + [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr, + [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr, +}; + +static const struct qcom_reset_map gcc_mdm9615_resets[] = { + [DMA_BAM_RESET] = { 0x25c0, 7 }, + [CE1_H_RESET] = { 0x2720, 7 }, + [CE1_CORE_RESET] = { 0x2724, 7 }, + [SDC1_RESET] = { 0x2830 }, + [SDC2_RESET] = { 0x2850 }, + [ADM0_C2_RESET] = { 0x220c, 4 }, + [ADM0_C1_RESET] = { 0x220c, 3 }, + [ADM0_C0_RESET] = { 0x220c, 2 }, + [ADM0_PBUS_RESET] = { 0x220c, 1 }, + [ADM0_RESET] = { 0x220c }, + [USB_HS1_RESET] = { 0x2910 }, + [USB_HSIC_RESET] = { 0x2934 }, + [GSBI1_RESET] = { 0x29dc }, + [GSBI2_RESET] = { 0x29fc }, + [GSBI3_RESET] = { 0x2a1c }, + [GSBI4_RESET] = { 0x2a3c }, + [GSBI5_RESET] = { 0x2a5c }, + [PDM_RESET] = { 0x2CC0, 12 }, +}; + +static const struct regmap_config gcc_mdm9615_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3660, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_mdm9615_desc = { + .config = &gcc_mdm9615_regmap_config, + .clks = gcc_mdm9615_clks, + .num_clks = ARRAY_SIZE(gcc_mdm9615_clks), + .resets = gcc_mdm9615_resets, + .num_resets = ARRAY_SIZE(gcc_mdm9615_resets), +}; + +static const struct of_device_id gcc_mdm9615_match_table[] = { + { .compatible = "qcom,gcc-mdm9615" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_mdm9615_match_table); + +static int gcc_mdm9615_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + int ret; + int i; + + regmap = qcom_cc_map(pdev, &gcc_mdm9615_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + for (i = 0; i < ARRAY_SIZE(gcc_mdm9615_hws); i++) { + ret = devm_clk_hw_register(dev, gcc_mdm9615_hws[i]); + if (ret) + return ret; + } + + return qcom_cc_really_probe(pdev, &gcc_mdm9615_desc, regmap); +} + +static struct platform_driver gcc_mdm9615_driver = { + .probe = gcc_mdm9615_probe, + .driver = { + .name = "gcc-mdm9615", + .of_match_table = gcc_mdm9615_match_table, + }, +}; + +static int __init gcc_mdm9615_init(void) +{ + return platform_driver_register(&gcc_mdm9615_driver); +} +core_initcall(gcc_mdm9615_init); + +static void __exit gcc_mdm9615_exit(void) +{ + platform_driver_unregister(&gcc_mdm9615_driver); +} +module_exit(gcc_mdm9615_exit); + +MODULE_DESCRIPTION("QCOM GCC MDM9615 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-mdm9615"); diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index bbf732bbc3fd..ebe5d187fa1b 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2592,9 +2592,9 @@ static struct clk_branch gcc_pcie_2_aux_clk = { }; static struct clk_branch gcc_pcie_2_pipe_clk = { - .halt_reg = 0x6e108, + .halt_reg = 0x6e018, .clkr = { - .enable_reg = 0x6e108, + .enable_reg = 0x6e018, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_pipe_clk", @@ -3404,6 +3404,8 @@ static const struct qcom_reset_map gcc_msm8996_resets[] = { [GCC_PCIE_2_BCR] = { 0x6e000 }, [GCC_PCIE_2_PHY_BCR] = { 0x6e038 }, [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f014 }, + [GCC_PCIE_PHY_COM_NOCSR_BCR] = { 0x6f00c }, [GCC_DCD_BCR] = { 0x70000 }, [GCC_OBT_ODT_BCR] = { 0x73000 }, [GCC_UFS_BCR] = { 0x75000 }, @@ -3447,9 +3449,8 @@ MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table); static int gcc_msm8996_probe(struct platform_device *pdev) { - struct clk *clk; struct device *dev = &pdev->dev; - int i; + int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &gcc_msm8996_desc); @@ -3463,9 +3464,9 @@ static int gcc_msm8996_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21)); for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) { - clk = devm_clk_register(dev, gcc_msm8996_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, gcc_msm8996_hws[i]); + if (ret) + return ret; } return qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap); diff --git a/drivers/clk/qcom/lcc-mdm9615.c b/drivers/clk/qcom/lcc-mdm9615.c new file mode 100644 index 000000000000..3237ef4c1197 --- /dev/null +++ b/drivers/clk/qcom/lcc-mdm9615.c @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong <narmstrong@baylibre.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk-provider.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,lcc-mdm9615.h> + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" + +static struct clk_pll pll4 = { + .l_reg = 0x4, + .m_reg = 0x8, + .n_reg = 0xc, + .config_reg = 0x14, + .mode_reg = 0x0, + .status_reg = 0x18, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll4", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +enum { + P_CXO, + P_PLL4, +}; + +static const struct parent_map lcc_cxo_pll4_map[] = { + { P_CXO, 0 }, + { P_PLL4, 2 } +}; + +static const char * const lcc_cxo_pll4[] = { + "cxo", + "pll4_vote", +}; + +static struct freq_tbl clk_tbl_aif_osr_492[] = { + { 512000, P_PLL4, 4, 1, 240 }, + { 768000, P_PLL4, 4, 1, 160 }, + { 1024000, P_PLL4, 4, 1, 120 }, + { 1536000, P_PLL4, 4, 1, 80 }, + { 2048000, P_PLL4, 4, 1, 60 }, + { 3072000, P_PLL4, 4, 1, 40 }, + { 4096000, P_PLL4, 4, 1, 30 }, + { 6144000, P_PLL4, 4, 1, 20 }, + { 8192000, P_PLL4, 4, 1, 15 }, + { 12288000, P_PLL4, 4, 1, 10 }, + { 24576000, P_PLL4, 4, 1, 5 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct freq_tbl clk_tbl_aif_osr_393[] = { + { 512000, P_PLL4, 4, 1, 192 }, + { 768000, P_PLL4, 4, 1, 128 }, + { 1024000, P_PLL4, 4, 1, 96 }, + { 1536000, P_PLL4, 4, 1, 64 }, + { 2048000, P_PLL4, 4, 1, 48 }, + { 3072000, P_PLL4, 4, 1, 32 }, + { 4096000, P_PLL4, 4, 1, 24 }, + { 6144000, P_PLL4, 4, 1, 16 }, + { 8192000, P_PLL4, 4, 1, 12 }, + { 12288000, P_PLL4, 4, 1, 8 }, + { 24576000, P_PLL4, 4, 1, 4 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg mi2s_osr_src = { + .ns_reg = 0x48, + .md_reg = 0x4c, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_aif_osr_393, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static const char * const lcc_mi2s_parents[] = { + "mi2s_osr_src", +}; + +static struct clk_branch mi2s_osr_clk = { + .halt_reg = 0x50, + .halt_bit = 1, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_clk", + .parent_names = lcc_mi2s_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_div mi2s_div_clk = { + .reg = 0x48, + .shift = 10, + .width = 4, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_div_clk", + .parent_names = lcc_mi2s_parents, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch mi2s_bit_div_clk = { + .halt_reg = 0x50, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_div_clk", + .parent_names = (const char *[]){ "mi2s_div_clk" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_mux mi2s_bit_clk = { + .reg = 0x48, + .shift = 14, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_clk", + .parent_names = (const char *[]){ + "mi2s_bit_div_clk", + "mi2s_codec_clk", + }, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \ +static struct clk_rcg prefix##_osr_src = { \ + .ns_reg = _ns, \ + .md_reg = _md, \ + .mn = { \ + .mnctr_en_bit = 8, \ + .mnctr_reset_bit = 7, \ + .mnctr_mode_shift = 5, \ + .n_val_shift = 24, \ + .m_val_shift = 8, \ + .width = 8, \ + }, \ + .p = { \ + .pre_div_shift = 3, \ + .pre_div_width = 2, \ + }, \ + .s = { \ + .src_sel_shift = 0, \ + .parent_map = lcc_cxo_pll4_map, \ + }, \ + .freq_tbl = clk_tbl_aif_osr_393, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(9), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_osr_src", \ + .parent_names = lcc_cxo_pll4, \ + .num_parents = 2, \ + .ops = &clk_rcg_ops, \ + .flags = CLK_SET_RATE_GATE, \ + }, \ + }, \ +}; \ + \ +static const char * const lcc_##prefix##_parents[] = { \ + #prefix "_osr_src", \ +}; \ + \ +static struct clk_branch prefix##_osr_clk = { \ + .halt_reg = hr, \ + .halt_bit = 1, \ + .halt_check = BRANCH_HALT_ENABLE, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(21), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_osr_clk", \ + .parent_names = lcc_##prefix##_parents, \ + .num_parents = 1, \ + .ops = &clk_branch_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +}; \ + \ +static struct clk_regmap_div prefix##_div_clk = { \ + .reg = _ns, \ + .shift = 10, \ + .width = 8, \ + .clkr = { \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_div_clk", \ + .parent_names = lcc_##prefix##_parents, \ + .num_parents = 1, \ + .ops = &clk_regmap_div_ops, \ + }, \ + }, \ +}; \ + \ +static struct clk_branch prefix##_bit_div_clk = { \ + .halt_reg = hr, \ + .halt_bit = 0, \ + .halt_check = BRANCH_HALT_ENABLE, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(19), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_bit_div_clk", \ + .parent_names = (const char *[]){ \ + #prefix "_div_clk" \ + }, \ + .num_parents = 1, \ + .ops = &clk_branch_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +}; \ + \ +static struct clk_regmap_mux prefix##_bit_clk = { \ + .reg = _ns, \ + .shift = 18, \ + .width = 1, \ + .clkr = { \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_bit_clk", \ + .parent_names = (const char *[]){ \ + #prefix "_bit_div_clk", \ + #prefix "_codec_clk", \ + }, \ + .num_parents = 2, \ + .ops = &clk_regmap_mux_closest_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +} + +CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68); +CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80); +CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74); +CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c); + +static struct freq_tbl clk_tbl_pcm_492[] = { + { 256000, P_PLL4, 4, 1, 480 }, + { 512000, P_PLL4, 4, 1, 240 }, + { 768000, P_PLL4, 4, 1, 160 }, + { 1024000, P_PLL4, 4, 1, 120 }, + { 1536000, P_PLL4, 4, 1, 80 }, + { 2048000, P_PLL4, 4, 1, 60 }, + { 3072000, P_PLL4, 4, 1, 40 }, + { 4096000, P_PLL4, 4, 1, 30 }, + { 6144000, P_PLL4, 4, 1, 20 }, + { 8192000, P_PLL4, 4, 1, 15 }, + { 12288000, P_PLL4, 4, 1, 10 }, + { 24576000, P_PLL4, 4, 1, 5 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct freq_tbl clk_tbl_pcm_393[] = { + { 256000, P_PLL4, 4, 1, 384 }, + { 512000, P_PLL4, 4, 1, 192 }, + { 768000, P_PLL4, 4, 1, 128 }, + { 1024000, P_PLL4, 4, 1, 96 }, + { 1536000, P_PLL4, 4, 1, 64 }, + { 2048000, P_PLL4, 4, 1, 48 }, + { 3072000, P_PLL4, 4, 1, 32 }, + { 4096000, P_PLL4, 4, 1, 24 }, + { 6144000, P_PLL4, 4, 1, 16 }, + { 8192000, P_PLL4, 4, 1, 12 }, + { 12288000, P_PLL4, 4, 1, 8 }, + { 24576000, P_PLL4, 4, 1, 4 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg pcm_src = { + .ns_reg = 0x54, + .md_reg = 0x58, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_pcm_393, + .clkr = { + .enable_reg = 0x54, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcm_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static struct clk_branch pcm_clk_out = { + .halt_reg = 0x5c, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x54, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk_out", + .parent_names = (const char *[]){ "pcm_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_mux pcm_clk = { + .reg = 0x54, + .shift = 10, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk", + .parent_names = (const char *[]){ + "pcm_clk_out", + "pcm_codec_clk", + }, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg slimbus_src = { + .ns_reg = 0xcc, + .md_reg = 0xd0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_aif_osr_393, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "slimbus_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static const char * const lcc_slimbus_parents[] = { + "slimbus_src", +}; + +static struct clk_branch audio_slimbus_clk = { + .halt_reg = 0xd4, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "audio_slimbus_clk", + .parent_names = lcc_slimbus_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch sps_slimbus_clk = { + .halt_reg = 0xd4, + .halt_bit = 1, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "sps_slimbus_clk", + .parent_names = lcc_slimbus_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap *lcc_mdm9615_clks[] = { + [PLL4] = &pll4.clkr, + [MI2S_OSR_SRC] = &mi2s_osr_src.clkr, + [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr, + [MI2S_DIV_CLK] = &mi2s_div_clk.clkr, + [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr, + [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr, + [PCM_SRC] = &pcm_src.clkr, + [PCM_CLK_OUT] = &pcm_clk_out.clkr, + [PCM_CLK] = &pcm_clk.clkr, + [SLIMBUS_SRC] = &slimbus_src.clkr, + [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr, + [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr, + [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr, + [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr, + [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr, + [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr, + [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr, + [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr, + [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr, + [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr, + [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr, + [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr, + [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr, + [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr, + [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr, + [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr, + [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr, + [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr, + [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr, + [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr, + [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr, + [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr, +}; + +static const struct regmap_config lcc_mdm9615_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xfc, + .fast_io = true, +}; + +static const struct qcom_cc_desc lcc_mdm9615_desc = { + .config = &lcc_mdm9615_regmap_config, + .clks = lcc_mdm9615_clks, + .num_clks = ARRAY_SIZE(lcc_mdm9615_clks), +}; + +static const struct of_device_id lcc_mdm9615_match_table[] = { + { .compatible = "qcom,lcc-mdm9615" }, + { } +}; +MODULE_DEVICE_TABLE(of, lcc_mdm9615_match_table); + +static int lcc_mdm9615_probe(struct platform_device *pdev) +{ + u32 val; + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &lcc_mdm9615_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Use the correct frequency plan depending on speed of PLL4 */ + regmap_read(regmap, 0x4, &val); + if (val == 0x12) { + slimbus_src.freq_tbl = clk_tbl_aif_osr_492; + mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492; + codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; + spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; + codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; + spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; + pcm_src.freq_tbl = clk_tbl_pcm_492; + } + /* Enable PLL4 source on the LPASS Primary PLL Mux */ + regmap_write(regmap, 0xc4, 0x1); + + return qcom_cc_really_probe(pdev, &lcc_mdm9615_desc, regmap); +} + +static struct platform_driver lcc_mdm9615_driver = { + .probe = lcc_mdm9615_probe, + .driver = { + .name = "lcc-mdm9615", + .of_match_table = lcc_mdm9615_match_table, + }, +}; +module_platform_driver(lcc_mdm9615_driver); + +MODULE_DESCRIPTION("QCOM LCC MDM9615 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:lcc-mdm9615"); diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 847dd9dadeca..ca97e1151797 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -2888,6 +2888,14 @@ static struct clk_hw *mmcc_msm8996_hws[] = { &gpll0_div.hw, }; +static struct gdsc mmagic_bimc_gdsc = { + .gdscr = 0x529c, + .pd = { + .name = "mmagic_bimc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct gdsc mmagic_video_gdsc = { .gdscr = 0x119c, .gds_hw_ctrl = 0x120c, @@ -3201,6 +3209,7 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = { }; static struct gdsc *mmcc_msm8996_gdscs[] = { + [MMAGIC_BIMC_GDSC] = &mmagic_bimc_gdsc, [MMAGIC_VIDEO_GDSC] = &mmagic_video_gdsc, [MMAGIC_MDSS_GDSC] = &mmagic_mdss_gdsc, [MMAGIC_CAMSS_GDSC] = &mmagic_camss_gdsc, @@ -3305,9 +3314,8 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table); static int mmcc_msm8996_probe(struct platform_device *pdev) { - struct clk *clk; struct device *dev = &pdev->dev; - int i; + int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc); @@ -3320,9 +3328,9 @@ static int mmcc_msm8996_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x5054, BIT(15), 0); for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) { - clk = devm_clk_register(dev, mmcc_msm8996_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, mmcc_msm8996_hws[i]); + if (ret) + return ret; } return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap); diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index d359c92e13a6..e38bf60c0ff4 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -69,6 +69,7 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), @@ -87,10 +88,10 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1), DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1), - DEF_GEN3_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074), - DEF_GEN3_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078), - DEF_GEN3_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268), - DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c), + DEF_GEN3_SD("sd0", R8A7795_CLK_SD0, CLK_SDSRC, 0x0074), + DEF_GEN3_SD("sd1", R8A7795_CLK_SD1, CLK_SDSRC, 0x0078), + DEF_GEN3_SD("sd2", R8A7795_CLK_SD2, CLK_SDSRC, 0x0268), + DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_SDSRC, 0x026c), DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index c84b549c14d2..891b353e8105 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -45,6 +45,7 @@ enum clk_ids { CLK_S3, CLK_SDSRC, CLK_SSPSRC, + CLK_RINT, /* Module Clocks */ MOD_CLK_BASE @@ -69,6 +70,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), @@ -92,13 +94,36 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED("s3d2", R8A7796_CLK_S3D2, CLK_S3, 2, 1), DEF_FIXED("s3d4", R8A7796_CLK_S3D4, CLK_S3, 4, 1), + DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, CLK_SDSRC, 0x0074), + DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, CLK_SDSRC, 0x0078), + DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, CLK_SDSRC, 0x0268), + DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x026c), + DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1), DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1), + + DEF_DIV6_RO("osc", R8A7796_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8), + DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), + + DEF_BASE("r", R8A7796_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), }; static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("scif2", 310, R8A7796_CLK_S3D4), + DEF_MOD("sdif3", 311, R8A7796_CLK_SD3), + DEF_MOD("sdif2", 312, R8A7796_CLK_SD2), + DEF_MOD("sdif1", 313, R8A7796_CLK_SD1), + DEF_MOD("sdif0", 314, R8A7796_CLK_SD0), + DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), + DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4), + DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4), + DEF_MOD("gpio5", 907, R8A7796_CLK_S3D4), + DEF_MOD("gpio4", 908, R8A7796_CLK_S3D4), + DEF_MOD("gpio3", 909, R8A7796_CLK_S3D4), + DEF_MOD("gpio2", 910, R8A7796_CLK_S3D4), + DEF_MOD("gpio1", 911, R8A7796_CLK_S3D4), + DEF_MOD("gpio0", 912, R8A7796_CLK_S3D4), }; static const unsigned int r8a7796_crit_mod_clks[] __initconst = { diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa962d2..b5f2c8ed12e1 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000000000000..8feba93672c5 --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang <hl@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/arm-smccc.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <soc/rockchip/rockchip_sip.h> +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem *reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int div_shift; + int div_width; + int ddr_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) + +static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + struct arm_smccc_res res; + + spin_lock_irqsave(ddrclk->lock, flags); + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, drate, 0, + ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE, + 0, 0, 0, 0, &res); + spin_unlock_irqrestore(ddrclk->lock, flags); + + return res.a0; +} + +static unsigned long +rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE, + 0, 0, 0, 0, &res); + + return res.a0; +} + +static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, rate, 0, + ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE, + 0, 0, 0, 0, &res); + + return res.a0; +} + +static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->mux_shift; + val &= GENMASK(ddrclk->mux_width - 1, 0); + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static const struct clk_ops rockchip_ddrclk_sip_ops = { + .recalc_rate = rockchip_ddrclk_sip_recalc_rate, + .set_rate = rockchip_ddrclk_sip_set_rate, + .round_rate = rockchip_ddrclk_sip_round_rate, + .get_parent = rockchip_ddrclk_get_parent, +}; + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int div_shift, int div_width, + int ddr_flag, void __iomem *reg_base, + spinlock_t *lock) +{ + struct rockchip_ddrclk *ddrclk; + struct clk_init_data init; + struct clk *clk; + + ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL); + if (!ddrclk) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.parent_names = parent_names; + init.num_parents = num_parents; + + init.flags = flags; + init.flags |= CLK_SET_RATE_NO_REPARENT; + + switch (ddr_flag) { + case ROCKCHIP_DDRCLK_SIP: + init.ops = &rockchip_ddrclk_sip_ops; + break; + default: + pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag); + kfree(ddrclk); + return ERR_PTR(-EINVAL); + } + + ddrclk->reg_base = reg_base; + ddrclk->lock = lock; + ddrclk->hw.init = &init; + ddrclk->mux_offset = mux_offset; + ddrclk->mux_shift = mux_shift; + ddrclk->mux_width = mux_width; + ddrclk->div_shift = div_shift; + ddrclk->div_width = div_width; + ddrclk->ddr_flag = ddr_flag; + + clk = clk_register(NULL, &ddrclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register ddrclk %s\n", __func__, name); + kfree(ddrclk); + return NULL; + } + + return clk; +} diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index db81e454166b..9c1373e81683 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -837,7 +837,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, u8 num_parents, int con_offset, int grf_lock_offset, int lock_shift, int mode_offset, int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags) + unsigned long flags, u8 clk_pll_flags) { const char *pll_parents[3]; struct clk_init_data init; @@ -892,7 +892,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, init.name = pll_name; /* keep all plls untouched for now */ - init.flags = CLK_IGNORE_UNUSED; + init.flags = flags | CLK_IGNORE_UNUSED; init.parent_names = &parent_names[0]; init.num_parents = 1; diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index c109d80e7a8a..8387c7a40bda 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -100,8 +100,10 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0), RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0), RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0), RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0), RK3036_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 65000000, 1, 65, 6, 4, 1, 0), RK3036_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0), RK3036_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0), { /* sentinel */ }, @@ -118,6 +120,10 @@ PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src", "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" }; +PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + "clk_ddrc_bpll_src", + "clk_ddrc_dpll_src", + "clk_ddrc_gpll_src" }; PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", @@ -373,6 +379,7 @@ static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11), RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10), RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(2016000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8), @@ -578,7 +585,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 13, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0, RK3399_CLKSEL_CON(99), 0, RK3399_CLKGATE_CON(8), 14, GFLAGS, &rk3399_spdif_fracmux), @@ -592,7 +599,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 3, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0, RK3399_CLKSEL_CON(96), 0, RK3399_CLKGATE_CON(8), 4, GFLAGS, &rk3399_i2s0_fracmux), @@ -602,7 +609,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 6, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0, RK3399_CLKSEL_CON(97), 0, RK3399_CLKGATE_CON(8), 7, GFLAGS, &rk3399_i2s1_fracmux), @@ -612,7 +619,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 9, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0, RK3399_CLKSEL_CON(98), 0, RK3399_CLKGATE_CON(8), 10, GFLAGS, &rk3399_i2s2_fracmux), @@ -631,7 +638,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0, RK3399_CLKSEL_CON(33), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 0, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0, RK3399_CLKSEL_CON(100), 0, RK3399_CLKGATE_CON(9), 1, GFLAGS, &rk3399_uart0_fracmux), @@ -641,7 +648,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(34), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 2, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0, RK3399_CLKSEL_CON(101), 0, RK3399_CLKGATE_CON(9), 3, GFLAGS, &rk3399_uart1_fracmux), @@ -649,7 +656,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(35), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 4, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0, RK3399_CLKSEL_CON(102), 0, RK3399_CLKGATE_CON(9), 5, GFLAGS, &rk3399_uart2_fracmux), @@ -657,7 +664,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(36), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 6, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0, RK3399_CLKSEL_CON(103), 0, RK3399_CLKGATE_CON(9), 7, GFLAGS, &rk3399_uart3_fracmux), @@ -833,9 +840,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { /* perihp */ GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED, - RK3399_CLKGATE_CON(5), 0, GFLAGS), - GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(5), 1, GFLAGS), + GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 0, GFLAGS), COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS, RK3399_CLKGATE_CON(5), 2, GFLAGS), @@ -846,9 +853,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(14), 12, 2, DFLAGS, RK3399_CLKGATE_CON(5), 4, GFLAGS), - GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", 0, RK3399_CLKGATE_CON(20), 2, GFLAGS), - GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", 0, RK3399_CLKGATE_CON(20), 10, GFLAGS), GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 12, GFLAGS), @@ -923,9 +930,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(6), 14, GFLAGS), GATE(0, "cpll_aclk_emmc_src", "cpll", CLK_IGNORE_UNUSED, - RK3399_CLKGATE_CON(6), 12, GFLAGS), - GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(6), 13, GFLAGS), + GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 12, GFLAGS), COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS), GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED, @@ -1071,7 +1078,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { /* vio */ COMPOSITE(ACLK_VIO, "aclk_vio", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, - RK3399_CLKGATE_CON(11), 10, GFLAGS), + RK3399_CLKGATE_CON(11), 0, GFLAGS), COMPOSITE_NOMUX(PCLK_VIO, "pclk_vio", "aclk_vio", 0, RK3399_CLKSEL_CON(43), 0, 5, DFLAGS, RK3399_CLKGATE_CON(11), 1, GFLAGS), @@ -1161,7 +1168,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 12, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0, RK3399_CLKSEL_CON(106), 0, &rk3399_dclk_vop0_fracmux), @@ -1191,7 +1198,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 13, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0, RK3399_CLKSEL_CON(107), 0, &rk3399_dclk_vop1_fracmux), @@ -1305,7 +1312,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { /* testout */ MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(58), 7, 1, MFLAGS), - COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", CLK_SET_RATE_PARENT, + COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0, RK3399_CLKSEL_CON(105), 0, RK3399_CLKGATE_CON(13), 9, GFLAGS), @@ -1377,6 +1384,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3), + 0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3), + 1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3), + 2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3), + 3, GFLAGS), + COMPOSITE_DDRCLK(SCLK_DDRC, "sclk_ddrc", mux_ddrclk_p, 0, + RK3399_CLKSEL_CON(6), 4, 2, 0, 0, ROCKCHIP_DDRCLK_SIP), }; static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { @@ -1398,7 +1417,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0, RK3399_PMU_CLKSEL_CON(7), 0, &rk3399_pmuclk_wifi_fracmux), @@ -1426,7 +1445,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0, RK3399_PMU_CLKSEL_CON(6), 0, RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS, &rk3399_uart4_pmu_fracmux), @@ -1468,6 +1487,9 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "aclk_cci_pre", "aclk_gic", "aclk_gic_noc", + "aclk_hdcp_noc", + "hclk_hdcp_noc", + "pclk_hdcp_noc", "pclk_perilp0", "pclk_perilp0", "hclk_perilp0", @@ -1484,9 +1506,14 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "hclk_perilp1", "hclk_perilp1_noc", "aclk_dmac0_perilp", + "aclk_emmc_noc", "gpll_hclk_perilp1_src", "gpll_aclk_perilp0_src", "gpll_aclk_perihp_src", + "aclk_vio_noc", + + /* ddrc */ + "sclk_ddrc" }; static const char *const rk3399_pmucru_critical_clocks[] __initconst = { diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c index 4cf838d52ef6..2c9bb81144c9 100644 --- a/drivers/clk/rockchip/clk-rockchip.c +++ b/drivers/clk/rockchip/clk-rockchip.c @@ -49,14 +49,19 @@ static void __init rk2928_gate_clk_init(struct device_node *node) } reg = of_iomap(node, 0); + if (!reg) + return; clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); - if (!clk_data) + if (!clk_data) { + iounmap(reg); return; + } clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) { kfree(clk_data); + iounmap(reg); return; } diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 7ffd134995f2..b886be30f34f 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -385,7 +385,7 @@ void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, list->con_offset, grf_lock_offset, list->lock_shift, list->mode_offset, list->mode_shift, list->rate_table, - list->pll_flags); + list->flags, list->pll_flags); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, list->name); @@ -484,6 +484,15 @@ void __init rockchip_clk_register_branches( list->gate_offset, list->gate_shift, list->gate_flags, flags, &ctx->lock); break; + case branch_ddrclk: + clk = rockchip_clk_register_ddrclk( + list->name, list->flags, + list->parent_names, list->num_parents, + list->muxdiv_offset, list->mux_shift, + list->mux_width, list->div_shift, + list->div_width, list->div_flags, + ctx->reg_base, &ctx->lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 2194ffa8c9fd..1653edd792a5 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -238,7 +238,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, u8 num_parents, int con_offset, int grf_lock_offset, int lock_shift, int mode_offset, int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags); + unsigned long flags, u8 clk_pll_flags); struct rockchip_cpuclk_clksel { int reg; @@ -281,6 +281,20 @@ struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *reg, int shift); +/* + * DDRCLK flags, including method of setting the rate + * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate. + */ +#define ROCKCHIP_DDRCLK_SIP BIT(0) + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int div_shift, int div_width, + int ddr_flags, void __iomem *reg_base, + spinlock_t *lock); + #define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) struct clk *rockchip_clk_register_inverter(const char *name, @@ -299,6 +313,7 @@ enum rockchip_clk_branch_type { branch_mmc, branch_inverter, branch_factor, + branch_ddrclk, }; struct rockchip_clk_branch { @@ -488,6 +503,24 @@ struct rockchip_clk_branch { .child = ch, \ } +#define COMPOSITE_DDRCLK(_id, cname, pnames, f, mo, ms, mw, \ + ds, dw, df) \ + { \ + .id = _id, \ + .branch_type = branch_ddrclk, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + #define MUX(_id, cname, pnames, f, o, s, w, mf) \ { \ .id = _id, \ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 9af359544110..267f99523fbe 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -783,14 +783,14 @@ static struct ccu_reset_map sun8i_h3_ccu_resets[] = { [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, [RST_BUS_I2S2] = { 0x2d0, BIT(14) }, - [RST_BUS_I2C0] = { 0x2d4, BIT(0) }, - [RST_BUS_I2C1] = { 0x2d4, BIT(1) }, - [RST_BUS_I2C2] = { 0x2d4, BIT(2) }, - [RST_BUS_UART0] = { 0x2d4, BIT(16) }, - [RST_BUS_UART1] = { 0x2d4, BIT(17) }, - [RST_BUS_UART2] = { 0x2d4, BIT(18) }, - [RST_BUS_UART3] = { 0x2d4, BIT(19) }, - [RST_BUS_SCR] = { 0x2d4, BIT(20) }, + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_SCR] = { 0x2d8, BIT(20) }, }; static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index fc17b5295e16..51d4bac97ab3 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -31,7 +31,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) return; WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg, - !(reg & lock), 100, 70000)); + reg & lock, 100, 70000)); } int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c index 4470ffc8cf0d..d6fafb397489 100644 --- a/drivers/clk/sunxi-ng/ccu_nk.c +++ b/drivers/clk/sunxi-ng/ccu_nk.c @@ -14,9 +14,9 @@ #include "ccu_gate.h" #include "ccu_nk.h" -void ccu_nk_find_best(unsigned long parent, unsigned long rate, - unsigned int max_n, unsigned int max_k, - unsigned int *n, unsigned int *k) +static void ccu_nk_find_best(unsigned long parent, unsigned long rate, + unsigned int max_n, unsigned int max_k, + unsigned int *n, unsigned int *k) { unsigned long best_rate = 0; unsigned int best_k = 0, best_n = 0; diff --git a/drivers/clk/sunxi/clk-a10-pll2.c b/drivers/clk/sunxi/clk-a10-pll2.c index 0ee1f363e4be..d8eab90ae661 100644 --- a/drivers/clk/sunxi/clk-a10-pll2.c +++ b/drivers/clk/sunxi/clk-a10-pll2.c @@ -73,7 +73,7 @@ static void __init sun4i_pll2_setup(struct device_node *node, SUN4I_PLL2_PRE_DIV_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &sun4i_a10_pll2_lock); - if (!prediv_clk) { + if (IS_ERR(prediv_clk)) { pr_err("Couldn't register the prediv clock\n"); goto err_free_array; } @@ -106,7 +106,7 @@ static void __init sun4i_pll2_setup(struct device_node *node, &mult->hw, &clk_multiplier_ops, &gate->hw, &clk_gate_ops, CLK_SET_RATE_PARENT); - if (!base_clk) { + if (IS_ERR(base_clk)) { pr_err("Couldn't register the base multiplier clock\n"); goto err_free_multiplier; } diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index b38d71cec74c..e54266cc1c51 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -91,7 +91,8 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node) sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock, reg); } -CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup); +CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", + sun4i_a10_mod0_setup); static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev) { diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index a5666e1d0ce7..ea1eed24778c 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c @@ -82,8 +82,8 @@ err_unmap: of_address_to_resource(node, 0, &res); release_mem_region(res.start, resource_size(&res)); } -CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", - sun8i_a23_apb0_setup); +CLK_OF_DECLARE_DRIVER(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", + sun8i_a23_apb0_setup); static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) { diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c index 411d3033a96e..b200ebf159ee 100644 --- a/drivers/clk/sunxi/clk-sun8i-mbus.c +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c @@ -48,7 +48,7 @@ static void __init sun8i_a23_mbus_setup(struct device_node *node) return; reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (!reg) { + if (IS_ERR(reg)) { pr_err("Could not get registers for sun8i-mbus-clk\n"); goto err_free_parents; } diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 64da7b79a6e4..933b5dd698b8 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -428,7 +428,7 @@ static struct tegra_clk_pll_params pll_d_params = { .div_nmp = &pllp_nmp, .freq_table = pll_d_freq_table, .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | - TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + TEGRA_PLL_HAS_LOCK_ENABLE, }; static struct tegra_clk_pll_params pll_d2_params = { @@ -446,7 +446,7 @@ static struct tegra_clk_pll_params pll_d2_params = { .div_nmp = &pllp_nmp, .freq_table = pll_d_freq_table, .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | - TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + TEGRA_PLL_HAS_LOCK_ENABLE, }; static const struct pdiv_map pllu_p[] = { diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 5e9b65278e4c..4faa94440779 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -27,6 +27,26 @@ /* Magic unlocking token used on all Versatile boards */ #define VERSATILE_LOCK_VAL 0xA05F +#define VERSATILE_AUX_OSC_BITS 0x7FFFF +#define INTEGRATOR_AP_CM_BITS 0xFF +#define INTEGRATOR_AP_SYS_BITS 0xFF +#define INTEGRATOR_CP_CM_CORE_BITS 0x7FF +#define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000 + +#define INTEGRATOR_AP_PCI_25_33_MHZ BIT(8) + +/** + * enum icst_control_type - the type of ICST control register + */ +enum icst_control_type { + ICST_VERSATILE, /* The standard type, all control bits available */ + ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_SYS, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ + ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ + ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ +}; + /** * struct clk_icst - ICST VCO clock wrapper * @hw: corresponding clock hardware entry @@ -34,6 +54,7 @@ * @lockreg: VCO lock register address * @params: parameters for this ICST instance * @rate: current rate + * @ctype: the type of control register for the ICST */ struct clk_icst { struct clk_hw hw; @@ -42,6 +63,7 @@ struct clk_icst { u32 lockreg_off; struct icst_params *params; unsigned long rate; + enum icst_control_type ctype; }; #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) @@ -59,6 +81,76 @@ static int vco_get(struct clk_icst *icst, struct icst_vco *vco) ret = regmap_read(icst->map, icst->vcoreg_off, &val); if (ret) return ret; + + /* + * The Integrator/AP core clock can only access the low eight + * bits of the v PLL divider. Bit 8 is tied low and always zero, + * r is hardwired to 22 and output divider s is hardwired to 1 + * (divide by 2) according to the document + * "Integrator CM926EJ-S, CM946E-S, CM966E-S, CM1026EJ-S and + * CM1136JF-S User Guide" ARM DUI 0138E, page 3-13 thru 3-14. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_CM) { + vco->v = val & INTEGRATOR_AP_CM_BITS; + vco->r = 22; + vco->s = 1; + return 0; + } + + /* + * The Integrator/AP system clock on the base board can only + * access the low eight bits of the v PLL divider. Bit 8 is tied low + * and always zero, r is hardwired to 46, and the output divider is + * hardwired to 3 (divide by 4) according to the document + * "Integrator AP ASIC Development Motherboard" ARM DUI 0098B, + * page 3-16. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { + vco->v = val & INTEGRATOR_AP_SYS_BITS; + vco->r = 46; + vco->s = 3; + return 0; + } + + /* + * The Integrator/AP PCI clock is using an odd pattern to create + * the child clock, basically a single bit called DIVX/Y is used + * to select between two different hardwired values: setting the + * bit to 0 yields v = 17, r = 22 and OD = 1, whereas setting the + * bit to 1 yields v = 14, r = 14 and OD = 1 giving the frequencies + * 33 or 25 MHz respectively. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + bool divxy = !!(val & INTEGRATOR_AP_PCI_25_33_MHZ); + + vco->v = divxy ? 17 : 14; + vco->r = divxy ? 22 : 14; + vco->s = 1; + return 0; + } + + /* + * The Integrator/CP core clock can access the low eight bits + * of the v PLL divider. Bit 8 is tied low and always zero, + * r is hardwired to 22 and the output divider s is accessible + * in bits 8 thru 10 according to the document + * "Integrator/CM940T, CM920T, CM740T, and CM720T User Guide" + * ARM DUI 0157A, page 3-20 thru 3-23 and 4-10. + */ + if (icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { + vco->v = val & 0xFF; + vco->r = 22; + vco->s = (val >> 8) & 7; + return 0; + } + + if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { + vco->v = (val >> 12) & 0xFF; + vco->r = 22; + vco->s = (val >> 20) & 7; + return 0; + } + vco->v = val & 0x1ff; vco->r = (val >> 9) & 0x7f; vco->s = (val >> 16) & 03; @@ -72,22 +164,62 @@ static int vco_get(struct clk_icst *icst, struct icst_vco *vco) */ static int vco_set(struct clk_icst *icst, struct icst_vco vco) { + u32 mask; u32 val; int ret; - ret = regmap_read(icst->map, icst->vcoreg_off, &val); - if (ret) - return ret; + /* Mask the bits used by the VCO */ + switch (icst->ctype) { + case ICST_INTEGRATOR_AP_CM: + mask = INTEGRATOR_AP_CM_BITS; + val = vco.v & 0xFF; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.s != 1) + pr_err("ICST error: tried to use VOD != 1\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + case ICST_INTEGRATOR_AP_SYS: + mask = INTEGRATOR_AP_SYS_BITS; + val = vco.v & 0xFF; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.s != 3) + pr_err("ICST error: tried to use VOD != 1\n"); + if (vco.r != 46) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + case ICST_INTEGRATOR_CP_CM_CORE: + mask = INTEGRATOR_CP_CM_CORE_BITS; /* Uses 12 bits */ + val = (vco.v & 0xFF) | vco.s << 8; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + case ICST_INTEGRATOR_CP_CM_MEM: + mask = INTEGRATOR_CP_CM_MEM_BITS; /* Uses 12 bits */ + val = ((vco.v & 0xFF) << 12) | (vco.s << 20); + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + default: + /* Regular auxilary oscillator */ + mask = VERSATILE_AUX_OSC_BITS; + val = vco.v | (vco.r << 9) | (vco.s << 16); + break; + } - /* Mask the 18 bits used by the VCO */ - val &= ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); + pr_debug("ICST: new val = 0x%08x\n", val); /* This magic unlocks the VCO so it can be controlled */ ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL); if (ret) return ret; - ret = regmap_write(icst->map, icst->vcoreg_off, val); + ret = regmap_update_bits(icst->map, icst->vcoreg_off, mask, val); if (ret) return ret; /* This locks the VCO again */ @@ -121,6 +253,46 @@ static long icst_round_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (icst->ctype == ICST_INTEGRATOR_AP_CM || + icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { + if (rate <= 12000000) + return 12000000; + if (rate >= 160000000) + return 160000000; + /* Slam to closest megahertz */ + return DIV_ROUND_CLOSEST(rate, 1000000) * 1000000; + } + + if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { + if (rate <= 6000000) + return 6000000; + if (rate >= 66000000) + return 66000000; + /* Slam to closest 0.5 megahertz */ + return DIV_ROUND_CLOSEST(rate, 500000) * 500000; + } + + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { + /* Divides between 3 and 50 MHz in steps of 0.25 MHz */ + if (rate <= 3000000) + return 3000000; + if (rate >= 50000000) + return 5000000; + /* Slam to closest 0.25 MHz */ + return DIV_ROUND_CLOSEST(rate, 250000) * 250000; + } + + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + /* + * If we're below or less than halfway from 25 to 33 MHz + * select 25 MHz + */ + if (rate <= 25000000 || rate < 29000000) + return 25000000; + /* Else just return the default frequency */ + return 33000000; + } + vco = icst_hz_to_vco(icst->params, rate); return icst_hz(icst->params, vco); } @@ -131,6 +303,36 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + /* This clock is especially primitive */ + unsigned int val; + int ret; + + if (rate == 25000000) { + val = 0; + } else if (rate == 33000000) { + val = INTEGRATOR_AP_PCI_25_33_MHZ; + } else { + pr_err("ICST: cannot set PCI frequency %lu\n", + rate); + return -EINVAL; + } + ret = regmap_write(icst->map, icst->lockreg_off, + VERSATILE_LOCK_VAL); + if (ret) + return ret; + ret = regmap_update_bits(icst->map, icst->vcoreg_off, + INTEGRATOR_AP_PCI_25_33_MHZ, + val); + if (ret) + return ret; + /* This locks the VCO again */ + ret = regmap_write(icst->map, icst->lockreg_off, 0); + if (ret) + return ret; + return 0; + } + if (parent_rate) icst->params->ref = parent_rate; vco = icst_hz_to_vco(icst->params, rate); @@ -148,7 +350,8 @@ static struct clk *icst_clk_setup(struct device *dev, const struct clk_icst_desc *desc, const char *name, const char *parent_name, - struct regmap *map) + struct regmap *map, + enum icst_control_type ctype) { struct clk *clk; struct clk_icst *icst; @@ -178,6 +381,7 @@ static struct clk *icst_clk_setup(struct device *dev, icst->params = pclone; icst->vcoreg_off = desc->vco_offset; icst->lockreg_off = desc->lock_offset; + icst->ctype = ctype; clk = clk_register(dev, &icst->hw); if (IS_ERR(clk)) { @@ -206,7 +410,8 @@ struct clk *icst_clk_register(struct device *dev, pr_err("could not initialize ICST regmap\n"); return ERR_CAST(map); } - return icst_clk_setup(dev, desc, name, parent_name, map); + return icst_clk_setup(dev, desc, name, parent_name, map, + ICST_VERSATILE); } EXPORT_SYMBOL_GPL(icst_clk_register); @@ -239,6 +444,56 @@ static const struct icst_params icst307_params = { .idx2s = icst307_idx2s, }; +/** + * The core modules on the Integrator/AP and Integrator/CP have + * especially crippled ICST525 control. + */ +static const struct icst_params icst525_apcp_cm_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 12 MHz, VDW = 4 */ + .vd_min = 12, + /* + * Maximum 160 MHz, VDW = 152 for all core modules, but + * CM926EJ-S, CM1026EJ-S and CM1136JF-S can actually + * go to 200 MHz (max VDW = 192). + */ + .vd_max = 192, + /* r is hardcoded to 22 and this is the actual divisor, +2 */ + .rd_min = 24, + .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + +static const struct icst_params icst525_ap_sys_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 3 MHz, VDW = 4 */ + .vd_min = 3, + /* Maximum 50 MHz, VDW = 192 */ + .vd_max = 50, + /* r is hardcoded to 46 and this is the actual divisor, +2 */ + .rd_min = 48, + .rd_max = 48, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + +static const struct icst_params icst525_ap_pci_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 25 MHz */ + .vd_min = 25, + /* Maximum 33 MHz */ + .vd_max = 33, + /* r is hardcoded to 14 or 22 and this is the actual divisors +2 */ + .rd_min = 16, + .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + static void __init of_syscon_icst_setup(struct device_node *np) { struct device_node *parent; @@ -247,6 +502,7 @@ static void __init of_syscon_icst_setup(struct device_node *np) const char *name = np->name; const char *parent_name; struct clk *regclk; + enum icst_control_type ctype; /* We do not release this reference, we are using it perpetually */ parent = of_get_parent(np); @@ -269,11 +525,28 @@ static void __init of_syscon_icst_setup(struct device_node *np) return; } - if (of_device_is_compatible(np, "arm,syscon-icst525")) + if (of_device_is_compatible(np, "arm,syscon-icst525")) { icst_desc.params = &icst525_params; - else if (of_device_is_compatible(np, "arm,syscon-icst307")) + ctype = ICST_VERSATILE; + } else if (of_device_is_compatible(np, "arm,syscon-icst307")) { icst_desc.params = &icst307_params; - else { + ctype = ICST_VERSATILE; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_AP_CM; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-sys")) { + icst_desc.params = &icst525_ap_sys_params; + ctype = ICST_INTEGRATOR_AP_SYS; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-pci")) { + icst_desc.params = &icst525_ap_pci_params; + ctype = ICST_INTEGRATOR_AP_PCI; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_CP_CM_CORE; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-mem")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_CP_CM_MEM; + } else { pr_err("unknown ICST clock %s\n", name); return; } @@ -281,7 +554,7 @@ static void __init of_syscon_icst_setup(struct device_node *np) /* Parent clock name is not the same as node parent */ parent_name = of_clk_get_parent_name(np, 0); - regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map); + regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map, ctype); if (IS_ERR(regclk)) { pr_err("error setting up syscon ICST clock %s\n", name); return; @@ -294,5 +567,14 @@ CLK_OF_DECLARE(arm_syscon_icst525_clk, "arm,syscon-icst525", of_syscon_icst_setup); CLK_OF_DECLARE(arm_syscon_icst307_clk, "arm,syscon-icst307", of_syscon_icst_setup); - +CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk, + "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorap_sys_clk, + "arm,syscon-icst525-integratorap-sys", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorap_pci_clk, + "arm,syscon-icst525-integratorap-pci", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk, + "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk, + "arm,syscon-icst525-integratorcp-cm-mem", of_syscon_icst_setup); #endif |