msm-pcm-loopback.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License version 2 and
  4. * only version 2 as published by the Free Software Foundation.
  5. * This program is distributed in the hope that it will be useful,
  6. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. * GNU General Public License for more details.
  9. */
  10. #include <linux/init.h>
  11. #include <linux/err.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/slab.h>
  15. #include <sound/apr_audio.h>
  16. #include <sound/core.h>
  17. #include <sound/soc.h>
  18. #include <sound/q6asm.h>
  19. #include <sound/pcm.h>
  20. #include <sound/initval.h>
  21. #include <sound/control.h>
  22. #include <sound/tlv.h>
  23. #include <asm/dma.h>
  24. #include <linux/dma-mapping.h>
  25. #include "msm-pcm-routing.h"
  26. #define LOOPBACK_VOL_MAX_STEPS 0x2000
  27. static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
  28. LOOPBACK_VOL_MAX_STEPS);
  29. struct msm_pcm_loopback {
  30. struct snd_pcm_substream *playback_substream;
  31. struct snd_pcm_substream *capture_substream;
  32. int instance;
  33. struct mutex lock;
  34. uint32_t samp_rate;
  35. uint32_t channel_mode;
  36. int playback_start;
  37. int capture_start;
  38. int session_id;
  39. struct audio_client *audio_client;
  40. int volume;
  41. };
  42. static void stop_pcm(struct msm_pcm_loopback *pcm);
  43. static const struct snd_pcm_hardware dummy_pcm_hardware = {
  44. .formats = 0xffffffff,
  45. .channels_min = 1,
  46. .channels_max = UINT_MAX,
  47. /* Random values to keep userspace happy when checking constraints */
  48. .info = SNDRV_PCM_INFO_INTERLEAVED |
  49. SNDRV_PCM_INFO_BLOCK_TRANSFER,
  50. .buffer_bytes_max = 128*1024,
  51. .period_bytes_min = 1024,
  52. .period_bytes_max = 1024*2,
  53. .periods_min = 2,
  54. .periods_max = 128,
  55. };
  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. BUG_ON(!pcm);
  61. pr_debug("%s: event %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. default:
  68. break;
  69. }
  70. }
  71. static void msm_pcm_loopback_event_handler(uint32_t opcode,
  72. uint32_t token, uint32_t *payload, void *priv)
  73. {
  74. pr_debug("%s\n", __func__);
  75. switch (opcode) {
  76. case APR_BASIC_RSP_RESULT: {
  77. switch (payload[0]) {
  78. break;
  79. default:
  80. break;
  81. }
  82. }
  83. break;
  84. default:
  85. pr_err("Not Supported Event opcode[0x%x]\n", opcode);
  86. break;
  87. }
  88. }
  89. static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
  90. {
  91. int rc = 0;
  92. pr_debug("%s Setting volume 0x%x\n", __func__, volume);
  93. if (prtd) {
  94. rc = q6asm_set_volume(prtd->audio_client, volume);
  95. if (rc < 0) {
  96. pr_err("%s: Send Volume command failed rc = %d\n",
  97. __func__, rc);
  98. return rc;
  99. }
  100. prtd->volume = volume;
  101. }
  102. return rc;
  103. }
  104. static int msm_pcm_open(struct snd_pcm_substream *substream)
  105. {
  106. struct snd_pcm_runtime *runtime = substream->runtime;
  107. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  108. struct msm_pcm_loopback *pcm;
  109. int ret = 0;
  110. struct msm_pcm_routing_evt event;
  111. pcm = dev_get_drvdata(rtd->platform->dev);
  112. mutex_lock(&pcm->lock);
  113. snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
  114. pcm->volume = 0x2000;
  115. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  116. pcm->playback_substream = substream;
  117. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  118. pcm->capture_substream = substream;
  119. pcm->instance++;
  120. dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
  121. pcm->instance, substream->stream);
  122. if (pcm->instance == 2) {
  123. struct snd_soc_pcm_runtime *soc_pcm_rx =
  124. pcm->playback_substream->private_data;
  125. struct snd_soc_pcm_runtime *soc_pcm_tx =
  126. pcm->capture_substream->private_data;
  127. if (pcm->audio_client != NULL)
  128. stop_pcm(pcm);
  129. pcm->audio_client = q6asm_audio_client_alloc(
  130. (app_cb)msm_pcm_loopback_event_handler, pcm);
  131. if (!pcm->audio_client) {
  132. dev_err(rtd->platform->dev,
  133. "%s: Could not allocate memory\n", __func__);
  134. mutex_unlock(&pcm->lock);
  135. return -ENOMEM;
  136. }
  137. pcm->session_id = pcm->audio_client->session;
  138. pcm->audio_client->perf_mode = false;
  139. ret = q6asm_open_loopack(pcm->audio_client);
  140. if (ret < 0) {
  141. dev_err(rtd->platform->dev,
  142. "%s: pcm out open failed\n", __func__);
  143. q6asm_audio_client_free(pcm->audio_client);
  144. mutex_unlock(&pcm->lock);
  145. return -ENOMEM;
  146. }
  147. event.event_func = msm_pcm_route_event_handler;
  148. event.priv_data = (void *) pcm;
  149. msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
  150. pcm->audio_client->perf_mode,
  151. pcm->session_id, pcm->capture_substream->stream);
  152. msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
  153. pcm->audio_client->perf_mode,
  154. pcm->session_id, pcm->playback_substream->stream,
  155. event);
  156. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  157. pcm->playback_substream = substream;
  158. ret = pcm_loopback_set_volume(pcm, pcm->volume);
  159. if (ret < 0)
  160. dev_err(rtd->platform->dev,
  161. "Error %d setting volume", ret);
  162. }
  163. }
  164. dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
  165. __func__ , pcm->instance, substream->pcm->id);
  166. runtime->private_data = pcm;
  167. mutex_unlock(&pcm->lock);
  168. return 0;
  169. }
  170. static void stop_pcm(struct msm_pcm_loopback *pcm)
  171. {
  172. struct snd_soc_pcm_runtime *soc_pcm_rx;
  173. struct snd_soc_pcm_runtime *soc_pcm_tx;
  174. if (pcm->audio_client == NULL)
  175. return;
  176. q6asm_cmd(pcm->audio_client, CMD_CLOSE);
  177. if (pcm->playback_substream != NULL) {
  178. soc_pcm_rx = pcm->playback_substream->private_data;
  179. msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
  180. SNDRV_PCM_STREAM_PLAYBACK);
  181. }
  182. if (pcm->capture_substream != NULL) {
  183. soc_pcm_tx = pcm->capture_substream->private_data;
  184. msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
  185. SNDRV_PCM_STREAM_CAPTURE);
  186. }
  187. q6asm_audio_client_free(pcm->audio_client);
  188. pcm->audio_client = NULL;
  189. }
  190. static int msm_pcm_close(struct snd_pcm_substream *substream)
  191. {
  192. struct snd_pcm_runtime *runtime = substream->runtime;
  193. struct msm_pcm_loopback *pcm = runtime->private_data;
  194. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  195. int ret = 0;
  196. mutex_lock(&pcm->lock);
  197. dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
  198. __func__, substream->stream);
  199. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  200. pcm->playback_start = 0;
  201. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  202. pcm->capture_start = 0;
  203. pcm->instance--;
  204. if (!pcm->playback_start || !pcm->capture_start) {
  205. dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
  206. stop_pcm(pcm);
  207. }
  208. mutex_unlock(&pcm->lock);
  209. return ret;
  210. }
  211. static int msm_pcm_prepare(struct snd_pcm_substream *substream)
  212. {
  213. int ret = 0;
  214. struct snd_pcm_runtime *runtime = substream->runtime;
  215. struct msm_pcm_loopback *pcm = runtime->private_data;
  216. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  217. mutex_lock(&pcm->lock);
  218. dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
  219. __func__, substream->stream);
  220. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  221. if (!pcm->playback_start)
  222. pcm->playback_start = 1;
  223. } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  224. if (!pcm->capture_start)
  225. pcm->capture_start = 1;
  226. }
  227. mutex_unlock(&pcm->lock);
  228. return ret;
  229. }
  230. static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  231. {
  232. struct snd_pcm_runtime *runtime = substream->runtime;
  233. struct msm_pcm_loopback *pcm = runtime->private_data;
  234. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  235. switch (cmd) {
  236. case SNDRV_PCM_TRIGGER_START:
  237. case SNDRV_PCM_TRIGGER_RESUME:
  238. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  239. dev_dbg(rtd->platform->dev,
  240. "%s: playback_start:%d,capture_start:%d\n", __func__,
  241. pcm->playback_start, pcm->capture_start);
  242. if (pcm->playback_start && pcm->capture_start)
  243. q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
  244. break;
  245. case SNDRV_PCM_TRIGGER_SUSPEND:
  246. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  247. case SNDRV_PCM_TRIGGER_STOP:
  248. dev_dbg(rtd->platform->dev,
  249. "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
  250. __func__, pcm->playback_start, pcm->capture_start);
  251. if (pcm->playback_start && pcm->capture_start)
  252. q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
  253. break;
  254. default:
  255. break;
  256. }
  257. return 0;
  258. }
  259. static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
  260. struct snd_pcm_hw_params *params)
  261. {
  262. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  263. dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
  264. return snd_pcm_lib_alloc_vmalloc_buffer(substream,
  265. params_buffer_bytes(params));
  266. }
  267. static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
  268. {
  269. return snd_pcm_lib_free_vmalloc_buffer(substream);
  270. }
  271. static struct snd_pcm_ops msm_pcm_ops = {
  272. .open = msm_pcm_open,
  273. .hw_params = msm_pcm_hw_params,
  274. .hw_free = msm_pcm_hw_free,
  275. .close = msm_pcm_close,
  276. .prepare = msm_pcm_prepare,
  277. .trigger = msm_pcm_trigger,
  278. };
  279. static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
  280. struct snd_ctl_elem_value *ucontrol)
  281. {
  282. int rc = 0;
  283. struct snd_pcm_volume *vol = kcontrol->private_data;
  284. struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
  285. struct msm_pcm_loopback *prtd = substream->runtime->private_data;
  286. int volume = ucontrol->value.integer.value[0];
  287. rc = pcm_loopback_set_volume(prtd, volume);
  288. return rc;
  289. }
  290. static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
  291. {
  292. struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
  293. struct snd_pcm_volume *volume_info;
  294. struct snd_kcontrol *kctl;
  295. int ret = 0;
  296. dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
  297. ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  298. NULL, 1,
  299. rtd->dai_link->be_id,
  300. &volume_info);
  301. if (ret < 0)
  302. return ret;
  303. kctl = volume_info->kctl;
  304. kctl->put = msm_pcm_volume_ctl_put;
  305. kctl->tlv.p = loopback_rx_vol_gain;
  306. return 0;
  307. }
  308. static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
  309. {
  310. struct snd_card *card = rtd->card->snd_card;
  311. int ret = 0;
  312. if (!card->dev->coherent_dma_mask)
  313. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  314. ret = msm_pcm_add_controls(rtd);
  315. if (ret)
  316. dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
  317. return ret;
  318. }
  319. static struct snd_soc_platform_driver msm_soc_platform = {
  320. .ops = &msm_pcm_ops,
  321. .pcm_new = msm_asoc_pcm_new,
  322. };
  323. static __devinit int msm_pcm_probe(struct platform_device *pdev)
  324. {
  325. struct msm_pcm_loopback *pcm;
  326. dev_dbg(&pdev->dev, "%s: dev name %s\n",
  327. __func__, dev_name(&pdev->dev));
  328. pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
  329. if (!pcm) {
  330. dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
  331. __func__);
  332. return -ENOMEM;
  333. } else {
  334. mutex_init(&pcm->lock);
  335. dev_set_drvdata(&pdev->dev, pcm);
  336. }
  337. return snd_soc_register_platform(&pdev->dev,
  338. &msm_soc_platform);
  339. }
  340. static int msm_pcm_remove(struct platform_device *pdev)
  341. {
  342. struct msm_pcm_loopback *pcm;
  343. pcm = dev_get_drvdata(&pdev->dev);
  344. mutex_destroy(&pcm->lock);
  345. snd_soc_unregister_platform(&pdev->dev);
  346. return 0;
  347. }
  348. static struct platform_driver msm_pcm_driver = {
  349. .driver = {
  350. .name = "msm-pcm-loopback",
  351. .owner = THIS_MODULE,
  352. },
  353. .probe = msm_pcm_probe,
  354. .remove = __devexit_p(msm_pcm_remove),
  355. };
  356. static int __init msm_soc_platform_init(void)
  357. {
  358. return platform_driver_register(&msm_pcm_driver);
  359. }
  360. module_init(msm_soc_platform_init);
  361. static void __exit msm_soc_platform_exit(void)
  362. {
  363. platform_driver_unregister(&msm_pcm_driver);
  364. }
  365. module_exit(msm_soc_platform_exit);
  366. MODULE_DESCRIPTION("PCM loopback platform driver");
  367. MODULE_LICENSE("GPL v2");