bf6xx-i2s.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. break;
  83. case SNDRV_PCM_FORMAT_S16_LE:
  84. param.spctl |= 0xf0;
  85. sport->wdsize = 2;
  86. break;
  87. case SNDRV_PCM_FORMAT_S24_LE:
  88. param.spctl |= 0x170;
  89. sport->wdsize = 3;
  90. break;
  91. case SNDRV_PCM_FORMAT_S32_LE:
  92. param.spctl |= 0x1f0;
  93. sport->wdsize = 4;
  94. break;
  95. }
  96. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  97. ret = sport_set_tx_params(sport, &param);
  98. if (ret) {
  99. dev_err(dev, "SPORT tx is busy!\n");
  100. return ret;
  101. }
  102. } else {
  103. ret = sport_set_rx_params(sport, &param);
  104. if (ret) {
  105. dev_err(dev, "SPORT rx is busy!\n");
  106. return ret;
  107. }
  108. }
  109. return 0;
  110. }
  111. #ifdef CONFIG_PM
  112. static int bfin_i2s_suspend(struct snd_soc_dai *dai)
  113. {
  114. struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
  115. if (dai->capture_active)
  116. sport_rx_stop(sport);
  117. if (dai->playback_active)
  118. sport_tx_stop(sport);
  119. return 0;
  120. }
  121. static int bfin_i2s_resume(struct snd_soc_dai *dai)
  122. {
  123. struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
  124. struct device *dev = &sport->pdev->dev;
  125. int ret;
  126. ret = sport_set_tx_params(sport, &param);
  127. if (ret) {
  128. dev_err(dev, "SPORT tx is busy!\n");
  129. return ret;
  130. }
  131. ret = sport_set_rx_params(sport, &param);
  132. if (ret) {
  133. dev_err(dev, "SPORT rx is busy!\n");
  134. return ret;
  135. }
  136. return 0;
  137. }
  138. #else
  139. #define bfin_i2s_suspend NULL
  140. #define bfin_i2s_resume NULL
  141. #endif
  142. #define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
  143. SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
  144. SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
  145. SNDRV_PCM_RATE_96000)
  146. #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
  147. SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
  148. static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
  149. .hw_params = bfin_i2s_hw_params,
  150. .set_fmt = bfin_i2s_set_dai_fmt,
  151. };
  152. static struct snd_soc_dai_driver bfin_i2s_dai = {
  153. .suspend = bfin_i2s_suspend,
  154. .resume = bfin_i2s_resume,
  155. .playback = {
  156. .channels_min = 1,
  157. .channels_max = 2,
  158. .rates = BFIN_I2S_RATES,
  159. .formats = BFIN_I2S_FORMATS,
  160. },
  161. .capture = {
  162. .channels_min = 1,
  163. .channels_max = 2,
  164. .rates = BFIN_I2S_RATES,
  165. .formats = BFIN_I2S_FORMATS,
  166. },
  167. .ops = &bfin_i2s_dai_ops,
  168. };
  169. static const struct snd_soc_component_driver bfin_i2s_component = {
  170. .name = "bfin-i2s",
  171. };
  172. static int bfin_i2s_probe(struct platform_device *pdev)
  173. {
  174. struct sport_device *sport;
  175. struct device *dev = &pdev->dev;
  176. int ret;
  177. sport = sport_create(pdev);
  178. if (!sport)
  179. return -ENODEV;
  180. /* register with the ASoC layers */
  181. ret = snd_soc_register_component(dev, &bfin_i2s_component,
  182. &bfin_i2s_dai, 1);
  183. if (ret) {
  184. dev_err(dev, "Failed to register DAI: %d\n", ret);
  185. sport_delete(sport);
  186. return ret;
  187. }
  188. platform_set_drvdata(pdev, sport);
  189. return 0;
  190. }
  191. static int bfin_i2s_remove(struct platform_device *pdev)
  192. {
  193. struct sport_device *sport = platform_get_drvdata(pdev);
  194. snd_soc_unregister_component(&pdev->dev);
  195. sport_delete(sport);
  196. return 0;
  197. }
  198. static struct platform_driver bfin_i2s_driver = {
  199. .probe = bfin_i2s_probe,
  200. .remove = bfin_i2s_remove,
  201. .driver = {
  202. .name = "bfin-i2s",
  203. },
  204. };
  205. module_platform_driver(bfin_i2s_driver);
  206. MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
  207. MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
  208. MODULE_LICENSE("GPL v2");