bf6xx-i2s.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
  3. *
  4. * Copyright (c) 2012 Analog Devices Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <linux/device.h>
  20. #include <linux/init.h>
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <sound/pcm.h>
  24. #include <sound/pcm_params.h>
  25. #include <sound/soc.h>
  26. #include <sound/soc-dai.h>
  27. #include "bf6xx-sport.h"
  28. struct sport_params param;
  29. static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
  30. unsigned int fmt)
  31. {
  32. struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
  33. struct device *dev = &sport->pdev->dev;
  34. int ret = 0;
  35. param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
  36. | SPORT_CTL_LFS | SPORT_CTL_LAFS);
  37. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  38. case SND_SOC_DAIFMT_I2S:
  39. param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
  40. | SPORT_CTL_LFS;
  41. break;
  42. case SND_SOC_DAIFMT_DSP_A:
  43. param.spctl |= SPORT_CTL_FSR;
  44. break;
  45. case SND_SOC_DAIFMT_LEFT_J:
  46. param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
  47. | SPORT_CTL_LAFS;
  48. break;
  49. default:
  50. dev_err(dev, "%s: Unknown DAI format type\n", __func__);
  51. ret = -EINVAL;
  52. break;
  53. }
  54. param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
  55. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  56. case SND_SOC_DAIFMT_CBM_CFM:
  57. break;
  58. case SND_SOC_DAIFMT_CBS_CFS:
  59. case SND_SOC_DAIFMT_CBM_CFS:
  60. case SND_SOC_DAIFMT_CBS_CFM:
  61. ret = -EINVAL;
  62. break;
  63. default:
  64. dev_err(dev, "%s: Unknown DAI master type\n", __func__);
  65. ret = -EINVAL;
  66. break;
  67. }
  68. return ret;
  69. }
  70. static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
  71. struct snd_pcm_hw_params *params,
  72. struct snd_soc_dai *dai)
  73. {
  74. struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
  75. struct device *dev = &sport->pdev->dev;
  76. int ret = 0;
  77. param.spctl &= ~SPORT_CTL_SLEN;
  78. switch (params_format(params)) {
  79. case SNDRV_PCM_FORMAT_S8:
  80. param.spctl |= 0x70;
  81. sport->wdsize = 1;
  82. case SNDRV_PCM_FORMAT_S16_LE:
  83. param.spctl |= 0xf0;
  84. sport->wdsize = 2;
  85. break;
  86. case SNDRV_PCM_FORMAT_S24_LE:
  87. param.spctl |= 0x170;
  88. sport->wdsize = 3;
  89. break;
  90. case SNDRV_PCM_FORMAT_S32_LE:
  91. param.spctl |= 0x1f0;
  92. sport->wdsize = 4;
  93. break;
  94. }
  95. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  96. ret = sport_set_tx_params(sport, &param);
  97. if (ret) {
  98. dev_err(dev, "SPORT tx is busy!\n");
  99. return ret;
  100. }
  101. } else {
  102. ret = sport_set_rx_params(sport, &param);
  103. if (ret) {
  104. dev_err(dev, "SPORT rx is busy!\n");
  105. return ret;
  106. }
  107. }
  108. return 0;
  109. }
  110. #ifdef CONFIG_PM
  111. static int bfin_i2s_suspend(struct snd_soc_dai *dai)
  112. {
  113. struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
  114. if (dai->capture_active)
  115. sport_rx_stop(sport);
  116. if (dai->playback_active)
  117. sport_tx_stop(sport);
  118. return 0;
  119. }
  120. static int bfin_i2s_resume(struct snd_soc_dai *dai)
  121. {
  122. struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
  123. struct device *dev = &sport->pdev->dev;
  124. int ret;
  125. ret = sport_set_tx_params(sport, &param);
  126. if (ret) {
  127. dev_err(dev, "SPORT tx is busy!\n");
  128. return ret;
  129. }
  130. ret = sport_set_rx_params(sport, &param);
  131. if (ret) {
  132. dev_err(dev, "SPORT rx is busy!\n");
  133. return ret;
  134. }
  135. return 0;
  136. }
  137. #else
  138. #define bfin_i2s_suspend NULL
  139. #define bfin_i2s_resume NULL
  140. #endif
  141. #define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
  142. SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
  143. SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
  144. SNDRV_PCM_RATE_96000)
  145. #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
  146. SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
  147. static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
  148. .hw_params = bfin_i2s_hw_params,
  149. .set_fmt = bfin_i2s_set_dai_fmt,
  150. };
  151. static struct snd_soc_dai_driver bfin_i2s_dai = {
  152. .suspend = bfin_i2s_suspend,
  153. .resume = bfin_i2s_resume,
  154. .playback = {
  155. .channels_min = 1,
  156. .channels_max = 2,
  157. .rates = BFIN_I2S_RATES,
  158. .formats = BFIN_I2S_FORMATS,
  159. },
  160. .capture = {
  161. .channels_min = 1,
  162. .channels_max = 2,
  163. .rates = BFIN_I2S_RATES,
  164. .formats = BFIN_I2S_FORMATS,
  165. },
  166. .ops = &bfin_i2s_dai_ops,
  167. };
  168. static int bfin_i2s_probe(struct platform_device *pdev)
  169. {
  170. struct sport_device *sport;
  171. struct device *dev = &pdev->dev;
  172. int ret;
  173. sport = sport_create(pdev);
  174. if (!sport)
  175. return -ENODEV;
  176. /* register with the ASoC layers */
  177. ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
  178. if (ret) {
  179. dev_err(dev, "Failed to register DAI: %d\n", ret);
  180. sport_delete(sport);
  181. return ret;
  182. }
  183. platform_set_drvdata(pdev, sport);
  184. return 0;
  185. }
  186. static int bfin_i2s_remove(struct platform_device *pdev)
  187. {
  188. struct sport_device *sport = platform_get_drvdata(pdev);
  189. snd_soc_unregister_dai(&pdev->dev);
  190. sport_delete(sport);
  191. return 0;
  192. }
  193. static struct platform_driver bfin_i2s_driver = {
  194. .probe = bfin_i2s_probe,
  195. .remove = bfin_i2s_remove,
  196. .driver = {
  197. .name = "bfin-i2s",
  198. .owner = THIS_MODULE,
  199. },
  200. };
  201. module_platform_driver(bfin_i2s_driver);
  202. MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
  203. MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
  204. MODULE_LICENSE("GPL v2");