mcbsp.c 20 KB

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