msm-pcm-loopback-v2.c 23 KB

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