bells.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * Bells audio support
  3. *
  4. * Copyright 2012 Wolfson Microelectronics
  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. #include <sound/soc.h>
  12. #include <sound/soc-dapm.h>
  13. #include <sound/jack.h>
  14. #include <linux/gpio.h>
  15. #include <linux/module.h>
  16. #include "../codecs/wm5102.h"
  17. #include "../codecs/wm9081.h"
  18. /* BCLK2 is fixed at this currently */
  19. #define BCLK2_RATE (64 * 8000)
  20. /*
  21. * Expect a 24.576MHz crystal if one is fitted (the driver will function
  22. * if this is not fitted).
  23. */
  24. #define MCLK_RATE 24576000
  25. #define SYS_AUDIO_RATE 44100
  26. #define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512)
  27. #define DAI_AP_DSP 0
  28. #define DAI_DSP_CODEC 1
  29. #define DAI_CODEC_CP 2
  30. #define DAI_CODEC_SUB 3
  31. struct bells_drvdata {
  32. int sysclk_rate;
  33. int asyncclk_rate;
  34. };
  35. static struct bells_drvdata wm2200_drvdata = {
  36. .sysclk_rate = 22579200,
  37. };
  38. static struct bells_drvdata wm5102_drvdata = {
  39. .sysclk_rate = 45158400,
  40. .asyncclk_rate = 49152000,
  41. };
  42. static struct bells_drvdata wm5110_drvdata = {
  43. .sysclk_rate = 135475200,
  44. .asyncclk_rate = 147456000,
  45. };
  46. static int bells_set_bias_level(struct snd_soc_card *card,
  47. struct snd_soc_dapm_context *dapm,
  48. enum snd_soc_bias_level level)
  49. {
  50. struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
  51. struct snd_soc_codec *codec = codec_dai->codec;
  52. struct bells_drvdata *bells = card->drvdata;
  53. int ret;
  54. if (dapm->dev != codec_dai->dev)
  55. return 0;
  56. switch (level) {
  57. case SND_SOC_BIAS_PREPARE:
  58. if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
  59. break;
  60. ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
  61. ARIZONA_FLL_SRC_MCLK1,
  62. MCLK_RATE,
  63. bells->sysclk_rate);
  64. if (ret < 0)
  65. pr_err("Failed to start FLL: %d\n", ret);
  66. if (bells->asyncclk_rate) {
  67. ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
  68. ARIZONA_FLL_SRC_AIF2BCLK,
  69. BCLK2_RATE,
  70. bells->asyncclk_rate);
  71. if (ret < 0)
  72. pr_err("Failed to start FLL: %d\n", ret);
  73. }
  74. break;
  75. default:
  76. break;
  77. }
  78. return 0;
  79. }
  80. static int bells_set_bias_level_post(struct snd_soc_card *card,
  81. struct snd_soc_dapm_context *dapm,
  82. enum snd_soc_bias_level level)
  83. {
  84. struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
  85. struct snd_soc_codec *codec = codec_dai->codec;
  86. struct bells_drvdata *bells = card->drvdata;
  87. int ret;
  88. if (dapm->dev != codec_dai->dev)
  89. return 0;
  90. switch (level) {
  91. case SND_SOC_BIAS_STANDBY:
  92. ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
  93. if (ret < 0) {
  94. pr_err("Failed to stop FLL: %d\n", ret);
  95. return ret;
  96. }
  97. if (bells->asyncclk_rate) {
  98. ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
  99. 0, 0, 0);
  100. if (ret < 0) {
  101. pr_err("Failed to stop FLL: %d\n", ret);
  102. return ret;
  103. }
  104. }
  105. break;
  106. default:
  107. break;
  108. }
  109. dapm->bias_level = level;
  110. return 0;
  111. }
  112. static int bells_late_probe(struct snd_soc_card *card)
  113. {
  114. struct bells_drvdata *bells = card->drvdata;
  115. struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
  116. struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
  117. struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
  118. struct snd_soc_dai *aif2_dai;
  119. struct snd_soc_dai *aif3_dai;
  120. struct snd_soc_dai *wm9081_dai;
  121. int ret;
  122. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
  123. ARIZONA_CLK_SRC_FLL1,
  124. bells->sysclk_rate,
  125. SND_SOC_CLOCK_IN);
  126. if (ret != 0) {
  127. dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
  128. return ret;
  129. }
  130. ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
  131. if (ret != 0) {
  132. dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret);
  133. return ret;
  134. }
  135. ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
  136. if (ret != 0)
  137. dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
  138. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
  139. SYS_MCLK_RATE, SND_SOC_CLOCK_OUT);
  140. if (ret != 0)
  141. dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
  142. if (card->num_rtd == DAI_CODEC_CP)
  143. return 0;
  144. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
  145. ARIZONA_CLK_SRC_FLL2,
  146. bells->asyncclk_rate,
  147. SND_SOC_CLOCK_IN);
  148. if (ret != 0) {
  149. dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret);
  150. return ret;
  151. }
  152. aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
  153. ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
  154. if (ret != 0) {
  155. dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
  156. return ret;
  157. }
  158. if (card->num_rtd == DAI_CODEC_SUB)
  159. return 0;
  160. aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
  161. wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
  162. ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
  163. if (ret != 0) {
  164. dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
  165. return ret;
  166. }
  167. ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
  168. 0, SYS_MCLK_RATE, 0);
  169. if (ret != 0) {
  170. dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
  171. return ret;
  172. }
  173. return 0;
  174. }
  175. static const struct snd_soc_pcm_stream baseband_params = {
  176. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  177. .rate_min = 8000,
  178. .rate_max = 8000,
  179. .channels_min = 2,
  180. .channels_max = 2,
  181. };
  182. static const struct snd_soc_pcm_stream sub_params = {
  183. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  184. .rate_min = SYS_AUDIO_RATE,
  185. .rate_max = SYS_AUDIO_RATE,
  186. .channels_min = 2,
  187. .channels_max = 2,
  188. };
  189. static struct snd_soc_dai_link bells_dai_wm2200[] = {
  190. {
  191. .name = "CPU-DSP",
  192. .stream_name = "CPU-DSP",
  193. .cpu_dai_name = "samsung-i2s.0",
  194. .codec_dai_name = "wm0010-sdi1",
  195. .platform_name = "samsung-i2s.0",
  196. .codec_name = "spi0.0",
  197. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  198. | SND_SOC_DAIFMT_CBM_CFM,
  199. },
  200. {
  201. .name = "DSP-CODEC",
  202. .stream_name = "DSP-CODEC",
  203. .cpu_dai_name = "wm0010-sdi2",
  204. .codec_dai_name = "wm2200",
  205. .codec_name = "wm2200.1-003a",
  206. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  207. | SND_SOC_DAIFMT_CBM_CFM,
  208. .params = &sub_params,
  209. .ignore_suspend = 1,
  210. },
  211. };
  212. static struct snd_soc_dai_link bells_dai_wm5102[] = {
  213. {
  214. .name = "CPU-DSP",
  215. .stream_name = "CPU-DSP",
  216. .cpu_dai_name = "samsung-i2s.0",
  217. .codec_dai_name = "wm0010-sdi1",
  218. .platform_name = "samsung-i2s.0",
  219. .codec_name = "spi0.0",
  220. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  221. | SND_SOC_DAIFMT_CBM_CFM,
  222. },
  223. {
  224. .name = "DSP-CODEC",
  225. .stream_name = "DSP-CODEC",
  226. .cpu_dai_name = "wm0010-sdi2",
  227. .codec_dai_name = "wm5102-aif1",
  228. .codec_name = "wm5102-codec",
  229. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  230. | SND_SOC_DAIFMT_CBM_CFM,
  231. .params = &sub_params,
  232. .ignore_suspend = 1,
  233. },
  234. {
  235. .name = "Baseband",
  236. .stream_name = "Baseband",
  237. .cpu_dai_name = "wm5102-aif2",
  238. .codec_dai_name = "wm1250-ev1",
  239. .codec_name = "wm1250-ev1.1-0027",
  240. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  241. | SND_SOC_DAIFMT_CBM_CFM,
  242. .ignore_suspend = 1,
  243. .params = &baseband_params,
  244. },
  245. {
  246. .name = "Sub",
  247. .stream_name = "Sub",
  248. .cpu_dai_name = "wm5102-aif3",
  249. .codec_dai_name = "wm9081-hifi",
  250. .codec_name = "wm9081.1-006c",
  251. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  252. | SND_SOC_DAIFMT_CBS_CFS,
  253. .ignore_suspend = 1,
  254. .params = &sub_params,
  255. },
  256. };
  257. static struct snd_soc_dai_link bells_dai_wm5110[] = {
  258. {
  259. .name = "CPU-DSP",
  260. .stream_name = "CPU-DSP",
  261. .cpu_dai_name = "samsung-i2s.0",
  262. .codec_dai_name = "wm0010-sdi1",
  263. .platform_name = "samsung-i2s.0",
  264. .codec_name = "spi0.0",
  265. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  266. | SND_SOC_DAIFMT_CBM_CFM,
  267. },
  268. {
  269. .name = "DSP-CODEC",
  270. .stream_name = "DSP-CODEC",
  271. .cpu_dai_name = "wm0010-sdi2",
  272. .codec_dai_name = "wm5110-aif1",
  273. .codec_name = "wm5110-codec",
  274. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  275. | SND_SOC_DAIFMT_CBM_CFM,
  276. .params = &sub_params,
  277. .ignore_suspend = 1,
  278. },
  279. {
  280. .name = "Baseband",
  281. .stream_name = "Baseband",
  282. .cpu_dai_name = "wm5110-aif2",
  283. .codec_dai_name = "wm1250-ev1",
  284. .codec_name = "wm1250-ev1.1-0027",
  285. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  286. | SND_SOC_DAIFMT_CBM_CFM,
  287. .ignore_suspend = 1,
  288. .params = &baseband_params,
  289. },
  290. {
  291. .name = "Sub",
  292. .stream_name = "Sub",
  293. .cpu_dai_name = "wm5110-aif3",
  294. .codec_dai_name = "wm9081-hifi",
  295. .codec_name = "wm9081.1-006c",
  296. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  297. | SND_SOC_DAIFMT_CBS_CFS,
  298. .ignore_suspend = 1,
  299. .params = &sub_params,
  300. },
  301. };
  302. static struct snd_soc_codec_conf bells_codec_conf[] = {
  303. {
  304. .dev_name = "wm9081.1-006c",
  305. .name_prefix = "Sub",
  306. },
  307. };
  308. static struct snd_soc_dapm_route bells_routes[] = {
  309. { "Sub CLK_SYS", NULL, "OPCLK" },
  310. };
  311. static struct snd_soc_card bells_cards[] = {
  312. {
  313. .name = "Bells WM2200",
  314. .owner = THIS_MODULE,
  315. .dai_link = bells_dai_wm2200,
  316. .num_links = ARRAY_SIZE(bells_dai_wm2200),
  317. .codec_conf = bells_codec_conf,
  318. .num_configs = ARRAY_SIZE(bells_codec_conf),
  319. .late_probe = bells_late_probe,
  320. .dapm_routes = bells_routes,
  321. .num_dapm_routes = ARRAY_SIZE(bells_routes),
  322. .set_bias_level = bells_set_bias_level,
  323. .set_bias_level_post = bells_set_bias_level_post,
  324. .drvdata = &wm2200_drvdata,
  325. },
  326. {
  327. .name = "Bells WM5102",
  328. .owner = THIS_MODULE,
  329. .dai_link = bells_dai_wm5102,
  330. .num_links = ARRAY_SIZE(bells_dai_wm5102),
  331. .codec_conf = bells_codec_conf,
  332. .num_configs = ARRAY_SIZE(bells_codec_conf),
  333. .late_probe = bells_late_probe,
  334. .dapm_routes = bells_routes,
  335. .num_dapm_routes = ARRAY_SIZE(bells_routes),
  336. .set_bias_level = bells_set_bias_level,
  337. .set_bias_level_post = bells_set_bias_level_post,
  338. .drvdata = &wm5102_drvdata,
  339. },
  340. {
  341. .name = "Bells WM5110",
  342. .owner = THIS_MODULE,
  343. .dai_link = bells_dai_wm5110,
  344. .num_links = ARRAY_SIZE(bells_dai_wm5110),
  345. .codec_conf = bells_codec_conf,
  346. .num_configs = ARRAY_SIZE(bells_codec_conf),
  347. .late_probe = bells_late_probe,
  348. .dapm_routes = bells_routes,
  349. .num_dapm_routes = ARRAY_SIZE(bells_routes),
  350. .set_bias_level = bells_set_bias_level,
  351. .set_bias_level_post = bells_set_bias_level_post,
  352. .drvdata = &wm5110_drvdata,
  353. },
  354. };
  355. static int bells_probe(struct platform_device *pdev)
  356. {
  357. int ret;
  358. bells_cards[pdev->id].dev = &pdev->dev;
  359. ret = snd_soc_register_card(&bells_cards[pdev->id]);
  360. if (ret) {
  361. dev_err(&pdev->dev,
  362. "snd_soc_register_card(%s) failed: %d\n",
  363. bells_cards[pdev->id].name, ret);
  364. return ret;
  365. }
  366. return 0;
  367. }
  368. static int bells_remove(struct platform_device *pdev)
  369. {
  370. snd_soc_unregister_card(&bells_cards[pdev->id]);
  371. return 0;
  372. }
  373. static struct platform_driver bells_driver = {
  374. .driver = {
  375. .name = "bells",
  376. .owner = THIS_MODULE,
  377. .pm = &snd_soc_pm_ops,
  378. },
  379. .probe = bells_probe,
  380. .remove = bells_remove,
  381. };
  382. module_platform_driver(bells_driver);
  383. MODULE_DESCRIPTION("Bells audio support");
  384. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  385. MODULE_LICENSE("GPL");
  386. MODULE_ALIAS("platform:bells");