Re: [PATCHv3 1/7] clk: at91: add a driver for the h32mx clock

From: Nicolas Ferre
Date: Fri Sep 19 2014 - 08:33:27 EST


On 15/09/2014 18:15, Alexandre Belloni :
> Newer SoCs have two different AHB interconnect. The AHB 32 bits Matrix
> interconnect (h32mx) has a clock that can be setup at the half of the h64mx
> clock (which is mck). The h32mx clock can not exceed 90 MHz.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxxxxxxxxx>

Okay on my side:

Acked-by: Nicolas Ferre <nicolas.ferre@xxxxxxxxx>


> ---
> Cc:Mike Turquette <mturquette@xxxxxxxxxx>

Mike,

I guess that you didn't get this v3. Can you "Ack" this one of should we
re-sent to you?

I would like to take this patch with the rest of the SAMA5D4 series: is
it okay for you?

Bye,


> .../devicetree/bindings/clock/at91-clock.txt | 15 +++
> arch/arm/mach-at91/Kconfig | 3 +
> drivers/clk/at91/Makefile | 1 +
> drivers/clk/at91/clk-h32mx.c | 123 +++++++++++++++++++++
> drivers/clk/at91/pmc.c | 6 +
> drivers/clk/at91/pmc.h | 5 +
> include/linux/clk/at91_pmc.h | 1 +
> 7 files changed, 154 insertions(+)
> create mode 100644 drivers/clk/at91/clk-h32mx.c
>
> diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt
> index b3d544ca522a..40dc2405de7c 100644
> --- a/Documentation/devicetree/bindings/clock/at91-clock.txt
> +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
> @@ -74,6 +74,9 @@ Required properties:
> "atmel,at91sam9x5-clk-utmi":
> at91 utmi clock
>
> + "atmel,sama5d4-clk-h32mx":
> + at91 h32mx clock
> +
> Required properties for SCKC node:
> - reg : defines the IO memory reserved for the SCKC.
> - #size-cells : shall be 0 (reg is used to encode clk id).
> @@ -447,3 +450,15 @@ For example:
> #clock-cells = <0>;
> clocks = <&main>;
> };
> +
> +Required properties for 32 bits bus Matrix clock (h32mx clock):
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the master clock source phandle.
> +
> +For example:
> + h32ck: h32mxck {
> + #clock-cells = <0>;
> + compatible = "atmel,sama5d4-clk-h32mx";
> + clocks = <&mck>;
> + };
> +
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 6eb3c658761d..fd177956dd56 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -39,6 +39,9 @@ config AT91_SAM9_TIME
> config HAVE_AT91_SMD
> bool
>
> +config HAVE_AT91_H32MX
> + bool
> +
> config SOC_AT91SAM9
> bool
> select AT91_SAM9_TIME
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 4998aee59267..89a48a7bd5df 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -9,3 +9,4 @@ obj-y += clk-system.o clk-peripheral.o clk-programmable.o
> obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o
> obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o
> obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
> +obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
> diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
> new file mode 100644
> index 000000000000..152dcb3f7b5f
> --- /dev/null
> +++ b/drivers/clk/at91/clk-h32mx.c
> @@ -0,0 +1,123 @@
> +/*
> + * clk-h32mx.c
> + *
> + * Copyright (C) 2014 Atmel
> + *
> + * Alexandre Belloni <alexandre.belloni@xxxxxxxxxxxxxxxxxx>
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +
> +#include "pmc.h"
> +
> +#define H32MX_MAX_FREQ 90000000
> +
> +struct clk_sama5d4_h32mx {
> + struct clk_hw hw;
> + struct at91_pmc *pmc;
> +};
> +
> +#define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
> +
> +static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
> +
> + if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV)
> + return parent_rate / 2;
> +
> + if (parent_rate > H32MX_MAX_FREQ)
> + pr_warn("H32MX clock is too fast\n");
> + return parent_rate;
> +}
> +
> +static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *parent_rate)
> +{
> + unsigned long div;
> +
> + if (rate > *parent_rate)
> + return *parent_rate;
> + div = *parent_rate / 2;
> + if (rate < div)
> + return div;
> +
> + if (rate - div < *parent_rate - rate)
> + return div;
> +
> + return *parent_rate;
> +}
> +
> +static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
> + struct at91_pmc *pmc = h32mxclk->pmc;
> + u32 tmp;
> +
> + if (parent_rate != rate && (parent_rate / 2) != rate)
> + return -EINVAL;
> +
> + pmc_lock(pmc);
> + tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV;
> + if ((parent_rate / 2) == rate)
> + tmp |= AT91_PMC_H32MXDIV;
> + pmc_write(pmc, AT91_PMC_MCKR, tmp);
> + pmc_unlock(pmc);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops h32mx_ops = {
> + .recalc_rate = clk_sama5d4_h32mx_recalc_rate,
> + .round_rate = clk_sama5d4_h32mx_round_rate,
> + .set_rate = clk_sama5d4_h32mx_set_rate,
> +};
> +
> +void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
> + struct at91_pmc *pmc)
> +{
> + struct clk_sama5d4_h32mx *h32mxclk;
> + struct clk_init_data init;
> + const char *parent_name;
> + struct clk *clk;
> +
> + h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
> + if (!h32mxclk)
> + return;
> +
> + parent_name = of_clk_get_parent_name(np, 0);
> +
> + init.name = np->name;
> + init.ops = &h32mx_ops;
> + init.parent_names = parent_name ? &parent_name : NULL;
> + init.num_parents = parent_name ? 1 : 0;
> + init.flags = CLK_SET_RATE_GATE;
> +
> + h32mxclk->hw.init = &init;
> + h32mxclk->pmc = pmc;
> +
> + clk = clk_register(NULL, &h32mxclk->hw);
> + if (!clk)
> + return;
> +
> + of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 524196bb35a5..386999b4f8eb 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -337,6 +337,12 @@ static const struct of_device_id pmc_clk_ids[] __initconst = {
> .data = of_at91sam9x5_clk_smd_setup,
> },
> #endif
> +#if defined(CONFIG_HAVE_AT91_H32MX)
> + {
> + .compatible = "atmel,sama5d4-clk-h32mx",
> + .data = of_sama5d4_clk_h32mx_setup,
> + },
> +#endif
> { /*sentinel*/ }
> };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 6c7625976113..52d2041fa3f6 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -120,4 +120,9 @@ extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
> struct at91_pmc *pmc);
> #endif
>
> +#if defined(CONFIG_HAVE_AT91_SMD)
> +extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
> + struct at91_pmc *pmc);
> +#endif
> +
> #endif /* __PMC_H_ */
> diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
> index de4268d4987a..c8e3b3d1eded 100644
> --- a/include/linux/clk/at91_pmc.h
> +++ b/include/linux/clk/at91_pmc.h
> @@ -125,6 +125,7 @@ extern void __iomem *at91_pmc_base;
> #define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */
> #define AT91_PMC_PLLADIV2_OFF (0 << 12)
> #define AT91_PMC_PLLADIV2_ON (1 << 12)
> +#define AT91_PMC_H32MXDIV BIT(24)
>
> #define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */
> #define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */
>


--
Nicolas Ferre
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/