mpc5200_psc_i2s.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Freescale MPC5200 PSC in I2S mode
  4. // ALSA SoC Digital Audio Interface (DAI) driver
  5. //
  6. // Copyright (C) 2008 Secret Lab Technologies Ltd.
  7. // Copyright (C) 2009 Jon Smirl, Digispeaker
  8. #include <linux/module.h>
  9. #include <linux/of_device.h>
  10. #include <linux/of_platform.h>
  11. #include <sound/pcm.h>
  12. #include <sound/pcm_params.h>
  13. #include <sound/soc.h>
  14. #include <asm/mpc52xx_psc.h>
  15. #include "mpc5200_dma.h"
  16. /**
  17. * PSC_I2S_RATES: sample rates supported by the I2S
  18. *
  19. * This driver currently only supports the PSC running in I2S slave mode,
  20. * which means the codec determines the sample rate. Therefore, we tell
  21. * ALSA that we support all rates and let the codec driver decide what rates
  22. * are really supported.
  23. */
  24. #define PSC_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
  25. /**
  26. * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
  27. */
  28. #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
  29. SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
  30. static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
  31. struct snd_pcm_hw_params *params,
  32. struct snd_soc_dai *dai)
  33. {
  34. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  35. struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
  36. u32 mode;
  37. dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
  38. " periods=%i buffer_size=%i buffer_bytes=%i\n",
  39. __func__, substream, params_period_size(params),
  40. params_period_bytes(params), params_periods(params),
  41. params_buffer_size(params), params_buffer_bytes(params));
  42. switch (params_format(params)) {
  43. case SNDRV_PCM_FORMAT_S8:
  44. mode = MPC52xx_PSC_SICR_SIM_CODEC_8;
  45. break;
  46. case SNDRV_PCM_FORMAT_S16_BE:
  47. mode = MPC52xx_PSC_SICR_SIM_CODEC_16;
  48. break;
  49. case SNDRV_PCM_FORMAT_S24_BE:
  50. mode = MPC52xx_PSC_SICR_SIM_CODEC_24;
  51. break;
  52. case SNDRV_PCM_FORMAT_S32_BE:
  53. mode = MPC52xx_PSC_SICR_SIM_CODEC_32;
  54. break;
  55. default:
  56. dev_dbg(psc_dma->dev, "invalid format\n");
  57. return -EINVAL;
  58. }
  59. out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);
  60. return 0;
  61. }
  62. /**
  63. * psc_i2s_set_sysclk: set the clock frequency and direction
  64. *
  65. * This function is called by the machine driver to tell us what the clock
  66. * frequency and direction are.
  67. *
  68. * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
  69. * and we don't care about the frequency. Return an error if the direction
  70. * is not SND_SOC_CLOCK_IN.
  71. *
  72. * @clk_id: reserved, should be zero
  73. * @freq: the frequency of the given clock ID, currently ignored
  74. * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
  75. */
  76. static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
  77. int clk_id, unsigned int freq, int dir)
  78. {
  79. struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
  80. dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
  81. cpu_dai, dir);
  82. return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
  83. }
  84. /**
  85. * psc_i2s_set_fmt: set the serial format.
  86. *
  87. * This function is called by the machine driver to tell us what serial
  88. * format to use.
  89. *
  90. * This driver only supports I2S mode. Return an error if the format is
  91. * not SND_SOC_DAIFMT_I2S.
  92. *
  93. * @format: one of SND_SOC_DAIFMT_xxx
  94. */
  95. static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
  96. {
  97. struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
  98. dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
  99. cpu_dai, format);
  100. return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
  101. }
  102. /* ---------------------------------------------------------------------
  103. * ALSA SoC Bindings
  104. *
  105. * - Digital Audio Interface (DAI) template
  106. * - create/destroy dai hooks
  107. */
  108. /**
  109. * psc_i2s_dai_template: template CPU Digital Audio Interface
  110. */
  111. static const struct snd_soc_dai_ops psc_i2s_dai_ops = {
  112. .hw_params = psc_i2s_hw_params,
  113. .set_sysclk = psc_i2s_set_sysclk,
  114. .set_fmt = psc_i2s_set_fmt,
  115. };
  116. static struct snd_soc_dai_driver psc_i2s_dai[] = {{
  117. .name = "mpc5200-psc-i2s.0",
  118. .playback = {
  119. .stream_name = "I2S Playback",
  120. .channels_min = 2,
  121. .channels_max = 2,
  122. .rates = PSC_I2S_RATES,
  123. .formats = PSC_I2S_FORMATS,
  124. },
  125. .capture = {
  126. .stream_name = "I2S Capture",
  127. .channels_min = 2,
  128. .channels_max = 2,
  129. .rates = PSC_I2S_RATES,
  130. .formats = PSC_I2S_FORMATS,
  131. },
  132. .ops = &psc_i2s_dai_ops,
  133. } };
  134. static const struct snd_soc_component_driver psc_i2s_component = {
  135. .name = "mpc5200-i2s",
  136. };
  137. /* ---------------------------------------------------------------------
  138. * OF platform bus binding code:
  139. * - Probe/remove operations
  140. * - OF device match table
  141. */
  142. static int psc_i2s_of_probe(struct platform_device *op)
  143. {
  144. int rc;
  145. struct psc_dma *psc_dma;
  146. struct mpc52xx_psc __iomem *regs;
  147. rc = mpc5200_audio_dma_create(op);
  148. if (rc != 0)
  149. return rc;
  150. rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
  151. psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
  152. if (rc != 0) {
  153. pr_err("Failed to register DAI\n");
  154. return rc;
  155. }
  156. psc_dma = dev_get_drvdata(&op->dev);
  157. regs = psc_dma->psc_regs;
  158. /* Configure the serial interface mode; defaulting to CODEC8 mode */
  159. psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
  160. MPC52xx_PSC_SICR_CLKPOL;
  161. out_be32(&psc_dma->psc_regs->sicr,
  162. psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
  163. /* Check for the codec handle. If it is not present then we
  164. * are done */
  165. if (!of_get_property(op->dev.of_node, "codec-handle", NULL))
  166. return 0;
  167. /* Due to errata in the dma mode; need to line up enabling
  168. * the transmitter with a transition on the frame sync
  169. * line */
  170. /* first make sure it is low */
  171. while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
  172. ;
  173. /* then wait for the transition to high */
  174. while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
  175. ;
  176. /* Finally, enable the PSC.
  177. * Receiver must always be enabled; even when we only want
  178. * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */
  179. /* Go */
  180. out_8(&psc_dma->psc_regs->command,
  181. MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
  182. return 0;
  183. }
  184. static int psc_i2s_of_remove(struct platform_device *op)
  185. {
  186. mpc5200_audio_dma_destroy(op);
  187. snd_soc_unregister_component(&op->dev);
  188. return 0;
  189. }
  190. /* Match table for of_platform binding */
  191. static const struct of_device_id psc_i2s_match[] = {
  192. { .compatible = "fsl,mpc5200-psc-i2s", },
  193. { .compatible = "fsl,mpc5200b-psc-i2s", },
  194. {}
  195. };
  196. MODULE_DEVICE_TABLE(of, psc_i2s_match);
  197. static struct platform_driver psc_i2s_driver = {
  198. .probe = psc_i2s_of_probe,
  199. .remove = psc_i2s_of_remove,
  200. .driver = {
  201. .name = "mpc5200-psc-i2s",
  202. .of_match_table = psc_i2s_match,
  203. },
  204. };
  205. module_platform_driver(psc_i2s_driver);
  206. MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
  207. MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
  208. MODULE_LICENSE("GPL");