* [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
[not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
@ 2015-11-29 3:03 ` Chen-Yu Tsai
2015-12-01 10:04 ` Maxime Ripard
2015-11-29 3:03 ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
` (3 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29 3:03 UTC (permalink / raw)
To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai
The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
instead of through a PRCM mfd device and subdevices for each clock
and reset control. As such we need a CLK_OF_DECLARE version of
the sun8i-a23-apb0-clk driver.
Also, build it for sun9i/A80, and not just for configurations with
MFD_SUN6I_PRCM enabled.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/clk/sunxi/Makefile | 5 +--
drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
2 files changed, 62 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299214ce..c55d5cd1c0e5 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
obj-y += clk-sun9i-mmc.o
obj-y += clk-usb.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
- clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
- clk-sun8i-apb0.o
+ clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
--- a/drivers/clk/sunxi/clk-sun8i-apb0.c
+++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
@@ -17,13 +17,68 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
+static struct clk *sun8i_a23_apb0_register(struct device_node *node,
+ void __iomem *reg)
+{
+ const char *clk_name = node->name;
+ const char *clk_parent;
+ struct clk *clk;
+ int ret;
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+ if (!clk_parent)
+ return ERR_PTR(-EINVAL);
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /* The A23 APB0 clock is a standard 2 bit wide divider clock */
+ clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
+ 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ if (IS_ERR(clk))
+ return clk;
+
+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (ret)
+ goto err_unregister;
+
+ return clk;
+
+err_unregister:
+ clk_unregister_divider(clk);
+
+ return ERR_PTR(ret);
+}
+
+static void sun8i_a23_apb0_setup(struct device_node *node)
+{
+ void __iomem *reg;
+ struct resource res;
+ struct clk *clk;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg))
+ return;
+
+ clk = sun8i_a23_apb0_register(node, reg);
+ if (IS_ERR(clk))
+ goto err_unmap;
+
+ return;
+
+err_unmap:
+ iounmap(reg);
+ 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);
+
static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const char *clk_name = np->name;
- const char *clk_parent;
struct resource *r;
void __iomem *reg;
struct clk *clk;
@@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
if (IS_ERR(reg))
return PTR_ERR(reg);
- clk_parent = of_clk_get_parent_name(np, 0);
- if (!clk_parent)
- return -EINVAL;
-
- of_property_read_string(np, "clock-output-names", &clk_name);
-
- /* The A23 APB0 clock is a standard 2 bit wide divider clock */
- clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
- 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ clk = sun8i_a23_apb0_register(np, reg);
if (IS_ERR(clk))
return PTR_ERR(clk);
- return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return 0;
}
static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
--
2.6.2
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
2015-11-29 3:03 ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
@ 2015-12-01 10:04 ` Maxime Ripard
2015-12-01 11:54 ` Chen-Yu Tsai
0 siblings, 1 reply; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 10:04 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Emilio Lopez, Michael Turquette, Stephen Boyd, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
linux-arm-kernel, linux-kernel, devicetree, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 4556 bytes --]
Hi,
On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
> instead of through a PRCM mfd device and subdevices for each clock
> and reset control. As such we need a CLK_OF_DECLARE version of
> the sun8i-a23-apb0-clk driver.
>
> Also, build it for sun9i/A80, and not just for configurations with
> MFD_SUN6I_PRCM enabled.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> drivers/clk/sunxi/Makefile | 5 +--
> drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
> 2 files changed, 62 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index cb4c299214ce..c55d5cd1c0e5 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
> obj-y += clk-sun9i-mmc.o
> obj-y += clk-usb.o
>
> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> +
So sun8i doesn't use it?
> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> - clk-sun8i-apb0.o
> + clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
> @@ -17,13 +17,68 @@
> #include <linux/clk-provider.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/platform_device.h>
>
> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
> + void __iomem *reg)
> +{
> + const char *clk_name = node->name;
> + const char *clk_parent;
> + struct clk *clk;
> + int ret;
> +
> + clk_parent = of_clk_get_parent_name(node, 0);
> + if (!clk_parent)
> + return ERR_PTR(-EINVAL);
> +
> + of_property_read_string(node, "clock-output-names", &clk_name);
> +
> + /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
> + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> + if (IS_ERR(clk))
> + return clk;
> +
> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> + if (ret)
> + goto err_unregister;
> +
> + return clk;
> +
> +err_unregister:
> + clk_unregister_divider(clk);
> +
> + return ERR_PTR(ret);
> +}
> +
> +static void sun8i_a23_apb0_setup(struct device_node *node)
> +{
> + void __iomem *reg;
> + struct resource res;
> + struct clk *clk;
> +
> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> + if (IS_ERR(reg))
> + return;
> +
> + clk = sun8i_a23_apb0_register(node, reg);
> + if (IS_ERR(clk))
> + goto err_unmap;
> +
> + return;
> +
> +err_unmap:
> + iounmap(reg);
> + 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);
> +
> static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> - const char *clk_name = np->name;
> - const char *clk_parent;
> struct resource *r;
> void __iomem *reg;
> struct clk *clk;
> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> if (IS_ERR(reg))
> return PTR_ERR(reg);
>
> - clk_parent = of_clk_get_parent_name(np, 0);
> - if (!clk_parent)
> - return -EINVAL;
> -
> - of_property_read_string(np, "clock-output-names", &clk_name);
> -
> - /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> - clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
> - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> + clk = sun8i_a23_apb0_register(np, reg);
> if (IS_ERR(clk))
> return PTR_ERR(clk);
>
> - return of_clk_add_provider(np, of_clk_src_simple_get, clk);
> + return 0;
> }
Won't this probe twice now? First the CLK_OF_DECLARE will register a
clock, and then the device model will call probe a second time.
I guess then request_mem_region will catch it, but then you return an
error code, which is probably an error success, since the clock is
registered :)
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
2015-12-01 10:04 ` Maxime Ripard
@ 2015-12-01 11:54 ` Chen-Yu Tsai
2015-12-01 12:50 ` Maxime Ripard
0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 11:54 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
linux-clk, linux-arm-kernel, linux-kernel, devicetree,
linux-sunxi
On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>> instead of through a PRCM mfd device and subdevices for each clock
>> and reset control. As such we need a CLK_OF_DECLARE version of
>> the sun8i-a23-apb0-clk driver.
>>
>> Also, build it for sun9i/A80, and not just for configurations with
>> MFD_SUN6I_PRCM enabled.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> drivers/clk/sunxi/Makefile | 5 +--
>> drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>> 2 files changed, 62 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>> index cb4c299214ce..c55d5cd1c0e5 100644
>> --- a/drivers/clk/sunxi/Makefile
>> +++ b/drivers/clk/sunxi/Makefile
>> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>> obj-y += clk-sun9i-mmc.o
>> obj-y += clk-usb.o
>>
>> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>> +
>
> So sun8i doesn't use it?
Shit... I messed up. clk-sun8i-apb0.o should also be under
CONFIG_MFD_SUN6I_PRCM.
I'll send a new version of this patch. No need to keep spamming
people with the whole series.
>> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>> - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>> - clk-sun8i-apb0.o
>> + clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> @@ -17,13 +17,68 @@
>> #include <linux/clk-provider.h>
>> #include <linux/module.h>
>> #include <linux/of.h>
>> +#include <linux/of_address.h>
>> #include <linux/platform_device.h>
>>
>> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>> + void __iomem *reg)
>> +{
>> + const char *clk_name = node->name;
>> + const char *clk_parent;
>> + struct clk *clk;
>> + int ret;
>> +
>> + clk_parent = of_clk_get_parent_name(node, 0);
>> + if (!clk_parent)
>> + return ERR_PTR(-EINVAL);
>> +
>> + of_property_read_string(node, "clock-output-names", &clk_name);
>> +
>> + /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>> + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> + if (IS_ERR(clk))
>> + return clk;
>> +
>> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> + if (ret)
>> + goto err_unregister;
>> +
>> + return clk;
>> +
>> +err_unregister:
>> + clk_unregister_divider(clk);
>> +
>> + return ERR_PTR(ret);
>> +}
>> +
>> +static void sun8i_a23_apb0_setup(struct device_node *node)
>> +{
>> + void __iomem *reg;
>> + struct resource res;
>> + struct clk *clk;
>> +
>> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> + if (IS_ERR(reg))
>> + return;
>> +
>> + clk = sun8i_a23_apb0_register(node, reg);
>> + if (IS_ERR(clk))
>> + goto err_unmap;
>> +
>> + return;
>> +
>> +err_unmap:
>> + iounmap(reg);
>> + 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);
>> +
>> static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> {
>> struct device_node *np = pdev->dev.of_node;
>> - const char *clk_name = np->name;
>> - const char *clk_parent;
>> struct resource *r;
>> void __iomem *reg;
>> struct clk *clk;
>> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> if (IS_ERR(reg))
>> return PTR_ERR(reg);
>>
>> - clk_parent = of_clk_get_parent_name(np, 0);
>> - if (!clk_parent)
>> - return -EINVAL;
>> -
>> - of_property_read_string(np, "clock-output-names", &clk_name);
>> -
>> - /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> - clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>> - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> + clk = sun8i_a23_apb0_register(np, reg);
>> if (IS_ERR(clk))
>> return PTR_ERR(clk);
>>
>> - return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> + return 0;
>> }
>
> Won't this probe twice now? First the CLK_OF_DECLARE will register a
> clock, and then the device model will call probe a second time.
AFAIK it will.
> I guess then request_mem_region will catch it, but then you return an
> error code, which is probably an error success, since the clock is
> registered :)
Indeed. clk-mod0.c actually has a comment block explaining this.
I didn't want to repeat the whole thing though.
Regards
ChenYu
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
2015-12-01 11:54 ` Chen-Yu Tsai
@ 2015-12-01 12:50 ` Maxime Ripard
2015-12-01 14:19 ` Chen-Yu Tsai
0 siblings, 1 reply; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 12:50 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Emilio Lopez, Michael Turquette, Stephen Boyd, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
linux-arm-kernel, linux-kernel, devicetree, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 5946 bytes --]
On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
> >> instead of through a PRCM mfd device and subdevices for each clock
> >> and reset control. As such we need a CLK_OF_DECLARE version of
> >> the sun8i-a23-apb0-clk driver.
> >>
> >> Also, build it for sun9i/A80, and not just for configurations with
> >> MFD_SUN6I_PRCM enabled.
> >>
> >> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> >> ---
> >> drivers/clk/sunxi/Makefile | 5 +--
> >> drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
> >> 2 files changed, 62 insertions(+), 14 deletions(-)
> >>
> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> >> index cb4c299214ce..c55d5cd1c0e5 100644
> >> --- a/drivers/clk/sunxi/Makefile
> >> +++ b/drivers/clk/sunxi/Makefile
> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
> >> obj-y += clk-sun9i-mmc.o
> >> obj-y += clk-usb.o
> >>
> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> >> +
> >
> > So sun8i doesn't use it?
>
> Shit... I messed up. clk-sun8i-apb0.o should also be under
> CONFIG_MFD_SUN6I_PRCM.
>
> I'll send a new version of this patch. No need to keep spamming
> people with the whole series.
Ok.
> >> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> >> - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> >> - clk-sun8i-apb0.o
> >> + clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> @@ -17,13 +17,68 @@
> >> #include <linux/clk-provider.h>
> >> #include <linux/module.h>
> >> #include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> #include <linux/platform_device.h>
> >>
> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
> >> + void __iomem *reg)
> >> +{
> >> + const char *clk_name = node->name;
> >> + const char *clk_parent;
> >> + struct clk *clk;
> >> + int ret;
> >> +
> >> + clk_parent = of_clk_get_parent_name(node, 0);
> >> + if (!clk_parent)
> >> + return ERR_PTR(-EINVAL);
> >> +
> >> + of_property_read_string(node, "clock-output-names", &clk_name);
> >> +
> >> + /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> >> + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
> >> + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> >> + if (IS_ERR(clk))
> >> + return clk;
> >> +
> >> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> >> + if (ret)
> >> + goto err_unregister;
> >> +
> >> + return clk;
> >> +
> >> +err_unregister:
> >> + clk_unregister_divider(clk);
> >> +
> >> + return ERR_PTR(ret);
> >> +}
> >> +
> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
> >> +{
> >> + void __iomem *reg;
> >> + struct resource res;
> >> + struct clk *clk;
> >> +
> >> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> >> + if (IS_ERR(reg))
> >> + return;
> >> +
> >> + clk = sun8i_a23_apb0_register(node, reg);
> >> + if (IS_ERR(clk))
> >> + goto err_unmap;
> >> +
> >> + return;
> >> +
> >> +err_unmap:
> >> + iounmap(reg);
> >> + 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);
> >> +
> >> static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> >> {
> >> struct device_node *np = pdev->dev.of_node;
> >> - const char *clk_name = np->name;
> >> - const char *clk_parent;
> >> struct resource *r;
> >> void __iomem *reg;
> >> struct clk *clk;
> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> >> if (IS_ERR(reg))
> >> return PTR_ERR(reg);
> >>
> >> - clk_parent = of_clk_get_parent_name(np, 0);
> >> - if (!clk_parent)
> >> - return -EINVAL;
> >> -
> >> - of_property_read_string(np, "clock-output-names", &clk_name);
> >> -
> >> - /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> >> - clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
> >> - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> >> + clk = sun8i_a23_apb0_register(np, reg);
> >> if (IS_ERR(clk))
> >> return PTR_ERR(clk);
> >>
> >> - return of_clk_add_provider(np, of_clk_src_simple_get, clk);
> >> + return 0;
> >> }
> >
> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
> > clock, and then the device model will call probe a second time.
>
> AFAIK it will.
>
> > I guess then request_mem_region will catch it, but then you return an
> > error code, which is probably an error success, since the clock is
> > registered :)
>
> Indeed. clk-mod0.c actually has a comment block explaining this.
> I didn't want to repeat the whole thing though.
I guess, we can simply return 0 if of_io_request_and_map returns
EBUSY, since it would simply mean that we already probed.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
2015-12-01 12:50 ` Maxime Ripard
@ 2015-12-01 14:19 ` Chen-Yu Tsai
2015-12-01 14:39 ` Chen-Yu Tsai
0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 14:19 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
linux-clk, linux-arm-kernel, linux-kernel, devicetree,
linux-sunxi
On Tue, Dec 1, 2015 at 8:50 PM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
>> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
>> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>> > Hi,
>> >
>> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>> >> instead of through a PRCM mfd device and subdevices for each clock
>> >> and reset control. As such we need a CLK_OF_DECLARE version of
>> >> the sun8i-a23-apb0-clk driver.
>> >>
>> >> Also, build it for sun9i/A80, and not just for configurations with
>> >> MFD_SUN6I_PRCM enabled.
>> >>
>> >> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>> >> ---
>> >> drivers/clk/sunxi/Makefile | 5 +--
>> >> drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>> >> 2 files changed, 62 insertions(+), 14 deletions(-)
>> >>
>> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>> >> index cb4c299214ce..c55d5cd1c0e5 100644
>> >> --- a/drivers/clk/sunxi/Makefile
>> >> +++ b/drivers/clk/sunxi/Makefile
>> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>> >> obj-y += clk-sun9i-mmc.o
>> >> obj-y += clk-usb.o
>> >>
>> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>> >> +
>> >
>> > So sun8i doesn't use it?
>>
>> Shit... I messed up. clk-sun8i-apb0.o should also be under
>> CONFIG_MFD_SUN6I_PRCM.
>>
>> I'll send a new version of this patch. No need to keep spamming
>> people with the whole series.
>
> Ok.
>
>> >> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>> >> - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>> >> - clk-sun8i-apb0.o
>> >> + clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> @@ -17,13 +17,68 @@
>> >> #include <linux/clk-provider.h>
>> >> #include <linux/module.h>
>> >> #include <linux/of.h>
>> >> +#include <linux/of_address.h>
>> >> #include <linux/platform_device.h>
>> >>
>> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>> >> + void __iomem *reg)
>> >> +{
>> >> + const char *clk_name = node->name;
>> >> + const char *clk_parent;
>> >> + struct clk *clk;
>> >> + int ret;
>> >> +
>> >> + clk_parent = of_clk_get_parent_name(node, 0);
>> >> + if (!clk_parent)
>> >> + return ERR_PTR(-EINVAL);
>> >> +
>> >> + of_property_read_string(node, "clock-output-names", &clk_name);
>> >> +
>> >> + /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> >> + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>> >> + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> >> + if (IS_ERR(clk))
>> >> + return clk;
>> >> +
>> >> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> >> + if (ret)
>> >> + goto err_unregister;
>> >> +
>> >> + return clk;
>> >> +
>> >> +err_unregister:
>> >> + clk_unregister_divider(clk);
>> >> +
>> >> + return ERR_PTR(ret);
>> >> +}
>> >> +
>> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
>> >> +{
>> >> + void __iomem *reg;
>> >> + struct resource res;
>> >> + struct clk *clk;
>> >> +
>> >> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> >> + if (IS_ERR(reg))
>> >> + return;
>> >> +
>> >> + clk = sun8i_a23_apb0_register(node, reg);
>> >> + if (IS_ERR(clk))
>> >> + goto err_unmap;
>> >> +
>> >> + return;
>> >> +
>> >> +err_unmap:
>> >> + iounmap(reg);
>> >> + 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);
>> >> +
>> >> static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> >> {
>> >> struct device_node *np = pdev->dev.of_node;
>> >> - const char *clk_name = np->name;
>> >> - const char *clk_parent;
>> >> struct resource *r;
>> >> void __iomem *reg;
>> >> struct clk *clk;
>> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> >> if (IS_ERR(reg))
>> >> return PTR_ERR(reg);
>> >>
>> >> - clk_parent = of_clk_get_parent_name(np, 0);
>> >> - if (!clk_parent)
>> >> - return -EINVAL;
>> >> -
>> >> - of_property_read_string(np, "clock-output-names", &clk_name);
>> >> -
>> >> - /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> >> - clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>> >> - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> >> + clk = sun8i_a23_apb0_register(np, reg);
>> >> if (IS_ERR(clk))
>> >> return PTR_ERR(clk);
>> >>
>> >> - return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> >> + return 0;
>> >> }
>> >
>> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
>> > clock, and then the device model will call probe a second time.
>>
>> AFAIK it will.
>>
>> > I guess then request_mem_region will catch it, but then you return an
>> > error code, which is probably an error success, since the clock is
>> > registered :)
>>
>> Indeed. clk-mod0.c actually has a comment block explaining this.
>> I didn't want to repeat the whole thing though.
>
> I guess, we can simply return 0 if of_io_request_and_map returns
> EBUSY, since it would simply mean that we already probed.
I think CLK_OF_DECLARE gets probed first, then platform devices.
of_io_request_and_map fails for mfd cells, which have no DT reg
properties. So we should be ignoring -EINVAL instead of -EBUSY.
But yeah, I'll have it return 0 in this case, and add a brief
comment.
ChenYu
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
2015-12-01 14:19 ` Chen-Yu Tsai
@ 2015-12-01 14:39 ` Chen-Yu Tsai
0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 14:39 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
linux-clk, linux-arm-kernel, linux-kernel, devicetree,
linux-sunxi
On Tue, Dec 1, 2015 at 10:19 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Tue, Dec 1, 2015 at 8:50 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
>>> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
>>> <maxime.ripard@free-electrons.com> wrote:
>>> > Hi,
>>> >
>>> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>>> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>>> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>>> >> instead of through a PRCM mfd device and subdevices for each clock
>>> >> and reset control. As such we need a CLK_OF_DECLARE version of
>>> >> the sun8i-a23-apb0-clk driver.
>>> >>
>>> >> Also, build it for sun9i/A80, and not just for configurations with
>>> >> MFD_SUN6I_PRCM enabled.
>>> >>
>>> >> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> >> ---
>>> >> drivers/clk/sunxi/Makefile | 5 +--
>>> >> drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>>> >> 2 files changed, 62 insertions(+), 14 deletions(-)
>>> >>
>>> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>>> >> index cb4c299214ce..c55d5cd1c0e5 100644
>>> >> --- a/drivers/clk/sunxi/Makefile
>>> >> +++ b/drivers/clk/sunxi/Makefile
>>> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>>> >> obj-y += clk-sun9i-mmc.o
>>> >> obj-y += clk-usb.o
>>> >>
>>> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>>> >> +
>>> >
>>> > So sun8i doesn't use it?
>>>
>>> Shit... I messed up. clk-sun8i-apb0.o should also be under
>>> CONFIG_MFD_SUN6I_PRCM.
>>>
>>> I'll send a new version of this patch. No need to keep spamming
>>> people with the whole series.
>>
>> Ok.
>>
>>> >> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>>> >> - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>>> >> - clk-sun8i-apb0.o
>>> >> + clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>>> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>>> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> @@ -17,13 +17,68 @@
>>> >> #include <linux/clk-provider.h>
>>> >> #include <linux/module.h>
>>> >> #include <linux/of.h>
>>> >> +#include <linux/of_address.h>
>>> >> #include <linux/platform_device.h>
>>> >>
>>> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>>> >> + void __iomem *reg)
>>> >> +{
>>> >> + const char *clk_name = node->name;
>>> >> + const char *clk_parent;
>>> >> + struct clk *clk;
>>> >> + int ret;
>>> >> +
>>> >> + clk_parent = of_clk_get_parent_name(node, 0);
>>> >> + if (!clk_parent)
>>> >> + return ERR_PTR(-EINVAL);
>>> >> +
>>> >> + of_property_read_string(node, "clock-output-names", &clk_name);
>>> >> +
>>> >> + /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>>> >> + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>>> >> + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>>> >> + if (IS_ERR(clk))
>>> >> + return clk;
>>> >> +
>>> >> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>>> >> + if (ret)
>>> >> + goto err_unregister;
>>> >> +
>>> >> + return clk;
>>> >> +
>>> >> +err_unregister:
>>> >> + clk_unregister_divider(clk);
>>> >> +
>>> >> + return ERR_PTR(ret);
>>> >> +}
>>> >> +
>>> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
>>> >> +{
>>> >> + void __iomem *reg;
>>> >> + struct resource res;
>>> >> + struct clk *clk;
>>> >> +
>>> >> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>>> >> + if (IS_ERR(reg))
>>> >> + return;
>>> >> +
>>> >> + clk = sun8i_a23_apb0_register(node, reg);
>>> >> + if (IS_ERR(clk))
>>> >> + goto err_unmap;
>>> >> +
>>> >> + return;
>>> >> +
>>> >> +err_unmap:
>>> >> + iounmap(reg);
>>> >> + 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);
>>> >> +
>>> >> static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>> >> {
>>> >> struct device_node *np = pdev->dev.of_node;
>>> >> - const char *clk_name = np->name;
>>> >> - const char *clk_parent;
>>> >> struct resource *r;
>>> >> void __iomem *reg;
>>> >> struct clk *clk;
>>> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>> >> if (IS_ERR(reg))
>>> >> return PTR_ERR(reg);
>>> >>
>>> >> - clk_parent = of_clk_get_parent_name(np, 0);
>>> >> - if (!clk_parent)
>>> >> - return -EINVAL;
>>> >> -
>>> >> - of_property_read_string(np, "clock-output-names", &clk_name);
>>> >> -
>>> >> - /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>>> >> - clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>>> >> - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>>> >> + clk = sun8i_a23_apb0_register(np, reg);
>>> >> if (IS_ERR(clk))
>>> >> return PTR_ERR(clk);
>>> >>
>>> >> - return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>>> >> + return 0;
>>> >> }
>>> >
>>> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
>>> > clock, and then the device model will call probe a second time.
>>>
>>> AFAIK it will.
>>>
>>> > I guess then request_mem_region will catch it, but then you return an
>>> > error code, which is probably an error success, since the clock is
>>> > registered :)
>>>
>>> Indeed. clk-mod0.c actually has a comment block explaining this.
>>> I didn't want to repeat the whole thing though.
>>
>> I guess, we can simply return 0 if of_io_request_and_map returns
>> EBUSY, since it would simply mean that we already probed.
>
> I think CLK_OF_DECLARE gets probed first, then platform devices.
> of_io_request_and_map fails for mfd cells, which have no DT reg
> properties. So we should be ignoring -EINVAL instead of -EBUSY.
Right... I misread your comment. You're talking about the platform device
part. About ignoring the error here: normally we use CLK_OF_DECLARE with
clocks under the "clocks" node, which don't get registered as platform
device. (Or is this not so common?) So if one does get probed twice, I
think we shouldn't ignore the error. It's likely the DT has a problem
and the probe error will let the user know.
What do you think?
ChenYu
> But yeah, I'll have it return 0 in this case, and add a brief
> comment.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
[not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-11-29 3:03 ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
@ 2015-11-29 3:03 ` Chen-Yu Tsai
2015-11-30 17:14 ` Rob Herring
2015-11-29 3:03 ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
` (2 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29 3:03 UTC (permalink / raw)
To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai
This patch adds support for the PRCM apbs clock gates found on the
Allwinner A80 SoC.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-simple-gates.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index a94bb56a0e9e..b6859ed6913f 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -55,6 +55,7 @@ Required properties:
"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
+ "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 0214c6548afd..c8acc0612c15 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
+ sunxi_simple_gates_init);
static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
14, /* ahb_sdram */
--
2.6.2
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
2015-11-29 3:03 ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
@ 2015-11-30 17:14 ` Rob Herring
2015-12-01 11:16 ` Maxime Ripard
0 siblings, 1 reply; 16+ messages in thread
From: Rob Herring @ 2015-11-30 17:14 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
linux-arm-kernel, linux-kernel, devicetree, linux-sunxi
On Sun, Nov 29, 2015 at 11:03:07AM +0800, Chen-Yu Tsai wrote:
> This patch adds support for the PRCM apbs clock gates found on the
> Allwinner A80 SoC.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
> drivers/clk/sunxi/clk-simple-gates.c | 2 ++
> 2 files changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index a94bb56a0e9e..b6859ed6913f 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -55,6 +55,7 @@ Required properties:
> "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
> "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
> "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
> + "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
> "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
> "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
> "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
> index 0214c6548afd..c8acc0612c15 100644
> --- a/drivers/clk/sunxi/clk-simple-gates.c
> +++ b/drivers/clk/sunxi/clk-simple-gates.c
> @@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
> sunxi_simple_gates_init);
> CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
> sunxi_simple_gates_init);
> +CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
> + sunxi_simple_gates_init);
>
> static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
> 14, /* ahb_sdram */
> --
> 2.6.2
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
2015-11-30 17:14 ` Rob Herring
@ 2015-12-01 11:16 ` Maxime Ripard
0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 11:16 UTC (permalink / raw)
To: Rob Herring
Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
[-- Attachment #1: Type: text/plain, Size: 499 bytes --]
On Mon, Nov 30, 2015 at 11:14:06AM -0600, Rob Herring wrote:
> On Sun, Nov 29, 2015 at 11:03:07AM +0800, Chen-Yu Tsai wrote:
> > This patch adds support for the PRCM apbs clock gates found on the
> > Allwinner A80 SoC.
> >
> > Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Applied, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
[not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-11-29 3:03 ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
2015-11-29 3:03 ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
@ 2015-11-29 3:03 ` Chen-Yu Tsai
2015-11-30 17:13 ` Rob Herring
2015-11-29 3:03 ` [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes Chen-Yu Tsai
2015-11-29 3:03 ` [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks Chen-Yu Tsai
4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29 3:03 UTC (permalink / raw)
To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai
The "cpus" clock is the clock for the embedded processor in the A80.
It is also part of the PRCM clock tree. This clock includes a pre-
divider on one of its inputs. For now we are using a custom clock
driver for it. In the future we may want to develop a generalized
driver for these types of clocks, which also includes the AHB clock
driver on sun[5678]i.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-sun9i-cpus.c | 240 ++++++++++++++++++++++
3 files changed, 242 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-sun9i-cpus.c
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index b6859ed6913f..153ac72869e8 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -27,6 +27,7 @@ Required properties:
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
+ "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index c55d5cd1c0e5..f7d439fa9980 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -16,6 +16,7 @@ obj-y += clk-sun9i-mmc.o
obj-y += clk-usb.o
obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
new file mode 100644
index 000000000000..7626d2194b96
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
+ *
+ * Allwinner A80 CPUS clock driver
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
+
+/**
+ * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
+ */
+
+#define SUN9I_CPUS_MAX_PARENTS 4
+#define SUN9I_CPUS_MUX_PARENT_PLL4 3
+#define SUN9I_CPUS_MUX_SHIFT 16
+#define SUN9I_CPUS_MUX_MASK GENMASK(17, 16)
+#define SUN9I_CPUS_MUX_GET_PARENT(reg) ((reg & SUN9I_CPUS_MUX_MASK) >> \
+ SUN9I_CPUS_MUX_SHIFT)
+
+#define SUN9I_CPUS_DIV_SHIFT 4
+#define SUN9I_CPUS_DIV_MASK GENMASK(5, 4)
+#define SUN9I_CPUS_DIV_GET(reg) ((reg & SUN9I_CPUS_DIV_MASK) >> \
+ SUN9I_CPUS_DIV_SHIFT)
+#define SUN9I_CPUS_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_DIV_MASK) | \
+ (div << SUN9I_CPUS_DIV_SHIFT))
+#define SUN9I_CPUS_PLL4_DIV_SHIFT 8
+#define SUN9I_CPUS_PLL4_DIV_MASK GENMASK(12, 8)
+#define SUN9I_CPUS_PLL4_DIV_GET(reg) ((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
+ SUN9I_CPUS_PLL4_DIV_SHIFT)
+#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
+ (div << SUN9I_CPUS_PLL4_DIV_SHIFT))
+
+struct sun9i_a80_cpus_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
+
+static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+ unsigned long rate;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(cpus->reg);
+
+ /* apply pre-divider first if parent is pll4 */
+ if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
+ parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
+
+ /* clk divider */
+ rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
+
+ return rate;
+}
+
+static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+ u8 parent, unsigned long parent_rate)
+{
+ u8 div, pre_div = 1;
+
+ /*
+ * clock can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency
+ */
+ if (parent_rate && rate > parent_rate)
+ rate = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /* calculate pre-divider if parent is pll4 */
+ if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
+ /* pre-divider is 1 ~ 32 */
+ if (div < 32) {
+ pre_div = div;
+ div = 1;
+ } else if (div < 64) {
+ pre_div = DIV_ROUND_UP(div, 2);
+ div = 2;
+ } else if (div < 96) {
+ pre_div = DIV_ROUND_UP(div, 3);
+ div = 3;
+ } else {
+ pre_div = DIV_ROUND_UP(div, 4);
+ div = 4;
+ }
+ }
+
+ /* we were asked to pass back divider values */
+ if (divp) {
+ *divp = div - 1;
+ *pre_divp = pre_div - 1;
+ }
+
+ return parent_rate / pre_div / div;
+}
+
+static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
+ struct clk_rate_request *req)
+{
+ struct clk_hw *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+ unsigned long rate = req->rate;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = clk_hw_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_hw_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = clk_hw_round_rate(parent, rate);
+ else
+ parent_rate = clk_hw_get_rate(parent);
+
+ child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
+ parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (!best_parent)
+ return -EINVAL;
+
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best;
+ req->rate = best_child_rate;
+
+ return 0;
+}
+
+static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+ unsigned long flags;
+ u8 div, pre_div, parent;
+ u32 reg;
+
+ spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
+
+ reg = readl(cpus->reg);
+
+ /* need to know which parent is used to apply pre-divider */
+ parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
+ sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+ reg = SUN9I_CPUS_DIV_SET(reg, div);
+ reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
+ writel(reg, cpus->reg);
+
+ spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops sun9i_a80_cpus_clk_ops = {
+ .determine_rate = sun9i_a80_cpus_clk_determine_rate,
+ .recalc_rate = sun9i_a80_cpus_clk_recalc_rate,
+ .set_rate = sun9i_a80_cpus_clk_set_rate,
+};
+
+static void sun9i_a80_cpus_setup(struct device_node *node)
+{
+ const char *clk_name = node->name;
+ const char *parents[SUN9I_CPUS_MAX_PARENTS];
+ struct resource res;
+ struct sun9i_a80_cpus_clk *cpus;
+ struct clk_mux *mux;
+ struct clk *clk;
+ int ret;
+
+ cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return;
+
+ cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(cpus->reg))
+ goto err_free_cpus;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /* we have a mux, we will have >1 parents */
+ ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ goto err_unmap;
+
+ /* set up clock properties */
+ mux->reg = cpus->reg;
+ mux->shift = SUN9I_CPUS_MUX_SHIFT;
+ /* un-shifted mask is what mux_clk expects */
+ mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
+ mux->lock = &sun9i_a80_cpus_lock;
+
+ clk = clk_register_composite(NULL, clk_name, parents, ret,
+ &mux->hw, &clk_mux_ops,
+ &cpus->hw, &sun9i_a80_cpus_clk_ops,
+ NULL, NULL, 0);
+ if (IS_ERR(clk))
+ goto err_free_mux;
+
+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (ret)
+ goto err_unregister;
+
+ return;
+
+err_unregister:
+ clk_unregister(clk);
+err_free_mux:
+ kfree(mux);
+err_unmap:
+ iounmap(cpus->reg);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+err_free_cpus:
+ kfree(cpus);
+}
+CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
+ sun9i_a80_cpus_setup);
--
2.6.2
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
2015-11-29 3:03 ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
@ 2015-11-30 17:13 ` Rob Herring
2015-12-01 13:07 ` Maxime Ripard
0 siblings, 1 reply; 16+ messages in thread
From: Rob Herring @ 2015-11-30 17:13 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
linux-arm-kernel, linux-kernel, devicetree, linux-sunxi
On Sun, Nov 29, 2015 at 11:03:08AM +0800, Chen-Yu Tsai wrote:
> The "cpus" clock is the clock for the embedded processor in the A80.
> It is also part of the PRCM clock tree. This clock includes a pre-
> divider on one of its inputs. For now we are using a custom clock
> driver for it. In the future we may want to develop a generalized
> driver for these types of clocks, which also includes the AHB clock
> driver on sun[5678]i.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
For the binding:
Acked-by: Rob Herring <robh@kernel.org>
> drivers/clk/sunxi/Makefile | 1 +
> drivers/clk/sunxi/clk-sun9i-cpus.c | 240 ++++++++++++++++++++++
> 3 files changed, 242 insertions(+)
> create mode 100644 drivers/clk/sunxi/clk-sun9i-cpus.c
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index b6859ed6913f..153ac72869e8 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -27,6 +27,7 @@ Required properties:
> "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
> "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
> "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
> + "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
> "allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
> "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
> "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index c55d5cd1c0e5..f7d439fa9980 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -16,6 +16,7 @@ obj-y += clk-sun9i-mmc.o
> obj-y += clk-usb.o
>
> obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> +obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
>
> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
> new file mode 100644
> index 000000000000..7626d2194b96
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
> @@ -0,0 +1,240 @@
> +/*
> + * Copyright (C) 2015 Chen-Yu Tsai
> + *
> + * Chen-Yu Tsai <wens@csie.org>
> + *
> + * Allwinner A80 CPUS clock driver
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +
> +static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
> +
> +/**
> + * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
> + */
> +
> +#define SUN9I_CPUS_MAX_PARENTS 4
> +#define SUN9I_CPUS_MUX_PARENT_PLL4 3
> +#define SUN9I_CPUS_MUX_SHIFT 16
> +#define SUN9I_CPUS_MUX_MASK GENMASK(17, 16)
> +#define SUN9I_CPUS_MUX_GET_PARENT(reg) ((reg & SUN9I_CPUS_MUX_MASK) >> \
> + SUN9I_CPUS_MUX_SHIFT)
> +
> +#define SUN9I_CPUS_DIV_SHIFT 4
> +#define SUN9I_CPUS_DIV_MASK GENMASK(5, 4)
> +#define SUN9I_CPUS_DIV_GET(reg) ((reg & SUN9I_CPUS_DIV_MASK) >> \
> + SUN9I_CPUS_DIV_SHIFT)
> +#define SUN9I_CPUS_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_DIV_MASK) | \
> + (div << SUN9I_CPUS_DIV_SHIFT))
> +#define SUN9I_CPUS_PLL4_DIV_SHIFT 8
> +#define SUN9I_CPUS_PLL4_DIV_MASK GENMASK(12, 8)
> +#define SUN9I_CPUS_PLL4_DIV_GET(reg) ((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
> + SUN9I_CPUS_PLL4_DIV_SHIFT)
> +#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
> + (div << SUN9I_CPUS_PLL4_DIV_SHIFT))
> +
> +struct sun9i_a80_cpus_clk {
> + struct clk_hw hw;
> + void __iomem *reg;
> +};
> +
> +#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
> +
> +static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
> + unsigned long rate;
> + u32 reg;
> +
> + /* Fetch the register value */
> + reg = readl(cpus->reg);
> +
> + /* apply pre-divider first if parent is pll4 */
> + if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
> + parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
> +
> + /* clk divider */
> + rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
> +
> + return rate;
> +}
> +
> +static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
> + u8 parent, unsigned long parent_rate)
> +{
> + u8 div, pre_div = 1;
> +
> + /*
> + * clock can only divide, so we will never be able to achieve
> + * frequencies higher than the parent frequency
> + */
> + if (parent_rate && rate > parent_rate)
> + rate = parent_rate;
> +
> + div = DIV_ROUND_UP(parent_rate, rate);
> +
> + /* calculate pre-divider if parent is pll4 */
> + if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
> + /* pre-divider is 1 ~ 32 */
> + if (div < 32) {
> + pre_div = div;
> + div = 1;
> + } else if (div < 64) {
> + pre_div = DIV_ROUND_UP(div, 2);
> + div = 2;
> + } else if (div < 96) {
> + pre_div = DIV_ROUND_UP(div, 3);
> + div = 3;
> + } else {
> + pre_div = DIV_ROUND_UP(div, 4);
> + div = 4;
> + }
> + }
> +
> + /* we were asked to pass back divider values */
> + if (divp) {
> + *divp = div - 1;
> + *pre_divp = pre_div - 1;
> + }
> +
> + return parent_rate / pre_div / div;
> +}
> +
> +static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
> + struct clk_rate_request *req)
> +{
> + struct clk_hw *parent, *best_parent = NULL;
> + int i, num_parents;
> + unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
> + unsigned long rate = req->rate;
> +
> + /* find the parent that can help provide the fastest rate <= rate */
> + num_parents = clk_hw_get_num_parents(clk);
> + for (i = 0; i < num_parents; i++) {
> + parent = clk_hw_get_parent_by_index(clk, i);
> + if (!parent)
> + continue;
> + if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
> + parent_rate = clk_hw_round_rate(parent, rate);
> + else
> + parent_rate = clk_hw_get_rate(parent);
> +
> + child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
> + parent_rate);
> +
> + if (child_rate <= rate && child_rate > best_child_rate) {
> + best_parent = parent;
> + best = parent_rate;
> + best_child_rate = child_rate;
> + }
> + }
> +
> + if (!best_parent)
> + return -EINVAL;
> +
> + req->best_parent_hw = best_parent;
> + req->best_parent_rate = best;
> + req->rate = best_child_rate;
> +
> + return 0;
> +}
> +
> +static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
> + unsigned long flags;
> + u8 div, pre_div, parent;
> + u32 reg;
> +
> + spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
> +
> + reg = readl(cpus->reg);
> +
> + /* need to know which parent is used to apply pre-divider */
> + parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
> + sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
> +
> + reg = SUN9I_CPUS_DIV_SET(reg, div);
> + reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
> + writel(reg, cpus->reg);
> +
> + spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops sun9i_a80_cpus_clk_ops = {
> + .determine_rate = sun9i_a80_cpus_clk_determine_rate,
> + .recalc_rate = sun9i_a80_cpus_clk_recalc_rate,
> + .set_rate = sun9i_a80_cpus_clk_set_rate,
> +};
> +
> +static void sun9i_a80_cpus_setup(struct device_node *node)
> +{
> + const char *clk_name = node->name;
> + const char *parents[SUN9I_CPUS_MAX_PARENTS];
> + struct resource res;
> + struct sun9i_a80_cpus_clk *cpus;
> + struct clk_mux *mux;
> + struct clk *clk;
> + int ret;
> +
> + cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
> + if (!cpus)
> + return;
> +
> + cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> + if (IS_ERR(cpus->reg))
> + goto err_free_cpus;
> +
> + of_property_read_string(node, "clock-output-names", &clk_name);
> +
> + /* we have a mux, we will have >1 parents */
> + ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
> +
> + mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> + if (!mux)
> + goto err_unmap;
> +
> + /* set up clock properties */
> + mux->reg = cpus->reg;
> + mux->shift = SUN9I_CPUS_MUX_SHIFT;
> + /* un-shifted mask is what mux_clk expects */
> + mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
> + mux->lock = &sun9i_a80_cpus_lock;
> +
> + clk = clk_register_composite(NULL, clk_name, parents, ret,
> + &mux->hw, &clk_mux_ops,
> + &cpus->hw, &sun9i_a80_cpus_clk_ops,
> + NULL, NULL, 0);
> + if (IS_ERR(clk))
> + goto err_free_mux;
> +
> + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> + if (ret)
> + goto err_unregister;
> +
> + return;
> +
> +err_unregister:
> + clk_unregister(clk);
> +err_free_mux:
> + kfree(mux);
> +err_unmap:
> + iounmap(cpus->reg);
> + of_address_to_resource(node, 0, &res);
> + release_mem_region(res.start, resource_size(&res));
> +err_free_cpus:
> + kfree(cpus);
> +}
> +CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
> + sun9i_a80_cpus_setup);
> --
> 2.6.2
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
2015-11-30 17:13 ` Rob Herring
@ 2015-12-01 13:07 ` Maxime Ripard
0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 13:07 UTC (permalink / raw)
To: Rob Herring
Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
[-- Attachment #1: Type: text/plain, Size: 880 bytes --]
On Mon, Nov 30, 2015 at 11:13:25AM -0600, Rob Herring wrote:
> On Sun, Nov 29, 2015 at 11:03:08AM +0800, Chen-Yu Tsai wrote:
> > The "cpus" clock is the clock for the embedded processor in the A80.
> > It is also part of the PRCM clock tree. This clock includes a pre-
> > divider on one of its inputs. For now we are using a custom clock
> > driver for it. In the future we may want to develop a generalized
> > driver for these types of clocks, which also includes the AHB clock
> > driver on sun[5678]i.
> >
> > Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> > ---
> > Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
>
> For the binding:
>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Applied, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes
[not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
` (2 preceding siblings ...)
2015-11-29 3:03 ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
@ 2015-11-29 3:03 ` Chen-Yu Tsai
2015-11-29 3:03 ` [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks Chen-Yu Tsai
4 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29 3:03 UTC (permalink / raw)
To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai
This adds the supported PRCM clocks and reset controls to the A80 dtsi.
The DAUDIO module clocks are not supported yet.
Also update clock and reset phandles for r_uart.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 79 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 1118bf5cc4fb..a4ce348c0831 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -164,6 +164,14 @@
"usb_phy2", "usb_hsic_12M";
};
+ pll3: clk@06000008 {
+ /* placeholder until implemented */
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-rate = <0>;
+ clock-output-names = "pll3";
+ };
+
pll4: clk@0600000c {
#clock-cells = <0>;
compatible = "allwinner,sun9i-a80-pll4-clk";
@@ -350,6 +358,68 @@
"apb1_uart2", "apb1_uart3",
"apb1_uart4", "apb1_uart5";
};
+
+ cpus_clk: clk@08001410 {
+ compatible = "allwinner,sun9i-a80-cpus-clk";
+ reg = <0x08001410 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc32k>, <&osc24M>, <&pll4>, <&pll3>;
+ clock-output-names = "cpus";
+ };
+
+ ahbs: ahbs_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&cpus_clk>;
+ clock-output-names = "ahbs";
+ };
+
+ apbs: clk@0800141c {
+ compatible = "allwinner,sun8i-a23-apb0-clk";
+ reg = <0x0800141c 0x4>;
+ #clock-cells = <0>;
+ clocks = <&ahbs>;
+ clock-output-names = "apbs";
+ };
+
+ apbs_gates: clk@08001428 {
+ compatible = "allwinner,sun9i-a80-apbs-gates-clk";
+ reg = <0x08001428 0x4>;
+ #clock-cells = <1>;
+ clocks = <&apbs>;
+ clock-indices = <0>, <1>,
+ <2>, <3>,
+ <4>, <5>,
+ <6>, <7>,
+ <12>, <13>,
+ <16>, <17>,
+ <18>, <20>;
+ clock-output-names = "apbs_pio", "apbs_ir",
+ "apbs_timer", "apbs_rsb",
+ "apbs_uart", "apbs_1wire",
+ "apbs_i2c0", "apbs_i2c1",
+ "apbs_ps2_0", "apbs_ps2_1",
+ "apbs_dma", "apbs_i2s0",
+ "apbs_i2s1", "apbs_twd";
+ };
+
+ r_1wire_clk: clk@08001450 {
+ reg = <0x08001450 0x4>;
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ clocks = <&osc32k>, <&osc24M>;
+ clock-output-names = "r_1wire";
+ };
+
+ r_ir_clk: clk@08001454 {
+ reg = <0x08001454 0x4>;
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ clocks = <&osc32k>, <&osc24M>;
+ clock-output-names = "r_ir";
+ };
};
soc {
@@ -764,13 +834,20 @@
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
};
+ apbs_rst: reset@080014b0 {
+ reg = <0x080014b0 0x4>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ #reset-cells = <1>;
+ };
+
r_uart: serial@08002800 {
compatible = "snps,dw-apb-uart";
reg = <0x08002800 0x400>;
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&osc24M>;
+ clocks = <&apbs_gates 4>;
+ resets = <&apbs_rst 4>;
status = "disabled";
};
};
--
2.6.2
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks
[not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
` (3 preceding siblings ...)
2015-11-29 3:03 ` [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes Chen-Yu Tsai
@ 2015-11-29 3:03 ` Chen-Yu Tsai
[not found] ` <1448766190-11345-6-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29 3:03 UTC (permalink / raw)
To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai
The main (24MHz) clock on the A80 is configurable via the PRCM address
space. The low power/speed (32kHz) clock is from an external chip, the
AC100.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index a4ce348c0831..eb69a62f6bc4 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -128,6 +128,17 @@
*/
ranges = <0 0 0 0x20000000>;
+ /*
+ * This clock is actually configurable from the PRCM address
+ * space. The external 24M oscillator can be turned off, and
+ * the clock switched to an internal 16M RC oscillator. Under
+ * normal operation there's no reason to do this, and the
+ * default is to use the external good one, so just model this
+ * as a fixed clock. Also it is not entirely clear if the
+ * osc24M mux in the PRCM affects the entire clock tree, which
+ * would also throw all the PLL clock rates off, or just the
+ * downstream clocks in the PRCM.
+ */
osc24M: osc24M_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -135,6 +146,13 @@
clock-output-names = "osc24M";
};
+ /*
+ * The 32k clock is from an external source, normally the
+ * AC100 codec/RTC chip. This clock is by default enabled
+ * and clocked at 32768 Hz, from the oscillator connected
+ * to the AC100. It is configurable, but no such driver or
+ * bindings exist yet.
+ */
osc32k: osc32k_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
--
2.6.2
^ permalink raw reply related [flat|nested] 16+ messages in thread