msm-pcm-loopback-v2.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/init.h>
  5. #include <linux/err.h>
  6. #include <linux/module.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/slab.h>
  9. #include <linux/dma-mapping.h>
  10. #include <sound/core.h>
  11. #include <sound/soc.h>
  12. #include <sound/pcm.h>
  13. #include <sound/initval.h>
  14. #include <sound/control.h>
  15. #include <sound/tlv.h>
  16. #include <asm/dma.h>
  17. #include <dsp/apr_audio-v2.h>
  18. #include <dsp/q6audio-v2.h>
  19. #include <dsp/q6asm-v2.h>
  20. #include "msm-pcm-routing-v2.h"
  21. #define LOOPBACK_VOL_MAX_STEPS 0x2000
  22. #define LOOPBACK_SESSION_MAX 4
  23. static DEFINE_MUTEX(loopback_session_lock);
  24. static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
  25. LOOPBACK_VOL_MAX_STEPS);
  26. struct msm_pcm_loopback {
  27. struct snd_pcm_substream *playback_substream;
  28. struct snd_pcm_substream *capture_substream;
  29. int instance;
  30. struct mutex lock;
  31. uint32_t samp_rate;
  32. uint32_t channel_mode;
  33. int playback_start;
  34. int capture_start;
  35. int session_id;
  36. struct audio_client *audio_client;
  37. uint32_t volume;
  38. };
  39. struct fe_dai_session_map {
  40. char stream_name[32];
  41. struct msm_pcm_loopback *loopback_priv;
  42. };
  43. static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = {
  44. { {}, NULL},
  45. { {}, NULL},
  46. { {}, NULL},
  47. { {}, NULL},
  48. };
  49. static u32 hfp_tx_mute;
  50. struct msm_pcm_pdata {
  51. int perf_mode;
  52. };
  53. static void stop_pcm(struct msm_pcm_loopback *pcm);
  54. static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
  55. struct msm_pcm_loopback **pcm);
  56. static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
  57. void *priv_data)
  58. {
  59. struct msm_pcm_loopback *pcm = priv_data;
  60. WARN_ON(!pcm);
  61. pr_debug("%s: event 0x%x\n", __func__, event);
  62. switch (event) {
  63. case MSM_PCM_RT_EVT_DEVSWITCH:
  64. q6asm_cmd(pcm->audio_client, CMD_PAUSE);
  65. q6asm_cmd(pcm->audio_client, CMD_FLUSH);
  66. q6asm_run(pcm->audio_client, 0, 0, 0);
  67. /* fallthrough */
  68. default:
  69. pr_err("%s: default event 0x%x\n", __func__, event);
  70. break;
  71. }
  72. }
  73. static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
  74. uint32_t *payload, void *priv)
  75. {
  76. pr_debug("%s:\n", __func__);
  77. switch (opcode) {
  78. case APR_BASIC_RSP_RESULT: {
  79. switch (payload[0]) {
  80. break;
  81. default:
  82. break;
  83. }
  84. }
  85. break;
  86. default:
  87. pr_err("%s: Not Supported Event opcode[0x%x]\n",
  88. __func__, opcode);
  89. break;
  90. }
  91. }
  92. static int msm_loopback_session_mute_get(struct snd_kcontrol *kcontrol,
  93. struct snd_ctl_elem_value *ucontrol)
  94. {
  95. ucontrol->value.integer.value[0] = hfp_tx_mute;
  96. return 0;
  97. }
  98. static int msm_loopback_session_mute_put(struct snd_kcontrol *kcontrol,
  99. struct snd_ctl_elem_value *ucontrol)
  100. {
  101. int ret = 0, n = 0;
  102. int mute = ucontrol->value.integer.value[0];
  103. struct msm_pcm_loopback *pcm = NULL;
  104. if ((mute < 0) || (mute > 1)) {
  105. pr_err(" %s Invalid arguments", __func__);
  106. ret = -EINVAL;
  107. goto done;
  108. }
  109. pr_debug("%s: mute=%d\n", __func__, mute);
  110. hfp_tx_mute = mute;
  111. for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
  112. if (!strcmp(session_map[n].stream_name, "MultiMedia6"))
  113. pcm = session_map[n].loopback_priv;
  114. }
  115. if (pcm && pcm->audio_client) {
  116. ret = q6asm_set_mute(pcm->audio_client, mute);
  117. if (ret < 0)
  118. pr_err("%s: Send mute command failed rc=%d\n",
  119. __func__, ret);
  120. }
  121. done:
  122. return ret;
  123. }
  124. static struct snd_kcontrol_new msm_loopback_controls[] = {
  125. SOC_SINGLE_EXT("HFP TX Mute", SND_SOC_NOPM, 0, 1, 0,
  126. msm_loopback_session_mute_get,
  127. msm_loopback_session_mute_put),
  128. };
  129. static int msm_pcm_loopback_probe(struct snd_soc_platform *platform)
  130. {
  131. snd_soc_add_platform_controls(platform, msm_loopback_controls,
  132. ARRAY_SIZE(msm_loopback_controls));
  133. return 0;
  134. }
  135. static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd,
  136. uint32_t volume)
  137. {
  138. int rc = -EINVAL;
  139. pr_debug("%s: Setting volume 0x%x\n", __func__, volume);
  140. if (prtd && prtd->audio_client) {
  141. rc = q6asm_set_volume(prtd->audio_client, volume);
  142. if (rc < 0) {
  143. pr_err("%s: Send Volume command failed rc = %d\n",
  144. __func__, rc);
  145. return rc;
  146. }
  147. prtd->volume = volume;
  148. }
  149. return rc;
  150. }
  151. static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
  152. struct msm_pcm_loopback **pcm)
  153. {
  154. int ret = 0;
  155. int n, index = -1;
  156. dev_dbg(rtd->platform->dev, "%s: stream %s\n", __func__,
  157. rtd->dai_link->stream_name);
  158. mutex_lock(&loopback_session_lock);
  159. for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
  160. if (!strcmp(rtd->dai_link->stream_name,
  161. session_map[n].stream_name)) {
  162. *pcm = session_map[n].loopback_priv;
  163. goto exit;
  164. }
  165. /*
  166. * Store the min index value for allocating a new session.
  167. * Here, if session stream name is not found in the
  168. * existing entries after the loop iteration, then this
  169. * index will be used to allocate the new session.
  170. * This index variable is expected to point to the topmost
  171. * available free session.
  172. */
  173. if (!(session_map[n].stream_name[0]) && (index < 0))
  174. index = n;
  175. }
  176. if (index < 0) {
  177. dev_err(rtd->platform->dev, "%s: Max Sessions allocated\n",
  178. __func__);
  179. ret = -EAGAIN;
  180. goto exit;
  181. }
  182. session_map[index].loopback_priv = kzalloc(
  183. sizeof(struct msm_pcm_loopback), GFP_KERNEL);
  184. if (!session_map[index].loopback_priv) {
  185. ret = -ENOMEM;
  186. goto exit;
  187. }
  188. strlcpy(session_map[index].stream_name,
  189. rtd->dai_link->stream_name,
  190. sizeof(session_map[index].stream_name));
  191. dev_dbg(rtd->platform->dev, "%s: stream %s index %d\n",
  192. __func__, session_map[index].stream_name, index);
  193. mutex_init(&session_map[index].loopback_priv->lock);
  194. *pcm = session_map[index].loopback_priv;
  195. exit:
  196. mutex_unlock(&loopback_session_lock);
  197. return ret;
  198. }
  199. static int msm_pcm_open(struct snd_pcm_substream *substream)
  200. {
  201. struct snd_pcm_runtime *runtime = substream->runtime;
  202. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  203. struct msm_pcm_loopback *pcm = NULL;
  204. int ret = 0;
  205. uint16_t bits_per_sample = 16;
  206. struct msm_pcm_routing_evt event;
  207. struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
  208. uint32_t param_id;
  209. struct msm_pcm_pdata *pdata;
  210. ret = msm_pcm_loopback_get_session(rtd, &pcm);
  211. if (ret)
  212. return ret;
  213. mutex_lock(&pcm->lock);
  214. pcm->volume = 0x2000;
  215. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  216. pcm->playback_substream = substream;
  217. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  218. pcm->capture_substream = substream;
  219. pcm->instance++;
  220. dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
  221. pcm->instance, substream->stream);
  222. if (pcm->instance == 2) {
  223. struct snd_soc_pcm_runtime *soc_pcm_rx =
  224. pcm->playback_substream->private_data;
  225. struct snd_soc_pcm_runtime *soc_pcm_tx =
  226. pcm->capture_substream->private_data;
  227. if (pcm->audio_client != NULL)
  228. stop_pcm(pcm);
  229. pdata = (struct msm_pcm_pdata *)
  230. dev_get_drvdata(rtd->platform->dev);
  231. if (!pdata) {
  232. dev_err(rtd->platform->dev,
  233. "%s: platform data not populated\n", __func__);
  234. mutex_unlock(&pcm->lock);
  235. return -EINVAL;
  236. }
  237. pcm->audio_client = q6asm_audio_client_alloc(
  238. (app_cb)msm_pcm_loopback_event_handler, pcm);
  239. if (!pcm->audio_client) {
  240. dev_err(rtd->platform->dev,
  241. "%s: Could not allocate memory\n", __func__);
  242. mutex_unlock(&pcm->lock);
  243. return -ENOMEM;
  244. }
  245. pcm->session_id = pcm->audio_client->session;
  246. pcm->audio_client->perf_mode = pdata->perf_mode;
  247. ret = q6asm_open_loopback_v2(pcm->audio_client,
  248. bits_per_sample);
  249. if (ret < 0) {
  250. dev_err(rtd->platform->dev,
  251. "%s: pcm out open failed\n", __func__);
  252. q6asm_audio_client_free(pcm->audio_client);
  253. mutex_unlock(&pcm->lock);
  254. return -ENOMEM;
  255. }
  256. event.event_func = msm_pcm_route_event_handler;
  257. event.priv_data = (void *) pcm;
  258. msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id,
  259. pcm->audio_client->perf_mode,
  260. pcm->session_id, pcm->capture_substream->stream);
  261. msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id,
  262. pcm->audio_client->perf_mode,
  263. pcm->session_id, pcm->playback_substream->stream,
  264. event);
  265. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  266. pcm->playback_substream = substream;
  267. ret = pcm_loopback_set_volume(pcm, pcm->volume);
  268. if (ret < 0)
  269. dev_err(rtd->platform->dev,
  270. "Error %d setting volume", ret);
  271. }
  272. /* Set to largest negative value */
  273. asm_mtmx_strtr_window.window_lsw = 0x00000000;
  274. asm_mtmx_strtr_window.window_msw = 0x80000000;
  275. param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2;
  276. q6asm_send_mtmx_strtr_window(pcm->audio_client,
  277. &asm_mtmx_strtr_window,
  278. param_id);
  279. /* Set to largest positive value */
  280. asm_mtmx_strtr_window.window_lsw = 0xffffffff;
  281. asm_mtmx_strtr_window.window_msw = 0x7fffffff;
  282. param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2;
  283. q6asm_send_mtmx_strtr_window(pcm->audio_client,
  284. &asm_mtmx_strtr_window,
  285. param_id);
  286. }
  287. dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
  288. __func__, pcm->instance, substream->pcm->id);
  289. runtime->private_data = pcm;
  290. mutex_unlock(&pcm->lock);
  291. return 0;
  292. }
  293. static void stop_pcm(struct msm_pcm_loopback *pcm)
  294. {
  295. struct snd_soc_pcm_runtime *soc_pcm_rx;
  296. struct snd_soc_pcm_runtime *soc_pcm_tx;
  297. if (pcm->audio_client == NULL)
  298. return;
  299. q6asm_cmd(pcm->audio_client, CMD_CLOSE);
  300. if (pcm->playback_substream != NULL) {
  301. soc_pcm_rx = pcm->playback_substream->private_data;
  302. msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->id,
  303. SNDRV_PCM_STREAM_PLAYBACK);
  304. }
  305. if (pcm->capture_substream != NULL) {
  306. soc_pcm_tx = pcm->capture_substream->private_data;
  307. msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->id,
  308. SNDRV_PCM_STREAM_CAPTURE);
  309. }
  310. q6asm_audio_client_free(pcm->audio_client);
  311. pcm->audio_client = NULL;
  312. }
  313. static int msm_pcm_close(struct snd_pcm_substream *substream)
  314. {
  315. struct snd_pcm_runtime *runtime = substream->runtime;
  316. struct msm_pcm_loopback *pcm = runtime->private_data;
  317. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  318. int ret = 0, n;
  319. bool found = false;
  320. mutex_lock(&pcm->lock);
  321. dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
  322. __func__, substream->stream);
  323. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  324. pcm->playback_start = 0;
  325. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  326. pcm->capture_start = 0;
  327. pcm->instance--;
  328. if (!pcm->playback_start || !pcm->capture_start) {
  329. dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
  330. stop_pcm(pcm);
  331. }
  332. if (!pcm->instance) {
  333. mutex_lock(&loopback_session_lock);
  334. for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
  335. if (!strcmp(rtd->dai_link->stream_name,
  336. session_map[n].stream_name)) {
  337. found = true;
  338. break;
  339. }
  340. }
  341. if (found) {
  342. memset(session_map[n].stream_name, 0,
  343. sizeof(session_map[n].stream_name));
  344. mutex_unlock(&pcm->lock);
  345. mutex_destroy(&session_map[n].loopback_priv->lock);
  346. session_map[n].loopback_priv = NULL;
  347. kfree(pcm);
  348. dev_dbg(rtd->platform->dev, "%s: stream freed %s\n",
  349. __func__, rtd->dai_link->stream_name);
  350. mutex_unlock(&loopback_session_lock);
  351. return 0;
  352. }
  353. mutex_unlock(&loopback_session_lock);
  354. }
  355. mutex_unlock(&pcm->lock);
  356. return ret;
  357. }
  358. static int msm_pcm_prepare(struct snd_pcm_substream *substream)
  359. {
  360. int ret = 0;
  361. struct snd_pcm_runtime *runtime = substream->runtime;
  362. struct msm_pcm_loopback *pcm = runtime->private_data;
  363. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  364. mutex_lock(&pcm->lock);
  365. dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
  366. __func__, substream->stream);
  367. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  368. if (!pcm->playback_start)
  369. pcm->playback_start = 1;
  370. } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  371. if (!pcm->capture_start)
  372. pcm->capture_start = 1;
  373. }
  374. mutex_unlock(&pcm->lock);
  375. return ret;
  376. }
  377. static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  378. {
  379. struct snd_pcm_runtime *runtime = substream->runtime;
  380. struct msm_pcm_loopback *pcm = runtime->private_data;
  381. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  382. switch (cmd) {
  383. case SNDRV_PCM_TRIGGER_START:
  384. case SNDRV_PCM_TRIGGER_RESUME:
  385. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  386. dev_dbg(rtd->platform->dev,
  387. "%s: playback_start:%d,capture_start:%d\n", __func__,
  388. pcm->playback_start, pcm->capture_start);
  389. if (pcm->playback_start && pcm->capture_start)
  390. q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
  391. break;
  392. case SNDRV_PCM_TRIGGER_SUSPEND:
  393. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  394. case SNDRV_PCM_TRIGGER_STOP:
  395. dev_dbg(rtd->platform->dev,
  396. "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
  397. __func__, pcm->playback_start, pcm->capture_start);
  398. if (pcm->playback_start && pcm->capture_start)
  399. q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
  400. break;
  401. default:
  402. pr_err("%s: default cmd %d\n", __func__, cmd);
  403. break;
  404. }
  405. return 0;
  406. }
  407. static const struct snd_pcm_ops msm_pcm_ops = {
  408. .open = msm_pcm_open,
  409. .close = msm_pcm_close,
  410. .prepare = msm_pcm_prepare,
  411. .trigger = msm_pcm_trigger,
  412. };
  413. static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
  414. struct snd_ctl_elem_value *ucontrol)
  415. {
  416. int rc = 0;
  417. struct snd_pcm_volume *vol = kcontrol->private_data;
  418. struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
  419. struct msm_pcm_loopback *prtd;
  420. int volume = ucontrol->value.integer.value[0];
  421. pr_debug("%s: volume : 0x%x\n", __func__, volume);
  422. if ((!substream) || (!substream->runtime)) {
  423. pr_err("%s substream or runtime not found\n", __func__);
  424. rc = -ENODEV;
  425. goto exit;
  426. }
  427. prtd = substream->runtime->private_data;
  428. if (!prtd) {
  429. rc = -ENODEV;
  430. goto exit;
  431. }
  432. rc = pcm_loopback_set_volume(prtd, volume);
  433. exit:
  434. return rc;
  435. }
  436. static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
  437. struct snd_ctl_elem_value *ucontrol)
  438. {
  439. int rc = 0;
  440. struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
  441. struct snd_pcm_substream *substream =
  442. vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
  443. struct msm_pcm_loopback *prtd;
  444. pr_debug("%s\n", __func__);
  445. if ((!substream) || (!substream->runtime)) {
  446. pr_debug("%s substream or runtime not found\n", __func__);
  447. rc = -ENODEV;
  448. goto exit;
  449. }
  450. prtd = substream->runtime->private_data;
  451. if (!prtd) {
  452. rc = -ENODEV;
  453. goto exit;
  454. }
  455. ucontrol->value.integer.value[0] = prtd->volume;
  456. exit:
  457. return rc;
  458. }
  459. static int msm_pcm_add_volume_controls(struct snd_soc_pcm_runtime *rtd)
  460. {
  461. struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
  462. struct snd_pcm_volume *volume_info;
  463. struct snd_kcontrol *kctl;
  464. int ret = 0;
  465. dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
  466. ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  467. NULL, 1,
  468. rtd->dai_link->id,
  469. &volume_info);
  470. if (ret < 0)
  471. return ret;
  472. kctl = volume_info->kctl;
  473. kctl->put = msm_pcm_volume_ctl_put;
  474. kctl->get = msm_pcm_volume_ctl_get;
  475. kctl->tlv.p = loopback_rx_vol_gain;
  476. return 0;
  477. }
  478. static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
  479. struct snd_ctl_elem_value *ucontrol)
  480. {
  481. u64 fe_id = kcontrol->private_value;
  482. int session_type = SESSION_TYPE_RX;
  483. int be_id = ucontrol->value.integer.value[3];
  484. struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
  485. int ret = 0;
  486. cfg_data.app_type = ucontrol->value.integer.value[0];
  487. cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
  488. if (ucontrol->value.integer.value[2] != 0)
  489. cfg_data.sample_rate = ucontrol->value.integer.value[2];
  490. pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
  491. __func__, fe_id, session_type, be_id,
  492. cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
  493. ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
  494. be_id, &cfg_data);
  495. if (ret < 0)
  496. pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
  497. __func__, ret);
  498. return ret;
  499. }
  500. static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
  501. struct snd_ctl_elem_value *ucontrol)
  502. {
  503. u64 fe_id = kcontrol->private_value;
  504. int session_type = SESSION_TYPE_RX;
  505. int be_id = 0;
  506. struct msm_pcm_stream_app_type_cfg cfg_data = {0};
  507. int ret = 0;
  508. ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
  509. &be_id, &cfg_data);
  510. if (ret < 0) {
  511. pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
  512. __func__, ret);
  513. goto done;
  514. }
  515. ucontrol->value.integer.value[0] = cfg_data.app_type;
  516. ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
  517. ucontrol->value.integer.value[2] = cfg_data.sample_rate;
  518. ucontrol->value.integer.value[3] = be_id;
  519. pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
  520. __func__, fe_id, session_type, be_id,
  521. cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
  522. done:
  523. return ret;
  524. }
  525. static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
  526. struct snd_ctl_elem_value *ucontrol)
  527. {
  528. u64 fe_id = kcontrol->private_value;
  529. int session_type = SESSION_TYPE_TX;
  530. int be_id = ucontrol->value.integer.value[3];
  531. struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
  532. int ret = 0;
  533. cfg_data.app_type = ucontrol->value.integer.value[0];
  534. cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
  535. if (ucontrol->value.integer.value[2] != 0)
  536. cfg_data.sample_rate = ucontrol->value.integer.value[2];
  537. pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
  538. __func__, fe_id, session_type, be_id,
  539. cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
  540. ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
  541. be_id, &cfg_data);
  542. if (ret < 0)
  543. pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
  544. __func__, ret);
  545. return ret;
  546. }
  547. static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
  548. struct snd_ctl_elem_value *ucontrol)
  549. {
  550. u64 fe_id = kcontrol->private_value;
  551. int session_type = SESSION_TYPE_TX;
  552. int be_id = 0;
  553. struct msm_pcm_stream_app_type_cfg cfg_data = {0};
  554. int ret = 0;
  555. ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
  556. &be_id, &cfg_data);
  557. if (ret < 0) {
  558. pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
  559. __func__, ret);
  560. goto done;
  561. }
  562. ucontrol->value.integer.value[0] = cfg_data.app_type;
  563. ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
  564. ucontrol->value.integer.value[2] = cfg_data.sample_rate;
  565. ucontrol->value.integer.value[3] = be_id;
  566. pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
  567. __func__, fe_id, session_type, be_id,
  568. cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
  569. done:
  570. return ret;
  571. }
  572. static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
  573. {
  574. struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
  575. struct snd_pcm_usr *app_type_info;
  576. struct snd_kcontrol *kctl;
  577. const char *playback_mixer_ctl_name = "Audio Stream";
  578. const char *capture_mixer_ctl_name = "Audio Stream Capture";
  579. const char *deviceNo = "NN";
  580. const char *suffix = "App Type Cfg";
  581. int ctl_len, ret = 0;
  582. if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  583. ctl_len = strlen(playback_mixer_ctl_name) + 1 +
  584. strlen(deviceNo) + 1 + strlen(suffix) + 1;
  585. pr_debug("%s: Playback app type cntrl add\n", __func__);
  586. ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  587. NULL, 1, ctl_len, rtd->dai_link->id,
  588. &app_type_info);
  589. if (ret < 0)
  590. return ret;
  591. kctl = app_type_info->kctl;
  592. snprintf(kctl->id.name, ctl_len, "%s %d %s",
  593. playback_mixer_ctl_name, rtd->pcm->device, suffix);
  594. kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
  595. kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
  596. }
  597. if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  598. ctl_len = strlen(capture_mixer_ctl_name) + 1 +
  599. strlen(deviceNo) + 1 + strlen(suffix) + 1;
  600. pr_debug("%s: Capture app type cntrl add\n", __func__);
  601. ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
  602. NULL, 1, ctl_len, rtd->dai_link->id,
  603. &app_type_info);
  604. if (ret < 0)
  605. return ret;
  606. kctl = app_type_info->kctl;
  607. snprintf(kctl->id.name, ctl_len, "%s %d %s",
  608. capture_mixer_ctl_name, rtd->pcm->device, suffix);
  609. kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
  610. kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
  611. }
  612. return 0;
  613. }
  614. static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
  615. {
  616. int ret = 0;
  617. pr_debug("%s\n", __func__);
  618. ret = msm_pcm_add_volume_controls(rtd);
  619. if (ret)
  620. pr_err("%s: pcm add volume controls failed:%d\n",
  621. __func__, ret);
  622. ret = msm_pcm_add_app_type_controls(rtd);
  623. if (ret)
  624. pr_err("%s: pcm add app type controls failed:%d\n",
  625. __func__, ret);
  626. return ret;
  627. }
  628. static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
  629. {
  630. struct snd_card *card = rtd->card->snd_card;
  631. int ret = 0;
  632. if (!card->dev->coherent_dma_mask)
  633. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  634. ret = msm_pcm_add_controls(rtd);
  635. if (ret)
  636. dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
  637. return ret;
  638. }
  639. static struct snd_soc_platform_driver msm_soc_platform = {
  640. .ops = &msm_pcm_ops,
  641. .pcm_new = msm_asoc_pcm_new,
  642. .probe = msm_pcm_loopback_probe,
  643. };
  644. static int msm_pcm_probe(struct platform_device *pdev)
  645. {
  646. struct msm_pcm_pdata *pdata;
  647. dev_dbg(&pdev->dev, "%s: dev name %s\n",
  648. __func__, dev_name(&pdev->dev));
  649. pdata = kzalloc(sizeof(struct msm_pcm_pdata), GFP_KERNEL);
  650. if (!pdata)
  651. return -ENOMEM;
  652. if (of_property_read_bool(pdev->dev.of_node,
  653. "qcom,msm-pcm-loopback-low-latency"))
  654. pdata->perf_mode = LOW_LATENCY_PCM_MODE;
  655. else
  656. pdata->perf_mode = LEGACY_PCM_MODE;
  657. dev_set_drvdata(&pdev->dev, pdata);
  658. return snd_soc_register_platform(&pdev->dev,
  659. &msm_soc_platform);
  660. }
  661. static int msm_pcm_remove(struct platform_device *pdev)
  662. {
  663. snd_soc_unregister_platform(&pdev->dev);
  664. return 0;
  665. }
  666. static const struct of_device_id msm_pcm_loopback_dt_match[] = {
  667. {.compatible = "qcom,msm-pcm-loopback"},
  668. {}
  669. };
  670. static struct platform_driver msm_pcm_driver = {
  671. .driver = {
  672. .name = "msm-pcm-loopback",
  673. .owner = THIS_MODULE,
  674. .of_match_table = msm_pcm_loopback_dt_match,
  675. },
  676. .probe = msm_pcm_probe,
  677. .remove = msm_pcm_remove,
  678. };
  679. int __init msm_pcm_loopback_init(void)
  680. {
  681. return platform_driver_register(&msm_pcm_driver);
  682. }
  683. void msm_pcm_loopback_exit(void)
  684. {
  685. platform_driver_unregister(&msm_pcm_driver);
  686. }
  687. MODULE_DESCRIPTION("PCM loopback platform driver");
  688. MODULE_LICENSE("GPL v2");