* [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support
@ 2014-05-15 8:55 Boris BREZILLON
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge, kevin,
Hans de Goede, Randy Dunlap, devicetree, linux-doc,
linux-arm-kernel, dev, Boris BREZILLON
Hello,
This patch series adds support for some functions provided by the PRCM
(Power/Reset/Clock Management) unit:
- AR100, AHB0 and APB0 clocks
- APB0 reset controller
Best Regards,
Boris
Changes since v4:
- remove merged patch from the series
- move the MFD_SUN6I_PRCM option selection out of the clk support commit
Changes since v3:
- split clk drivers into 3 different drivers: ar100, apb0 and apb0_gates
- fix indentation
- add comments to the clk drivers
- select the MFD_SUN6I_PRCM when compiling for SUN6I arch
Changes since v2:
- use devm_ioremap_resource instead of devm_request_and_ioremap
- remove unnecessary header inclusions
- remove info trace when the probe succeed
- rename apb0_timer01 clk into apb0_timer
Changes since v1:
- fix prcm and prcm-clks DT documentation
- remove unneeded iounmap and kfree calls from sunxi_reset_remove function
- rework the AR100 clk implementation
Boris BREZILLON (5):
mfd: add support for sun6i PRCM (Power/Reset/Clock Management) unit
mfd: sun6i-prcm: document DT bindings
clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support
clk: sunxi: document PRCM clock compatible strings
ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled
Documentation/devicetree/bindings/clock/sunxi.txt | 3 +
.../devicetree/bindings/mfd/sun6i-prcm.txt | 59 ++++++
arch/arm/mach-sunxi/Kconfig | 1 +
drivers/clk/sunxi/Makefile | 2 +
drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 99 +++++++++
drivers/clk/sunxi/clk-sun6i-apb0.c | 77 +++++++
drivers/clk/sunxi/clk-sun6i-ar100.c | 233 +++++++++++++++++++++
drivers/mfd/Kconfig | 8 +
drivers/mfd/Makefile | 1 +
drivers/mfd/sun6i-prcm.c | 134 ++++++++++++
10 files changed, 617 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
create mode 100644 drivers/clk/sunxi/clk-sun6i-apb0-gates.c
create mode 100644 drivers/clk/sunxi/clk-sun6i-apb0.c
create mode 100644 drivers/clk/sunxi/clk-sun6i-ar100.c
create mode 100644 drivers/mfd/sun6i-prcm.c
--
1.8.3.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v5 1/5] mfd: add support for sun6i PRCM (Power/Reset/Clock Management) unit
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2014-05-15 8:55 ` Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 5/5] ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled Boris BREZILLON
1 sibling, 0 replies; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge,
kevin-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf, Hans de Goede,
Randy Dunlap, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dev-3kdeTeqwOZ9EV1b7eY7vFQ, Boris BREZILLON
The PRCM (Power/Reset/Clock Management) block exposes several subdevices
in different subsystems (clk, reset ...)
Add basic support for the PRCM unit with clk (AR100, AHB0, and APB0 clks)
and reset controller subdevices.
Other subdevices might be added later (if needed).
Signed-off-by: Boris BREZILLON <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/mfd/Kconfig | 8 +++
drivers/mfd/Makefile | 1 +
drivers/mfd/sun6i-prcm.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+)
create mode 100644 drivers/mfd/sun6i-prcm.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6c2a920..34d246f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -731,6 +731,14 @@ config MFD_STA2X11
select MFD_CORE
select REGMAP_MMIO
+config MFD_SUN6I_PRCM
+ bool "Allwinner A31 PRCM controller"
+ depends on ARCH_SUNXI
+ select MFD_CORE
+ help
+ Support for the PRCM (Power/Reset/Clock Management) unit available
+ in A31 SoC.
+
config MFD_SYSCON
bool "System Controller Register R/W Based on Regmap"
select REGMAP_MMIO
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1efecf2..df7823c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
+obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o
obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
new file mode 100644
index 0000000..718fc4d
--- /dev/null
+++ b/drivers/mfd/sun6i-prcm.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * Allwinner PRCM (Power/Reset/Clock Management) driver
+ *
+ */
+
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+struct prcm_data {
+ int nsubdevs;
+ const struct mfd_cell *subdevs;
+};
+
+static const struct resource sun6i_a31_ar100_clk_res[] = {
+ {
+ .start = 0x0,
+ .end = 0x3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static const struct resource sun6i_a31_apb0_clk_res[] = {
+ {
+ .start = 0xc,
+ .end = 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
+ {
+ .start = 0x28,
+ .end = 0x2b,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static const struct resource sun6i_a31_apb0_rstc_res[] = {
+ {
+ .start = 0xb0,
+ .end = 0xb3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
+ {
+ .name = "sun6i-a31-ar100-clk",
+ .of_compatible = "allwinner,sun6i-a31-ar100-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res),
+ .resources = sun6i_a31_ar100_clk_res,
+ },
+ {
+ .name = "sun6i-a31-apb0-clk",
+ .of_compatible = "allwinner,sun6i-a31-apb0-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
+ .resources = sun6i_a31_apb0_clk_res,
+ },
+ {
+ .name = "sun6i-a31-apb0-gates-clk",
+ .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
+ .resources = sun6i_a31_apb0_gates_clk_res,
+ },
+ {
+ .name = "sun6i-a31-apb0-clock-reset",
+ .of_compatible = "allwinner,sun6i-a31-clock-reset",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
+ .resources = sun6i_a31_apb0_rstc_res,
+ },
+};
+
+static const struct prcm_data sun6i_a31_prcm_data = {
+ .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
+ .subdevs = sun6i_a31_prcm_subdevs,
+};
+
+static const struct of_device_id sun6i_prcm_dt_ids[] = {
+ {
+ .compatible = "allwinner,sun6i-a31-prcm",
+ .data = &sun6i_a31_prcm_data,
+ },
+ { /* sentinel */ },
+};
+
+static int sun6i_prcm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ const struct prcm_data *data;
+ struct resource *res;
+ int ret;
+
+ match = of_match_node(sun6i_prcm_dt_ids, np);
+ if (!match)
+ return -EINVAL;
+
+ data = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no prcm memory region provided\n");
+ return -ENOENT;
+ }
+
+ ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs,
+ res, -1, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add subdevices\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver sun6i_prcm_driver = {
+ .driver = {
+ .name = "sun6i-prcm",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_prcm_dt_ids,
+ },
+ .probe = sun6i_prcm_probe,
+};
+module_platform_driver(sun6i_prcm_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
+MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
+MODULE_LICENSE("GPL v2");
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 2/5] mfd: sun6i-prcm: document DT bindings
2014-05-15 8:55 [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Boris BREZILLON
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2014-05-15 8:55 ` Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 3/5] clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support Boris BREZILLON
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge, kevin,
Hans de Goede, Randy Dunlap, devicetree, linux-doc,
linux-arm-kernel, dev, Boris BREZILLON
Document DT bindings of the PRCM (Power/Reset/Clock Management) unit.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
.../devicetree/bindings/mfd/sun6i-prcm.txt | 59 ++++++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
diff --git a/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
new file mode 100644
index 0000000..1f5a31f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
@@ -0,0 +1,59 @@
+* Allwinner PRCM (Power/Reset/Clock Management) Multi-Functional Device
+
+PRCM is an MFD device exposing several Power Management related devices
+(like clks and reset controllers).
+
+Required properties:
+ - compatible: "allwinner,sun6i-a31-prcm"
+ - reg: The PRCM registers range
+
+The prcm node may contain several subdevices definitions:
+ - see Documentation/devicetree/clk/sunxi.txt for clock devices
+ - see Documentation/devicetree/reset/allwinner,sunxi-clock-reset.txt for reset
+ controller devices
+
+
+Example:
+
+ prcm: prcm@01f01400 {
+ compatible = "allwinner,sun6i-a31-prcm";
+ reg = <0x01f01400 0x200>;
+
+ /* Put subdevices here */
+ ar100: ar100_clk {
+ compatible = "allwinner,sun6i-a31-ar100-clk";
+ #clock-cells = <0>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ };
+
+ ahb0: ahb0_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&ar100_div>;
+ clock-output-names = "ahb0";
+ };
+
+ apb0: apb0_clk {
+ compatible = "allwinner,sun6i-a31-apb0-clk";
+ #clock-cells = <0>;
+ clocks = <&ahb0>;
+ clock-output-names = "apb0";
+ };
+
+ apb0_gates: apb0_gates_clk {
+ compatible = "allwinner,sun6i-a31-apb0-gates-clk";
+ #clock-cells = <1>;
+ clocks = <&apb0>;
+ clock-output-names = "apb0_pio", "apb0_ir",
+ "apb0_timer01", "apb0_p2wi",
+ "apb0_uart", "apb0_1wire",
+ "apb0_i2c";
+ };
+
+ apb0_rst: apb0_rst {
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ #reset-cells = <1>;
+ };
+ };
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 3/5] clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support
2014-05-15 8:55 [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Boris BREZILLON
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2014-05-15 8:55 ` [PATCH v5 2/5] mfd: sun6i-prcm: document DT bindings Boris BREZILLON
@ 2014-05-15 8:55 ` Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 4/5] clk: sunxi: document PRCM clock compatible strings Boris BREZILLON
2014-05-15 15:33 ` [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Emilio López
4 siblings, 0 replies; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge, kevin,
Hans de Goede, Randy Dunlap, devicetree, linux-doc,
linux-arm-kernel, dev, Boris BREZILLON
The PRCM (Power/Reset/Clock Management) unit provides several clock
devices:
- AR100 clk: used to clock the Power Management co-processor
- AHB0 clk: used to clock the AHB0 bus
- APB0 clk and gates: used to clk peripherals connected to the APB0 bus
Add support for these clks in a separate driver so that they can be probed
as platform devices instead of registered during early init.
This is needed to be able to probe PRCM MFD subdevices.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/clk/sunxi/Makefile | 2 +
drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 99 +++++++++++++
drivers/clk/sunxi/clk-sun6i-apb0.c | 77 ++++++++++
drivers/clk/sunxi/clk-sun6i-ar100.c | 233 +++++++++++++++++++++++++++++++
4 files changed, 411 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-sun6i-apb0-gates.c
create mode 100644 drivers/clk/sunxi/clk-sun6i-apb0.c
create mode 100644 drivers/clk/sunxi/clk-sun6i-ar100.c
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index b5bac91..3d6c124 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -3,3 +3,5 @@
#
obj-y += clk-sunxi.o clk-factors.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-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
new file mode 100644
index 0000000..44cd27c
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 APB0 clock gates driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define SUN6I_APB0_GATES_MAX_SIZE 32
+
+static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct clk_onecell_data *clk_data;
+ const char *clk_parent;
+ const char *clk_name;
+ struct resource *r;
+ void __iomem *reg;
+ int gate_id;
+ int ngates;
+ int i;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (!reg)
+ return PTR_ERR(reg);
+
+ clk_parent = of_clk_get_parent_name(np, 0);
+ if (!clk_parent)
+ return -EINVAL;
+
+ ngates = of_property_count_strings(np, "clock-output-names");
+ if (ngates < 0)
+ return ngates;
+
+ if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE)
+ return -EINVAL;
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kzalloc(&pdev->dev,
+ SUN6I_APB0_GATES_MAX_SIZE *
+ sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < ngates; i++) {
+ of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+
+ gate_id = i;
+ of_property_read_u32_index(np, "clock-indices", i, &gate_id);
+
+ WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE);
+ if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE)
+ continue;
+
+ clk_data->clks[gate_id] = clk_register_gate(&pdev->dev,
+ clk_name,
+ clk_parent, 0,
+ reg, gate_id,
+ 0, NULL);
+ WARN_ON(IS_ERR(clk_data->clks[gate_id]));
+ }
+
+ clk_data->clk_num = ngates;
+
+ return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+}
+
+const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-apb0-gates-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids,
+ },
+ .probe = sun6i_a31_apb0_gates_clk_probe,
+};
+module_platform_driver(sun6i_a31_apb0_gates_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 APB0 gate clocks driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
new file mode 100644
index 0000000..11f17c3
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 APB0 clock driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+/*
+ * The APB0 clk has a configurable divisor.
+ *
+ * We must use a clk_div_table and not a regular power of 2
+ * divisor here, because the first 2 values divide the clock
+ * by 2.
+ */
+static const struct clk_div_table sun6i_a31_apb0_divs[] = {
+ { .val = 0, .div = 2, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 4, },
+ { .val = 3, .div = 8, },
+ { /* sentinel */ },
+};
+
+static int sun6i_a31_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;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ 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);
+
+ clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
+ 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
+ NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_apb0_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-apb0-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_apb0_clk_dt_ids,
+ },
+ .probe = sun6i_a31_apb0_clk_probe,
+};
+module_platform_driver(sun6i_a31_apb0_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 APB0 clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
new file mode 100644
index 0000000..f73cc05
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 AR100 clock driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define SUN6I_AR100_MAX_PARENTS 4
+#define SUN6I_AR100_SHIFT_MASK 0x3
+#define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK
+#define SUN6I_AR100_SHIFT_SHIFT 4
+#define SUN6I_AR100_DIV_MASK 0x1f
+#define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1)
+#define SUN6I_AR100_DIV_SHIFT 8
+#define SUN6I_AR100_MUX_MASK 0x3
+#define SUN6I_AR100_MUX_SHIFT 16
+
+struct ar100_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct ar100_clk, hw);
+}
+
+static unsigned long ar100_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+ int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK;
+ int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK;
+
+ return (parent_rate >> shift) / (div + 1);
+}
+
+static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk)
+{
+ int nparents = __clk_get_num_parents(hw->clk);
+ long best_rate = -EINVAL;
+ int i;
+
+ *best_parent_clk = NULL;
+
+ for (i = 0; i < nparents; i++) {
+ unsigned long parent_rate;
+ unsigned long tmp_rate;
+ struct clk *parent;
+ unsigned long div;
+ int shift;
+
+ parent = clk_get_parent_by_index(hw->clk, i);
+ parent_rate = __clk_get_rate(parent);
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /*
+ * The AR100 clk contains 2 divisors:
+ * - one power of 2 divisor
+ * - one regular divisor
+ *
+ * First check if we can safely shift (or divide by a power
+ * of 2) without losing precision on the requested rate.
+ */
+ shift = ffs(div) - 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ shift = SUN6I_AR100_SHIFT_MAX;
+
+ div >>= shift;
+
+ /*
+ * Then if the divisor is still bigger than what the HW
+ * actually supports, use a bigger shift (or power of 2
+ * divider) value and accept to lose some precision.
+ */
+ while (div > SUN6I_AR100_DIV_MAX) {
+ shift++;
+ div >>= 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ break;
+ }
+
+ /*
+ * If the shift value (or power of 2 divider) is bigger
+ * than what the HW actually support, skip this parent.
+ */
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ continue;
+
+ tmp_rate = (parent_rate >> shift) / div;
+ if (!*best_parent_clk || tmp_rate > best_rate) {
+ *best_parent_clk = parent;
+ *best_parent_rate = parent_rate;
+ best_rate = tmp_rate;
+ }
+ }
+
+ return best_rate;
+}
+
+static int ar100_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+
+ if (index >= SUN6I_AR100_MAX_PARENTS)
+ return -EINVAL;
+
+ val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT);
+ val |= (index << SUN6I_AR100_MUX_SHIFT);
+ writel(val, clk->reg);
+
+ return 0;
+}
+
+static u8 ar100_get_parent(struct clk_hw *hw)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) &
+ SUN6I_AR100_MUX_MASK;
+}
+
+static int ar100_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned long div = parent_rate / rate;
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+ int shift;
+
+ if (parent_rate % rate)
+ return -EINVAL;
+
+ shift = ffs(div) - 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ shift = SUN6I_AR100_SHIFT_MAX;
+
+ div >>= shift;
+
+ if (div > SUN6I_AR100_DIV_MAX)
+ return -EINVAL;
+
+ val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) |
+ (SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT));
+ val |= (shift << SUN6I_AR100_SHIFT_SHIFT) |
+ (div << SUN6I_AR100_DIV_SHIFT);
+ writel(val, clk->reg);
+
+ return 0;
+}
+
+struct clk_ops ar100_ops = {
+ .recalc_rate = ar100_recalc_rate,
+ .determine_rate = ar100_determine_rate,
+ .set_parent = ar100_set_parent,
+ .get_parent = ar100_get_parent,
+ .set_rate = ar100_set_rate,
+};
+
+static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
+{
+ const char *parents[SUN6I_AR100_MAX_PARENTS];
+ struct device_node *np = pdev->dev.of_node;
+ const char *clk_name = np->name;
+ struct clk_init_data init;
+ struct ar100_clk *ar100;
+ struct resource *r;
+ struct clk *clk;
+ int nparents;
+ int i;
+
+ ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
+ if (!ar100)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ar100->reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ar100->reg))
+ return PTR_ERR(ar100->reg);
+
+ nparents = of_clk_get_parent_count(np);
+ if (nparents > SUN6I_AR100_MAX_PARENTS)
+ nparents = SUN6I_AR100_MAX_PARENTS;
+
+ for (i = 0; i < nparents; i++)
+ parents[i] = of_clk_get_parent_name(np, i);
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &ar100_ops;
+ init.parent_names = parents;
+ init.num_parents = nparents;
+ init.flags = 0;
+
+ ar100->hw.init = &init;
+
+ clk = clk_register(&pdev->dev, &ar100->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-ar100-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_ar100_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-ar100-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_ar100_clk_dt_ids,
+ },
+ .probe = sun6i_a31_ar100_clk_probe,
+};
+module_platform_driver(sun6i_a31_ar100_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
+MODULE_LICENSE("GPL v2");
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 4/5] clk: sunxi: document PRCM clock compatible strings
2014-05-15 8:55 [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Boris BREZILLON
` (2 preceding siblings ...)
2014-05-15 8:55 ` [PATCH v5 3/5] clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support Boris BREZILLON
@ 2014-05-15 8:55 ` Boris BREZILLON
2014-05-15 15:33 ` [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Emilio López
4 siblings, 0 replies; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge, kevin,
Hans de Goede, Randy Dunlap, devicetree, linux-doc,
linux-arm-kernel, dev, Boris BREZILLON
Document new compatible strings for clock provided by the PRCM
(Power/Reset/Clock Management) unit.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index a5160d8..ffa1ab1 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -20,12 +20,15 @@ Required properties:
"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
"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,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
+ "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
+ "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
"allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 5/5] ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2014-05-15 8:55 ` [PATCH v5 1/5] mfd: add support for sun6i PRCM (Power/Reset/Clock Management) unit Boris BREZILLON
@ 2014-05-15 8:55 ` Boris BREZILLON
2014-05-15 15:30 ` Maxime Ripard
1 sibling, 1 reply; 8+ messages in thread
From: Boris BREZILLON @ 2014-05-15 8:55 UTC (permalink / raw)
To: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones
Cc: Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge,
kevin-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf, Hans de Goede,
Randy Dunlap, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dev-3kdeTeqwOZ9EV1b7eY7vFQ, Boris BREZILLON
Select the MFD_SUN6I_PRCM option when sun6i arch is enabled in order to get
the PRCM (Power/Reset/Clock Management) related drivers compiled.
Signed-off-by: Boris BREZILLON <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
arch/arm/mach-sunxi/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 3aff966..0fbd4f1 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -23,6 +23,7 @@ config MACH_SUN6I
default ARCH_SUNXI
select ARCH_HAS_RESET_CONTROLLER
select ARM_GIC
+ select MFD_SUN6I_PRCM
select RESET_CONTROLLER
select SUN5I_HSTIMER
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v5 5/5] ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled
2014-05-15 8:55 ` [PATCH v5 5/5] ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled Boris BREZILLON
@ 2014-05-15 15:30 ` Maxime Ripard
0 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-05-15 15:30 UTC (permalink / raw)
To: Boris BREZILLON
Cc: Emilio López, Mike Turquette, Samuel Ortiz, Lee Jones,
Chen-Yu Tsai, Philipp Zabel, Shuge, kevin, Hans de Goede,
Randy Dunlap, devicetree, linux-doc, linux-arm-kernel, dev
[-- Attachment #1: Type: text/plain, Size: 430 bytes --]
On Thu, May 15, 2014 at 10:55:13AM +0200, Boris BREZILLON wrote:
> Select the MFD_SUN6I_PRCM option when sun6i arch is enabled in order to get
> the PRCM (Power/Reset/Clock Management) related drivers compiled.
>
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Applied, thanks!
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] 8+ messages in thread
* Re: [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support
2014-05-15 8:55 [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Boris BREZILLON
` (3 preceding siblings ...)
2014-05-15 8:55 ` [PATCH v5 4/5] clk: sunxi: document PRCM clock compatible strings Boris BREZILLON
@ 2014-05-15 15:33 ` Emilio López
4 siblings, 0 replies; 8+ messages in thread
From: Emilio López @ 2014-05-15 15:33 UTC (permalink / raw)
To: Boris BREZILLON, Mike Turquette, Lee Jones
Cc: Samuel Ortiz, Chen-Yu Tsai, Maxime Ripard, Philipp Zabel, Shuge,
kevin, Hans de Goede, Randy Dunlap, devicetree, linux-doc,
linux-arm-kernel, dev
Hi Boris,
El 15/05/14 05:55, Boris BREZILLON escribió:
> Hello,
>
> This patch series adds support for some functions provided by the PRCM
> (Power/Reset/Clock Management) unit:
> - AR100, AHB0 and APB0 clocks
> - APB0 reset controller
(snip)
> clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support
> clk: sunxi: document PRCM clock compatible strings
I have taken these two on sunxi-clk-for-mike, and I'll be sending the
pull to Mike soon.
Cheers,
Emilio
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-05-15 15:33 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-15 8:55 [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Boris BREZILLON
[not found] ` <1400144113-27659-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2014-05-15 8:55 ` [PATCH v5 1/5] mfd: add support for sun6i PRCM (Power/Reset/Clock Management) unit Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 5/5] ARM: sunxi: select MFD_SUN6I_PRCM when sun6i arch support is enabled Boris BREZILLON
2014-05-15 15:30 ` Maxime Ripard
2014-05-15 8:55 ` [PATCH v5 2/5] mfd: sun6i-prcm: document DT bindings Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 3/5] clk: sunxi: add PRCM (Power/Reset/Clock Management) clks support Boris BREZILLON
2014-05-15 8:55 ` [PATCH v5 4/5] clk: sunxi: document PRCM clock compatible strings Boris BREZILLON
2014-05-15 15:33 ` [PATCH v5 0/5] mfd: add basic sun6i A31 PRCM support Emilio López
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).