mpc5200_psc_i2s.c 6.5 KB

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