aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris BREZILLON <boris.brezillon@free-electrons.com>2014-05-09 07:11:47 -0400
committerLee Jones <lee.jones@linaro.org>2014-06-03 03:11:40 -0400
commitd58603cc304b717707e8f8ff05bf6aff9d9c82b5 (patch)
treee9a93f788e1b07a9db34439decbb64e1c3df7491
parente4e3d1b03695c458a954954c8efae745517dd44d (diff)
mfd: Add support for sun6i PRCM (Power/Reset/Clock Management) unit
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@free-electrons.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/sun6i-prcm.c134
3 files changed, 143 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c681741ce492..e56fb3749bca 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -732,6 +732,14 @@ config MFD_STA2X11
732 select MFD_CORE 732 select MFD_CORE
733 select REGMAP_MMIO 733 select REGMAP_MMIO
734 734
735config MFD_SUN6I_PRCM
736 bool "Allwinner A31 PRCM controller"
737 depends on ARCH_SUNXI
738 select MFD_CORE
739 help
740 Support for the PRCM (Power/Reset/Clock Management) unit available
741 in A31 SoC.
742
735config MFD_SYSCON 743config MFD_SYSCON
736 bool "System Controller Register R/W Based on Regmap" 744 bool "System Controller Register R/W Based on Regmap"
737 select REGMAP_MMIO 745 select REGMAP_MMIO
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1efecf2793ae..df7823cae5af 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
29obj-$(CONFIG_MFD_STMPE) += stmpe.o 29obj-$(CONFIG_MFD_STMPE) += stmpe.o
30obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o 30obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
31obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o 31obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
32obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o
32obj-$(CONFIG_MFD_TC3589X) += tc3589x.o 33obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
33obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o 34obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
34obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o 35obj-$(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 000000000000..718fc4d2adc0
--- /dev/null
+++ b/drivers/mfd/sun6i-prcm.c
@@ -0,0 +1,134 @@
1/*
2 * Copyright (C) 2014 Free Electrons
3 *
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * Allwinner PRCM (Power/Reset/Clock Management) driver
8 *
9 */
10
11#include <linux/mfd/core.h>
12#include <linux/module.h>
13#include <linux/of.h>
14
15struct prcm_data {
16 int nsubdevs;
17 const struct mfd_cell *subdevs;
18};
19
20static const struct resource sun6i_a31_ar100_clk_res[] = {
21 {
22 .start = 0x0,
23 .end = 0x3,
24 .flags = IORESOURCE_MEM,
25 },
26};
27
28static const struct resource sun6i_a31_apb0_clk_res[] = {
29 {
30 .start = 0xc,
31 .end = 0xf,
32 .flags = IORESOURCE_MEM,
33 },
34};
35
36static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
37 {
38 .start = 0x28,
39 .end = 0x2b,
40 .flags = IORESOURCE_MEM,
41 },
42};
43
44static const struct resource sun6i_a31_apb0_rstc_res[] = {
45 {
46 .start = 0xb0,
47 .end = 0xb3,
48 .flags = IORESOURCE_MEM,
49 },
50};
51
52static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
53 {
54 .name = "sun6i-a31-ar100-clk",
55 .of_compatible = "allwinner,sun6i-a31-ar100-clk",
56 .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res),
57 .resources = sun6i_a31_ar100_clk_res,
58 },
59 {
60 .name = "sun6i-a31-apb0-clk",
61 .of_compatible = "allwinner,sun6i-a31-apb0-clk",
62 .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
63 .resources = sun6i_a31_apb0_clk_res,
64 },
65 {
66 .name = "sun6i-a31-apb0-gates-clk",
67 .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk",
68 .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
69 .resources = sun6i_a31_apb0_gates_clk_res,
70 },
71 {
72 .name = "sun6i-a31-apb0-clock-reset",
73 .of_compatible = "allwinner,sun6i-a31-clock-reset",
74 .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
75 .resources = sun6i_a31_apb0_rstc_res,
76 },
77};
78
79static const struct prcm_data sun6i_a31_prcm_data = {
80 .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
81 .subdevs = sun6i_a31_prcm_subdevs,
82};
83
84static const struct of_device_id sun6i_prcm_dt_ids[] = {
85 {
86 .compatible = "allwinner,sun6i-a31-prcm",
87 .data = &sun6i_a31_prcm_data,
88 },
89 { /* sentinel */ },
90};
91
92static int sun6i_prcm_probe(struct platform_device *pdev)
93{
94 struct device_node *np = pdev->dev.of_node;
95 const struct of_device_id *match;
96 const struct prcm_data *data;
97 struct resource *res;
98 int ret;
99
100 match = of_match_node(sun6i_prcm_dt_ids, np);
101 if (!match)
102 return -EINVAL;
103
104 data = match->data;
105
106 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
107 if (!res) {
108 dev_err(&pdev->dev, "no prcm memory region provided\n");
109 return -ENOENT;
110 }
111
112 ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs,
113 res, -1, NULL);
114 if (ret) {
115 dev_err(&pdev->dev, "failed to add subdevices\n");
116 return ret;
117 }
118
119 return 0;
120}
121
122static struct platform_driver sun6i_prcm_driver = {
123 .driver = {
124 .name = "sun6i-prcm",
125 .owner = THIS_MODULE,
126 .of_match_table = sun6i_prcm_dt_ids,
127 },
128 .probe = sun6i_prcm_probe,
129};
130module_platform_driver(sun6i_prcm_driver);
131
132MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
133MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
134MODULE_LICENSE("GPL v2");