2 * Copyright (C) 2014 Free Electrons
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
7 * Allwinner PRCM (Power/Reset/Clock Management) driver
11 #include <linux/mfd/core.h>
12 #include <linux/init.h>
15 #define SUN8I_CODEC_ANALOG_BASE 0x1c0
16 #define SUN8I_CODEC_ANALOG_SIZE 0x4
20 const struct mfd_cell
*subdevs
;
23 static const struct resource sun6i_a31_ar100_clk_res
[] = {
27 .flags
= IORESOURCE_MEM
,
31 static const struct resource sun6i_a31_apb0_clk_res
[] = {
35 .flags
= IORESOURCE_MEM
,
39 static const struct resource sun6i_a31_apb0_gates_clk_res
[] = {
43 .flags
= IORESOURCE_MEM
,
47 static const struct resource sun6i_a31_ir_clk_res
[] = {
51 .flags
= IORESOURCE_MEM
,
55 static const struct resource sun6i_a31_apb0_rstc_res
[] = {
59 .flags
= IORESOURCE_MEM
,
63 static const struct resource sun8i_codec_analog_res
[] = {
64 DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE
, SUN8I_CODEC_ANALOG_SIZE
),
67 static const struct mfd_cell sun6i_a31_prcm_subdevs
[] = {
69 .name
= "sun6i-a31-ar100-clk",
70 .of_compatible
= "allwinner,sun6i-a31-ar100-clk",
71 .num_resources
= ARRAY_SIZE(sun6i_a31_ar100_clk_res
),
72 .resources
= sun6i_a31_ar100_clk_res
,
75 .name
= "sun6i-a31-apb0-clk",
76 .of_compatible
= "allwinner,sun6i-a31-apb0-clk",
77 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_clk_res
),
78 .resources
= sun6i_a31_apb0_clk_res
,
81 .name
= "sun6i-a31-apb0-gates-clk",
82 .of_compatible
= "allwinner,sun6i-a31-apb0-gates-clk",
83 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res
),
84 .resources
= sun6i_a31_apb0_gates_clk_res
,
87 .name
= "sun6i-a31-ir-clk",
88 .of_compatible
= "allwinner,sun4i-a10-mod0-clk",
89 .num_resources
= ARRAY_SIZE(sun6i_a31_ir_clk_res
),
90 .resources
= sun6i_a31_ir_clk_res
,
93 .name
= "sun6i-a31-apb0-clock-reset",
94 .of_compatible
= "allwinner,sun6i-a31-clock-reset",
95 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_rstc_res
),
96 .resources
= sun6i_a31_apb0_rstc_res
,
100 static const struct mfd_cell sun8i_a23_prcm_subdevs
[] = {
102 .name
= "sun8i-a23-apb0-clk",
103 .of_compatible
= "allwinner,sun8i-a23-apb0-clk",
104 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_clk_res
),
105 .resources
= sun6i_a31_apb0_clk_res
,
108 .name
= "sun6i-a31-apb0-gates-clk",
109 .of_compatible
= "allwinner,sun8i-a23-apb0-gates-clk",
110 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res
),
111 .resources
= sun6i_a31_apb0_gates_clk_res
,
114 .name
= "sun6i-a31-apb0-clock-reset",
115 .of_compatible
= "allwinner,sun6i-a31-clock-reset",
116 .num_resources
= ARRAY_SIZE(sun6i_a31_apb0_rstc_res
),
117 .resources
= sun6i_a31_apb0_rstc_res
,
120 .name
= "sun8i-codec-analog",
121 .of_compatible
= "allwinner,sun8i-a23-codec-analog",
122 .num_resources
= ARRAY_SIZE(sun8i_codec_analog_res
),
123 .resources
= sun8i_codec_analog_res
,
127 static const struct prcm_data sun6i_a31_prcm_data
= {
128 .nsubdevs
= ARRAY_SIZE(sun6i_a31_prcm_subdevs
),
129 .subdevs
= sun6i_a31_prcm_subdevs
,
132 static const struct prcm_data sun8i_a23_prcm_data
= {
133 .nsubdevs
= ARRAY_SIZE(sun8i_a23_prcm_subdevs
),
134 .subdevs
= sun8i_a23_prcm_subdevs
,
137 static const struct of_device_id sun6i_prcm_dt_ids
[] = {
139 .compatible
= "allwinner,sun6i-a31-prcm",
140 .data
= &sun6i_a31_prcm_data
,
143 .compatible
= "allwinner,sun8i-a23-prcm",
144 .data
= &sun8i_a23_prcm_data
,
149 static int sun6i_prcm_probe(struct platform_device
*pdev
)
151 struct device_node
*np
= pdev
->dev
.of_node
;
152 const struct of_device_id
*match
;
153 const struct prcm_data
*data
;
154 struct resource
*res
;
157 match
= of_match_node(sun6i_prcm_dt_ids
, np
);
163 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
165 dev_err(&pdev
->dev
, "no prcm memory region provided\n");
169 ret
= mfd_add_devices(&pdev
->dev
, 0, data
->subdevs
, data
->nsubdevs
,
172 dev_err(&pdev
->dev
, "failed to add subdevices\n");
179 static struct platform_driver sun6i_prcm_driver
= {
181 .name
= "sun6i-prcm",
182 .of_match_table
= sun6i_prcm_dt_ids
,
184 .probe
= sun6i_prcm_probe
,
186 builtin_platform_driver(sun6i_prcm_driver
);