tm2_wm5110.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // SPDX-License-Identifier: GPL-2.0+
  2. //
  3. // Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
  4. //
  5. // Authors: Inha Song <[email protected]>
  6. // Sylwester Nawrocki <[email protected]>
  7. #include <linux/clk.h>
  8. #include <linux/gpio.h>
  9. #include <linux/gpio/consumer.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <sound/pcm_params.h>
  13. #include <sound/soc.h>
  14. #include "i2s.h"
  15. #include "../codecs/wm5110.h"
  16. /*
  17. * The source clock is XCLKOUT with its mux set to the external fixed rate
  18. * oscillator (XXTI).
  19. */
  20. #define MCLK_RATE 24000000U
  21. #define TM2_DAI_AIF1 0
  22. #define TM2_DAI_AIF2 1
  23. struct tm2_machine_priv {
  24. struct snd_soc_component *component;
  25. unsigned int sysclk_rate;
  26. struct gpio_desc *gpio_mic_bias;
  27. };
  28. static int tm2_start_sysclk(struct snd_soc_card *card)
  29. {
  30. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  31. struct snd_soc_component *component = priv->component;
  32. int ret;
  33. ret = snd_soc_component_set_pll(component, WM5110_FLL1_REFCLK,
  34. ARIZONA_FLL_SRC_MCLK1,
  35. MCLK_RATE,
  36. priv->sysclk_rate);
  37. if (ret < 0) {
  38. dev_err(component->dev, "Failed to set FLL1 source: %d\n", ret);
  39. return ret;
  40. }
  41. ret = snd_soc_component_set_pll(component, WM5110_FLL1,
  42. ARIZONA_FLL_SRC_MCLK1,
  43. MCLK_RATE,
  44. priv->sysclk_rate);
  45. if (ret < 0) {
  46. dev_err(component->dev, "Failed to start FLL1: %d\n", ret);
  47. return ret;
  48. }
  49. ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
  50. ARIZONA_CLK_SRC_FLL1,
  51. priv->sysclk_rate,
  52. SND_SOC_CLOCK_IN);
  53. if (ret < 0) {
  54. dev_err(component->dev, "Failed to set SYSCLK source: %d\n", ret);
  55. return ret;
  56. }
  57. return 0;
  58. }
  59. static int tm2_stop_sysclk(struct snd_soc_card *card)
  60. {
  61. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  62. struct snd_soc_component *component = priv->component;
  63. int ret;
  64. ret = snd_soc_component_set_pll(component, WM5110_FLL1, 0, 0, 0);
  65. if (ret < 0) {
  66. dev_err(component->dev, "Failed to stop FLL1: %d\n", ret);
  67. return ret;
  68. }
  69. ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
  70. ARIZONA_CLK_SRC_FLL1, 0, 0);
  71. if (ret < 0) {
  72. dev_err(component->dev, "Failed to stop SYSCLK: %d\n", ret);
  73. return ret;
  74. }
  75. return 0;
  76. }
  77. static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
  78. struct snd_pcm_hw_params *params)
  79. {
  80. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  81. struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
  82. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
  83. switch (params_rate(params)) {
  84. case 4000:
  85. case 8000:
  86. case 12000:
  87. case 16000:
  88. case 24000:
  89. case 32000:
  90. case 48000:
  91. case 96000:
  92. case 192000:
  93. /* Highest possible SYSCLK frequency: 147.456MHz */
  94. priv->sysclk_rate = 147456000U;
  95. break;
  96. case 11025:
  97. case 22050:
  98. case 44100:
  99. case 88200:
  100. case 176400:
  101. /* Highest possible SYSCLK frequency: 135.4752 MHz */
  102. priv->sysclk_rate = 135475200U;
  103. break;
  104. default:
  105. dev_err(component->dev, "Not supported sample rate: %d\n",
  106. params_rate(params));
  107. return -EINVAL;
  108. }
  109. return tm2_start_sysclk(rtd->card);
  110. }
  111. static const struct snd_soc_ops tm2_aif1_ops = {
  112. .hw_params = tm2_aif1_hw_params,
  113. };
  114. static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
  115. struct snd_pcm_hw_params *params)
  116. {
  117. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  118. struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
  119. unsigned int asyncclk_rate;
  120. int ret;
  121. switch (params_rate(params)) {
  122. case 8000:
  123. case 12000:
  124. case 16000:
  125. /* Highest possible ASYNCCLK frequency: 49.152MHz */
  126. asyncclk_rate = 49152000U;
  127. break;
  128. case 11025:
  129. /* Highest possible ASYNCCLK frequency: 45.1584 MHz */
  130. asyncclk_rate = 45158400U;
  131. break;
  132. default:
  133. dev_err(component->dev, "Not supported sample rate: %d\n",
  134. params_rate(params));
  135. return -EINVAL;
  136. }
  137. ret = snd_soc_component_set_pll(component, WM5110_FLL2_REFCLK,
  138. ARIZONA_FLL_SRC_MCLK1,
  139. MCLK_RATE,
  140. asyncclk_rate);
  141. if (ret < 0) {
  142. dev_err(component->dev, "Failed to set FLL2 source: %d\n", ret);
  143. return ret;
  144. }
  145. ret = snd_soc_component_set_pll(component, WM5110_FLL2,
  146. ARIZONA_FLL_SRC_MCLK1,
  147. MCLK_RATE,
  148. asyncclk_rate);
  149. if (ret < 0) {
  150. dev_err(component->dev, "Failed to start FLL2: %d\n", ret);
  151. return ret;
  152. }
  153. ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
  154. ARIZONA_CLK_SRC_FLL2,
  155. asyncclk_rate,
  156. SND_SOC_CLOCK_IN);
  157. if (ret < 0) {
  158. dev_err(component->dev, "Failed to set ASYNCCLK source: %d\n", ret);
  159. return ret;
  160. }
  161. return 0;
  162. }
  163. static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
  164. {
  165. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  166. struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
  167. int ret;
  168. /* disable FLL2 */
  169. ret = snd_soc_component_set_pll(component, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
  170. 0, 0);
  171. if (ret < 0)
  172. dev_err(component->dev, "Failed to stop FLL2: %d\n", ret);
  173. return ret;
  174. }
  175. static const struct snd_soc_ops tm2_aif2_ops = {
  176. .hw_params = tm2_aif2_hw_params,
  177. .hw_free = tm2_aif2_hw_free,
  178. };
  179. static int tm2_hdmi_hw_params(struct snd_pcm_substream *substream,
  180. struct snd_pcm_hw_params *params)
  181. {
  182. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  183. struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
  184. unsigned int bfs;
  185. int bitwidth, ret;
  186. bitwidth = snd_pcm_format_width(params_format(params));
  187. if (bitwidth < 0) {
  188. dev_err(rtd->card->dev, "Invalid bit-width: %d\n", bitwidth);
  189. return bitwidth;
  190. }
  191. switch (bitwidth) {
  192. case 48:
  193. bfs = 64;
  194. break;
  195. case 16:
  196. bfs = 32;
  197. break;
  198. default:
  199. dev_err(rtd->card->dev, "Unsupported bit-width: %d\n", bitwidth);
  200. return -EINVAL;
  201. }
  202. switch (params_rate(params)) {
  203. case 48000:
  204. case 96000:
  205. case 192000:
  206. break;
  207. default:
  208. dev_err(rtd->card->dev, "Unsupported sample rate: %d\n",
  209. params_rate(params));
  210. return -EINVAL;
  211. }
  212. ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK,
  213. 0, SAMSUNG_I2S_OPCLK_PCLK);
  214. if (ret < 0)
  215. return ret;
  216. ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
  217. if (ret < 0)
  218. return ret;
  219. return 0;
  220. }
  221. static const struct snd_soc_ops tm2_hdmi_ops = {
  222. .hw_params = tm2_hdmi_hw_params,
  223. };
  224. static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
  225. struct snd_kcontrol *kcontrol, int event)
  226. {
  227. struct snd_soc_card *card = w->dapm->card;
  228. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  229. switch (event) {
  230. case SND_SOC_DAPM_PRE_PMU:
  231. gpiod_set_value_cansleep(priv->gpio_mic_bias, 1);
  232. break;
  233. case SND_SOC_DAPM_POST_PMD:
  234. gpiod_set_value_cansleep(priv->gpio_mic_bias, 0);
  235. break;
  236. }
  237. return 0;
  238. }
  239. static int tm2_set_bias_level(struct snd_soc_card *card,
  240. struct snd_soc_dapm_context *dapm,
  241. enum snd_soc_bias_level level)
  242. {
  243. struct snd_soc_pcm_runtime *rtd;
  244. rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
  245. if (dapm->dev != asoc_rtd_to_codec(rtd, 0)->dev)
  246. return 0;
  247. switch (level) {
  248. case SND_SOC_BIAS_STANDBY:
  249. if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
  250. tm2_start_sysclk(card);
  251. break;
  252. case SND_SOC_BIAS_OFF:
  253. tm2_stop_sysclk(card);
  254. break;
  255. default:
  256. break;
  257. }
  258. return 0;
  259. }
  260. static struct snd_soc_aux_dev tm2_speaker_amp_dev;
  261. static int tm2_late_probe(struct snd_soc_card *card)
  262. {
  263. struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
  264. unsigned int ch_map[] = { 0, 1 };
  265. struct snd_soc_dai *amp_pdm_dai;
  266. struct snd_soc_pcm_runtime *rtd;
  267. struct snd_soc_dai *aif1_dai;
  268. struct snd_soc_dai *aif2_dai;
  269. int ret;
  270. rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF1]);
  271. aif1_dai = asoc_rtd_to_codec(rtd, 0);
  272. priv->component = asoc_rtd_to_codec(rtd, 0)->component;
  273. ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
  274. if (ret < 0) {
  275. dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret);
  276. return ret;
  277. }
  278. rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF2]);
  279. aif2_dai = asoc_rtd_to_codec(rtd, 0);
  280. ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
  281. if (ret < 0) {
  282. dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret);
  283. return ret;
  284. }
  285. amp_pdm_dai = snd_soc_find_dai(&tm2_speaker_amp_dev.dlc);
  286. if (!amp_pdm_dai)
  287. return -ENODEV;
  288. /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
  289. ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map),
  290. ch_map, 0, NULL);
  291. if (ret < 0)
  292. return ret;
  293. ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16);
  294. if (ret < 0)
  295. return ret;
  296. return 0;
  297. }
  298. static const struct snd_kcontrol_new tm2_controls[] = {
  299. SOC_DAPM_PIN_SWITCH("HP"),
  300. SOC_DAPM_PIN_SWITCH("SPK"),
  301. SOC_DAPM_PIN_SWITCH("RCV"),
  302. SOC_DAPM_PIN_SWITCH("VPS"),
  303. SOC_DAPM_PIN_SWITCH("HDMI"),
  304. SOC_DAPM_PIN_SWITCH("Main Mic"),
  305. SOC_DAPM_PIN_SWITCH("Sub Mic"),
  306. SOC_DAPM_PIN_SWITCH("Third Mic"),
  307. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  308. };
  309. static const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
  310. SND_SOC_DAPM_HP("HP", NULL),
  311. SND_SOC_DAPM_SPK("SPK", NULL),
  312. SND_SOC_DAPM_SPK("RCV", NULL),
  313. SND_SOC_DAPM_LINE("VPS", NULL),
  314. SND_SOC_DAPM_LINE("HDMI", NULL),
  315. SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias),
  316. SND_SOC_DAPM_MIC("Sub Mic", NULL),
  317. SND_SOC_DAPM_MIC("Third Mic", NULL),
  318. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  319. };
  320. static const struct snd_soc_component_driver tm2_component = {
  321. .name = "tm2-audio",
  322. };
  323. static struct snd_soc_dai_driver tm2_ext_dai[] = {
  324. {
  325. .name = "Voice call",
  326. .playback = {
  327. .channels_min = 1,
  328. .channels_max = 4,
  329. .rate_min = 8000,
  330. .rate_max = 48000,
  331. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  332. SNDRV_PCM_RATE_48000),
  333. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  334. },
  335. .capture = {
  336. .channels_min = 1,
  337. .channels_max = 4,
  338. .rate_min = 8000,
  339. .rate_max = 48000,
  340. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  341. SNDRV_PCM_RATE_48000),
  342. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  343. },
  344. },
  345. {
  346. .name = "Bluetooth",
  347. .playback = {
  348. .channels_min = 1,
  349. .channels_max = 4,
  350. .rate_min = 8000,
  351. .rate_max = 16000,
  352. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
  353. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  354. },
  355. .capture = {
  356. .channels_min = 1,
  357. .channels_max = 2,
  358. .rate_min = 8000,
  359. .rate_max = 16000,
  360. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
  361. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  362. },
  363. },
  364. };
  365. SND_SOC_DAILINK_DEFS(aif1,
  366. DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)),
  367. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif1")),
  368. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  369. SND_SOC_DAILINK_DEFS(voice,
  370. DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)),
  371. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif2")),
  372. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  373. SND_SOC_DAILINK_DEFS(bt,
  374. DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)),
  375. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif3")),
  376. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  377. SND_SOC_DAILINK_DEFS(hdmi,
  378. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  379. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  380. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  381. static struct snd_soc_dai_link tm2_dai_links[] = {
  382. {
  383. .name = "WM5110 AIF1",
  384. .stream_name = "HiFi Primary",
  385. .ops = &tm2_aif1_ops,
  386. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  387. SND_SOC_DAIFMT_CBM_CFM,
  388. SND_SOC_DAILINK_REG(aif1),
  389. }, {
  390. .name = "WM5110 Voice",
  391. .stream_name = "Voice call",
  392. .ops = &tm2_aif2_ops,
  393. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  394. SND_SOC_DAIFMT_CBM_CFM,
  395. .ignore_suspend = 1,
  396. SND_SOC_DAILINK_REG(voice),
  397. }, {
  398. .name = "WM5110 BT",
  399. .stream_name = "Bluetooth",
  400. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  401. SND_SOC_DAIFMT_CBM_CFM,
  402. .ignore_suspend = 1,
  403. SND_SOC_DAILINK_REG(bt),
  404. }, {
  405. .name = "HDMI",
  406. .stream_name = "i2s1",
  407. .ops = &tm2_hdmi_ops,
  408. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  409. SND_SOC_DAIFMT_CBS_CFS,
  410. SND_SOC_DAILINK_REG(hdmi),
  411. }
  412. };
  413. static struct snd_soc_card tm2_card = {
  414. .owner = THIS_MODULE,
  415. .dai_link = tm2_dai_links,
  416. .controls = tm2_controls,
  417. .num_controls = ARRAY_SIZE(tm2_controls),
  418. .dapm_widgets = tm2_dapm_widgets,
  419. .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets),
  420. .aux_dev = &tm2_speaker_amp_dev,
  421. .num_aux_devs = 1,
  422. .late_probe = tm2_late_probe,
  423. .set_bias_level = tm2_set_bias_level,
  424. };
  425. static int tm2_probe(struct platform_device *pdev)
  426. {
  427. struct device_node *cpu_dai_node[2] = {};
  428. struct device_node *codec_dai_node[2] = {};
  429. const char *cells_name = NULL;
  430. struct device *dev = &pdev->dev;
  431. struct snd_soc_card *card = &tm2_card;
  432. struct tm2_machine_priv *priv;
  433. struct snd_soc_dai_link *dai_link;
  434. int num_codecs, ret, i;
  435. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  436. if (!priv)
  437. return -ENOMEM;
  438. snd_soc_card_set_drvdata(card, priv);
  439. card->dev = dev;
  440. priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", GPIOD_OUT_HIGH);
  441. if (IS_ERR(priv->gpio_mic_bias)) {
  442. dev_err(dev, "Failed to get mic bias gpio\n");
  443. return PTR_ERR(priv->gpio_mic_bias);
  444. }
  445. ret = snd_soc_of_parse_card_name(card, "model");
  446. if (ret < 0) {
  447. dev_err(dev, "Card name is not specified\n");
  448. return ret;
  449. }
  450. ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
  451. if (ret < 0) {
  452. dev_err(dev, "Audio routing is not specified or invalid\n");
  453. return ret;
  454. }
  455. card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node,
  456. "audio-amplifier", 0);
  457. if (!card->aux_dev[0].dlc.of_node) {
  458. dev_err(dev, "audio-amplifier property invalid or missing\n");
  459. return -EINVAL;
  460. }
  461. num_codecs = of_count_phandle_with_args(dev->of_node, "audio-codec",
  462. NULL);
  463. /* Skip the HDMI link if not specified in DT */
  464. if (num_codecs > 1) {
  465. card->num_links = ARRAY_SIZE(tm2_dai_links);
  466. cells_name = "#sound-dai-cells";
  467. } else {
  468. card->num_links = ARRAY_SIZE(tm2_dai_links) - 1;
  469. }
  470. for (i = 0; i < num_codecs; i++) {
  471. struct of_phandle_args args;
  472. ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller",
  473. cells_name, i, &args);
  474. if (ret) {
  475. dev_err(dev, "i2s-controller property parse error: %d\n", i);
  476. ret = -EINVAL;
  477. goto dai_node_put;
  478. }
  479. cpu_dai_node[i] = args.np;
  480. codec_dai_node[i] = of_parse_phandle(dev->of_node,
  481. "audio-codec", i);
  482. if (!codec_dai_node[i]) {
  483. dev_err(dev, "audio-codec property parse error\n");
  484. ret = -EINVAL;
  485. goto dai_node_put;
  486. }
  487. }
  488. /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */
  489. for_each_card_prelinks(card, i, dai_link) {
  490. unsigned int dai_index = 0; /* WM5110 */
  491. dai_link->cpus->name = NULL;
  492. dai_link->platforms->name = NULL;
  493. if (num_codecs > 1 && i == card->num_links - 1)
  494. dai_index = 1; /* HDMI */
  495. dai_link->codecs->of_node = codec_dai_node[dai_index];
  496. dai_link->cpus->of_node = cpu_dai_node[dai_index];
  497. dai_link->platforms->of_node = cpu_dai_node[dai_index];
  498. }
  499. if (num_codecs > 1) {
  500. struct of_phandle_args args;
  501. /* HDMI DAI link (I2S1) */
  502. i = card->num_links - 1;
  503. ret = of_parse_phandle_with_fixed_args(dev->of_node,
  504. "audio-codec", 0, 1, &args);
  505. if (ret) {
  506. dev_err(dev, "audio-codec property parse error\n");
  507. goto dai_node_put;
  508. }
  509. ret = snd_soc_get_dai_name(&args, &card->dai_link[i].codecs->dai_name);
  510. if (ret) {
  511. dev_err(dev, "Unable to get codec_dai_name\n");
  512. goto dai_node_put;
  513. }
  514. }
  515. ret = devm_snd_soc_register_component(dev, &tm2_component,
  516. tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
  517. if (ret < 0) {
  518. dev_err(dev, "Failed to register component: %d\n", ret);
  519. goto dai_node_put;
  520. }
  521. ret = devm_snd_soc_register_card(dev, card);
  522. if (ret < 0) {
  523. dev_err_probe(dev, ret, "Failed to register card\n");
  524. goto dai_node_put;
  525. }
  526. dai_node_put:
  527. for (i = 0; i < num_codecs; i++) {
  528. of_node_put(codec_dai_node[i]);
  529. of_node_put(cpu_dai_node[i]);
  530. }
  531. of_node_put(card->aux_dev[0].dlc.of_node);
  532. return ret;
  533. }
  534. static int tm2_pm_prepare(struct device *dev)
  535. {
  536. struct snd_soc_card *card = dev_get_drvdata(dev);
  537. return tm2_stop_sysclk(card);
  538. }
  539. static void tm2_pm_complete(struct device *dev)
  540. {
  541. struct snd_soc_card *card = dev_get_drvdata(dev);
  542. tm2_start_sysclk(card);
  543. }
  544. static const struct dev_pm_ops tm2_pm_ops = {
  545. .prepare = tm2_pm_prepare,
  546. .suspend = snd_soc_suspend,
  547. .resume = snd_soc_resume,
  548. .complete = tm2_pm_complete,
  549. .freeze = snd_soc_suspend,
  550. .thaw = snd_soc_resume,
  551. .poweroff = snd_soc_poweroff,
  552. .restore = snd_soc_resume,
  553. };
  554. static const struct of_device_id tm2_of_match[] = {
  555. { .compatible = "samsung,tm2-audio" },
  556. { },
  557. };
  558. MODULE_DEVICE_TABLE(of, tm2_of_match);
  559. static struct platform_driver tm2_driver = {
  560. .driver = {
  561. .name = "tm2-audio",
  562. .pm = &tm2_pm_ops,
  563. .of_match_table = tm2_of_match,
  564. },
  565. .probe = tm2_probe,
  566. };
  567. module_platform_driver(tm2_driver);
  568. MODULE_AUTHOR("Inha Song <[email protected]>");
  569. MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
  570. MODULE_LICENSE("GPL v2");