fsl_sai.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
  3. *
  4. * Copyright 2012-2013 Freescale Semiconductor, Inc.
  5. *
  6. * This program is free software, you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 2 of the License, or(at your
  9. * option) any later version.
  10. *
  11. */
  12. #include <linux/clk.h>
  13. #include <linux/delay.h>
  14. #include <linux/dmaengine.h>
  15. #include <linux/module.h>
  16. #include <linux/of_address.h>
  17. #include <linux/regmap.h>
  18. #include <linux/slab.h>
  19. #include <sound/core.h>
  20. #include <sound/dmaengine_pcm.h>
  21. #include <sound/pcm_params.h>
  22. #include "fsl_sai.h"
  23. #include "imx-pcm.h"
  24. #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
  25. FSL_SAI_CSR_FEIE)
  26. static irqreturn_t fsl_sai_isr(int irq, void *devid)
  27. {
  28. struct fsl_sai *sai = (struct fsl_sai *)devid;
  29. struct device *dev = &sai->pdev->dev;
  30. u32 flags, xcsr, mask;
  31. bool irq_none = true;
  32. /*
  33. * Both IRQ status bits and IRQ mask bits are in the xCSR but
  34. * different shifts. And we here create a mask only for those
  35. * IRQs that we activated.
  36. */
  37. mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
  38. /* Tx IRQ */
  39. regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
  40. flags = xcsr & mask;
  41. if (flags)
  42. irq_none = false;
  43. else
  44. goto irq_rx;
  45. if (flags & FSL_SAI_CSR_WSF)
  46. dev_dbg(dev, "isr: Start of Tx word detected\n");
  47. if (flags & FSL_SAI_CSR_SEF)
  48. dev_warn(dev, "isr: Tx Frame sync error detected\n");
  49. if (flags & FSL_SAI_CSR_FEF) {
  50. dev_warn(dev, "isr: Transmit underrun detected\n");
  51. /* FIFO reset for safety */
  52. xcsr |= FSL_SAI_CSR_FR;
  53. }
  54. if (flags & FSL_SAI_CSR_FWF)
  55. dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
  56. if (flags & FSL_SAI_CSR_FRF)
  57. dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
  58. flags &= FSL_SAI_CSR_xF_W_MASK;
  59. xcsr &= ~FSL_SAI_CSR_xF_MASK;
  60. if (flags)
  61. regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
  62. irq_rx:
  63. /* Rx IRQ */
  64. regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
  65. flags = xcsr & mask;
  66. if (flags)
  67. irq_none = false;
  68. else
  69. goto out;
  70. if (flags & FSL_SAI_CSR_WSF)
  71. dev_dbg(dev, "isr: Start of Rx word detected\n");
  72. if (flags & FSL_SAI_CSR_SEF)
  73. dev_warn(dev, "isr: Rx Frame sync error detected\n");
  74. if (flags & FSL_SAI_CSR_FEF) {
  75. dev_warn(dev, "isr: Receive overflow detected\n");
  76. /* FIFO reset for safety */
  77. xcsr |= FSL_SAI_CSR_FR;
  78. }
  79. if (flags & FSL_SAI_CSR_FWF)
  80. dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
  81. if (flags & FSL_SAI_CSR_FRF)
  82. dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
  83. flags &= FSL_SAI_CSR_xF_W_MASK;
  84. xcsr &= ~FSL_SAI_CSR_xF_MASK;
  85. if (flags)
  86. regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr);
  87. out:
  88. if (irq_none)
  89. return IRQ_NONE;
  90. else
  91. return IRQ_HANDLED;
  92. }
  93. static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
  94. int clk_id, unsigned int freq, int fsl_dir)
  95. {
  96. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  97. bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
  98. u32 val_cr2 = 0;
  99. switch (clk_id) {
  100. case FSL_SAI_CLK_BUS:
  101. val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
  102. break;
  103. case FSL_SAI_CLK_MAST1:
  104. val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
  105. break;
  106. case FSL_SAI_CLK_MAST2:
  107. val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
  108. break;
  109. case FSL_SAI_CLK_MAST3:
  110. val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
  111. break;
  112. default:
  113. return -EINVAL;
  114. }
  115. regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
  116. FSL_SAI_CR2_MSEL_MASK, val_cr2);
  117. return 0;
  118. }
  119. static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
  120. int clk_id, unsigned int freq, int dir)
  121. {
  122. int ret;
  123. if (dir == SND_SOC_CLOCK_IN)
  124. return 0;
  125. ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
  126. FSL_FMT_TRANSMITTER);
  127. if (ret) {
  128. dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
  129. return ret;
  130. }
  131. ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
  132. FSL_FMT_RECEIVER);
  133. if (ret)
  134. dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
  135. return ret;
  136. }
  137. static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
  138. unsigned int fmt, int fsl_dir)
  139. {
  140. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  141. bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
  142. u32 val_cr2 = 0, val_cr4 = 0;
  143. if (!sai->is_lsb_first)
  144. val_cr4 |= FSL_SAI_CR4_MF;
  145. /* DAI mode */
  146. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  147. case SND_SOC_DAIFMT_I2S:
  148. /*
  149. * Frame low, 1clk before data, one word length for frame sync,
  150. * frame sync starts one serial clock cycle earlier,
  151. * that is, together with the last bit of the previous
  152. * data word.
  153. */
  154. val_cr2 |= FSL_SAI_CR2_BCP;
  155. val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
  156. break;
  157. case SND_SOC_DAIFMT_LEFT_J:
  158. /*
  159. * Frame high, one word length for frame sync,
  160. * frame sync asserts with the first bit of the frame.
  161. */
  162. val_cr2 |= FSL_SAI_CR2_BCP;
  163. break;
  164. case SND_SOC_DAIFMT_DSP_A:
  165. /*
  166. * Frame high, 1clk before data, one bit for frame sync,
  167. * frame sync starts one serial clock cycle earlier,
  168. * that is, together with the last bit of the previous
  169. * data word.
  170. */
  171. val_cr2 |= FSL_SAI_CR2_BCP;
  172. val_cr4 |= FSL_SAI_CR4_FSE;
  173. sai->is_dsp_mode = true;
  174. break;
  175. case SND_SOC_DAIFMT_DSP_B:
  176. /*
  177. * Frame high, one bit for frame sync,
  178. * frame sync asserts with the first bit of the frame.
  179. */
  180. val_cr2 |= FSL_SAI_CR2_BCP;
  181. sai->is_dsp_mode = true;
  182. break;
  183. case SND_SOC_DAIFMT_RIGHT_J:
  184. /* To be done */
  185. default:
  186. return -EINVAL;
  187. }
  188. /* DAI clock inversion */
  189. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  190. case SND_SOC_DAIFMT_IB_IF:
  191. /* Invert both clocks */
  192. val_cr2 ^= FSL_SAI_CR2_BCP;
  193. val_cr4 ^= FSL_SAI_CR4_FSP;
  194. break;
  195. case SND_SOC_DAIFMT_IB_NF:
  196. /* Invert bit clock */
  197. val_cr2 ^= FSL_SAI_CR2_BCP;
  198. break;
  199. case SND_SOC_DAIFMT_NB_IF:
  200. /* Invert frame clock */
  201. val_cr4 ^= FSL_SAI_CR4_FSP;
  202. break;
  203. case SND_SOC_DAIFMT_NB_NF:
  204. /* Nothing to do for both normal cases */
  205. break;
  206. default:
  207. return -EINVAL;
  208. }
  209. /* DAI clock master masks */
  210. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  211. case SND_SOC_DAIFMT_CBS_CFS:
  212. val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
  213. val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
  214. break;
  215. case SND_SOC_DAIFMT_CBM_CFM:
  216. break;
  217. case SND_SOC_DAIFMT_CBS_CFM:
  218. val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
  219. break;
  220. case SND_SOC_DAIFMT_CBM_CFS:
  221. val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
  222. break;
  223. default:
  224. return -EINVAL;
  225. }
  226. regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
  227. FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
  228. regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
  229. FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
  230. FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
  231. return 0;
  232. }
  233. static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
  234. {
  235. int ret;
  236. ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
  237. if (ret) {
  238. dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
  239. return ret;
  240. }
  241. ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
  242. if (ret)
  243. dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
  244. return ret;
  245. }
  246. static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
  247. struct snd_pcm_hw_params *params,
  248. struct snd_soc_dai *cpu_dai)
  249. {
  250. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  251. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  252. unsigned int channels = params_channels(params);
  253. u32 word_width = snd_pcm_format_width(params_format(params));
  254. u32 val_cr4 = 0, val_cr5 = 0;
  255. if (!sai->is_dsp_mode)
  256. val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
  257. val_cr5 |= FSL_SAI_CR5_WNW(word_width);
  258. val_cr5 |= FSL_SAI_CR5_W0W(word_width);
  259. if (sai->is_lsb_first)
  260. val_cr5 |= FSL_SAI_CR5_FBT(0);
  261. else
  262. val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
  263. val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
  264. regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
  265. FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
  266. val_cr4);
  267. regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
  268. FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
  269. FSL_SAI_CR5_FBT_MASK, val_cr5);
  270. regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
  271. return 0;
  272. }
  273. static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
  274. struct snd_soc_dai *cpu_dai)
  275. {
  276. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  277. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  278. u32 xcsr, count = 100;
  279. /*
  280. * Asynchronous mode: Clear SYNC for both Tx and Rx.
  281. * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
  282. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
  283. */
  284. regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
  285. regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
  286. sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
  287. /*
  288. * It is recommended that the transmitter is the last enabled
  289. * and the first disabled.
  290. */
  291. switch (cmd) {
  292. case SNDRV_PCM_TRIGGER_START:
  293. case SNDRV_PCM_TRIGGER_RESUME:
  294. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  295. regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
  296. FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
  297. regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
  298. FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
  299. regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
  300. FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
  301. regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
  302. FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
  303. break;
  304. case SNDRV_PCM_TRIGGER_STOP:
  305. case SNDRV_PCM_TRIGGER_SUSPEND:
  306. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  307. regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
  308. FSL_SAI_CSR_FRDE, 0);
  309. regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
  310. FSL_SAI_CSR_xIE_MASK, 0);
  311. /* Check if the opposite FRDE is also disabled */
  312. regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr);
  313. if (!(xcsr & FSL_SAI_CSR_FRDE)) {
  314. /* Disable both directions and reset their FIFOs */
  315. regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
  316. FSL_SAI_CSR_TERE, 0);
  317. regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
  318. FSL_SAI_CSR_TERE, 0);
  319. /* TERE will remain set till the end of current frame */
  320. do {
  321. udelay(10);
  322. regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr);
  323. } while (--count && xcsr & FSL_SAI_CSR_TERE);
  324. regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
  325. FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
  326. regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
  327. FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
  328. }
  329. break;
  330. default:
  331. return -EINVAL;
  332. }
  333. return 0;
  334. }
  335. static int fsl_sai_startup(struct snd_pcm_substream *substream,
  336. struct snd_soc_dai *cpu_dai)
  337. {
  338. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  339. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  340. struct device *dev = &sai->pdev->dev;
  341. int ret;
  342. ret = clk_prepare_enable(sai->bus_clk);
  343. if (ret) {
  344. dev_err(dev, "failed to enable bus clock: %d\n", ret);
  345. return ret;
  346. }
  347. regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
  348. FSL_SAI_CR3_TRCE);
  349. return 0;
  350. }
  351. static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
  352. struct snd_soc_dai *cpu_dai)
  353. {
  354. struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
  355. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  356. regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
  357. clk_disable_unprepare(sai->bus_clk);
  358. }
  359. static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
  360. .set_sysclk = fsl_sai_set_dai_sysclk,
  361. .set_fmt = fsl_sai_set_dai_fmt,
  362. .hw_params = fsl_sai_hw_params,
  363. .trigger = fsl_sai_trigger,
  364. .startup = fsl_sai_startup,
  365. .shutdown = fsl_sai_shutdown,
  366. };
  367. static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
  368. {
  369. struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
  370. /* Software Reset for both Tx and Rx */
  371. regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
  372. regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
  373. /* Clear SR bit to finish the reset */
  374. regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
  375. regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
  376. regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
  377. FSL_SAI_MAXBURST_TX * 2);
  378. regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
  379. FSL_SAI_MAXBURST_RX - 1);
  380. snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
  381. &sai->dma_params_rx);
  382. snd_soc_dai_set_drvdata(cpu_dai, sai);
  383. return 0;
  384. }
  385. static struct snd_soc_dai_driver fsl_sai_dai = {
  386. .probe = fsl_sai_dai_probe,
  387. .playback = {
  388. .stream_name = "CPU-Playback",
  389. .channels_min = 1,
  390. .channels_max = 2,
  391. .rates = SNDRV_PCM_RATE_8000_96000,
  392. .formats = FSL_SAI_FORMATS,
  393. },
  394. .capture = {
  395. .stream_name = "CPU-Capture",
  396. .channels_min = 1,
  397. .channels_max = 2,
  398. .rates = SNDRV_PCM_RATE_8000_96000,
  399. .formats = FSL_SAI_FORMATS,
  400. },
  401. .ops = &fsl_sai_pcm_dai_ops,
  402. };
  403. static const struct snd_soc_component_driver fsl_component = {
  404. .name = "fsl-sai",
  405. };
  406. static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
  407. {
  408. switch (reg) {
  409. case FSL_SAI_TCSR:
  410. case FSL_SAI_TCR1:
  411. case FSL_SAI_TCR2:
  412. case FSL_SAI_TCR3:
  413. case FSL_SAI_TCR4:
  414. case FSL_SAI_TCR5:
  415. case FSL_SAI_TFR:
  416. case FSL_SAI_TMR:
  417. case FSL_SAI_RCSR:
  418. case FSL_SAI_RCR1:
  419. case FSL_SAI_RCR2:
  420. case FSL_SAI_RCR3:
  421. case FSL_SAI_RCR4:
  422. case FSL_SAI_RCR5:
  423. case FSL_SAI_RDR:
  424. case FSL_SAI_RFR:
  425. case FSL_SAI_RMR:
  426. return true;
  427. default:
  428. return false;
  429. }
  430. }
  431. static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
  432. {
  433. switch (reg) {
  434. case FSL_SAI_TFR:
  435. case FSL_SAI_RFR:
  436. case FSL_SAI_TDR:
  437. case FSL_SAI_RDR:
  438. return true;
  439. default:
  440. return false;
  441. }
  442. }
  443. static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
  444. {
  445. switch (reg) {
  446. case FSL_SAI_TCSR:
  447. case FSL_SAI_TCR1:
  448. case FSL_SAI_TCR2:
  449. case FSL_SAI_TCR3:
  450. case FSL_SAI_TCR4:
  451. case FSL_SAI_TCR5:
  452. case FSL_SAI_TDR:
  453. case FSL_SAI_TMR:
  454. case FSL_SAI_RCSR:
  455. case FSL_SAI_RCR1:
  456. case FSL_SAI_RCR2:
  457. case FSL_SAI_RCR3:
  458. case FSL_SAI_RCR4:
  459. case FSL_SAI_RCR5:
  460. case FSL_SAI_RMR:
  461. return true;
  462. default:
  463. return false;
  464. }
  465. }
  466. static const struct regmap_config fsl_sai_regmap_config = {
  467. .reg_bits = 32,
  468. .reg_stride = 4,
  469. .val_bits = 32,
  470. .max_register = FSL_SAI_RMR,
  471. .readable_reg = fsl_sai_readable_reg,
  472. .volatile_reg = fsl_sai_volatile_reg,
  473. .writeable_reg = fsl_sai_writeable_reg,
  474. };
  475. static int fsl_sai_probe(struct platform_device *pdev)
  476. {
  477. struct device_node *np = pdev->dev.of_node;
  478. struct fsl_sai *sai;
  479. struct resource *res;
  480. void __iomem *base;
  481. char tmp[8];
  482. int irq, ret, i;
  483. sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
  484. if (!sai)
  485. return -ENOMEM;
  486. sai->pdev = pdev;
  487. if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
  488. sai->sai_on_imx = true;
  489. sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
  490. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  491. base = devm_ioremap_resource(&pdev->dev, res);
  492. if (IS_ERR(base))
  493. return PTR_ERR(base);
  494. sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
  495. "bus", base, &fsl_sai_regmap_config);
  496. /* Compatible with old DTB cases */
  497. if (IS_ERR(sai->regmap))
  498. sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
  499. "sai", base, &fsl_sai_regmap_config);
  500. if (IS_ERR(sai->regmap)) {
  501. dev_err(&pdev->dev, "regmap init failed\n");
  502. return PTR_ERR(sai->regmap);
  503. }
  504. /* No error out for old DTB cases but only mark the clock NULL */
  505. sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
  506. if (IS_ERR(sai->bus_clk)) {
  507. dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
  508. PTR_ERR(sai->bus_clk));
  509. sai->bus_clk = NULL;
  510. }
  511. for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
  512. sprintf(tmp, "mclk%d", i + 1);
  513. sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
  514. if (IS_ERR(sai->mclk_clk[i])) {
  515. dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
  516. i + 1, PTR_ERR(sai->mclk_clk[i]));
  517. sai->mclk_clk[i] = NULL;
  518. }
  519. }
  520. irq = platform_get_irq(pdev, 0);
  521. if (irq < 0) {
  522. dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
  523. return irq;
  524. }
  525. ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
  526. if (ret) {
  527. dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
  528. return ret;
  529. }
  530. /* Sync Tx with Rx as default by following old DT binding */
  531. sai->synchronous[RX] = true;
  532. sai->synchronous[TX] = false;
  533. fsl_sai_dai.symmetric_rates = 1;
  534. fsl_sai_dai.symmetric_channels = 1;
  535. fsl_sai_dai.symmetric_samplebits = 1;
  536. if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
  537. of_find_property(np, "fsl,sai-asynchronous", NULL)) {
  538. /* error out if both synchronous and asynchronous are present */
  539. dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
  540. return -EINVAL;
  541. }
  542. if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
  543. /* Sync Rx with Tx */
  544. sai->synchronous[RX] = false;
  545. sai->synchronous[TX] = true;
  546. } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
  547. /* Discard all settings for asynchronous mode */
  548. sai->synchronous[RX] = false;
  549. sai->synchronous[TX] = false;
  550. fsl_sai_dai.symmetric_rates = 0;
  551. fsl_sai_dai.symmetric_channels = 0;
  552. fsl_sai_dai.symmetric_samplebits = 0;
  553. }
  554. sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
  555. sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
  556. sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
  557. sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
  558. platform_set_drvdata(pdev, sai);
  559. ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
  560. &fsl_sai_dai, 1);
  561. if (ret)
  562. return ret;
  563. if (sai->sai_on_imx)
  564. return imx_pcm_dma_init(pdev);
  565. else
  566. return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
  567. SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
  568. }
  569. static const struct of_device_id fsl_sai_ids[] = {
  570. { .compatible = "fsl,vf610-sai", },
  571. { .compatible = "fsl,imx6sx-sai", },
  572. { /* sentinel */ }
  573. };
  574. static struct platform_driver fsl_sai_driver = {
  575. .probe = fsl_sai_probe,
  576. .driver = {
  577. .name = "fsl-sai",
  578. .owner = THIS_MODULE,
  579. .of_match_table = fsl_sai_ids,
  580. },
  581. };
  582. module_platform_driver(fsl_sai_driver);
  583. MODULE_DESCRIPTION("Freescale Soc SAI Interface");
  584. MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
  585. MODULE_ALIAS("platform:fsl-sai");
  586. MODULE_LICENSE("GPL");