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
30static int dsp_use;
31static struct clk *api_clk;
32static struct clk *dsp_clk;
33static struct platform_device **omap_mcbsp_devices;
34
35static 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, "api_ck");
44			dsp_clk = clk_get(NULL, "dsp_ck");
45			if (!IS_ERR(api_clk) && !IS_ERR(dsp_clk)) {
46				clk_prepare_enable(api_clk);
47				clk_prepare_enable(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
60static void omap1_mcbsp_free(unsigned int id)
61{
62	if (id == 0 || id == 2) {
63		if (--dsp_use == 0) {
64			if (!IS_ERR(api_clk)) {
65				clk_disable_unprepare(api_clk);
66				clk_put(api_clk);
67			}
68			if (!IS_ERR(dsp_clk)) {
69				clk_disable_unprepare(dsp_clk);
70				clk_put(dsp_clk);
71			}
72		}
73	}
74}
75
76static 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
92struct 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
178static 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
192struct 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
278static 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
292static 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(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("omap-mcbsp", i + 1);
309		if (!new_mcbsp)
310			continue;
311		platform_device_add_resources(new_mcbsp, &res[i * res_count],
312					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(new_mcbsp);
317		if (ret) {
318			platform_device_put(new_mcbsp);
319			continue;
320		}
321		omap_mcbsp_devices[i] = new_mcbsp;
322	}
323}
324
325static 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					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					omap16xx_mcbsp_pdata,
340					OMAP16XX_MCBSP_COUNT);
341
342	return 0;
343}
344
345arch_initcall(omap1_mcbsp_init);
346