at91-i2s.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * at91-i2s.c -- ALSA SoC I2S Audio Layer Platform driver
  3. *
  4. * Author: Frank Mandarino <fmandarino@endrelia.com>
  5. * Endrelia Technologies Inc.
  6. *
  7. * Based on pxa2xx Platform drivers by
  8. * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2 of the License, or (at your
  13. * option) any later version.
  14. *
  15. * Revision history
  16. * 3rd Mar 2006 Initial version.
  17. */
  18. #include <linux/init.h>
  19. #include <linux/module.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/device.h>
  22. #include <linux/delay.h>
  23. #include <linux/clk.h>
  24. #include <sound/driver.h>
  25. #include <sound/core.h>
  26. #include <sound/pcm.h>
  27. #include <sound/initval.h>
  28. #include <sound/soc.h>
  29. #include <asm/arch/hardware.h>
  30. #include <asm/arch/at91_pmc.h>
  31. #include <asm/arch/at91_ssc.h>
  32. #include <asm/arch/at91_pdc.h>
  33. #include "at91-pcm.h"
  34. #if 0
  35. #define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x)
  36. #else
  37. #define DBG(x...)
  38. #endif
  39. #if defined(CONFIG_ARCH_AT91SAM9260)
  40. #define NUM_SSC_DEVICES 1
  41. #else
  42. #define NUM_SSC_DEVICES 3
  43. #endif
  44. #define AT91_I2S_DAIFMT \
  45. (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF)
  46. #define AT91_I2S_DIR \
  47. (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
  48. /* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */
  49. static struct snd_soc_dai_mode at91_i2s[] = {
  50. /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */
  51. {
  52. .fmt = AT91_I2S_DAIFMT,
  53. .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
  54. .pcmrate = SNDRV_PCM_RATE_8000,
  55. .pcmdir = AT91_I2S_DIR,
  56. .flags = SND_SOC_DAI_BFS_DIV,
  57. .fs = 1500,
  58. .bfs = SND_SOC_FSBD(10),
  59. .priv = (25 << 16 | 74),
  60. },
  61. /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */
  62. {
  63. .fmt = AT91_I2S_DAIFMT,
  64. .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
  65. .pcmrate = SNDRV_PCM_RATE_16000,
  66. .pcmdir = AT91_I2S_DIR,
  67. .flags = SND_SOC_DAI_BFS_DIV,
  68. .fs = 750,
  69. .bfs = SND_SOC_FSBD(3),
  70. .priv = (7 << 16 | 133),
  71. },
  72. /* 32k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */
  73. {
  74. .fmt = AT91_I2S_DAIFMT,
  75. .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
  76. .pcmrate = SNDRV_PCM_RATE_32000,
  77. .pcmdir = AT91_I2S_DIR,
  78. .flags = SND_SOC_DAI_BFS_DIV,
  79. .fs = 375,
  80. .bfs = SND_SOC_FSBD(3),
  81. .priv = (7 << 16 | 66),
  82. },
  83. /* 48k: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */
  84. {
  85. .fmt = AT91_I2S_DAIFMT,
  86. .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
  87. .pcmrate = SNDRV_PCM_RATE_48000,
  88. .pcmdir = AT91_I2S_DIR,
  89. .flags = SND_SOC_DAI_BFS_DIV,
  90. .fs = 250,
  91. .bfs SND_SOC_FSBD(5),
  92. .priv = (13 << 16 | 23),
  93. },
  94. };
  95. /*
  96. * SSC PDC registers required by the PCM DMA engine.
  97. */
  98. static struct at91_pdc_regs pdc_tx_reg = {
  99. .xpr = AT91_PDC_TPR,
  100. .xcr = AT91_PDC_TCR,
  101. .xnpr = AT91_PDC_TNPR,
  102. .xncr = AT91_PDC_TNCR,
  103. };
  104. static struct at91_pdc_regs pdc_rx_reg = {
  105. .xpr = AT91_PDC_RPR,
  106. .xcr = AT91_PDC_RCR,
  107. .xnpr = AT91_PDC_RNPR,
  108. .xncr = AT91_PDC_RNCR,
  109. };
  110. /*
  111. * SSC & PDC status bits for transmit and receive.
  112. */
  113. static struct at91_ssc_mask ssc_tx_mask = {
  114. .ssc_enable = AT91_SSC_TXEN,
  115. .ssc_disable = AT91_SSC_TXDIS,
  116. .ssc_endx = AT91_SSC_ENDTX,
  117. .ssc_endbuf = AT91_SSC_TXBUFE,
  118. .pdc_enable = AT91_PDC_TXTEN,
  119. .pdc_disable = AT91_PDC_TXTDIS,
  120. };
  121. static struct at91_ssc_mask ssc_rx_mask = {
  122. .ssc_enable = AT91_SSC_RXEN,
  123. .ssc_disable = AT91_SSC_RXDIS,
  124. .ssc_endx = AT91_SSC_ENDRX,
  125. .ssc_endbuf = AT91_SSC_RXBUFF,
  126. .pdc_enable = AT91_PDC_RXTEN,
  127. .pdc_disable = AT91_PDC_RXTDIS,
  128. };
  129. /*
  130. * DMA parameters.
  131. */
  132. static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
  133. {{
  134. .name = "SSC0/I2S PCM Stereo out",
  135. .pdc = &pdc_tx_reg,
  136. .mask = &ssc_tx_mask,
  137. },
  138. {
  139. .name = "SSC0/I2S PCM Stereo in",
  140. .pdc = &pdc_rx_reg,
  141. .mask = &ssc_rx_mask,
  142. }},
  143. #if NUM_SSC_DEVICES == 3
  144. {{
  145. .name = "SSC1/I2S PCM Stereo out",
  146. .pdc = &pdc_tx_reg,
  147. .mask = &ssc_tx_mask,
  148. },
  149. {
  150. .name = "SSC1/I2S PCM Stereo in",
  151. .pdc = &pdc_rx_reg,
  152. .mask = &ssc_rx_mask,
  153. }},
  154. {{
  155. .name = "SSC2/I2S PCM Stereo out",
  156. .pdc = &pdc_tx_reg,
  157. .mask = &ssc_tx_mask,
  158. },
  159. {
  160. .name = "SSC1/I2S PCM Stereo in",
  161. .pdc = &pdc_rx_reg,
  162. .mask = &ssc_rx_mask,
  163. }},
  164. #endif
  165. };
  166. /*
  167. * A MUTEX is used to protect an SSC initialzed flag which allows
  168. * the substream hw_params() call to initialize the SSC only if
  169. * there are no other substreams open. If there are other
  170. * substreams open, the hw_param() call can only check that
  171. * it is using the same format and rate.
  172. */
  173. static DECLARE_MUTEX(ssc0_mutex);
  174. #if NUM_SSC_DEVICES == 3
  175. static DECLARE_MUTEX(ssc1_mutex);
  176. static DECLARE_MUTEX(ssc2_mutex);
  177. #endif
  178. struct at91_ssc_state {
  179. u32 ssc_cmr;
  180. u32 ssc_rcmr;
  181. u32 ssc_rfmr;
  182. u32 ssc_tcmr;
  183. u32 ssc_tfmr;
  184. u32 ssc_sr;
  185. u32 ssc_imr;
  186. };
  187. static struct at91_ssc_info {
  188. char *name;
  189. struct at91_ssc_periph ssc;
  190. spinlock_t lock; /* lock for dir_mask */
  191. int dir_mask; /* 0=unused, 1=playback, 2=capture */
  192. struct semaphore *mutex;
  193. int initialized;
  194. int pcmfmt;
  195. int rate;
  196. struct at91_pcm_dma_params *dma_params[2];
  197. struct at91_ssc_state ssc_state;
  198. } ssc_info[NUM_SSC_DEVICES] = {
  199. {
  200. .name = "ssc0",
  201. .lock = SPIN_LOCK_UNLOCKED,
  202. .dir_mask = 0,
  203. .mutex = &ssc0_mutex,
  204. .initialized = 0,
  205. },
  206. #if NUM_SSC_DEVICES == 3
  207. {
  208. .name = "ssc1",
  209. .lock = SPIN_LOCK_UNLOCKED,
  210. .dir_mask = 0,
  211. .mutex = &ssc1_mutex,
  212. .initialized = 0,
  213. },
  214. {
  215. .name = "ssc2",
  216. .lock = SPIN_LOCK_UNLOCKED,
  217. .dir_mask = 0,
  218. .mutex = &ssc2_mutex,
  219. .initialized = 0,
  220. },
  221. #endif
  222. };
  223. static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id)
  224. {
  225. struct at91_ssc_info *ssc_p = dev_id;
  226. struct at91_pcm_dma_params *dma_params;
  227. u32 ssc_sr;
  228. int i;
  229. ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
  230. & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
  231. /*
  232. * Loop through the substreams attached to this SSC. If
  233. * a DMA-related interrupt occurred on that substream, call
  234. * the DMA interrupt handler function, if one has been
  235. * registered in the dma_params structure by the PCM driver.
  236. */
  237. for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
  238. dma_params = ssc_p->dma_params[i];
  239. if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
  240. (ssc_sr &
  241. (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
  242. dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
  243. }
  244. return IRQ_HANDLED;
  245. }
  246. static int at91_i2s_startup(struct snd_pcm_substream *substream)
  247. {
  248. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  249. struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id];
  250. int dir_mask;
  251. DBG("i2s_startup: SSC_SR=0x%08lx\n",
  252. at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
  253. dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
  254. spin_lock_irq(&ssc_p->lock);
  255. if (ssc_p->dir_mask & dir_mask) {
  256. spin_unlock_irq(&ssc_p->lock);
  257. return -EBUSY;
  258. }
  259. ssc_p->dir_mask |= dir_mask;
  260. spin_unlock_irq(&ssc_p->lock);
  261. return 0;
  262. }
  263. static void at91_i2s_shutdown(struct snd_pcm_substream *substream)
  264. {
  265. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  266. struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id];
  267. struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data;
  268. int dir, dir_mask;
  269. dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
  270. if (dma_params != NULL) {
  271. at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
  272. dma_params->mask->ssc_disable);
  273. DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
  274. at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
  275. dma_params->ssc_base = NULL;
  276. dma_params->substream = NULL;
  277. ssc_p->dma_params[dir] = NULL;
  278. }
  279. dir_mask = 1 << dir;
  280. spin_lock_irq(&ssc_p->lock);
  281. ssc_p->dir_mask &= ~dir_mask;
  282. if (!ssc_p->dir_mask) {
  283. /* Shutdown the SSC clock. */
  284. DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
  285. at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
  286. if (ssc_p->initialized)
  287. free_irq(ssc_p->ssc.pid, ssc_p);
  288. /* Reset the SSC */
  289. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
  290. /* Force a re-init on the next hw_params() call. */
  291. ssc_p->initialized = 0;
  292. }
  293. spin_unlock_irq(&ssc_p->lock);
  294. }
  295. #ifdef CONFIG_PM
  296. static int at91_i2s_suspend(struct platform_device *pdev,
  297. struct snd_soc_cpu_dai *dai)
  298. {
  299. struct at91_ssc_info *ssc_p;
  300. if(!dai->active)
  301. return 0;
  302. ssc_p = &ssc_info[dai->id];
  303. /* Save the status register before disabling transmit and receive. */
  304. ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
  305. at91_ssc_write(ssc_p->ssc.base +
  306. AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS);
  307. /* Save the current interrupt mask, then disable unmasked interrupts. */
  308. ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
  309. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->state->ssc_imr);
  310. ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
  311. ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
  312. ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
  313. ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
  314. ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
  315. return 0;
  316. }
  317. static int at91_i2s_resume(struct platform_device *pdev,
  318. struct snd_soc_cpu_dai *dai)
  319. {
  320. struct at91_ssc_info *ssc_p;
  321. u32 cr_mask;
  322. if(!dai->active)
  323. return 0;
  324. ssc_p = &ssc_info[dai->id];
  325. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr);
  326. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr);
  327. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr);
  328. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr);
  329. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->state->ssc_cmr);
  330. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->state->ssc_imr);
  331. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
  332. ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
  333. ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
  334. return 0;
  335. }
  336. #else
  337. #define at91_i2s_suspend NULL
  338. #define at91_i2s_resume NULL
  339. #endif
  340. static unsigned int at91_i2s_config_sysclk(
  341. struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info,
  342. unsigned int clk)
  343. {
  344. /* Currently, there is only support for USB (12Mhz) mode */
  345. if (clk != 12000000)
  346. return 0;
  347. return 12000000;
  348. }
  349. static int at91_i2s_hw_params(struct snd_pcm_substream *substream,
  350. struct snd_pcm_hw_params *params)
  351. {
  352. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  353. int id = rtd->cpu_dai->id;
  354. struct at91_ssc_info *ssc_p = &ssc_info[id];
  355. struct at91_pcm_dma_params *dma_params;
  356. unsigned int pcmfmt, rate;
  357. int dir, channels, bits;
  358. struct clk *mck_clk;
  359. u32 div, period, tfmr, rfmr, tcmr, rcmr;
  360. int ret;
  361. /*
  362. * Currently, there is only one set of dma params for
  363. * each direction. If more are added, this code will
  364. * have to be changed to select the proper set.
  365. */
  366. dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
  367. dma_params = &ssc_dma_params[id][dir];
  368. dma_params->ssc_base = ssc_p->ssc.base;
  369. dma_params->substream = substream;
  370. ssc_p->dma_params[dir] = dma_params;
  371. rtd->cpu_dai->dma_data = dma_params;
  372. rate = params_rate(params);
  373. channels = params_channels(params);
  374. pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt;
  375. switch (pcmfmt) {
  376. case SNDRV_PCM_FMTBIT_S16_LE:
  377. /* likely this is all we'll ever support, but ... */
  378. bits = 16;
  379. dma_params->pdc_xfer_size = 2;
  380. break;
  381. default:
  382. printk(KERN_WARNING "at91-i2s: unsupported format %x\n",
  383. pcmfmt);
  384. return -EINVAL;
  385. }
  386. /* Don't allow both SSC substreams to initialize at the same time. */
  387. down(ssc_p->mutex);
  388. /*
  389. * If this SSC is alreadly initialized, then this substream must use
  390. * the same format and rate.
  391. */
  392. if (ssc_p->initialized) {
  393. if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) {
  394. printk(KERN_WARNING "at91-i2s: "
  395. "incompatible substream in other direction\n");
  396. up(ssc_p->mutex);
  397. return -EINVAL;
  398. }
  399. } else {
  400. /* Enable PMC peripheral clock for this SSC */
  401. DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
  402. at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
  403. /* Reset the SSC */
  404. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
  405. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0);
  406. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0);
  407. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0);
  408. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0);
  409. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0);
  410. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0);
  411. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0);
  412. at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0);
  413. div = rtd->cpu_dai->dai_runtime.priv >> 16;
  414. period = rtd->cpu_dai->dai_runtime.priv & 0xffff;
  415. mck_clk = clk_get(NULL, "mck");
  416. DBG("mck %lu fsbd %u bfs %llu bfs_real %u bclk %lu div %u period %u\n",
  417. clk_get_rate(mck_clk),
  418. SND_SOC_FSBD(6),
  419. rtd->cpu_dai->dai_runtime.bfs,
  420. SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs),
  421. clk_get_rate(mck_clk) / (2 * div),
  422. div,
  423. period);
  424. clk_put(mck_clk);
  425. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, div);
  426. /*
  427. * Setup the TFMR and RFMR for the proper data format.
  428. */
  429. tfmr =
  430. (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
  431. | (( 0 << 23) & AT91_SSC_FSDEN)
  432. | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
  433. | (((bits - 1) << 16) & AT91_SSC_FSLEN)
  434. | (((channels - 1) << 8) & AT91_SSC_DATNB)
  435. | (( 1 << 7) & AT91_SSC_MSBF)
  436. | (( 0 << 5) & AT91_SSC_DATDEF)
  437. | (((bits - 1) << 0) & AT91_SSC_DATALEN);
  438. DBG("SSC_TFMR=0x%08x\n", tfmr);
  439. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
  440. rfmr =
  441. (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
  442. | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
  443. | (( 0 << 16) & AT91_SSC_FSLEN)
  444. | (((channels - 1) << 8) & AT91_SSC_DATNB)
  445. | (( 1 << 7) & AT91_SSC_MSBF)
  446. | (( 0 << 5) & AT91_SSC_LOOP)
  447. | (((bits - 1) << 0) & AT91_SSC_DATALEN);
  448. DBG("SSC_RFMR=0x%08x\n", rfmr);
  449. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
  450. /*
  451. * Setup the TCMR and RCMR to generate the proper BCLK
  452. * and LRC signals.
  453. */
  454. tcmr =
  455. (( period << 24) & AT91_SSC_PERIOD)
  456. | (( 1 << 16) & AT91_SSC_STTDLY)
  457. | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
  458. | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
  459. | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
  460. | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
  461. DBG("SSC_TCMR=0x%08x\n", tcmr);
  462. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
  463. rcmr =
  464. (( 0 << 24) & AT91_SSC_PERIOD)
  465. | (( 1 << 16) & AT91_SSC_STTDLY)
  466. | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START)
  467. | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
  468. | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
  469. | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS);
  470. DBG("SSC_RCMR=0x%08x\n", rcmr);
  471. at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
  472. if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt,
  473. 0, ssc_p->name, ssc_p)) < 0) {
  474. printk(KERN_WARNING "at91-i2s: request_irq failure\n");
  475. return ret;
  476. }
  477. /*
  478. * Save the current substream parameters in order to check
  479. * that the substream in the opposite direction uses the
  480. * same parameters.
  481. */
  482. ssc_p->pcmfmt = pcmfmt;
  483. ssc_p->rate = rate;
  484. ssc_p->initialized = 1;
  485. DBG("hw_params: SSC initialized\n");
  486. }
  487. up(ssc_p->mutex);
  488. return 0;
  489. }
  490. static int at91_i2s_prepare(struct snd_pcm_substream *substream)
  491. {
  492. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  493. struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data;
  494. at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
  495. dma_params->mask->ssc_enable);
  496. DBG("%s enabled SSC_SR=0x%08lx\n",
  497. substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive",
  498. at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc.base + AT91_SSC_SR));
  499. return 0;
  500. }
  501. struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = {
  502. { .name = "at91_ssc0/i2s",
  503. .id = 0,
  504. .type = SND_SOC_DAI_I2S,
  505. .suspend = at91_i2s_suspend,
  506. .resume = at91_i2s_resume,
  507. .config_sysclk = at91_i2s_config_sysclk,
  508. .playback = {
  509. .channels_min = 1,
  510. .channels_max = 2,},
  511. .capture = {
  512. .channels_min = 1,
  513. .channels_max = 2,},
  514. .ops = {
  515. .startup = at91_i2s_startup,
  516. .shutdown = at91_i2s_shutdown,
  517. .prepare = at91_i2s_prepare,
  518. .hw_params = at91_i2s_hw_params,},
  519. .caps = {
  520. .mode = &at91_i2s[0],
  521. .num_modes = ARRAY_SIZE(at91_i2s),},
  522. .private_data = &ssc_info[0].ssc,
  523. },
  524. #if NUM_SSC_DEVICES == 3
  525. { .name = "at91_ssc1/i2s",
  526. .id = 1,
  527. .type = SND_SOC_DAI_I2S,
  528. .suspend = at91_i2s_suspend,
  529. .resume = at91_i2s_resume,
  530. .config_sysclk = at91_i2s_config_sysclk,
  531. .playback = {
  532. .channels_min = 1,
  533. .channels_max = 2,},
  534. .capture = {
  535. .channels_min = 1,
  536. .channels_max = 2,},
  537. .ops = {
  538. .startup = at91_i2s_startup,
  539. .shutdown = at91_i2s_shutdown,
  540. .prepare = at91_i2s_prepare,
  541. .hw_params = at91_i2s_hw_params,},
  542. .caps = {
  543. .mode = &at91_i2s[0],
  544. .num_modes = ARRAY_SIZE(at91_i2s),},
  545. .private_data = &ssc_info[1].ssc,
  546. },
  547. { .name = "at91_ssc2/i2s",
  548. .id = 2,
  549. .type = SND_SOC_DAI_I2S,
  550. .suspend = at91_i2s_suspend,
  551. .resume = at91_i2s_resume,
  552. .config_sysclk = at91_i2s_config_sysclk,
  553. .playback = {
  554. .channels_min = 1,
  555. .channels_max = 2,},
  556. .capture = {
  557. .channels_min = 1,
  558. .channels_max = 2,},
  559. .ops = {
  560. .startup = at91_i2s_startup,
  561. .shutdown = at91_i2s_shutdown,
  562. .prepare = at91_i2s_prepare,
  563. .hw_params = at91_i2s_hw_params,},
  564. .caps = {
  565. .mode = &at91_i2s[0],
  566. .num_modes = ARRAY_SIZE(at91_i2s),},
  567. .private_data = &ssc_info[2].ssc,
  568. },
  569. #endif
  570. };
  571. EXPORT_SYMBOL_GPL(at91_i2s_dai);
  572. /* Module information */
  573. MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
  574. MODULE_DESCRIPTION("AT91 I2S ASoC Interface");
  575. MODULE_LICENSE("GPL");