tm2_wm5110.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*
  2. * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
  3. *
  4. * Authors: Inha Song <ideal.song@samsung.com>
  5. * Sylwester Nawrocki <s.nawrocki@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or (at your
  10. * option) any later version.
  11. */
  12. #include <linux/clk.h>
  13. #include <linux/gpio.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/soc.h>
  18. #include "i2s.h"
  19. #include "../codecs/wm5110.h"
  20. /*
  21. * The source clock is XCLKOUT with its mux set to the external fixed rate
  22. * oscillator (XXTI).
  23. */
  24. #define MCLK_RATE 24000000U
  25. #define TM2_DAI_AIF1 0
  26. #define TM2_DAI_AIF2 1
  27. struct tm2_machine_priv {
  28. struct snd_soc_codec *codec;
  29. unsigned int sysclk_rate;
  30. struct gpio_desc *gpio_mic_bias;
  31. };
  32. static int tm2_start_sysclk(struct snd_soc_card *card)
  33. {
  34. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  35. struct snd_soc_codec *codec = priv->codec;
  36. int ret;
  37. ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
  38. ARIZONA_FLL_SRC_MCLK1,
  39. MCLK_RATE,
  40. priv->sysclk_rate);
  41. if (ret < 0) {
  42. dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret);
  43. return ret;
  44. }
  45. ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
  46. ARIZONA_FLL_SRC_MCLK1,
  47. MCLK_RATE,
  48. priv->sysclk_rate);
  49. if (ret < 0) {
  50. dev_err(codec->dev, "Failed to start FLL1: %d\n", ret);
  51. return ret;
  52. }
  53. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
  54. ARIZONA_CLK_SRC_FLL1,
  55. priv->sysclk_rate,
  56. SND_SOC_CLOCK_IN);
  57. if (ret < 0) {
  58. dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret);
  59. return ret;
  60. }
  61. return 0;
  62. }
  63. static int tm2_stop_sysclk(struct snd_soc_card *card)
  64. {
  65. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  66. struct snd_soc_codec *codec = priv->codec;
  67. int ret;
  68. ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
  69. if (ret < 0) {
  70. dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret);
  71. return ret;
  72. }
  73. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
  74. ARIZONA_CLK_SRC_FLL1, 0, 0);
  75. if (ret < 0) {
  76. dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
  77. return ret;
  78. }
  79. return 0;
  80. }
  81. static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
  82. struct snd_pcm_hw_params *params)
  83. {
  84. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  85. struct snd_soc_codec *codec = rtd->codec;
  86. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
  87. switch (params_rate(params)) {
  88. case 4000:
  89. case 8000:
  90. case 12000:
  91. case 16000:
  92. case 24000:
  93. case 32000:
  94. case 48000:
  95. case 96000:
  96. case 192000:
  97. /* Highest possible SYSCLK frequency: 147.456MHz */
  98. priv->sysclk_rate = 147456000U;
  99. break;
  100. case 11025:
  101. case 22050:
  102. case 44100:
  103. case 88200:
  104. case 176400:
  105. /* Highest possible SYSCLK frequency: 135.4752 MHz */
  106. priv->sysclk_rate = 135475200U;
  107. break;
  108. default:
  109. dev_err(codec->dev, "Not supported sample rate: %d\n",
  110. params_rate(params));
  111. return -EINVAL;
  112. }
  113. return tm2_start_sysclk(rtd->card);
  114. }
  115. static struct snd_soc_ops tm2_aif1_ops = {
  116. .hw_params = tm2_aif1_hw_params,
  117. };
  118. static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
  119. struct snd_pcm_hw_params *params)
  120. {
  121. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  122. struct snd_soc_codec *codec = rtd->codec;
  123. unsigned int asyncclk_rate;
  124. int ret;
  125. switch (params_rate(params)) {
  126. case 8000:
  127. case 12000:
  128. case 16000:
  129. /* Highest possible ASYNCCLK frequency: 49.152MHz */
  130. asyncclk_rate = 49152000U;
  131. break;
  132. case 11025:
  133. /* Highest possible ASYNCCLK frequency: 45.1584 MHz */
  134. asyncclk_rate = 45158400U;
  135. break;
  136. default:
  137. dev_err(codec->dev, "Not supported sample rate: %d\n",
  138. params_rate(params));
  139. return -EINVAL;
  140. }
  141. ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK,
  142. ARIZONA_FLL_SRC_MCLK1,
  143. MCLK_RATE,
  144. asyncclk_rate);
  145. if (ret < 0) {
  146. dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret);
  147. return ret;
  148. }
  149. ret = snd_soc_codec_set_pll(codec, WM5110_FLL2,
  150. ARIZONA_FLL_SRC_MCLK1,
  151. MCLK_RATE,
  152. asyncclk_rate);
  153. if (ret < 0) {
  154. dev_err(codec->dev, "Failed to start FLL2: %d\n", ret);
  155. return ret;
  156. }
  157. ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
  158. ARIZONA_CLK_SRC_FLL2,
  159. asyncclk_rate,
  160. SND_SOC_CLOCK_IN);
  161. if (ret < 0) {
  162. dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret);
  163. return ret;
  164. }
  165. return 0;
  166. }
  167. static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
  168. {
  169. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  170. struct snd_soc_codec *codec = rtd->codec;
  171. int ret;
  172. /* disable FLL2 */
  173. ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
  174. 0, 0);
  175. if (ret < 0)
  176. dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret);
  177. return ret;
  178. }
  179. static struct snd_soc_ops tm2_aif2_ops = {
  180. .hw_params = tm2_aif2_hw_params,
  181. .hw_free = tm2_aif2_hw_free,
  182. };
  183. static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
  184. struct snd_kcontrol *kcontrol, int event)
  185. {
  186. struct snd_soc_card *card = w->dapm->card;
  187. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  188. switch (event) {
  189. case SND_SOC_DAPM_PRE_PMU:
  190. gpiod_set_value_cansleep(priv->gpio_mic_bias, 1);
  191. break;
  192. case SND_SOC_DAPM_POST_PMD:
  193. gpiod_set_value_cansleep(priv->gpio_mic_bias, 0);
  194. break;
  195. }
  196. return 0;
  197. }
  198. static int tm2_set_bias_level(struct snd_soc_card *card,
  199. struct snd_soc_dapm_context *dapm,
  200. enum snd_soc_bias_level level)
  201. {
  202. struct snd_soc_pcm_runtime *rtd;
  203. rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
  204. if (dapm->dev != rtd->codec_dai->dev)
  205. return 0;
  206. switch (level) {
  207. case SND_SOC_BIAS_STANDBY:
  208. if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
  209. tm2_start_sysclk(card);
  210. break;
  211. case SND_SOC_BIAS_OFF:
  212. tm2_stop_sysclk(card);
  213. break;
  214. default:
  215. break;
  216. }
  217. return 0;
  218. }
  219. static struct snd_soc_aux_dev tm2_speaker_amp_dev;
  220. static int tm2_late_probe(struct snd_soc_card *card)
  221. {
  222. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  223. struct snd_soc_dai_link_component dlc = { 0 };
  224. unsigned int ch_map[] = { 0, 1 };
  225. struct snd_soc_dai *amp_pdm_dai;
  226. struct snd_soc_pcm_runtime *rtd;
  227. struct snd_soc_dai *aif1_dai;
  228. struct snd_soc_dai *aif2_dai;
  229. int ret;
  230. rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
  231. aif1_dai = rtd->codec_dai;
  232. priv->codec = rtd->codec;
  233. ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
  234. if (ret < 0) {
  235. dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret);
  236. return ret;
  237. }
  238. rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name);
  239. aif2_dai = rtd->codec_dai;
  240. ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
  241. if (ret < 0) {
  242. dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret);
  243. return ret;
  244. }
  245. dlc.of_node = tm2_speaker_amp_dev.codec_of_node;
  246. amp_pdm_dai = snd_soc_find_dai(&dlc);
  247. if (!amp_pdm_dai)
  248. return -ENODEV;
  249. /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
  250. ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map),
  251. ch_map, 0, NULL);
  252. if (ret < 0)
  253. return ret;
  254. ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16);
  255. if (ret < 0)
  256. return ret;
  257. return 0;
  258. }
  259. static const struct snd_kcontrol_new tm2_controls[] = {
  260. SOC_DAPM_PIN_SWITCH("HP"),
  261. SOC_DAPM_PIN_SWITCH("SPK"),
  262. SOC_DAPM_PIN_SWITCH("RCV"),
  263. SOC_DAPM_PIN_SWITCH("VPS"),
  264. SOC_DAPM_PIN_SWITCH("HDMI"),
  265. SOC_DAPM_PIN_SWITCH("Main Mic"),
  266. SOC_DAPM_PIN_SWITCH("Sub Mic"),
  267. SOC_DAPM_PIN_SWITCH("Third Mic"),
  268. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  269. };
  270. const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
  271. SND_SOC_DAPM_HP("HP", NULL),
  272. SND_SOC_DAPM_SPK("SPK", NULL),
  273. SND_SOC_DAPM_SPK("RCV", NULL),
  274. SND_SOC_DAPM_LINE("VPS", NULL),
  275. SND_SOC_DAPM_LINE("HDMI", NULL),
  276. SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias),
  277. SND_SOC_DAPM_MIC("Sub Mic", NULL),
  278. SND_SOC_DAPM_MIC("Third Mic", NULL),
  279. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  280. };
  281. static const struct snd_soc_component_driver tm2_component = {
  282. .name = "tm2-audio",
  283. };
  284. static struct snd_soc_dai_driver tm2_ext_dai[] = {
  285. {
  286. .name = "Voice call",
  287. .playback = {
  288. .channels_min = 1,
  289. .channels_max = 4,
  290. .rate_min = 8000,
  291. .rate_max = 48000,
  292. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  293. SNDRV_PCM_RATE_48000),
  294. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  295. },
  296. .capture = {
  297. .channels_min = 1,
  298. .channels_max = 4,
  299. .rate_min = 8000,
  300. .rate_max = 48000,
  301. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  302. SNDRV_PCM_RATE_48000),
  303. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  304. },
  305. },
  306. {
  307. .name = "Bluetooth",
  308. .playback = {
  309. .channels_min = 1,
  310. .channels_max = 4,
  311. .rate_min = 8000,
  312. .rate_max = 16000,
  313. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
  314. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  315. },
  316. .capture = {
  317. .channels_min = 1,
  318. .channels_max = 2,
  319. .rate_min = 8000,
  320. .rate_max = 16000,
  321. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
  322. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  323. },
  324. },
  325. };
  326. static struct snd_soc_dai_link tm2_dai_links[] = {
  327. {
  328. .name = "WM5110 AIF1",
  329. .stream_name = "HiFi Primary",
  330. .codec_dai_name = "wm5110-aif1",
  331. .ops = &tm2_aif1_ops,
  332. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  333. SND_SOC_DAIFMT_CBM_CFM,
  334. }, {
  335. .name = "WM5110 Voice",
  336. .stream_name = "Voice call",
  337. .codec_dai_name = "wm5110-aif2",
  338. .ops = &tm2_aif2_ops,
  339. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  340. SND_SOC_DAIFMT_CBM_CFM,
  341. .ignore_suspend = 1,
  342. }, {
  343. .name = "WM5110 BT",
  344. .stream_name = "Bluetooth",
  345. .codec_dai_name = "wm5110-aif3",
  346. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  347. SND_SOC_DAIFMT_CBM_CFM,
  348. .ignore_suspend = 1,
  349. }
  350. };
  351. static struct snd_soc_card tm2_card = {
  352. .owner = THIS_MODULE,
  353. .dai_link = tm2_dai_links,
  354. .num_links = ARRAY_SIZE(tm2_dai_links),
  355. .controls = tm2_controls,
  356. .num_controls = ARRAY_SIZE(tm2_controls),
  357. .dapm_widgets = tm2_dapm_widgets,
  358. .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets),
  359. .aux_dev = &tm2_speaker_amp_dev,
  360. .num_aux_devs = 1,
  361. .late_probe = tm2_late_probe,
  362. .set_bias_level = tm2_set_bias_level,
  363. };
  364. static int tm2_probe(struct platform_device *pdev)
  365. {
  366. struct device *dev = &pdev->dev;
  367. struct snd_soc_card *card = &tm2_card;
  368. struct tm2_machine_priv *priv;
  369. struct device_node *cpu_dai_node, *codec_dai_node;
  370. int ret, i;
  371. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  372. if (!priv)
  373. return -ENOMEM;
  374. snd_soc_card_set_drvdata(card, priv);
  375. card->dev = dev;
  376. priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias",
  377. GPIOF_OUT_INIT_LOW);
  378. if (IS_ERR(priv->gpio_mic_bias)) {
  379. dev_err(dev, "Failed to get mic bias gpio\n");
  380. return PTR_ERR(priv->gpio_mic_bias);
  381. }
  382. ret = snd_soc_of_parse_card_name(card, "model");
  383. if (ret < 0) {
  384. dev_err(dev, "Card name is not specified\n");
  385. return ret;
  386. }
  387. ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
  388. if (ret < 0) {
  389. dev_err(dev, "Audio routing is not specified or invalid\n");
  390. return ret;
  391. }
  392. card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node,
  393. "audio-amplifier", 0);
  394. if (!card->aux_dev[0].codec_of_node) {
  395. dev_err(dev, "audio-amplifier property invalid or missing\n");
  396. return -EINVAL;
  397. }
  398. cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0);
  399. if (!cpu_dai_node) {
  400. dev_err(dev, "i2s-controllers property invalid or missing\n");
  401. ret = -EINVAL;
  402. goto amp_node_put;
  403. }
  404. codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0);
  405. if (!codec_dai_node) {
  406. dev_err(dev, "audio-codec property invalid or missing\n");
  407. ret = -EINVAL;
  408. goto cpu_dai_node_put;
  409. }
  410. for (i = 0; i < card->num_links; i++) {
  411. card->dai_link[i].cpu_dai_name = NULL;
  412. card->dai_link[i].cpu_name = NULL;
  413. card->dai_link[i].platform_name = NULL;
  414. card->dai_link[i].codec_of_node = codec_dai_node;
  415. card->dai_link[i].cpu_of_node = cpu_dai_node;
  416. card->dai_link[i].platform_of_node = cpu_dai_node;
  417. }
  418. ret = devm_snd_soc_register_component(dev, &tm2_component,
  419. tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
  420. if (ret < 0) {
  421. dev_err(dev, "Failed to register component: %d\n", ret);
  422. goto codec_dai_node_put;
  423. }
  424. ret = devm_snd_soc_register_card(dev, card);
  425. if (ret < 0) {
  426. dev_err(dev, "Failed to register card: %d\n", ret);
  427. goto codec_dai_node_put;
  428. }
  429. codec_dai_node_put:
  430. of_node_put(codec_dai_node);
  431. cpu_dai_node_put:
  432. of_node_put(cpu_dai_node);
  433. amp_node_put:
  434. of_node_put(card->aux_dev[0].codec_of_node);
  435. return ret;
  436. }
  437. static int tm2_pm_prepare(struct device *dev)
  438. {
  439. struct snd_soc_card *card = dev_get_drvdata(dev);
  440. return tm2_stop_sysclk(card);
  441. }
  442. static void tm2_pm_complete(struct device *dev)
  443. {
  444. struct snd_soc_card *card = dev_get_drvdata(dev);
  445. tm2_start_sysclk(card);
  446. }
  447. const struct dev_pm_ops tm2_pm_ops = {
  448. .prepare = tm2_pm_prepare,
  449. .suspend = snd_soc_suspend,
  450. .resume = snd_soc_resume,
  451. .complete = tm2_pm_complete,
  452. .freeze = snd_soc_suspend,
  453. .thaw = snd_soc_resume,
  454. .poweroff = snd_soc_poweroff,
  455. .restore = snd_soc_resume,
  456. };
  457. static const struct of_device_id tm2_of_match[] = {
  458. { .compatible = "samsung,tm2-audio" },
  459. { },
  460. };
  461. MODULE_DEVICE_TABLE(of, tm2_of_match);
  462. static struct platform_driver tm2_driver = {
  463. .driver = {
  464. .name = "tm2-audio",
  465. .pm = &tm2_pm_ops,
  466. .of_match_table = tm2_of_match,
  467. },
  468. .probe = tm2_probe,
  469. };
  470. module_platform_driver(tm2_driver);
  471. MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>");
  472. MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
  473. MODULE_LICENSE("GPL v2");