kona.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/delay.h>
  7. #include <linux/gpio.h>
  8. #include <linux/of_gpio.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/slab.h>
  11. #include <linux/io.h>
  12. #include <linux/module.h>
  13. #include <linux/input.h>
  14. #include <linux/of_device.h>
  15. #include <sound/core.h>
  16. #include <sound/soc.h>
  17. #include <sound/soc-dapm.h>
  18. #include <sound/pcm.h>
  19. #include <sound/pcm_params.h>
  20. #include <sound/info.h>
  21. #include <dsp/audio_notifier.h>
  22. #include <dsp/q6afe-v2.h>
  23. #include <dsp/q6core.h>
  24. #include "device_event.h"
  25. #include "msm-pcm-routing-v2.h"
  26. #include "codecs/wsa881x.h"
  27. #define DRV_NAME "kona-asoc-snd"
  28. #define __CHIPSET__ "KONA "
  29. #define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
  30. #define SAMPLING_RATE_8KHZ 8000
  31. #define SAMPLING_RATE_16KHZ 16000
  32. struct msm_asoc_mach_data {
  33. u32 mclk_freq;
  34. struct snd_info_entry *codec_root;
  35. };
  36. struct dev_config {
  37. u32 sample_rate;
  38. u32 bit_format;
  39. u32 channels;
  40. };
  41. enum {
  42. PRIM_AUX_PCM = 0,
  43. };
  44. static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
  45. static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
  46. "S32_LE"};
  47. /* Default configuration of aux pcm channels */
  48. static struct dev_config aux_pcm_rx_cfg[] = {
  49. [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
  50. };
  51. static struct dev_config aux_pcm_tx_cfg[] = {
  52. [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
  53. };
  54. static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
  55. static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
  56. static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
  57. static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
  58. static inline int param_is_mask(int p)
  59. {
  60. return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
  61. (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
  62. }
  63. static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
  64. int n)
  65. {
  66. return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
  67. }
  68. static void param_set_mask(struct snd_pcm_hw_params *p, int n,
  69. unsigned int bit)
  70. {
  71. if (bit >= SNDRV_MASK_MAX)
  72. return;
  73. if (param_is_mask(n)) {
  74. struct snd_mask *m = param_to_mask(p, n);
  75. m->bits[0] = 0;
  76. m->bits[1] = 0;
  77. m->bits[bit >> 5] |= (1 << (bit & 31));
  78. }
  79. }
  80. static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
  81. {
  82. int idx = 0;
  83. if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
  84. sizeof("PRIM_AUX_PCM"))) {
  85. idx = PRIM_AUX_PCM;
  86. } else {
  87. pr_err("%s: unsupported port: %s\n",
  88. __func__, kcontrol->id.name);
  89. idx = -EINVAL;
  90. }
  91. return idx;
  92. }
  93. static int aux_pcm_get_format(int value)
  94. {
  95. int format = 0;
  96. switch (value) {
  97. case 1:
  98. format = SNDRV_PCM_FORMAT_S24_LE;
  99. break;
  100. case 2:
  101. format = SNDRV_PCM_FORMAT_S24_3LE;
  102. break;
  103. case 3:
  104. format = SNDRV_PCM_FORMAT_S32_LE;
  105. break;
  106. case 0:
  107. default:
  108. format = SNDRV_PCM_FORMAT_S16_LE;
  109. break;
  110. }
  111. return format;
  112. }
  113. static int auxpcm_get_format_value(int format)
  114. {
  115. int value = 0;
  116. switch (format) {
  117. case SNDRV_PCM_FORMAT_S24_LE:
  118. value = 1;
  119. break;
  120. case SNDRV_PCM_FORMAT_S24_3LE:
  121. value = 2;
  122. break;
  123. case SNDRV_PCM_FORMAT_S32_LE:
  124. value = 3;
  125. break;
  126. case SNDRV_PCM_FORMAT_S16_LE:
  127. default:
  128. value = 0;
  129. break;
  130. }
  131. return value;
  132. }
  133. static int aux_pcm_get_sample_rate(int value)
  134. {
  135. int sample_rate = 0;
  136. switch (value) {
  137. case 1:
  138. sample_rate = SAMPLING_RATE_16KHZ;
  139. break;
  140. case 0:
  141. default:
  142. sample_rate = SAMPLING_RATE_8KHZ;
  143. break;
  144. }
  145. return sample_rate;
  146. }
  147. static int aux_pcm_get_sample_rate_val(int sample_rate)
  148. {
  149. int sample_rate_val = 0;
  150. switch (sample_rate) {
  151. case SAMPLING_RATE_16KHZ:
  152. sample_rate_val = 1;
  153. break;
  154. case SAMPLING_RATE_8KHZ:
  155. default:
  156. sample_rate_val = 0;
  157. break;
  158. }
  159. return sample_rate_val;
  160. }
  161. static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
  162. struct snd_ctl_elem_value *ucontrol)
  163. {
  164. int idx = aux_pcm_get_port_idx(kcontrol);
  165. if (idx < 0)
  166. return idx;
  167. ucontrol->value.enumerated.item[0] =
  168. auxpcm_get_format_value(aux_pcm_rx_cfg[idx].bit_format);
  169. pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
  170. idx, aux_pcm_rx_cfg[idx].bit_format,
  171. ucontrol->value.enumerated.item[0]);
  172. return 0;
  173. }
  174. static int msm_aux_pcm_rx_format_put(struct snd_kcontrol *kcontrol,
  175. struct snd_ctl_elem_value *ucontrol)
  176. {
  177. int idx = aux_pcm_get_port_idx(kcontrol);
  178. if (idx < 0)
  179. return idx;
  180. aux_pcm_rx_cfg[idx].bit_format =
  181. aux_pcm_get_format(ucontrol->value.enumerated.item[0]);
  182. pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
  183. idx, aux_pcm_rx_cfg[idx].bit_format,
  184. ucontrol->value.enumerated.item[0]);
  185. return 0;
  186. }
  187. static int msm_aux_pcm_tx_format_get(struct snd_kcontrol *kcontrol,
  188. struct snd_ctl_elem_value *ucontrol)
  189. {
  190. int idx = aux_pcm_get_port_idx(kcontrol);
  191. if (idx < 0)
  192. return idx;
  193. ucontrol->value.enumerated.item[0] =
  194. auxpcm_get_format_value(aux_pcm_tx_cfg[idx].bit_format);
  195. pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
  196. idx, aux_pcm_tx_cfg[idx].bit_format,
  197. ucontrol->value.enumerated.item[0]);
  198. return 0;
  199. }
  200. static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol,
  201. struct snd_ctl_elem_value *ucontrol)
  202. {
  203. int idx = aux_pcm_get_port_idx(kcontrol);
  204. if (idx < 0)
  205. return idx;
  206. aux_pcm_tx_cfg[idx].bit_format =
  207. aux_pcm_get_format(ucontrol->value.enumerated.item[0]);
  208. pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
  209. idx, aux_pcm_tx_cfg[idx].bit_format,
  210. ucontrol->value.enumerated.item[0]);
  211. return 0;
  212. }
  213. static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
  214. struct snd_ctl_elem_value *ucontrol)
  215. {
  216. int idx = aux_pcm_get_port_idx(kcontrol);
  217. if (idx < 0)
  218. return idx;
  219. aux_pcm_rx_cfg[idx].sample_rate =
  220. aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
  221. pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
  222. idx, aux_pcm_rx_cfg[idx].sample_rate,
  223. ucontrol->value.enumerated.item[0]);
  224. return 0;
  225. }
  226. static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
  227. struct snd_ctl_elem_value *ucontrol)
  228. {
  229. int idx = aux_pcm_get_port_idx(kcontrol);
  230. if (idx < 0)
  231. return idx;
  232. ucontrol->value.enumerated.item[0] =
  233. aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
  234. pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
  235. idx, aux_pcm_rx_cfg[idx].sample_rate,
  236. ucontrol->value.enumerated.item[0]);
  237. return 0;
  238. }
  239. static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
  240. struct snd_ctl_elem_value *ucontrol)
  241. {
  242. int idx = aux_pcm_get_port_idx(kcontrol);
  243. if (idx < 0)
  244. return idx;
  245. aux_pcm_tx_cfg[idx].sample_rate =
  246. aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
  247. pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
  248. idx, aux_pcm_tx_cfg[idx].sample_rate,
  249. ucontrol->value.enumerated.item[0]);
  250. return 0;
  251. }
  252. static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
  253. struct snd_ctl_elem_value *ucontrol)
  254. {
  255. int idx = aux_pcm_get_port_idx(kcontrol);
  256. if (idx < 0)
  257. return idx;
  258. ucontrol->value.enumerated.item[0] =
  259. aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
  260. pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
  261. idx, aux_pcm_tx_cfg[idx].sample_rate,
  262. ucontrol->value.enumerated.item[0]);
  263. return 0;
  264. }
  265. static const struct snd_kcontrol_new msm_snd_controls[] = {
  266. SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
  267. msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
  268. SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
  269. msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
  270. SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
  271. aux_pcm_rx_sample_rate_get,
  272. aux_pcm_rx_sample_rate_put),
  273. SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
  274. aux_pcm_tx_sample_rate_get,
  275. aux_pcm_tx_sample_rate_put),
  276. };
  277. static int msm_populate_dai_link_component_of_node(
  278. struct snd_soc_card *card)
  279. {
  280. int i, index, ret = 0;
  281. struct device *cdev = card->dev;
  282. struct snd_soc_dai_link *dai_link = card->dai_link;
  283. struct device_node *np;
  284. if (!cdev) {
  285. dev_err(cdev, "%s: Sound card device memory NULL\n", __func__);
  286. return -ENODEV;
  287. }
  288. for (i = 0; i < card->num_links; i++) {
  289. if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
  290. continue;
  291. /* populate platform_of_node for snd card dai links */
  292. if (dai_link[i].platform_name &&
  293. !dai_link[i].platform_of_node) {
  294. index = of_property_match_string(cdev->of_node,
  295. "asoc-platform-names",
  296. dai_link[i].platform_name);
  297. if (index < 0) {
  298. dev_err(cdev, "%s: No match found for platform name: %s\n",
  299. __func__, dai_link[i].platform_name);
  300. ret = index;
  301. goto err;
  302. }
  303. np = of_parse_phandle(cdev->of_node, "asoc-platform",
  304. index);
  305. if (!np) {
  306. dev_err(cdev, "%s: retrieving phandle for platform %s, index %d failed\n",
  307. __func__, dai_link[i].platform_name,
  308. index);
  309. ret = -ENODEV;
  310. goto err;
  311. }
  312. dai_link[i].platform_of_node = np;
  313. dai_link[i].platform_name = NULL;
  314. }
  315. /* populate cpu_of_node for snd card dai links */
  316. if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
  317. index = of_property_match_string(cdev->of_node,
  318. "asoc-cpu-names",
  319. dai_link[i].cpu_dai_name);
  320. if (index >= 0) {
  321. np = of_parse_phandle(cdev->of_node, "asoc-cpu",
  322. index);
  323. if (!np) {
  324. dev_err(cdev, "%s: retrieving phandle for cpu dai %s failed\n",
  325. __func__,
  326. dai_link[i].cpu_dai_name);
  327. ret = -ENODEV;
  328. goto err;
  329. }
  330. dai_link[i].cpu_of_node = np;
  331. dai_link[i].cpu_dai_name = NULL;
  332. }
  333. }
  334. /* populate codec_of_node for snd card dai links */
  335. if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
  336. index = of_property_match_string(cdev->of_node,
  337. "asoc-codec-names",
  338. dai_link[i].codec_name);
  339. if (index < 0)
  340. continue;
  341. np = of_parse_phandle(cdev->of_node, "asoc-codec",
  342. index);
  343. if (!np) {
  344. dev_err(cdev, "%s: retrieving phandle for codec %s failed\n",
  345. __func__, dai_link[i].codec_name);
  346. ret = -ENODEV;
  347. goto err;
  348. }
  349. dai_link[i].codec_of_node = np;
  350. dai_link[i].codec_name = NULL;
  351. }
  352. }
  353. err:
  354. return ret;
  355. }
  356. static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd)
  357. {
  358. int ret = -EINVAL;
  359. struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, "msm-stub-codec");
  360. if (!component) {
  361. pr_err("* %s: No match for msm-stub-codec component\n", __func__);
  362. return ret;
  363. }
  364. ret = snd_soc_add_component_controls(component, msm_snd_controls,
  365. ARRAY_SIZE(msm_snd_controls));
  366. if (ret < 0) {
  367. dev_err(component->dev,
  368. "%s: add_codec_controls failed, err = %d\n",
  369. __func__, ret);
  370. return ret;
  371. }
  372. return ret;
  373. }
  374. static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream,
  375. struct snd_pcm_hw_params *params)
  376. {
  377. return 0;
  378. }
  379. static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  380. struct snd_pcm_hw_params *params)
  381. {
  382. struct snd_soc_dai_link *dai_link = rtd->dai_link;
  383. struct snd_interval *rate = hw_param_interval(params,
  384. SNDRV_PCM_HW_PARAM_RATE);
  385. struct snd_interval *channels = hw_param_interval(params,
  386. SNDRV_PCM_HW_PARAM_CHANNELS);
  387. int rc = 0;
  388. pr_debug("%s: format = %d, rate = %d\n",
  389. __func__, params_format(params), params_rate(params));
  390. switch (dai_link->id) {
  391. case MSM_BACKEND_DAI_AUXPCM_RX:
  392. param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
  393. aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format);
  394. rate->min = rate->max =
  395. aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
  396. channels->min = channels->max =
  397. aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
  398. break;
  399. case MSM_BACKEND_DAI_AUXPCM_TX:
  400. param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
  401. aux_pcm_tx_cfg[PRIM_AUX_PCM].bit_format);
  402. rate->min = rate->max =
  403. aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
  404. channels->min = channels->max =
  405. aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
  406. break;
  407. default:
  408. rate->min = rate->max = SAMPLING_RATE_8KHZ;
  409. break;
  410. }
  411. return rc;
  412. }
  413. static struct snd_soc_ops msm_stub_be_ops = {
  414. .hw_params = msm_snd_stub_hw_params,
  415. };
  416. struct snd_soc_card snd_soc_card_stub_msm = {
  417. .name = "kona-stub-snd-card",
  418. };
  419. static struct snd_soc_dai_link msm_stub_fe_dai_links[] = {
  420. /* FrontEnd DAI Links */
  421. {
  422. .name = "MSMSTUB Media1",
  423. .stream_name = "MultiMedia1",
  424. .cpu_dai_name = "MultiMedia1",
  425. .platform_name = "msm-pcm-dsp.0",
  426. .dynamic = 1,
  427. .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
  428. .dpcm_playback = 1,
  429. .dpcm_capture = 1,
  430. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  431. SND_SOC_DPCM_TRIGGER_POST},
  432. .codec_dai_name = "snd-soc-dummy-dai",
  433. .codec_name = "snd-soc-dummy",
  434. .ignore_suspend = 1,
  435. /* this dainlink has playback support */
  436. .ignore_pmdown_time = 1,
  437. .id = MSM_FRONTEND_DAI_MULTIMEDIA1
  438. },
  439. };
  440. static struct snd_soc_dai_link msm_stub_be_dai_links[] = {
  441. /* Backend DAI Links */
  442. {
  443. .name = LPASS_BE_AUXPCM_RX,
  444. .stream_name = "AUX PCM Playback",
  445. .cpu_dai_name = "msm-dai-q6-auxpcm.1",
  446. .platform_name = "msm-pcm-routing",
  447. .codec_name = "msm-stub-codec.1",
  448. .codec_dai_name = "msm-stub-rx",
  449. .no_pcm = 1,
  450. .dpcm_playback = 1,
  451. .id = MSM_BACKEND_DAI_AUXPCM_RX,
  452. .init = &msm_audrx_stub_init,
  453. .be_hw_params_fixup = msm_be_hw_params_fixup,
  454. .ignore_pmdown_time = 1,
  455. .ignore_suspend = 1,
  456. .ops = &msm_stub_be_ops,
  457. },
  458. {
  459. .name = LPASS_BE_AUXPCM_TX,
  460. .stream_name = "AUX PCM Capture",
  461. .cpu_dai_name = "msm-dai-q6-auxpcm.1",
  462. .platform_name = "msm-pcm-routing",
  463. .codec_name = "msm-stub-codec.1",
  464. .codec_dai_name = "msm-stub-tx",
  465. .no_pcm = 1,
  466. .dpcm_capture = 1,
  467. .id = MSM_BACKEND_DAI_AUXPCM_TX,
  468. .be_hw_params_fixup = msm_be_hw_params_fixup,
  469. .ignore_suspend = 1,
  470. .ops = &msm_stub_be_ops,
  471. },
  472. };
  473. static struct snd_soc_dai_link msm_stub_dai_links[
  474. ARRAY_SIZE(msm_stub_fe_dai_links) +
  475. ARRAY_SIZE(msm_stub_be_dai_links)];
  476. static const struct of_device_id kona_asoc_machine_of_match[] = {
  477. { .compatible = "qcom,kona-asoc-snd-stub",
  478. .data = "stub_codec"},
  479. {},
  480. };
  481. static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
  482. {
  483. struct snd_soc_card *card = NULL;
  484. struct snd_soc_dai_link *dailink;
  485. int len_1, len_2;
  486. int total_links;
  487. const struct of_device_id *match;
  488. match = of_match_node(kona_asoc_machine_of_match, dev->of_node);
  489. if (!match) {
  490. dev_err(dev, "%s: No DT match found for sound card\n",
  491. __func__);
  492. return NULL;
  493. }
  494. if (!strcmp(match->data, "stub_codec")) {
  495. card = &snd_soc_card_stub_msm;
  496. len_1 = ARRAY_SIZE(msm_stub_fe_dai_links);
  497. len_2 = len_1 + ARRAY_SIZE(msm_stub_be_dai_links);
  498. memcpy(msm_stub_dai_links,
  499. msm_stub_fe_dai_links,
  500. sizeof(msm_stub_fe_dai_links));
  501. memcpy(msm_stub_dai_links + len_1,
  502. msm_stub_be_dai_links,
  503. sizeof(msm_stub_be_dai_links));
  504. dailink = msm_stub_dai_links;
  505. total_links = len_2;
  506. }
  507. if (card) {
  508. card->dai_link = dailink;
  509. card->num_links = total_links;
  510. }
  511. return card;
  512. }
  513. static int msm_asoc_machine_probe(struct platform_device *pdev)
  514. {
  515. struct snd_soc_card *card;
  516. struct msm_asoc_mach_data *pdata;
  517. const struct of_device_id *match;
  518. int ret;
  519. if (!pdev->dev.of_node) {
  520. dev_err(&pdev->dev, "%s: No platform supplied from device tree\n", __func__);
  521. return -EINVAL;
  522. }
  523. pdata = devm_kzalloc(&pdev->dev,
  524. sizeof(struct msm_asoc_mach_data), GFP_KERNEL);
  525. if (!pdata)
  526. return -ENOMEM;
  527. card = populate_snd_card_dailinks(&pdev->dev);
  528. if (!card) {
  529. dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
  530. ret = -EINVAL;
  531. goto err;
  532. }
  533. card->dev = &pdev->dev;
  534. platform_set_drvdata(pdev, card);
  535. snd_soc_card_set_drvdata(card, pdata);
  536. ret = snd_soc_of_parse_card_name(card, "qcom,model");
  537. if (ret) {
  538. dev_err(&pdev->dev, "%s: parse card name failed, err:%d\n",
  539. __func__, ret);
  540. goto err;
  541. }
  542. match = of_match_node(kona_asoc_machine_of_match,
  543. pdev->dev.of_node);
  544. if (!match) {
  545. dev_err(&pdev->dev, "%s: no matched codec is found.\n",
  546. __func__);
  547. goto err;
  548. }
  549. ret = msm_populate_dai_link_component_of_node(card);
  550. if (ret) {
  551. ret = -EPROBE_DEFER;
  552. goto err;
  553. }
  554. ret = devm_snd_soc_register_card(&pdev->dev, card);
  555. if (ret) {
  556. dev_err(&pdev->dev, "%s: snd_soc_register_card failed (%d)\n",
  557. __func__, ret);
  558. goto err;
  559. }
  560. dev_info(&pdev->dev, "%s: Sound card %s registered\n",
  561. __func__, card->name);
  562. return 0;
  563. err:
  564. devm_kfree(&pdev->dev, pdata);
  565. return ret;
  566. }
  567. static int msm_asoc_machine_remove(struct platform_device *pdev)
  568. {
  569. struct snd_soc_card *card = platform_get_drvdata(pdev);
  570. snd_soc_unregister_card(card);
  571. return 0;
  572. }
  573. static struct platform_driver kona_asoc_machine_driver = {
  574. .driver = {
  575. .name = DRV_NAME,
  576. .owner = THIS_MODULE,
  577. .pm = &snd_soc_pm_ops,
  578. .of_match_table = kona_asoc_machine_of_match,
  579. },
  580. .probe = msm_asoc_machine_probe,
  581. .remove = msm_asoc_machine_remove,
  582. };
  583. module_platform_driver(kona_asoc_machine_driver);
  584. MODULE_DESCRIPTION("ALSA SoC msm");
  585. MODULE_LICENSE("GPL v2");
  586. MODULE_ALIAS("platform:" DRV_NAME);
  587. MODULE_DEVICE_TABLE(of, kona_asoc_machine_of_match);