1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/arch/arm/mach-omap1/mcbsp.c |
4 | * |
5 | * Copyright (C) 2008 Instituto Nokia de Tecnologia |
6 | * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br> |
7 | * |
8 | * Multichannel mode not supported. |
9 | */ |
10 | #include <linux/ioport.h> |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/err.h> |
15 | #include <linux/io.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/omap-dma.h> |
19 | #include <linux/soc/ti/omap1-io.h> |
20 | #include <linux/platform_data/asoc-ti-mcbsp.h> |
21 | |
22 | #include "mux.h" |
23 | #include "soc.h" |
24 | #include "irqs.h" |
25 | #include "iomap.h" |
26 | |
27 | #define DPS_RSTCT2_PER_EN (1 << 0) |
28 | #define DSP_RSTCT2_WD_PER_EN (1 << 1) |
29 | |
30 | static int dsp_use; |
31 | static struct clk *api_clk; |
32 | static struct clk *dsp_clk; |
33 | static struct platform_device **omap_mcbsp_devices; |
34 | |
35 | static void omap1_mcbsp_request(unsigned int id) |
36 | { |
37 | /* |
38 | * On 1510, 1610 and 1710, McBSP1 and McBSP3 |
39 | * are DSP public peripherals. |
40 | */ |
41 | if (id == 0 || id == 2) { |
42 | if (dsp_use++ == 0) { |
43 | api_clk = clk_get(NULL, id: "api_ck" ); |
44 | dsp_clk = clk_get(NULL, id: "dsp_ck" ); |
45 | if (!IS_ERR(ptr: api_clk) && !IS_ERR(ptr: dsp_clk)) { |
46 | clk_prepare_enable(clk: api_clk); |
47 | clk_prepare_enable(clk: dsp_clk); |
48 | |
49 | /* |
50 | * DSP external peripheral reset |
51 | * FIXME: This should be moved to dsp code |
52 | */ |
53 | __raw_writew(__raw_readw(DSP_RSTCT2) | DPS_RSTCT2_PER_EN | |
54 | DSP_RSTCT2_WD_PER_EN, DSP_RSTCT2); |
55 | } |
56 | } |
57 | } |
58 | } |
59 | |
60 | static void omap1_mcbsp_free(unsigned int id) |
61 | { |
62 | if (id == 0 || id == 2) { |
63 | if (--dsp_use == 0) { |
64 | if (!IS_ERR(ptr: api_clk)) { |
65 | clk_disable_unprepare(clk: api_clk); |
66 | clk_put(clk: api_clk); |
67 | } |
68 | if (!IS_ERR(ptr: dsp_clk)) { |
69 | clk_disable_unprepare(clk: dsp_clk); |
70 | clk_put(clk: dsp_clk); |
71 | } |
72 | } |
73 | } |
74 | } |
75 | |
76 | static struct omap_mcbsp_ops omap1_mcbsp_ops = { |
77 | .request = omap1_mcbsp_request, |
78 | .free = omap1_mcbsp_free, |
79 | }; |
80 | |
81 | #define OMAP7XX_MCBSP1_BASE 0xfffb1000 |
82 | #define OMAP7XX_MCBSP2_BASE 0xfffb1800 |
83 | |
84 | #define OMAP1510_MCBSP1_BASE 0xe1011800 |
85 | #define OMAP1510_MCBSP2_BASE 0xfffb1000 |
86 | #define OMAP1510_MCBSP3_BASE 0xe1017000 |
87 | |
88 | #define OMAP1610_MCBSP1_BASE 0xe1011800 |
89 | #define OMAP1610_MCBSP2_BASE 0xfffb1000 |
90 | #define OMAP1610_MCBSP3_BASE 0xe1017000 |
91 | |
92 | struct resource omap15xx_mcbsp_res[][6] = { |
93 | { |
94 | { |
95 | .start = OMAP1510_MCBSP1_BASE, |
96 | .end = OMAP1510_MCBSP1_BASE + SZ_256, |
97 | .flags = IORESOURCE_MEM, |
98 | }, |
99 | { |
100 | .name = "rx" , |
101 | .start = INT_McBSP1RX, |
102 | .flags = IORESOURCE_IRQ, |
103 | }, |
104 | { |
105 | .name = "tx" , |
106 | .start = INT_McBSP1TX, |
107 | .flags = IORESOURCE_IRQ, |
108 | }, |
109 | { |
110 | .name = "rx" , |
111 | .start = 9, |
112 | .flags = IORESOURCE_DMA, |
113 | }, |
114 | { |
115 | .name = "tx" , |
116 | .start = 8, |
117 | .flags = IORESOURCE_DMA, |
118 | }, |
119 | }, |
120 | { |
121 | { |
122 | .start = OMAP1510_MCBSP2_BASE, |
123 | .end = OMAP1510_MCBSP2_BASE + SZ_256, |
124 | .flags = IORESOURCE_MEM, |
125 | }, |
126 | { |
127 | .name = "rx" , |
128 | .start = INT_1510_SPI_RX, |
129 | .flags = IORESOURCE_IRQ, |
130 | }, |
131 | { |
132 | .name = "tx" , |
133 | .start = INT_1510_SPI_TX, |
134 | .flags = IORESOURCE_IRQ, |
135 | }, |
136 | { |
137 | .name = "rx" , |
138 | .start = 17, |
139 | .flags = IORESOURCE_DMA, |
140 | }, |
141 | { |
142 | .name = "tx" , |
143 | .start = 16, |
144 | .flags = IORESOURCE_DMA, |
145 | }, |
146 | }, |
147 | { |
148 | { |
149 | .start = OMAP1510_MCBSP3_BASE, |
150 | .end = OMAP1510_MCBSP3_BASE + SZ_256, |
151 | .flags = IORESOURCE_MEM, |
152 | }, |
153 | { |
154 | .name = "rx" , |
155 | .start = INT_McBSP3RX, |
156 | .flags = IORESOURCE_IRQ, |
157 | }, |
158 | { |
159 | .name = "tx" , |
160 | .start = INT_McBSP3TX, |
161 | .flags = IORESOURCE_IRQ, |
162 | }, |
163 | { |
164 | .name = "rx" , |
165 | .start = 11, |
166 | .flags = IORESOURCE_DMA, |
167 | }, |
168 | { |
169 | .name = "tx" , |
170 | .start = 10, |
171 | .flags = IORESOURCE_DMA, |
172 | }, |
173 | }, |
174 | }; |
175 | |
176 | #define omap15xx_mcbsp_res_0 omap15xx_mcbsp_res[0] |
177 | |
178 | static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { |
179 | { |
180 | .ops = &omap1_mcbsp_ops, |
181 | }, |
182 | { |
183 | .ops = &omap1_mcbsp_ops, |
184 | }, |
185 | { |
186 | .ops = &omap1_mcbsp_ops, |
187 | }, |
188 | }; |
189 | #define OMAP15XX_MCBSP_RES_SZ ARRAY_SIZE(omap15xx_mcbsp_res[1]) |
190 | #define OMAP15XX_MCBSP_COUNT ARRAY_SIZE(omap15xx_mcbsp_res) |
191 | |
192 | struct resource omap16xx_mcbsp_res[][6] = { |
193 | { |
194 | { |
195 | .start = OMAP1610_MCBSP1_BASE, |
196 | .end = OMAP1610_MCBSP1_BASE + SZ_256, |
197 | .flags = IORESOURCE_MEM, |
198 | }, |
199 | { |
200 | .name = "rx" , |
201 | .start = INT_McBSP1RX, |
202 | .flags = IORESOURCE_IRQ, |
203 | }, |
204 | { |
205 | .name = "tx" , |
206 | .start = INT_McBSP1TX, |
207 | .flags = IORESOURCE_IRQ, |
208 | }, |
209 | { |
210 | .name = "rx" , |
211 | .start = 9, |
212 | .flags = IORESOURCE_DMA, |
213 | }, |
214 | { |
215 | .name = "tx" , |
216 | .start = 8, |
217 | .flags = IORESOURCE_DMA, |
218 | }, |
219 | }, |
220 | { |
221 | { |
222 | .start = OMAP1610_MCBSP2_BASE, |
223 | .end = OMAP1610_MCBSP2_BASE + SZ_256, |
224 | .flags = IORESOURCE_MEM, |
225 | }, |
226 | { |
227 | .name = "rx" , |
228 | .start = INT_1610_McBSP2_RX, |
229 | .flags = IORESOURCE_IRQ, |
230 | }, |
231 | { |
232 | .name = "tx" , |
233 | .start = INT_1610_McBSP2_TX, |
234 | .flags = IORESOURCE_IRQ, |
235 | }, |
236 | { |
237 | .name = "rx" , |
238 | .start = 17, |
239 | .flags = IORESOURCE_DMA, |
240 | }, |
241 | { |
242 | .name = "tx" , |
243 | .start = 16, |
244 | .flags = IORESOURCE_DMA, |
245 | }, |
246 | }, |
247 | { |
248 | { |
249 | .start = OMAP1610_MCBSP3_BASE, |
250 | .end = OMAP1610_MCBSP3_BASE + SZ_256, |
251 | .flags = IORESOURCE_MEM, |
252 | }, |
253 | { |
254 | .name = "rx" , |
255 | .start = INT_McBSP3RX, |
256 | .flags = IORESOURCE_IRQ, |
257 | }, |
258 | { |
259 | .name = "tx" , |
260 | .start = INT_McBSP3TX, |
261 | .flags = IORESOURCE_IRQ, |
262 | }, |
263 | { |
264 | .name = "rx" , |
265 | .start = 11, |
266 | .flags = IORESOURCE_DMA, |
267 | }, |
268 | { |
269 | .name = "tx" , |
270 | .start = 10, |
271 | .flags = IORESOURCE_DMA, |
272 | }, |
273 | }, |
274 | }; |
275 | |
276 | #define omap16xx_mcbsp_res_0 omap16xx_mcbsp_res[0] |
277 | |
278 | static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { |
279 | { |
280 | .ops = &omap1_mcbsp_ops, |
281 | }, |
282 | { |
283 | .ops = &omap1_mcbsp_ops, |
284 | }, |
285 | { |
286 | .ops = &omap1_mcbsp_ops, |
287 | }, |
288 | }; |
289 | #define OMAP16XX_MCBSP_RES_SZ ARRAY_SIZE(omap16xx_mcbsp_res[1]) |
290 | #define OMAP16XX_MCBSP_COUNT ARRAY_SIZE(omap16xx_mcbsp_res) |
291 | |
292 | static void omap_mcbsp_register_board_cfg(struct resource *res, int res_count, |
293 | struct omap_mcbsp_platform_data *config, int size) |
294 | { |
295 | int i; |
296 | |
297 | omap_mcbsp_devices = kcalloc(n: size, size: sizeof(struct platform_device *), |
298 | GFP_KERNEL); |
299 | if (!omap_mcbsp_devices) { |
300 | printk(KERN_ERR "Could not register McBSP devices\n" ); |
301 | return; |
302 | } |
303 | |
304 | for (i = 0; i < size; i++) { |
305 | struct platform_device *new_mcbsp; |
306 | int ret; |
307 | |
308 | new_mcbsp = platform_device_alloc(name: "omap-mcbsp" , id: i + 1); |
309 | if (!new_mcbsp) |
310 | continue; |
311 | platform_device_add_resources(pdev: new_mcbsp, res: &res[i * res_count], |
312 | num: res_count); |
313 | config[i].reg_size = 2; |
314 | config[i].reg_step = 2; |
315 | new_mcbsp->dev.platform_data = &config[i]; |
316 | ret = platform_device_add(pdev: new_mcbsp); |
317 | if (ret) { |
318 | platform_device_put(pdev: new_mcbsp); |
319 | continue; |
320 | } |
321 | omap_mcbsp_devices[i] = new_mcbsp; |
322 | } |
323 | } |
324 | |
325 | static int __init omap1_mcbsp_init(void) |
326 | { |
327 | if (!cpu_class_is_omap1()) |
328 | return -ENODEV; |
329 | |
330 | if (cpu_is_omap15xx()) |
331 | omap_mcbsp_register_board_cfg(omap15xx_mcbsp_res_0, |
332 | OMAP15XX_MCBSP_RES_SZ, |
333 | config: omap15xx_mcbsp_pdata, |
334 | OMAP15XX_MCBSP_COUNT); |
335 | |
336 | if (cpu_is_omap16xx()) |
337 | omap_mcbsp_register_board_cfg(omap16xx_mcbsp_res_0, |
338 | OMAP16XX_MCBSP_RES_SZ, |
339 | config: omap16xx_mcbsp_pdata, |
340 | OMAP16XX_MCBSP_COUNT); |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | arch_initcall(omap1_mcbsp_init); |
346 | |