mcbsp.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /*
  2. * linux/arch/arm/omap/mcbsp.c
  3. *
  4. * Copyright (C) 2004 Nokia Corporation
  5. * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
  6. *
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. *
  12. * Multichannel mode not supported.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/init.h>
  16. #include <linux/device.h>
  17. #include <linux/wait.h>
  18. #include <linux/completion.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/err.h>
  21. #include <asm/delay.h>
  22. #include <asm/io.h>
  23. #include <asm/irq.h>
  24. #include <asm/arch/dma.h>
  25. #include <asm/arch/mux.h>
  26. #include <asm/arch/irqs.h>
  27. #include <asm/arch/mcbsp.h>
  28. #include <asm/hardware/clock.h>
  29. #ifdef CONFIG_MCBSP_DEBUG
  30. #define DBG(x...) printk(x)
  31. #else
  32. #define DBG(x...) do { } while (0)
  33. #endif
  34. struct omap_mcbsp {
  35. u32 io_base;
  36. u8 id;
  37. u8 free;
  38. omap_mcbsp_word_length rx_word_length;
  39. omap_mcbsp_word_length tx_word_length;
  40. /* IRQ based TX/RX */
  41. int rx_irq;
  42. int tx_irq;
  43. /* DMA stuff */
  44. u8 dma_rx_sync;
  45. short dma_rx_lch;
  46. u8 dma_tx_sync;
  47. short dma_tx_lch;
  48. /* Completion queues */
  49. struct completion tx_irq_completion;
  50. struct completion rx_irq_completion;
  51. struct completion tx_dma_completion;
  52. struct completion rx_dma_completion;
  53. spinlock_t lock;
  54. };
  55. static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
  56. static struct clk *mcbsp_dsp_ck = 0;
  57. static struct clk *mcbsp_api_ck = 0;
  58. static void omap_mcbsp_dump_reg(u8 id)
  59. {
  60. DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
  61. DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
  62. DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
  63. DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
  64. DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
  65. DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
  66. DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
  67. DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
  68. DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
  69. DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
  70. DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
  71. DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
  72. DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
  73. DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
  74. DBG("***********************\n");
  75. }
  76. static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
  77. {
  78. struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
  79. DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
  80. complete(&mcbsp_tx->tx_irq_completion);
  81. return IRQ_HANDLED;
  82. }
  83. static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
  84. {
  85. struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
  86. DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
  87. complete(&mcbsp_rx->rx_irq_completion);
  88. return IRQ_HANDLED;
  89. }
  90. static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
  91. {
  92. struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
  93. DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
  94. /* We can free the channels */
  95. omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
  96. mcbsp_dma_tx->dma_tx_lch = -1;
  97. complete(&mcbsp_dma_tx->tx_dma_completion);
  98. }
  99. static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
  100. {
  101. struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
  102. DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
  103. /* We can free the channels */
  104. omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
  105. mcbsp_dma_rx->dma_rx_lch = -1;
  106. complete(&mcbsp_dma_rx->rx_dma_completion);
  107. }
  108. /*
  109. * omap_mcbsp_config simply write a config to the
  110. * appropriate McBSP.
  111. * You either call this function or set the McBSP registers
  112. * by yourself before calling omap_mcbsp_start().
  113. */
  114. void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
  115. {
  116. u32 io_base = mcbsp[id].io_base;
  117. DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base);
  118. /* We write the given config */
  119. OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
  120. OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
  121. OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);
  122. OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);
  123. OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);
  124. OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);
  125. OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
  126. OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
  127. OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2);
  128. OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
  129. OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
  130. }
  131. static int omap_mcbsp_check(unsigned int id)
  132. {
  133. if (cpu_is_omap730()) {
  134. if (id > OMAP_MAX_MCBSP_COUNT - 1) {
  135. printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
  136. return -1;
  137. }
  138. return 0;
  139. }
  140. if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
  141. if (id > OMAP_MAX_MCBSP_COUNT) {
  142. printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
  143. return -1;
  144. }
  145. return 0;
  146. }
  147. return -1;
  148. }
  149. #define EN_XORPCK 1
  150. #define DSP_RSTCT2 0xe1008014
  151. static void omap_mcbsp_dsp_request(void)
  152. {
  153. if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
  154. omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
  155. ARM_RSTCT1);
  156. clk_enable(mcbsp_dsp_ck);
  157. clk_enable(mcbsp_api_ck);
  158. /* enable 12MHz clock to mcbsp 1 & 3 */
  159. __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
  160. DSP_IDLECT2);
  161. __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
  162. DSP_RSTCT2);
  163. }
  164. }
  165. static void omap_mcbsp_dsp_free(void)
  166. {
  167. /* Useless for now */
  168. }
  169. int omap_mcbsp_request(unsigned int id)
  170. {
  171. int err;
  172. if (omap_mcbsp_check(id) < 0)
  173. return -EINVAL;
  174. /*
  175. * On 1510, 1610 and 1710, McBSP1 and McBSP3
  176. * are DSP public peripherals.
  177. */
  178. if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
  179. omap_mcbsp_dsp_request();
  180. spin_lock(&mcbsp[id].lock);
  181. if (!mcbsp[id].free) {
  182. printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
  183. spin_unlock(&mcbsp[id].lock);
  184. return -1;
  185. }
  186. mcbsp[id].free = 0;
  187. spin_unlock(&mcbsp[id].lock);
  188. /* We need to get IRQs here */
  189. err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
  190. "McBSP",
  191. (void *) (&mcbsp[id]));
  192. if (err != 0) {
  193. printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
  194. mcbsp[id].tx_irq, mcbsp[id].id);
  195. return err;
  196. }
  197. init_completion(&(mcbsp[id].tx_irq_completion));
  198. err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
  199. "McBSP",
  200. (void *) (&mcbsp[id]));
  201. if (err != 0) {
  202. printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
  203. mcbsp[id].rx_irq, mcbsp[id].id);
  204. free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
  205. return err;
  206. }
  207. init_completion(&(mcbsp[id].rx_irq_completion));
  208. return 0;
  209. }
  210. void omap_mcbsp_free(unsigned int id)
  211. {
  212. if (omap_mcbsp_check(id) < 0)
  213. return;
  214. if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
  215. omap_mcbsp_dsp_free();
  216. spin_lock(&mcbsp[id].lock);
  217. if (mcbsp[id].free) {
  218. printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
  219. spin_unlock(&mcbsp[id].lock);
  220. return;
  221. }
  222. mcbsp[id].free = 1;
  223. spin_unlock(&mcbsp[id].lock);
  224. /* Free IRQs */
  225. free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
  226. free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
  227. }
  228. /*
  229. * Here we start the McBSP, by enabling the sample
  230. * generator, both transmitter and receivers,
  231. * and the frame sync.
  232. */
  233. void omap_mcbsp_start(unsigned int id)
  234. {
  235. u32 io_base;
  236. u16 w;
  237. if (omap_mcbsp_check(id) < 0)
  238. return;
  239. io_base = mcbsp[id].io_base;
  240. mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
  241. mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
  242. /* Start the sample generator */
  243. w = OMAP_MCBSP_READ(io_base, SPCR2);
  244. OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
  245. /* Enable transmitter and receiver */
  246. w = OMAP_MCBSP_READ(io_base, SPCR2);
  247. OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
  248. w = OMAP_MCBSP_READ(io_base, SPCR1);
  249. OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
  250. udelay(100);
  251. /* Start frame sync */
  252. w = OMAP_MCBSP_READ(io_base, SPCR2);
  253. OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
  254. /* Dump McBSP Regs */
  255. omap_mcbsp_dump_reg(id);
  256. }
  257. void omap_mcbsp_stop(unsigned int id)
  258. {
  259. u32 io_base;
  260. u16 w;
  261. if (omap_mcbsp_check(id) < 0)
  262. return;
  263. io_base = mcbsp[id].io_base;
  264. /* Reset transmitter */
  265. w = OMAP_MCBSP_READ(io_base, SPCR2);
  266. OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
  267. /* Reset receiver */
  268. w = OMAP_MCBSP_READ(io_base, SPCR1);
  269. OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
  270. /* Reset the sample rate generator */
  271. w = OMAP_MCBSP_READ(io_base, SPCR2);
  272. OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
  273. }
  274. /*
  275. * IRQ based word transmission.
  276. */
  277. void omap_mcbsp_xmit_word(unsigned int id, u32 word)
  278. {
  279. u32 io_base;
  280. omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
  281. if (omap_mcbsp_check(id) < 0)
  282. return;
  283. io_base = mcbsp[id].io_base;
  284. wait_for_completion(&(mcbsp[id].tx_irq_completion));
  285. if (word_length > OMAP_MCBSP_WORD_16)
  286. OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
  287. OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
  288. }
  289. u32 omap_mcbsp_recv_word(unsigned int id)
  290. {
  291. u32 io_base;
  292. u16 word_lsb, word_msb = 0;
  293. omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
  294. if (omap_mcbsp_check(id) < 0)
  295. return -EINVAL;
  296. io_base = mcbsp[id].io_base;
  297. wait_for_completion(&(mcbsp[id].rx_irq_completion));
  298. if (word_length > OMAP_MCBSP_WORD_16)
  299. word_msb = OMAP_MCBSP_READ(io_base, DRR2);
  300. word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
  301. return (word_lsb | (word_msb << 16));
  302. }
  303. /*
  304. * Simple DMA based buffer rx/tx routines.
  305. * Nothing fancy, just a single buffer tx/rx through DMA.
  306. * The DMA resources are released once the transfer is done.
  307. * For anything fancier, you should use your own customized DMA
  308. * routines and callbacks.
  309. */
  310. int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
  311. {
  312. int dma_tx_ch;
  313. if (omap_mcbsp_check(id) < 0)
  314. return -EINVAL;
  315. if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
  316. &mcbsp[id],
  317. &dma_tx_ch)) {
  318. printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
  319. return -EAGAIN;
  320. }
  321. mcbsp[id].dma_tx_lch = dma_tx_ch;
  322. DBG("TX DMA on channel %d\n", dma_tx_ch);
  323. init_completion(&(mcbsp[id].tx_dma_completion));
  324. omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
  325. OMAP_DMA_DATA_TYPE_S16,
  326. length >> 1, 1,
  327. OMAP_DMA_SYNC_ELEMENT);
  328. omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
  329. OMAP_DMA_PORT_TIPB,
  330. OMAP_DMA_AMODE_CONSTANT,
  331. mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
  332. omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
  333. OMAP_DMA_PORT_EMIFF,
  334. OMAP_DMA_AMODE_POST_INC,
  335. buffer);
  336. omap_start_dma(mcbsp[id].dma_tx_lch);
  337. wait_for_completion(&(mcbsp[id].tx_dma_completion));
  338. return 0;
  339. }
  340. int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
  341. {
  342. int dma_rx_ch;
  343. if (omap_mcbsp_check(id) < 0)
  344. return -EINVAL;
  345. if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
  346. &mcbsp[id],
  347. &dma_rx_ch)) {
  348. printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
  349. return -EAGAIN;
  350. }
  351. mcbsp[id].dma_rx_lch = dma_rx_ch;
  352. DBG("RX DMA on channel %d\n", dma_rx_ch);
  353. init_completion(&(mcbsp[id].rx_dma_completion));
  354. omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
  355. OMAP_DMA_DATA_TYPE_S16,
  356. length >> 1, 1,
  357. OMAP_DMA_SYNC_ELEMENT);
  358. omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
  359. OMAP_DMA_PORT_TIPB,
  360. OMAP_DMA_AMODE_CONSTANT,
  361. mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
  362. omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
  363. OMAP_DMA_PORT_EMIFF,
  364. OMAP_DMA_AMODE_POST_INC,
  365. buffer);
  366. omap_start_dma(mcbsp[id].dma_rx_lch);
  367. wait_for_completion(&(mcbsp[id].rx_dma_completion));
  368. return 0;
  369. }
  370. /*
  371. * SPI wrapper.
  372. * Since SPI setup is much simpler than the generic McBSP one,
  373. * this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
  374. * Once this is done, you can call omap_mcbsp_start().
  375. */
  376. void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
  377. {
  378. struct omap_mcbsp_reg_cfg mcbsp_cfg;
  379. if (omap_mcbsp_check(id) < 0)
  380. return;
  381. memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
  382. /* SPI has only one frame */
  383. mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
  384. mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
  385. /* Clock stop mode */
  386. if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
  387. mcbsp_cfg.spcr1 |= (1 << 12);
  388. else
  389. mcbsp_cfg.spcr1 |= (3 << 11);
  390. /* Set clock parities */
  391. if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)
  392. mcbsp_cfg.pcr0 |= CLKRP;
  393. else
  394. mcbsp_cfg.pcr0 &= ~CLKRP;
  395. if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)
  396. mcbsp_cfg.pcr0 &= ~CLKXP;
  397. else
  398. mcbsp_cfg.pcr0 |= CLKXP;
  399. /* Set SCLKME to 0 and CLKSM to 1 */
  400. mcbsp_cfg.pcr0 &= ~SCLKME;
  401. mcbsp_cfg.srgr2 |= CLKSM;
  402. /* Set FSXP */
  403. if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)
  404. mcbsp_cfg.pcr0 &= ~FSXP;
  405. else
  406. mcbsp_cfg.pcr0 |= FSXP;
  407. if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
  408. mcbsp_cfg.pcr0 |= CLKXM;
  409. mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
  410. mcbsp_cfg.pcr0 |= FSXM;
  411. mcbsp_cfg.srgr2 &= ~FSGM;
  412. mcbsp_cfg.xcr2 |= XDATDLY(1);
  413. mcbsp_cfg.rcr2 |= RDATDLY(1);
  414. }
  415. else {
  416. mcbsp_cfg.pcr0 &= ~CLKXM;
  417. mcbsp_cfg.srgr1 |= CLKGDV(1);
  418. mcbsp_cfg.pcr0 &= ~FSXM;
  419. mcbsp_cfg.xcr2 &= ~XDATDLY(3);
  420. mcbsp_cfg.rcr2 &= ~RDATDLY(3);
  421. }
  422. mcbsp_cfg.xcr2 &= ~XPHASE;
  423. mcbsp_cfg.rcr2 &= ~RPHASE;
  424. omap_mcbsp_config(id, &mcbsp_cfg);
  425. }
  426. /*
  427. * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
  428. * 730 has only 2 McBSP, and both of them are MPU peripherals.
  429. */
  430. struct omap_mcbsp_info {
  431. u32 virt_base;
  432. u8 dma_rx_sync, dma_tx_sync;
  433. u16 rx_irq, tx_irq;
  434. };
  435. #ifdef CONFIG_ARCH_OMAP730
  436. static const struct omap_mcbsp_info mcbsp_730[] = {
  437. [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),
  438. .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
  439. .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
  440. .rx_irq = INT_730_McBSP1RX,
  441. .tx_irq = INT_730_McBSP1TX },
  442. [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),
  443. .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
  444. .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
  445. .rx_irq = INT_730_McBSP2RX,
  446. .tx_irq = INT_730_McBSP2TX },
  447. };
  448. #endif
  449. #ifdef CONFIG_ARCH_OMAP1510
  450. static const struct omap_mcbsp_info mcbsp_1510[] = {
  451. [0] = { .virt_base = OMAP1510_MCBSP1_BASE,
  452. .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
  453. .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
  454. .rx_irq = INT_McBSP1RX,
  455. .tx_irq = INT_McBSP1TX },
  456. [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),
  457. .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
  458. .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
  459. .rx_irq = INT_1510_SPI_RX,
  460. .tx_irq = INT_1510_SPI_TX },
  461. [2] = { .virt_base = OMAP1510_MCBSP3_BASE,
  462. .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
  463. .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
  464. .rx_irq = INT_McBSP3RX,
  465. .tx_irq = INT_McBSP3TX },
  466. };
  467. #endif
  468. #if defined(CONFIG_ARCH_OMAP16XX)
  469. static const struct omap_mcbsp_info mcbsp_1610[] = {
  470. [0] = { .virt_base = OMAP1610_MCBSP1_BASE,
  471. .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
  472. .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
  473. .rx_irq = INT_McBSP1RX,
  474. .tx_irq = INT_McBSP1TX },
  475. [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),
  476. .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
  477. .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
  478. .rx_irq = INT_1610_McBSP2_RX,
  479. .tx_irq = INT_1610_McBSP2_TX },
  480. [2] = { .virt_base = OMAP1610_MCBSP3_BASE,
  481. .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
  482. .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
  483. .rx_irq = INT_McBSP3RX,
  484. .tx_irq = INT_McBSP3TX },
  485. };
  486. #endif
  487. static int __init omap_mcbsp_init(void)
  488. {
  489. int mcbsp_count = 0, i;
  490. static const struct omap_mcbsp_info *mcbsp_info;
  491. printk("Initializing OMAP McBSP system\n");
  492. mcbsp_dsp_ck = clk_get(0, "dsp_ck");
  493. if (IS_ERR(mcbsp_dsp_ck)) {
  494. printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
  495. return PTR_ERR(mcbsp_dsp_ck);
  496. }
  497. mcbsp_api_ck = clk_get(0, "api_ck");
  498. if (IS_ERR(mcbsp_dsp_ck)) {
  499. printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
  500. return PTR_ERR(mcbsp_api_ck);
  501. }
  502. #ifdef CONFIG_ARCH_OMAP730
  503. if (cpu_is_omap730()) {
  504. mcbsp_info = mcbsp_730;
  505. mcbsp_count = ARRAY_SIZE(mcbsp_730);
  506. }
  507. #endif
  508. #ifdef CONFIG_ARCH_OMAP1510
  509. if (cpu_is_omap1510()) {
  510. mcbsp_info = mcbsp_1510;
  511. mcbsp_count = ARRAY_SIZE(mcbsp_1510);
  512. }
  513. #endif
  514. #if defined(CONFIG_ARCH_OMAP16XX)
  515. if (cpu_is_omap1610() || cpu_is_omap1710()) {
  516. mcbsp_info = mcbsp_1610;
  517. mcbsp_count = ARRAY_SIZE(mcbsp_1610);
  518. }
  519. #endif
  520. for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
  521. if (i >= mcbsp_count) {
  522. mcbsp[i].io_base = 0;
  523. mcbsp[i].free = 0;
  524. continue;
  525. }
  526. mcbsp[i].id = i + 1;
  527. mcbsp[i].free = 1;
  528. mcbsp[i].dma_tx_lch = -1;
  529. mcbsp[i].dma_rx_lch = -1;
  530. mcbsp[i].io_base = mcbsp_info[i].virt_base;
  531. mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
  532. mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
  533. mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
  534. mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
  535. spin_lock_init(&mcbsp[i].lock);
  536. }
  537. return 0;
  538. }
  539. arch_initcall(omap_mcbsp_init);
  540. EXPORT_SYMBOL(omap_mcbsp_config);
  541. EXPORT_SYMBOL(omap_mcbsp_request);
  542. EXPORT_SYMBOL(omap_mcbsp_free);
  543. EXPORT_SYMBOL(omap_mcbsp_start);
  544. EXPORT_SYMBOL(omap_mcbsp_stop);
  545. EXPORT_SYMBOL(omap_mcbsp_xmit_word);
  546. EXPORT_SYMBOL(omap_mcbsp_recv_word);
  547. EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
  548. EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
  549. EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);