From 45b5ec8498ffc6bf860bfcc19478482d19fa6379 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 19 Feb 2019 18:01:55 +0100 Subject: clk: at91: modernize sckc binding Remove the need for child nodes in the sckc binding and register the whole sckc tree (3 clocks in total) from the sckc node. DT backward compatibility is kept by looking for properties in child nodes when they are not present in the sckc node. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 125 ++++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 89 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index ab6ecefc49ad..470aef586f57 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -152,28 +152,6 @@ at91_clk_register_slow_osc(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - u32 startup; - bool bypass; - - parent_name = of_clk_get_parent_name(np, 0); - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - - hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, - bypass); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -266,28 +244,6 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) -{ - struct clk_hw *hw; - u32 frequency = 0; - u32 accuracy = 0; - u32 startup = 0; - const char *name = np->name; - - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "clock-frequency", &frequency); - of_property_read_u32(np, "clock-accuracy", &accuracy); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - - hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, - startup); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) { struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); @@ -365,64 +321,55 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) +static void __init of_at91sam9x5_sckc_setup(struct device_node *np) { + const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; + void __iomem *regbase = of_iomap(np, 0); + struct device_node *child = NULL; + const char *xtal_name; struct clk_hw *hw; - const char *parent_names[2]; - unsigned int num_parents; - const char *name = np->name; + bool bypass; - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > 2) + if (!regbase) return; - of_clk_parent_fill(np, parent_names, num_parents); - - of_property_read_string(np, "clock-output-names", &name); - - hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, - num_parents); + hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768, + 50000000, 75); if (IS_ERR(hw)) return; - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} + xtal_name = of_clk_get_parent_name(np, 0); + if (!xtal_name) { + /* DT backward compatibility */ + child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc"); + if (!child) + return; + + xtal_name = of_clk_get_parent_name(child, 0); + bypass = of_property_read_bool(child, "atmel,osc-bypass"); + + child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow"); + } else { + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + } -static const struct of_device_id sckc_clk_ids[] __initconst = { - /* Slow clock */ - { - .compatible = "atmel,at91sam9x5-clk-slow-osc", - .data = of_at91sam9x5_clk_slow_osc_setup, - }, - { - .compatible = "atmel,at91sam9x5-clk-slow-rc-osc", - .data = of_at91sam9x5_clk_slow_rc_osc_setup, - }, - { - .compatible = "atmel,at91sam9x5-clk-slow", - .data = of_at91sam9x5_clk_slow_setup, - }, - { /*sentinel*/ } -}; + if (!xtal_name) + return; -static void __init of_at91sam9x5_sckc_setup(struct device_node *np) -{ - struct device_node *childnp; - void (*clk_setup)(struct device_node *, void __iomem *); - const struct of_device_id *clk_id; - void __iomem *regbase = of_iomap(np, 0); + hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name, + 1200000, bypass); + if (IS_ERR(hw)) + return; - if (!regbase) + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); + if (IS_ERR(hw)) return; - for_each_child_of_node(np, childnp) { - clk_id = of_match_node(sckc_clk_ids, childnp); - if (!clk_id) - continue; - clk_setup = clk_id->data; - clk_setup(childnp, regbase); - } + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); + + /* DT backward compatibility */ + if (child) + of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); -- cgit v1.2.3-59-g8ed1b From 5c16ffa795b7bcdbd73d5983482c5c0fe5566c06 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 19 Feb 2019 18:01:56 +0100 Subject: clk: at91: sckc: handle different RC startup time The sama5d3 slow RC oscillator as a different startup time than all the previous SoCs. Handle that using its own compatible. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 470aef586f57..e76b1d64e905 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -321,7 +321,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, return hw; } -static void __init of_at91sam9x5_sckc_setup(struct device_node *np) +static void __init at91sam9x5_sckc_register(struct device_node *np, + unsigned int rc_osc_startup_us) { const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; void __iomem *regbase = of_iomap(np, 0); @@ -334,7 +335,7 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np) return; hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768, - 50000000, 75); + 50000000, rc_osc_startup_us); if (IS_ERR(hw)) return; @@ -371,9 +372,21 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np) if (child) of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw); } + +static void __init of_at91sam9x5_sckc_setup(struct device_node *np) +{ + at91sam9x5_sckc_register(np, 75); +} CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); +static void __init of_sama5d3_sckc_setup(struct device_node *np) +{ + at91sam9x5_sckc_register(np, 500); +} +CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc", + of_sama5d3_sckc_setup); + static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) { struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); -- cgit v1.2.3-59-g8ed1b From cb4f4949b1c76f29ca804d6ecd879a2e84c88afc Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:50 +0200 Subject: clk: at91: allow configuring peripheral PCR layout The PCR register actually changed layout for each SoC. By chance, this didn't have impact on sama5d[2-4] support but since sama5d3, PID is seven bits wide and sama5d4 and sama5d2 don't have DIV. For the DT backward compatibility, keep the layout as is. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/at91sam9x5.c | 9 ++++++++ drivers/clk/at91/clk-peripheral.c | 46 ++++++++++++++++++++------------------- drivers/clk/at91/dt-compat.c | 9 ++++++++ drivers/clk/at91/pmc.h | 12 ++++++++++ drivers/clk/at91/sama5d2.c | 9 ++++++++ drivers/clk/at91/sama5d4.c | 8 +++++++ include/linux/clk/at91_pmc.h | 3 --- 7 files changed, 71 insertions(+), 25 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c index 3487e03d4bc6..f5cfcbd85f10 100644 --- a/drivers/clk/at91/at91sam9x5.c +++ b/drivers/clk/at91/at91sam9x5.c @@ -49,6 +49,13 @@ static const struct { { .n = "pck1", .p = "prog1", .id = 9 }, }; +static const struct clk_pcr_layout at91sam9x5_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + struct pck { char *n; u8 id; @@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, at91sam9x5_periphck[i].n, "masterck", at91sam9x5_periphck[i].id, @@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; extra_pcks[i].id; i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, extra_pcks[i].n, "masterck", extra_pcks[i].id, diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index 65c1defa78e4..6b7748b9588a 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock); #define PERIPHERAL_ID_MAX 31 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) -#define PERIPHERAL_RSHIFT_MASK 0x3 -#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK) - #define PERIPHERAL_MAX_SHIFT 3 struct clk_peripheral { @@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral { spinlock_t *lock; u32 id; u32 div; + const struct clk_pcr_layout *layout; bool auto_div; }; @@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) return 0; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + periph->layout->div_mask | periph->layout->cmd | AT91_PMC_PCR_EN, - AT91_PMC_PCR_DIV(periph->div) | - AT91_PMC_PCR_CMD | + field_prep(periph->layout->div_mask, periph->div) | + periph->layout->cmd | AT91_PMC_PCR_EN); spin_unlock_irqrestore(periph->lock, flags); @@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) return; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, - AT91_PMC_PCR_CMD); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + AT91_PMC_PCR_EN | periph->layout->cmd, + periph->layout->cmd); spin_unlock_irqrestore(periph->lock, flags); } @@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) return 1; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); return status & AT91_PMC_PCR_EN ? 1 : 0; @@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, return parent_rate; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); if (status & AT91_PMC_PCR_EN) { - periph->div = PERIPHERAL_RSHIFT(status); + periph->div = field_get(periph->layout->div_mask, status); periph->auto_div = false; } else { clk_sam9x5_peripheral_autodiv(periph); @@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range) { @@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, periph->div = 0; periph->regmap = regmap; periph->lock = lock; - periph->auto_div = true; + if (layout->div_mask) + periph->auto_div = true; + periph->layout = layout; periph->range = *range; hw = &periph->hw; diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index b95bb4e2a927..aa09072f36db 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, of_sama5d2_clk_audio_pll_pmc_setup); #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ +static const struct clk_pcr_layout dt_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), + .gckcss_mask = GENMASK(10, 8), +}; + #ifdef CONFIG_HAVE_AT91_GENERATED_CLK #define GENERATED_SOURCE_MAX 6 @@ -448,6 +456,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_name, id, &range); diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 672a79bda88c..616c04588093 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -80,6 +80,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; +struct clk_pcr_layout { + u32 offset; + u32 cmd; + u32 div_mask; + u32 gckcss_mask; + u32 pid_mask; +}; + +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + #define ndck(a, s) (a[s - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, @@ -143,6 +154,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name, const char *parent_name, u32 id); struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 1f70cb164b06..9d128bd60fee 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d2_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .gckcss_mask = GENMASK(10, 8), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -266,6 +273,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periphck[i].n, "masterck", sama5d2_periphck[i].id, @@ -278,6 +286,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periph32ck[i].n, "h32mxck", sama5d2_periph32ck[i].id, diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c index b645a9d59cdb..840edca77821 100644 --- a/drivers/clk/at91/sama5d4.c +++ b/drivers/clk/at91/sama5d4.c @@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d4_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periphck[i].n, "masterck", sama5d4_periphck[i].id, @@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periph32ck[i].n, "h32mxck", sama5d4_periph32ck[i].id, diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 931ab05f771d..b97b8dcbffe6 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -191,9 +191,6 @@ #define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) #define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_DIV_OFFSET 16 -#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) -#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ #define AT91_PMC_PCR_GCKDIV_OFFSET 20 #define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) #define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ -- cgit v1.2.3-59-g8ed1b From e4cfb823bd71c785fe482e4d7491ef04ac561a7d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:51 +0200 Subject: clk: at91: allow configuring generated PCR layout The PCR register layout for GCLKCSS is changing for the future SoCs, allow configuring it. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-generated.c | 48 +++++++++++++++++++++------------------- drivers/clk/at91/dt-compat.c | 3 ++- drivers/clk/at91/pmc.h | 1 + drivers/clk/at91/sama5d2.c | 1 + include/linux/clk/at91_pmc.h | 7 +----- 5 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 66e7f7baf958..5f18847965c1 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -11,6 +11,7 @@ * */ +#include #include #include #include @@ -31,6 +32,7 @@ struct clk_generated { spinlock_t *lock; u32 id; u32 gckdiv; + const struct clk_pcr_layout *layout; u8 parent_id; bool audio_pll_allowed; }; @@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw) __func__, gck->gckdiv, gck->parent_id); spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK | - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_GCKCSS(gck->parent_id) | - AT91_PMC_PCR_CMD | - AT91_PMC_PCR_GCKDIV(gck->gckdiv) | + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + field_prep(gck->layout->gckcss_mask, gck->parent_id) | + gck->layout->cmd | + FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) | AT91_PMC_PCR_GCKEN); spin_unlock_irqrestore(gck->lock, flags); return 0; @@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_CMD); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd); spin_unlock_irqrestore(gck->lock, flags); } @@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw) unsigned int status; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &status); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &status); spin_unlock_irqrestore(gck->lock, flags); return status & AT91_PMC_PCR_GCKEN ? 1 : 0; @@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &tmp); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &tmp); spin_unlock_irqrestore(gck->lock, flags); - gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) - >> AT91_PMC_PCR_GCKCSS_OFFSET; - gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) - >> AT91_PMC_PCR_GCKDIV_OFFSET; + gck->parent_id = field_get(gck->layout->gckcss_mask, tmp); + gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp); } struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range) @@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, gck->lock = lock; gck->range = *range; gck->audio_pll_allowed = pll_audio; + gck->layout = layout; clk_generated_startup(gck); hw = &gck->hw; diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index aa09072f36db..aa1754eac59f 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -154,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) id == GCK_ID_CLASSD)) pll_audio = true; - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_names, num_parents, id, pll_audio, &range); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 616c04588093..4027306b904c 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -116,6 +116,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 9d128bd60fee..096156850e08 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -305,6 +305,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[5] = "audiopll_pmcck"; for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_gck[i].n, parent_names, 6, sama5d2_gck[i].id, diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index b97b8dcbffe6..31f00ebf1315 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -187,13 +187,8 @@ #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ #define AT91_PMC_PCR_PID_MASK 0x3f -#define AT91_PMC_PCR_GCKCSS_OFFSET 8 -#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) -#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_GCKDIV_OFFSET 20 -#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) -#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ +#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20) #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ #define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ -- cgit v1.2.3-59-g8ed1b From 2423eeaead6f83f289c85394313e693cdefb728c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:52 +0200 Subject: clk: at91: usb: Add sam9x60 support The sam9x60 USB clock supports four different parents, ensure they can be selected. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-usb.c | 33 +++++++++++++++++++++++++++------ drivers/clk/at91/pmc.h | 3 +++ 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 79ee1c760f2a..ebc37ee33518 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -23,9 +23,13 @@ #define RM9200_USB_DIV_SHIFT 28 #define RM9200_USB_DIV_TAB_SIZE 4 +#define SAM9X5_USBS_MASK GENMASK(0, 0) +#define SAM9X60_USBS_MASK GENMASK(1, 0) + struct at91sam9x5_clk_usb { struct clk_hw hw; struct regmap *regmap; + u32 usbs_mask; }; #define to_at91sam9x5_clk_usb(hw) \ @@ -111,8 +115,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) if (index > 1) return -EINVAL; - regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, - index ? AT91_PMC_USBS : 0); + regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index); return 0; } @@ -124,7 +127,7 @@ static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) regmap_read(usb->regmap, AT91_PMC_USB, &usbr); - return usbr & AT91_PMC_USBS; + return usbr & usb->usbs_mask; } static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, @@ -190,9 +193,10 @@ static const struct clk_ops at91sam9n12_usb_ops = { .set_rate = at91sam9x5_clk_usb_set_rate, }; -struct clk_hw * __init -at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, - const char **parent_names, u8 num_parents) +static struct clk_hw * __init +_at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents, + u32 usbs_mask) { struct at91sam9x5_clk_usb *usb; struct clk_hw *hw; @@ -212,6 +216,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; + usb->usbs_mask = SAM9X5_USBS_MASK; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); @@ -223,6 +228,22 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, return hw; } +struct clk_hw * __init +at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X5_USBS_MASK); +} + +struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X60_USBS_MASK); +} + struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4027306b904c..44345e4ab1c9 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -194,6 +194,9 @@ struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name); struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents); +struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors); -- cgit v1.2.3-59-g8ed1b From e5be537064dd36129a724c65820e5fc2daebd5f4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:53 +0200 Subject: clk: at91: master: Add sam9x60 support The sam9x60 cpu clock is located at a different offset but is otherwise similar to the master clock. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-master.c | 8 +++++--- drivers/clk/at91/pmc.h | 1 + include/linux/clk/at91_pmc.h | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index eb53b4a8fab6..12b5bf4cc7bb 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -29,6 +29,7 @@ struct clk_master { struct regmap *regmap; const struct clk_master_layout *layout; const struct clk_master_characteristics *characteristics; + u32 mckr; }; static inline bool clk_master_ready(struct regmap *regmap) @@ -69,7 +70,7 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, master->characteristics; unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); mckr &= layout->mask; pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; @@ -95,7 +96,7 @@ static u8 clk_master_get_parent(struct clk_hw *hw) struct clk_master *master = to_clk_master(hw); unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); return mckr & AT91_PMC_CSS; } @@ -147,13 +148,14 @@ at91_clk_register_master(struct regmap *regmap, return hw; } - const struct clk_master_layout at91rm9200_master_layout = { .mask = 0x31F, .pres_shift = 2, + .offset = AT91_PMC_MCKR, }; const struct clk_master_layout at91sam9x5_master_layout = { .mask = 0x373, .pres_shift = 4, + .offset = AT91_PMC_MCKR, }; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 44345e4ab1c9..4a30c20f17f1 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -38,6 +38,7 @@ struct clk_range { #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} struct clk_master_layout { + u32 offset; u32 mask; u8 pres_shift; }; diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 31f00ebf1315..0c53f26ae3d3 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -74,6 +74,8 @@ #define AT91_PMC_USBDIV_4 (2 << 28) #define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ +#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */ + #define AT91_PMC_MCKR 0x30 /* Master Clock Register */ #define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ #define AT91_PMC_CSS_SLOW (0 << 0) -- cgit v1.2.3-59-g8ed1b From a436c2a447e59740e8bc5c604abac33419099673 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:54 +0200 Subject: clk: at91: add sam9x60 PLL driver The PLLs on the sam9x60 (PLLA and USB PLL) use a different register set and programming model than the previous SoCs. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-pll.c | 330 +++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 6 + 3 files changed, 337 insertions(+) create mode 100644 drivers/clk/at91/clk-sam9x60-pll.c (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index c75df1cad60e..0a30fc8dfcb0 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o +obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c new file mode 100644 index 000000000000..34b817825b22 --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Microchip Technology Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define PMC_PLL_CTRL0 0xc +#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) +#define PMC_PLL_CTRL0_ENPLL BIT(28) +#define PMC_PLL_CTRL0_ENPLLCK BIT(29) +#define PMC_PLL_CTRL0_ENLOCK BIT(31) + +#define PMC_PLL_CTRL1 0x10 +#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) +#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) + +#define PMC_PLL_ACR 0x18 +#define PMC_PLL_ACR_DEFAULT 0x1b040010UL +#define PMC_PLL_ACR_UTMIVR BIT(12) +#define PMC_PLL_ACR_UTMIBG BIT(13) +#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24) + +#define PMC_PLL_UPDT 0x1c +#define PMC_PLL_UPDT_UPDATE BIT(8) + +#define PMC_PLL_ISR0 0xec + +#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) +#define UPLL_DIV 2 +#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) + +#define PLL_MAX_ID 1 + +struct sam9x60_pll { + struct clk_hw hw; + struct regmap *regmap; + spinlock_t *lock; + const struct clk_pll_characteristics *characteristics; + u32 frac; + u8 id; + u8 div; + u16 mul; +}; + +#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw) + +static inline bool sam9x60_pll_ready(struct regmap *regmap, int id) +{ + unsigned int status; + + regmap_read(regmap, PMC_PLL_ISR0, &status); + + return !!(status & BIT(id)); +} + +static int sam9x60_pll_prepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + struct regmap *regmap = pll->regmap; + unsigned long flags; + u8 div; + u16 mul; + u32 val; + + spin_lock_irqsave(pll->lock, flags); + regmap_write(regmap, PMC_PLL_UPDT, pll->id); + + regmap_read(regmap, PMC_PLL_CTRL0, &val); + div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); + + regmap_read(regmap, PMC_PLL_CTRL1, &val); + mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); + + if (sam9x60_pll_ready(regmap, pll->id) && + (div == pll->div && mul == pll->mul)) { + spin_unlock_irqrestore(pll->lock, flags); + return 0; + } + + /* Recommended value for PMC_PLL_ACR */ + val = PMC_PLL_ACR_DEFAULT; + regmap_write(regmap, PMC_PLL_ACR, val); + + regmap_write(regmap, PMC_PLL_CTRL1, + FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul)); + + if (pll->characteristics->upll) { + /* Enable the UTMI internal bandgap */ + val |= PMC_PLL_ACR_UTMIBG; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + + /* Enable the UTMI internal regulator */ + val |= PMC_PLL_ACR_UTMIVR; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + } + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_write(regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL | + PMC_PLL_CTRL0_ENPLLCK | pll->div); + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + while (!sam9x60_pll_ready(regmap, pll->id)) + cpu_relax(); + + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static int sam9x60_pll_is_prepared(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_ready(pll->regmap, pll->id); +} + +static void sam9x60_pll_unprepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + unsigned long flags; + + spin_lock_irqsave(pll->lock, flags); + + regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENPLLCK, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0); + + if (pll->characteristics->upll) + regmap_update_bits(pll->regmap, PMC_PLL_ACR, + PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + spin_unlock_irqrestore(pll->lock, flags); +} + +static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return (parent_rate * (pll->mul + 1)) / (pll->div + 1); +} + +static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll, + unsigned long rate, + unsigned long parent_rate, + bool update) +{ + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + unsigned long bestremainder = ULONG_MAX; + unsigned long maxdiv, mindiv, tmpdiv; + long bestrate = -ERANGE; + unsigned long bestdiv = 0; + unsigned long bestmul = 0; + unsigned long bestfrac = 0; + + if (rate < characteristics->output[0].min || + rate > characteristics->output[0].max) + return -ERANGE; + + if (!pll->characteristics->upll) { + mindiv = parent_rate / rate; + if (mindiv < 2) + mindiv = 2; + + maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate); + if (maxdiv > PLL_DIV_MAX) + maxdiv = PLL_DIV_MAX; + } else { + mindiv = maxdiv = UPLL_DIV; + } + + for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { + unsigned long remainder; + unsigned long tmprate; + unsigned long tmpmul; + unsigned long tmpfrac = 0; + + /* + * Calculate the multiplier associated with the current + * divider that provide the closest rate to the requested one. + */ + tmpmul = mult_frac(rate, tmpdiv, parent_rate); + tmprate = mult_frac(parent_rate, tmpmul, tmpdiv); + remainder = rate - tmprate; + + if (remainder) { + tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22), + parent_rate); + + tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate, + tmpdiv * (1 << 22)); + + if (tmprate > rate) + remainder = tmprate - rate; + else + remainder = rate - tmprate; + } + + /* + * Compare the remainder with the best remainder found until + * now and elect a new best multiplier/divider pair if the + * current remainder is smaller than the best one. + */ + if (remainder < bestremainder) { + bestremainder = remainder; + bestdiv = tmpdiv; + bestmul = tmpmul; + bestrate = tmprate; + bestfrac = tmpfrac; + } + + /* We've found a perfect match! */ + if (!remainder) + break; + } + + /* Check if bestrate is a valid output rate */ + if (bestrate < characteristics->output[0].min && + bestrate > characteristics->output[0].max) + return -ERANGE; + + if (update) { + pll->div = bestdiv - 1; + pll->mul = bestmul - 1; + pll->frac = bestfrac; + } + + return bestrate; +} + +static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false); +} + +static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true); +} + +static const struct clk_ops pll_ops = { + .prepare = sam9x60_pll_prepare, + .unprepare = sam9x60_pll_unprepare, + .is_prepared = sam9x60_pll_is_prepared, + .recalc_rate = sam9x60_pll_recalc_rate, + .round_rate = sam9x60_pll_round_rate, + .set_rate = sam9x60_pll_set_rate, +}; + +struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics) +{ + struct sam9x60_pll *pll; + struct clk_hw *hw; + struct clk_init_data init; + unsigned int pllr; + int ret; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + pll->id = id; + pll->hw.init = &init; + pll->characteristics = characteristics; + pll->regmap = regmap; + pll->lock = lock; + + regmap_write(regmap, PMC_PLL_UPDT, id); + regmap_read(regmap, PMC_PLL_CTRL0, &pllr); + pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr); + regmap_read(regmap, PMC_PLL_CTRL1, &pllr); + pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr); + + hw = &pll->hw; + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(pll); + hw = ERR_PTR(ret); + } + + return hw; +} + diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4a30c20f17f1..fb9e9c4cdc8d 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -69,6 +69,7 @@ struct clk_pll_characteristics { struct clk_range *output; u16 *icpll; u8 *out; + u8 upll : 1; }; struct clk_programmable_layout { @@ -169,6 +170,11 @@ struct clk_hw * __init at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name); +struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics); + struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u8 id, -- cgit v1.2.3-59-g8ed1b From 01e2113de9a5288bee805db06a00a48295f7eaab Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 2 Apr 2019 14:50:56 +0200 Subject: clk: at91: add sam9x60 pmc driver Add a driver for the PMC clocks of the sam9c60. Signed-off-by: Alexandre Belloni [sboyd@kernel.org: Staticize spinlock] Signed-off-by: Stephen Boyd --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/sam9x60.c | 307 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 drivers/clk/at91/sam9x60.c (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 0a30fc8dfcb0..3732241352ce 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -16,5 +16,6 @@ obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c new file mode 100644 index 000000000000..0979c757cc58 --- /dev/null +++ b/drivers/clk/at91/sam9x60.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +static DEFINE_SPINLOCK(pmc_pll_lock); + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 140000000, .max = 200000000 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +static const struct clk_master_layout sam9x60_master_layout = { + .mask = 0x373, + .pres_shift = 4, + .offset = 0x28, +}; + +static struct clk_range plla_outputs[] = { + { .min = 300000000, .max = 600000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, +}; + +static struct clk_range upll_outputs[] = { + { .min = 300000000, .max = 500000000 }, +}; + +static const struct clk_pll_characteristics upll_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(upll_outputs), + .output = upll_outputs, + .upll = true, +}; + +static const struct clk_programmable_layout sam9x60_programmable_layout = { + .pres_shift = 8, + .css_mask = 0x1f, + .have_slck_mck = 0, +}; + +static const struct clk_pcr_layout sam9x60_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), +}; + +static const struct { + char *n; + char *p; + u8 id; +} sam9x60_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "qspick", .p = "masterck", .id = 19 }, +}; + +static const struct { + char *n; + u8 id; +} sam9x60_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "flex0_clk", .id = 5, }, + { .n = "flex1_clk", .id = 6, }, + { .n = "flex2_clk", .id = 7, }, + { .n = "flex3_clk", .id = 8, }, + { .n = "flex6_clk", .id = 9, }, + { .n = "flex7_clk", .id = 10, }, + { .n = "flex8_clk", .id = 11, }, + { .n = "sdmmc0_clk", .id = 12, }, + { .n = "flex4_clk", .id = 13, }, + { .n = "flex5_clk", .id = 14, }, + { .n = "flex9_clk", .id = 15, }, + { .n = "flex10_clk", .id = 16, }, + { .n = "tcb0_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "matrix_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "macb0_clk", .id = 24, }, + { .n = "lcd_clk", .id = 25, }, + { .n = "sdmmc1_clk", .id = 26, }, + { .n = "macb1_clk", .id = 27, }, + { .n = "ssc_clk", .id = 28, }, + { .n = "can0_clk", .id = 29, }, + { .n = "can1_clk", .id = 30, }, + { .n = "flex11_clk", .id = 32, }, + { .n = "flex12_clk", .id = 33, }, + { .n = "i2s_clk", .id = 34, }, + { .n = "qspi_clk", .id = 35, }, + { .n = "gfx2d_clk", .id = 36, }, + { .n = "pit64b_clk", .id = 37, }, + { .n = "trng_clk", .id = 38, }, + { .n = "aes_clk", .id = 39, }, + { .n = "tdes_clk", .id = 40, }, + { .n = "sha_clk", .id = 41, }, + { .n = "classd_clk", .id = 42, }, + { .n = "isi_clk", .id = 43, }, + { .n = "pioD_clk", .id = 44, }, + { .n = "tcb1_clk", .id = 45, }, + { .n = "dbgu_clk", .id = 47, }, + { .n = "mpddr_clk", .id = 49, }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; + bool pll; +} sam9x60_gck[] = { + { .n = "flex0_gclk", .id = 5, }, + { .n = "flex1_gclk", .id = 6, }, + { .n = "flex2_gclk", .id = 7, }, + { .n = "flex3_gclk", .id = 8, }, + { .n = "flex6_gclk", .id = 9, }, + { .n = "flex7_gclk", .id = 10, }, + { .n = "flex8_gclk", .id = 11, }, + { .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex4_gclk", .id = 13, }, + { .n = "flex5_gclk", .id = 14, }, + { .n = "flex9_gclk", .id = 15, }, + { .n = "flex10_gclk", .id = 16, }, + { .n = "tcb0_gclk", .id = 17, }, + { .n = "adc_gclk", .id = 19, }, + { .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, }, + { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex11_gclk", .id = 32, }, + { .n = "flex12_gclk", .id = 33, }, + { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, + .pll = true, }, + { .n = "pit64b_gclk", .id = 37, }, + { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, + .pll = true, }, + { .n = "tcb1_gclk", .id = 45, }, + { .n = "dbgu_gclk", .id = 47, }, +}; + +static void __init sam9x60_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *td_slck_name, *md_slck_name, *mainxtal_name; + struct pmc_data *sam9x60_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "td_slck"); + if (i < 0) + return; + + td_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "md_slck"); + if (i < 0) + return; + + md_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(sam9x60_systemck), + nck(sam9x60_periphck), + nck(sam9x60_gck)); + if (!sam9x60_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MAIN] = hw; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack", + "mainck", 0, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck", + "main_osc", 1, &upll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = md_slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + hw = at91_clk_register_master(regmap, "masterck", 3, parent_names, + &sam9x60_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "pllack"; + parent_names[1] = "upllck"; + parent_names[2] = "mainck"; + parent_names[3] = "mainck"; + hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = md_slck_name; + parent_names[1] = td_slck_name; + parent_names[2] = "mainck"; + parent_names[3] = "masterck"; + parent_names[4] = "pllack"; + parent_names[5] = "upllck"; + for (i = 0; i < 8; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 6, i, + &sam9x60_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) { + hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n, + sam9x60_systemck[i].p, + sam9x60_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_periphck[i].n, + "masterck", + sam9x60_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) { + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_gck[i].n, + parent_names, 6, + sam9x60_gck[i].id, + sam9x60_gck[i].pll, + &sam9x60_gck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc); + + return; + +err_free: + pmc_data_free(sam9x60_pmc); +} +/* Some clks are used for a clocksource */ +CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup); -- cgit v1.2.3-59-g8ed1b From 7b4c162e03d47e037f8ee773c3e300eefb599a83 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 25 Apr 2019 14:15:54 -0700 Subject: clk: at91: Mark struct clk_range as const It's just some static data that doesn't get changed after being used. Mark it const everywhere. Cc: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/at91sam9260.c | 14 +++++++------- drivers/clk/at91/at91sam9rl.c | 2 +- drivers/clk/at91/at91sam9x5.c | 2 +- drivers/clk/at91/pmc.h | 2 +- drivers/clk/at91/sam9x60.c | 4 ++-- drivers/clk/at91/sama5d2.c | 2 +- drivers/clk/at91/sama5d4.c | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/clk/at91') diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c index b1af5a395423..0aabe49aed09 100644 --- a/drivers/clk/at91/at91sam9260.c +++ b/drivers/clk/at91/at91sam9260.c @@ -41,7 +41,7 @@ static u8 sam9260_plla_out[] = { 0, 2 }; static u16 sam9260_plla_icpll[] = { 1, 1 }; -static struct clk_range sam9260_plla_outputs[] = { +static const struct clk_range sam9260_plla_outputs[] = { { .min = 80000000, .max = 160000000 }, { .min = 150000000, .max = 240000000 }, }; @@ -58,7 +58,7 @@ static u8 sam9260_pllb_out[] = { 1 }; static u16 sam9260_pllb_icpll[] = { 1 }; -static struct clk_range sam9260_pllb_outputs[] = { +static const struct clk_range sam9260_pllb_outputs[] = { { .min = 70000000, .max = 130000000 }, }; @@ -128,7 +128,7 @@ static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; -static struct clk_range sam9g20_plla_outputs[] = { +static const struct clk_range sam9g20_plla_outputs[] = { { .min = 745000000, .max = 800000000 }, { .min = 695000000, .max = 750000000 }, { .min = 645000000, .max = 700000000 }, @@ -151,7 +151,7 @@ static u8 sam9g20_pllb_out[] = { 0 }; static u16 sam9g20_pllb_icpll[] = { 0 }; -static struct clk_range sam9g20_pllb_outputs[] = { +static const struct clk_range sam9g20_pllb_outputs[] = { { .min = 30000000, .max = 100000000 }, }; @@ -182,7 +182,7 @@ static const struct clk_master_characteristics sam9261_mck_characteristics = { .divisors = { 1, 2, 4, 0 }, }; -static struct clk_range sam9261_plla_outputs[] = { +static const struct clk_range sam9261_plla_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; @@ -199,7 +199,7 @@ static u8 sam9261_pllb_out[] = { 1 }; static u16 sam9261_pllb_icpll[] = { 1 }; -static struct clk_range sam9261_pllb_outputs[] = { +static const struct clk_range sam9261_pllb_outputs[] = { { .min = 70000000, .max = 130000000 }, }; @@ -262,7 +262,7 @@ static const struct clk_master_characteristics sam9263_mck_characteristics = { .divisors = { 1, 2, 4, 0 }, }; -static struct clk_range sam9263_pll_outputs[] = { +static const struct clk_range sam9263_pll_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c index 5aeef68b4bdd..0ac34cdaa106 100644 --- a/drivers/clk/at91/at91sam9rl.c +++ b/drivers/clk/at91/at91sam9rl.c @@ -14,7 +14,7 @@ static const struct clk_master_characteristics sam9rl_mck_characteristics = { static u8 sam9rl_plla_out[] = { 0, 2 }; -static struct clk_range sam9rl_plla_outputs[] = { +static const struct clk_range sam9rl_plla_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c index f5cfcbd85f10..0855f3a80cc7 100644 --- a/drivers/clk/at91/at91sam9x5.c +++ b/drivers/clk/at91/at91sam9x5.c @@ -17,7 +17,7 @@ static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 745000000, .max = 800000000 }, { .min = 695000000, .max = 750000000 }, { .min = 645000000, .max = 700000000 }, diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index fb9e9c4cdc8d..775b77a433f5 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -66,7 +66,7 @@ extern const struct clk_pll_layout sama5d3_pll_layout; struct clk_pll_characteristics { struct clk_range input; int num_output; - struct clk_range *output; + const struct clk_range *output; u16 *icpll; u8 *out; u8 upll : 1; diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 0979c757cc58..9790ddfa5b3c 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -21,7 +21,7 @@ static const struct clk_master_layout sam9x60_master_layout = { .offset = 0x28, }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 300000000, .max = 600000000 }, }; @@ -31,7 +31,7 @@ static const struct clk_pll_characteristics plla_characteristics = { .output = plla_outputs, }; -static struct clk_range upll_outputs[] = { +static const struct clk_range upll_outputs[] = { { .min = 300000000, .max = 500000000 }, }; diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 096156850e08..f3d3f6c8e261 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; static u16 plla_icpll[] = { 0 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 600000000, .max = 1200000000 }, }; diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c index 840edca77821..25b156d4e645 100644 --- a/drivers/clk/at91/sama5d4.c +++ b/drivers/clk/at91/sama5d4.c @@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; static u16 plla_icpll[] = { 0 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 600000000, .max = 1200000000 }, }; -- cgit v1.2.3-59-g8ed1b