1/*
2 * linux/arch/arm/mach-omap1/mcbsp.c
3 *
4 * Copyright (C) 2008 Instituto Nokia de Tecnologia
5 * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Multichannel mode not supported.
12 */
13#include <linux/ioport.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include <linux/omap-dma.h>
23#include <mach/mux.h>
24#include "soc.h"
25#include <linux/platform_data/asoc-ti-mcbsp.h>
26
27#include <mach/irqs.h>
28
29#include "iomap.h"
30
31#define DPS_RSTCT2_PER_EN	(1 << 0)
32#define DSP_RSTCT2_WD_PER_EN	(1 << 1)
33
34static int dsp_use;
35static struct clk *api_clk;
36static struct clk *dsp_clk;
37static struct platform_device **omap_mcbsp_devices;
38
39static void omap1_mcbsp_request(unsigned int id)
40{
41	/*
42	 * On 1510, 1610 and 1710, McBSP1 and McBSP3
43	 * are DSP public peripherals.
44	 */
45	if (id == 0 || id == 2) {
46		if (dsp_use++ == 0) {
47			api_clk = clk_get(NULL, "api_ck");
48			dsp_clk = clk_get(NULL, "dsp_ck");
49			if (!IS_ERR(api_clk) && !IS_ERR(dsp_clk)) {
50				clk_enable(api_clk);
51				clk_enable(dsp_clk);
52
53				/*
54				 * DSP external peripheral reset
55				 * FIXME: This should be moved to dsp code
56				 */
57				__raw_writew(__raw_readw(DSP_RSTCT2) | DPS_RSTCT2_PER_EN |
58						DSP_RSTCT2_WD_PER_EN, DSP_RSTCT2);
59			}
60		}
61	}
62}
63
64static void omap1_mcbsp_free(unsigned int id)
65{
66	if (id == 0 || id == 2) {
67		if (--dsp_use == 0) {
68			if (!IS_ERR(api_clk)) {
69				clk_disable(api_clk);
70				clk_put(api_clk);
71			}
72			if (!IS_ERR(dsp_clk)) {
73				clk_disable(dsp_clk);
74				clk_put(dsp_clk);
75			}
76		}
77	}
78}
79
80static struct omap_mcbsp_ops omap1_mcbsp_ops = {
81	.request	= omap1_mcbsp_request,
82	.free		= omap1_mcbsp_free,
83};
84
85#define OMAP7XX_MCBSP1_BASE	0xfffb1000
86#define OMAP7XX_MCBSP2_BASE	0xfffb1800
87
88#define OMAP1510_MCBSP1_BASE	0xe1011800
89#define OMAP1510_MCBSP2_BASE	0xfffb1000
90#define OMAP1510_MCBSP3_BASE	0xe1017000
91
92#define OMAP1610_MCBSP1_BASE	0xe1011800
93#define OMAP1610_MCBSP2_BASE	0xfffb1000
94#define OMAP1610_MCBSP3_BASE	0xe1017000
95
96#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
97struct resource omap7xx_mcbsp_res[][6] = {
98	{
99		{
100			.start = OMAP7XX_MCBSP1_BASE,
101			.end   = OMAP7XX_MCBSP1_BASE + SZ_256,
102			.flags = IORESOURCE_MEM,
103		},
104		{
105			.name  = "rx",
106			.start = INT_7XX_McBSP1RX,
107			.flags = IORESOURCE_IRQ,
108		},
109		{
110			.name  = "tx",
111			.start = INT_7XX_McBSP1TX,
112			.flags = IORESOURCE_IRQ,
113		},
114		{
115			.name  = "rx",
116			.start = 9,
117			.flags = IORESOURCE_DMA,
118		},
119		{
120			.name  = "tx",
121			.start = 8,
122			.flags = IORESOURCE_DMA,
123		},
124	},
125	{
126		{
127			.start = OMAP7XX_MCBSP2_BASE,
128			.end   = OMAP7XX_MCBSP2_BASE + SZ_256,
129			.flags = IORESOURCE_MEM,
130		},
131		{
132			.name  = "rx",
133			.start = INT_7XX_McBSP2RX,
134			.flags = IORESOURCE_IRQ,
135		},
136		{
137			.name  = "tx",
138			.start = INT_7XX_McBSP2TX,
139			.flags = IORESOURCE_IRQ,
140		},
141		{
142			.name  = "rx",
143			.start = 11,
144			.flags = IORESOURCE_DMA,
145		},
146		{
147			.name  = "tx",
148			.start = 10,
149			.flags = IORESOURCE_DMA,
150		},
151	},
152};
153
154#define omap7xx_mcbsp_res_0		omap7xx_mcbsp_res[0]
155
156static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = {
157	{
158		.ops		= &omap1_mcbsp_ops,
159	},
160	{
161		.ops		= &omap1_mcbsp_ops,
162	},
163};
164#define OMAP7XX_MCBSP_RES_SZ		ARRAY_SIZE(omap7xx_mcbsp_res[1])
165#define OMAP7XX_MCBSP_COUNT		ARRAY_SIZE(omap7xx_mcbsp_res)
166#else
167#define omap7xx_mcbsp_res_0		NULL
168#define omap7xx_mcbsp_pdata		NULL
169#define OMAP7XX_MCBSP_RES_SZ		0
170#define OMAP7XX_MCBSP_COUNT		0
171#endif
172
173#ifdef CONFIG_ARCH_OMAP15XX
174struct resource omap15xx_mcbsp_res[][6] = {
175	{
176		{
177			.start = OMAP1510_MCBSP1_BASE,
178			.end   = OMAP1510_MCBSP1_BASE + SZ_256,
179			.flags = IORESOURCE_MEM,
180		},
181		{
182			.name  = "rx",
183			.start = INT_McBSP1RX,
184			.flags = IORESOURCE_IRQ,
185		},
186		{
187			.name  = "tx",
188			.start = INT_McBSP1TX,
189			.flags = IORESOURCE_IRQ,
190		},
191		{
192			.name  = "rx",
193			.start = 9,
194			.flags = IORESOURCE_DMA,
195		},
196		{
197			.name  = "tx",
198			.start = 8,
199			.flags = IORESOURCE_DMA,
200		},
201	},
202	{
203		{
204			.start = OMAP1510_MCBSP2_BASE,
205			.end   = OMAP1510_MCBSP2_BASE + SZ_256,
206			.flags = IORESOURCE_MEM,
207		},
208		{
209			.name  = "rx",
210			.start = INT_1510_SPI_RX,
211			.flags = IORESOURCE_IRQ,
212		},
213		{
214			.name  = "tx",
215			.start = INT_1510_SPI_TX,
216			.flags = IORESOURCE_IRQ,
217		},
218		{
219			.name  = "rx",
220			.start = 17,
221			.flags = IORESOURCE_DMA,
222		},
223		{
224			.name  = "tx",
225			.start = 16,
226			.flags = IORESOURCE_DMA,
227		},
228	},
229	{
230		{
231			.start = OMAP1510_MCBSP3_BASE,
232			.end   = OMAP1510_MCBSP3_BASE + SZ_256,
233			.flags = IORESOURCE_MEM,
234		},
235		{
236			.name  = "rx",
237			.start = INT_McBSP3RX,
238			.flags = IORESOURCE_IRQ,
239		},
240		{
241			.name  = "tx",
242			.start = INT_McBSP3TX,
243			.flags = IORESOURCE_IRQ,
244		},
245		{
246			.name  = "rx",
247			.start = 11,
248			.flags = IORESOURCE_DMA,
249		},
250		{
251			.name  = "tx",
252			.start = 10,
253			.flags = IORESOURCE_DMA,
254		},
255	},
256};
257
258#define omap15xx_mcbsp_res_0		omap15xx_mcbsp_res[0]
259
260static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
261	{
262		.ops		= &omap1_mcbsp_ops,
263	},
264	{
265		.ops		= &omap1_mcbsp_ops,
266	},
267	{
268		.ops		= &omap1_mcbsp_ops,
269	},
270};
271#define OMAP15XX_MCBSP_RES_SZ		ARRAY_SIZE(omap15xx_mcbsp_res[1])
272#define OMAP15XX_MCBSP_COUNT		ARRAY_SIZE(omap15xx_mcbsp_res)
273#else
274#define omap15xx_mcbsp_res_0		NULL
275#define omap15xx_mcbsp_pdata		NULL
276#define OMAP15XX_MCBSP_RES_SZ		0
277#define OMAP15XX_MCBSP_COUNT		0
278#endif
279
280#ifdef CONFIG_ARCH_OMAP16XX
281struct resource omap16xx_mcbsp_res[][6] = {
282	{
283		{
284			.start = OMAP1610_MCBSP1_BASE,
285			.end   = OMAP1610_MCBSP1_BASE + SZ_256,
286			.flags = IORESOURCE_MEM,
287		},
288		{
289			.name  = "rx",
290			.start = INT_McBSP1RX,
291			.flags = IORESOURCE_IRQ,
292		},
293		{
294			.name  = "tx",
295			.start = INT_McBSP1TX,
296			.flags = IORESOURCE_IRQ,
297		},
298		{
299			.name  = "rx",
300			.start = 9,
301			.flags = IORESOURCE_DMA,
302		},
303		{
304			.name  = "tx",
305			.start = 8,
306			.flags = IORESOURCE_DMA,
307		},
308	},
309	{
310		{
311			.start = OMAP1610_MCBSP2_BASE,
312			.end   = OMAP1610_MCBSP2_BASE + SZ_256,
313			.flags = IORESOURCE_MEM,
314		},
315		{
316			.name  = "rx",
317			.start = INT_1610_McBSP2_RX,
318			.flags = IORESOURCE_IRQ,
319		},
320		{
321			.name  = "tx",
322			.start = INT_1610_McBSP2_TX,
323			.flags = IORESOURCE_IRQ,
324		},
325		{
326			.name  = "rx",
327			.start = 17,
328			.flags = IORESOURCE_DMA,
329		},
330		{
331			.name  = "tx",
332			.start = 16,
333			.flags = IORESOURCE_DMA,
334		},
335	},
336	{
337		{
338			.start = OMAP1610_MCBSP3_BASE,
339			.end   = OMAP1610_MCBSP3_BASE + SZ_256,
340			.flags = IORESOURCE_MEM,
341		},
342		{
343			.name  = "rx",
344			.start = INT_McBSP3RX,
345			.flags = IORESOURCE_IRQ,
346		},
347		{
348			.name  = "tx",
349			.start = INT_McBSP3TX,
350			.flags = IORESOURCE_IRQ,
351		},
352		{
353			.name  = "rx",
354			.start = 11,
355			.flags = IORESOURCE_DMA,
356		},
357		{
358			.name  = "tx",
359			.start = 10,
360			.flags = IORESOURCE_DMA,
361		},
362	},
363};
364
365#define omap16xx_mcbsp_res_0		omap16xx_mcbsp_res[0]
366
367static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
368	{
369		.ops		= &omap1_mcbsp_ops,
370	},
371	{
372		.ops		= &omap1_mcbsp_ops,
373	},
374	{
375		.ops		= &omap1_mcbsp_ops,
376	},
377};
378#define OMAP16XX_MCBSP_RES_SZ		ARRAY_SIZE(omap16xx_mcbsp_res[1])
379#define OMAP16XX_MCBSP_COUNT		ARRAY_SIZE(omap16xx_mcbsp_res)
380#else
381#define omap16xx_mcbsp_res_0		NULL
382#define omap16xx_mcbsp_pdata		NULL
383#define OMAP16XX_MCBSP_RES_SZ		0
384#define OMAP16XX_MCBSP_COUNT		0
385#endif
386
387static void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
388			struct omap_mcbsp_platform_data *config, int size)
389{
390	int i;
391
392	omap_mcbsp_devices = kzalloc(size * sizeof(struct platform_device *),
393				     GFP_KERNEL);
394	if (!omap_mcbsp_devices) {
395		printk(KERN_ERR "Could not register McBSP devices\n");
396		return;
397	}
398
399	for (i = 0; i < size; i++) {
400		struct platform_device *new_mcbsp;
401		int ret;
402
403		new_mcbsp = platform_device_alloc("omap-mcbsp", i + 1);
404		if (!new_mcbsp)
405			continue;
406		platform_device_add_resources(new_mcbsp, &res[i * res_count],
407					res_count);
408		config[i].reg_size = 2;
409		config[i].reg_step = 2;
410		new_mcbsp->dev.platform_data = &config[i];
411		ret = platform_device_add(new_mcbsp);
412		if (ret) {
413			platform_device_put(new_mcbsp);
414			continue;
415		}
416		omap_mcbsp_devices[i] = new_mcbsp;
417	}
418}
419
420static int __init omap1_mcbsp_init(void)
421{
422	if (!cpu_class_is_omap1())
423		return -ENODEV;
424
425	if (cpu_is_omap7xx())
426		omap_mcbsp_register_board_cfg(omap7xx_mcbsp_res_0,
427					OMAP7XX_MCBSP_RES_SZ,
428					omap7xx_mcbsp_pdata,
429					OMAP7XX_MCBSP_COUNT);
430
431	if (cpu_is_omap15xx())
432		omap_mcbsp_register_board_cfg(omap15xx_mcbsp_res_0,
433					OMAP15XX_MCBSP_RES_SZ,
434					omap15xx_mcbsp_pdata,
435					OMAP15XX_MCBSP_COUNT);
436
437	if (cpu_is_omap16xx())
438		omap_mcbsp_register_board_cfg(omap16xx_mcbsp_res_0,
439					OMAP16XX_MCBSP_RES_SZ,
440					omap16xx_mcbsp_pdata,
441					OMAP16XX_MCBSP_COUNT);
442
443	return 0;
444}
445
446arch_initcall(omap1_mcbsp_init);
447