Message ID | 1410646408-28901-5-git-send-email-linux@rempel-privat.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, Please have a look at https://lkml.org/lkml/2014/5/14/598 which describe the preferred way of implementing clocks in the CCF where you only declare the clock generator in the DT instead of each separate clocks. On 14/09/2014 at 00:13:25 +0200, Oleksij Rempel wrote : > Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> > --- > drivers/clk/Makefile | 1 + > drivers/clk/clk-asm9260.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 160 insertions(+) > create mode 100644 drivers/clk/clk-asm9260.c > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index 567f102..351dd48 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -38,6 +38,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ > obj-$(CONFIG_ARCH_HIP04) += hisilicon/ > obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/ > obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ > +obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o > ifeq ($(CONFIG_COMMON_CLK), y) > obj-$(CONFIG_ARCH_MMP) += mmp/ > endif > diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c > new file mode 100644 > index 0000000..396cc09 > --- /dev/null > +++ b/drivers/clk/clk-asm9260.c > @@ -0,0 +1,159 @@ > +/* > + * U300 clock implementation > + * Copyright (C) 2007-2012 ST-Ericsson AB > + * License terms: GNU General Public License (GPL) version 2 > + * Author: Linus Walleij <linus.walleij@stericsson.com> > + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> > + */ > +#include <linux/clk.h> > +#include <linux/clkdev.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/clk-provider.h> > +#include <linux/spinlock.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > + > +static DEFINE_SPINLOCK(asm9260_clk_lock); > + > +struct asm9260_clk { > + void __iomem *reg; > + char *parent_name; > +}; > + > +static void __iomem *asm9260_get_sreg(struct device_node *node) > +{ > + u32 reg; > + void __iomem *iomem; > + struct device_node *srnp; > + int ret; > + > + ret = of_property_read_u32(node, "reg", ®); > + if (WARN_ON(ret)) > + return NULL; > + > + srnp = of_find_compatible_node(NULL, NULL, "alpscale,asm9260-sregs"); > + iomem = of_iomap(srnp, 0); > + iomem += reg; > + > + return iomem; > +} > + > +/* > + * On this chip gate used to disable or to update clock > + * after new source was selected > + */ > + > +static void __init asm9260_gate_init(struct device_node *node) > +{ > + struct clk *clk; > + const char *clk_name = node->name; > + void __iomem *iomem; > + const char *parent_name; > + u32 bit; > + int ret; > + > + iomem = asm9260_get_sreg(node); > + parent_name = of_clk_get_parent_name(node, 0); > + > + ret = of_property_read_u32(node, "bit-index", &bit); > + if (WARN_ON(ret)) > + return; > + > + clk = clk_register_gate(NULL, clk_name, parent_name, > + CLK_SET_RATE_PARENT, iomem, bit, 0, > + &asm9260_clk_lock); > + > + if (!IS_ERR(clk)) > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > +} > +CLK_OF_DECLARE(asm9260_gate, "alpscale,asm9260-gate-clock", asm9260_gate_init); > + > + > +static void __init asm9260_div_init(struct device_node *node) > +{ > + struct clk *clk; > + const char *clk_name = node->name; > + void __iomem *iomem; > + const char *parent_name; > + > + iomem = asm9260_get_sreg(node); > + > + parent_name = of_clk_get_parent_name(node, 0); > + clk = clk_register_divider(NULL, clk_name, parent_name, > + CLK_SET_RATE_PARENT, iomem, 0, 8, CLK_DIVIDER_ONE_BASED, > + &asm9260_clk_lock); > + > + if (!IS_ERR(clk)) > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > +} > +CLK_OF_DECLARE(asm9260_div, "alpscale,asm9260-div-clock", asm9260_div_init); > + > +/* > + * Simple one bit MUX for two sources > + */ > +static void __init asm9260_bimux_init(struct device_node *node) > +{ > + struct clk *clk; > + const char *clk_name = node->name; > + u8 num_parents; > + void __iomem *iomem; > + const char **parent_names; > + int ret, i; > + u32 *table; > + > + iomem = asm9260_get_sreg(node); > + if (!iomem) > + return; > + > + num_parents = of_clk_get_parent_count(node); > + if (WARN_ON(!num_parents || num_parents > 2)) > + return; > + > + parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL); > + if (WARN_ON(!parent_names)) > + return; > + > + table = kzalloc(sizeof(u32) * num_parents, GFP_KERNEL); > + if (WARN_ON(!table)) > + return; > + > + ret = of_property_read_u32_array(node, "mux-table", table, > + num_parents); > + if (WARN_ON(ret)) > + return; > + > + for (i = 0; i < num_parents; i++) > + parent_names[i] = of_clk_get_parent_name(node, i); > + > + clk = clk_register_mux_table(NULL, clk_name, parent_names, > + num_parents, 0, iomem, 0, 1, 0, table, > + &asm9260_clk_lock); > + > + if (!IS_ERR(clk)) > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > +} > +CLK_OF_DECLARE(asm9260_bimux, "alpscale,asm9260-bimux-clock", asm9260_bimux_init); > + > +static void __init asm9260_pll_init(struct device_node *node) > +{ > + struct clk *clk; > + const char *clk_name = node->name; > + u32 rate; > + void __iomem *iomem; > + const char *parent_name; > + u32 accuracy = 0; > + > + iomem = asm9260_get_sreg(node); > + rate = (ioread32(iomem) & 0xffff) * 1000000; > + > + parent_name = of_clk_get_parent_name(node, 0); > + accuracy = clk_get_accuracy(__clk_lookup(parent_name)); > + clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, parent_name, > + 0, rate, > + accuracy); > + > + if (!IS_ERR(clk)) > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > +} > +CLK_OF_DECLARE(asm9260_pll, "alpscale,asm9260-pll-clock", asm9260_pll_init); > -- > 1.9.1 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Am 17.09.2014 um 15:54 schrieb Alexandre Belloni: > Hi, > > Please have a look at https://lkml.org/lkml/2014/5/14/598 which describe > the preferred way of implementing clocks in the CCF where you only > declare the clock generator in the DT instead of each separate clocks. hm... if i see it correctly. i will need to move almost everything from DT to clk-driver. And i will need to create separate driver for other SoC provided by AlphaScale. On other side with current (generic) driver i will need only to change DT and it will work. May be instead of going qcom way, it will be better to have generic gate, div and mux bindings for DT? Sure it will make DT a bit fuzzy, but it will dramatically reduce kernel code and reduce the time of providing code to upstream. I don't think drivers/clk/qcom/gcc-msm8974.c is less complicated solution.
Hi, On 18/09/2014 at 08:46:57 +0200, Oleksij Rempel wrote : > Am 17.09.2014 um 15:54 schrieb Alexandre Belloni: > > Hi, > > > > Please have a look at https://lkml.org/lkml/2014/5/14/598 which describe > > the preferred way of implementing clocks in the CCF where you only > > declare the clock generator in the DT instead of each separate clocks. > > hm... if i see it correctly. i will need to move almost everything from > DT to clk-driver. And i will need to create separate driver for other > SoC provided by AlphaScale. On other side with current (generic) driver > i will need only to change DT and it will work. > > May be instead of going qcom way, it will be better to have generic > gate, div and mux bindings for DT? Sure it will make DT a bit fuzzy, but > it will dramatically reduce kernel code and reduce the time of providing > code to upstream. > > I don't think drivers/clk/qcom/gcc-msm8974.c is less complicated solution. IT is not less complicated but it is more flexible (for exemple when setting flags on individual clocks, like CLK_SET_RATE_PARENT or CLK_IGNORE_UNUSED). Describing all the individual clocks in DT is a mistake we made in at91 and it will definitely bother you in the future, for example when you realize that your clock controller is also taking care of reset or power management. Also, this is the kind of driver you write only once per SoC so it is about the same doing it in DT or in C with the added advantage that doing it in C takes less memory and is probably faster. You can have a look at how it has been done for the berlin SoCs to see how you can easily reuse code between drivers.
Am 18.09.2014 um 09:56 schrieb Alexandre Belloni: > Hi, > > On 18/09/2014 at 08:46:57 +0200, Oleksij Rempel wrote : >> Am 17.09.2014 um 15:54 schrieb Alexandre Belloni: >>> Hi, >>> >>> Please have a look at https://lkml.org/lkml/2014/5/14/598 which describe >>> the preferred way of implementing clocks in the CCF where you only >>> declare the clock generator in the DT instead of each separate clocks. >> >> hm... if i see it correctly. i will need to move almost everything from >> DT to clk-driver. And i will need to create separate driver for other >> SoC provided by AlphaScale. On other side with current (generic) driver >> i will need only to change DT and it will work. >> >> May be instead of going qcom way, it will be better to have generic >> gate, div and mux bindings for DT? Sure it will make DT a bit fuzzy, but >> it will dramatically reduce kernel code and reduce the time of providing >> code to upstream. >> >> I don't think drivers/clk/qcom/gcc-msm8974.c is less complicated solution. > > IT is not less complicated but it is more flexible (for exemple when > setting flags on individual clocks, like CLK_SET_RATE_PARENT or > CLK_IGNORE_UNUSED). Describing all the individual clocks in DT is a > mistake we made in at91 and it will definitely bother you in the future, > for example when you realize that your clock controller is also taking > care of reset or power management. > > Also, this is the kind of driver you write only once per SoC so it is > about the same doing it in DT or in C with the added advantage that > doing it in C takes less memory and is probably faster. > > You can have a look at how it has been done for the berlin SoCs to see > how you can easily reuse code between drivers. Ok, thank you. i'll rewrite it.
Am 18.09.2014 um 09:56 schrieb Alexandre Belloni: > Hi, > > On 18/09/2014 at 08:46:57 +0200, Oleksij Rempel wrote : >> Am 17.09.2014 um 15:54 schrieb Alexandre Belloni: >>> Hi, >>> >>> Please have a look at https://lkml.org/lkml/2014/5/14/598 which describe >>> the preferred way of implementing clocks in the CCF where you only >>> declare the clock generator in the DT instead of each separate clocks. >> >> hm... if i see it correctly. i will need to move almost everything from >> DT to clk-driver. And i will need to create separate driver for other >> SoC provided by AlphaScale. On other side with current (generic) driver >> i will need only to change DT and it will work. >> >> May be instead of going qcom way, it will be better to have generic >> gate, div and mux bindings for DT? Sure it will make DT a bit fuzzy, but >> it will dramatically reduce kernel code and reduce the time of providing >> code to upstream. >> >> I don't think drivers/clk/qcom/gcc-msm8974.c is less complicated solution. > > IT is not less complicated but it is more flexible (for exemple when > setting flags on individual clocks, like CLK_SET_RATE_PARENT or > CLK_IGNORE_UNUSED). Describing all the individual clocks in DT is a > mistake we made in at91 and it will definitely bother you in the future, > for example when you realize that your clock controller is also taking > care of reset or power management. > > Also, this is the kind of driver you write only once per SoC so it is > about the same doing it in DT or in C with the added advantage that > doing it in C takes less memory and is probably faster. > > You can have a look at how it has been done for the berlin SoCs to see > how you can easily reuse code between drivers. What is the correct way to handle/define i2s MCLK input? I have I2S mux clock with choice of 3 sources: Xtal, PLL and MCLK. One of pins can be configured as MCLK src. Should i define fixedrate-clk?
On 20/09/2014 at 20:06:21 +0200, Oleksij Rempel wrote : > Am 18.09.2014 um 09:56 schrieb Alexandre Belloni: > > You can have a look at how it has been done for the berlin SoCs to see > > how you can easily reuse code between drivers. > > What is the correct way to handle/define i2s MCLK input? I have I2S mux > clock with choice of 3 sources: Xtal, PLL and MCLK. One of pins can be > configured as MCLK src. Should i define fixedrate-clk? > It depends on where is your mux, if it is in the I2S controller adress range, I would simply give 3 parent clocks to your I2S controller, like: i2s@8fffffff { compatible = "..."; reg = <0x8fffffff 0x100>; clocks = <&xtal, &clkc CLKID_MCK, &clkc CLKID_PLL>; } If it is part of your clock generator, then simply register a clock mux with 3 parents as part of your clock controller binding. And use something like: clocks = <&clck CLKID_I2S>; Have a look at how this is done for berlin2, search for clk_register_mux()
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 567f102..351dd48 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/ obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ +obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c new file mode 100644 index 0000000..396cc09 --- /dev/null +++ b/drivers/clk/clk-asm9260.c @@ -0,0 +1,159 @@ +/* + * U300 clock implementation + * Copyright (C) 2007-2012 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * Author: Linus Walleij <linus.walleij@stericsson.com> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + */ +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> +#include <linux/of.h> +#include <linux/of_address.h> + +static DEFINE_SPINLOCK(asm9260_clk_lock); + +struct asm9260_clk { + void __iomem *reg; + char *parent_name; +}; + +static void __iomem *asm9260_get_sreg(struct device_node *node) +{ + u32 reg; + void __iomem *iomem; + struct device_node *srnp; + int ret; + + ret = of_property_read_u32(node, "reg", ®); + if (WARN_ON(ret)) + return NULL; + + srnp = of_find_compatible_node(NULL, NULL, "alpscale,asm9260-sregs"); + iomem = of_iomap(srnp, 0); + iomem += reg; + + return iomem; +} + +/* + * On this chip gate used to disable or to update clock + * after new source was selected + */ + +static void __init asm9260_gate_init(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + void __iomem *iomem; + const char *parent_name; + u32 bit; + int ret; + + iomem = asm9260_get_sreg(node); + parent_name = of_clk_get_parent_name(node, 0); + + ret = of_property_read_u32(node, "bit-index", &bit); + if (WARN_ON(ret)) + return; + + clk = clk_register_gate(NULL, clk_name, parent_name, + CLK_SET_RATE_PARENT, iomem, bit, 0, + &asm9260_clk_lock); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(asm9260_gate, "alpscale,asm9260-gate-clock", asm9260_gate_init); + + +static void __init asm9260_div_init(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + void __iomem *iomem; + const char *parent_name; + + iomem = asm9260_get_sreg(node); + + parent_name = of_clk_get_parent_name(node, 0); + clk = clk_register_divider(NULL, clk_name, parent_name, + CLK_SET_RATE_PARENT, iomem, 0, 8, CLK_DIVIDER_ONE_BASED, + &asm9260_clk_lock); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(asm9260_div, "alpscale,asm9260-div-clock", asm9260_div_init); + +/* + * Simple one bit MUX for two sources + */ +static void __init asm9260_bimux_init(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + u8 num_parents; + void __iomem *iomem; + const char **parent_names; + int ret, i; + u32 *table; + + iomem = asm9260_get_sreg(node); + if (!iomem) + return; + + num_parents = of_clk_get_parent_count(node); + if (WARN_ON(!num_parents || num_parents > 2)) + return; + + parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL); + if (WARN_ON(!parent_names)) + return; + + table = kzalloc(sizeof(u32) * num_parents, GFP_KERNEL); + if (WARN_ON(!table)) + return; + + ret = of_property_read_u32_array(node, "mux-table", table, + num_parents); + if (WARN_ON(ret)) + return; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + clk = clk_register_mux_table(NULL, clk_name, parent_names, + num_parents, 0, iomem, 0, 1, 0, table, + &asm9260_clk_lock); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(asm9260_bimux, "alpscale,asm9260-bimux-clock", asm9260_bimux_init); + +static void __init asm9260_pll_init(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + u32 rate; + void __iomem *iomem; + const char *parent_name; + u32 accuracy = 0; + + iomem = asm9260_get_sreg(node); + rate = (ioread32(iomem) & 0xffff) * 1000000; + + parent_name = of_clk_get_parent_name(node, 0); + accuracy = clk_get_accuracy(__clk_lookup(parent_name)); + clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, parent_name, + 0, rate, + accuracy); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(asm9260_pll, "alpscale,asm9260-pll-clock", asm9260_pll_init);
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> --- drivers/clk/Makefile | 1 + drivers/clk/clk-asm9260.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 drivers/clk/clk-asm9260.c