msm7k-pcm.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /* linux/sound/soc/msm/msm7k-pcm.c
  2. *
  3. * Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved.
  4. *
  5. * All source code in this file is licensed under the following license except
  6. * where indicated.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License version 2 as published
  10. * by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * See the GNU General Public License for more details.
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you can find it at http://www.fsf.org.
  19. */
  20. #include <linux/init.h>
  21. #include <linux/err.h>
  22. #include <linux/module.h>
  23. #include <linux/moduleparam.h>
  24. #include <linux/time.h>
  25. #include <linux/wait.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/slab.h>
  28. #include <sound/core.h>
  29. #include <sound/soc.h>
  30. #include <sound/soc-dapm.h>
  31. #include <sound/pcm.h>
  32. #include <sound/initval.h>
  33. #include <sound/control.h>
  34. #include <asm/dma.h>
  35. #include <linux/dma-mapping.h>
  36. #include "msm-pcm.h"
  37. #define SND_DRIVER "snd_msm"
  38. #define MAX_PCM_DEVICES SNDRV_CARDS
  39. #define MAX_PCM_SUBSTREAMS 1
  40. struct snd_msm {
  41. struct snd_card *card;
  42. struct snd_pcm *pcm;
  43. };
  44. int copy_count;
  45. struct audio_locks the_locks;
  46. EXPORT_SYMBOL(the_locks);
  47. struct msm_volume msm_vol_ctl;
  48. EXPORT_SYMBOL(msm_vol_ctl);
  49. static unsigned convert_dsp_samp_index(unsigned index)
  50. {
  51. switch (index) {
  52. case 48000:
  53. return AUDREC_CMD_SAMP_RATE_INDX_48000;
  54. case 44100:
  55. return AUDREC_CMD_SAMP_RATE_INDX_44100;
  56. case 32000:
  57. return AUDREC_CMD_SAMP_RATE_INDX_32000;
  58. case 24000:
  59. return AUDREC_CMD_SAMP_RATE_INDX_24000;
  60. case 22050:
  61. return AUDREC_CMD_SAMP_RATE_INDX_22050;
  62. case 16000:
  63. return AUDREC_CMD_SAMP_RATE_INDX_16000;
  64. case 12000:
  65. return AUDREC_CMD_SAMP_RATE_INDX_12000;
  66. case 11025:
  67. return AUDREC_CMD_SAMP_RATE_INDX_11025;
  68. case 8000:
  69. return AUDREC_CMD_SAMP_RATE_INDX_8000;
  70. default:
  71. return AUDREC_CMD_SAMP_RATE_INDX_44100;
  72. }
  73. }
  74. static unsigned convert_samp_rate(unsigned hz)
  75. {
  76. switch (hz) {
  77. case 48000:
  78. return RPC_AUD_DEF_SAMPLE_RATE_48000;
  79. case 44100:
  80. return RPC_AUD_DEF_SAMPLE_RATE_44100;
  81. case 32000:
  82. return RPC_AUD_DEF_SAMPLE_RATE_32000;
  83. case 24000:
  84. return RPC_AUD_DEF_SAMPLE_RATE_24000;
  85. case 22050:
  86. return RPC_AUD_DEF_SAMPLE_RATE_22050;
  87. case 16000:
  88. return RPC_AUD_DEF_SAMPLE_RATE_16000;
  89. case 12000:
  90. return RPC_AUD_DEF_SAMPLE_RATE_12000;
  91. case 11025:
  92. return RPC_AUD_DEF_SAMPLE_RATE_11025;
  93. case 8000:
  94. return RPC_AUD_DEF_SAMPLE_RATE_8000;
  95. default:
  96. return RPC_AUD_DEF_SAMPLE_RATE_44100;
  97. }
  98. }
  99. static struct snd_pcm_hardware msm_pcm_playback_hardware = {
  100. .info = SNDRV_PCM_INFO_MMAP |
  101. SNDRV_PCM_INFO_MMAP_VALID |
  102. SNDRV_PCM_INFO_INTERLEAVED,
  103. .formats = USE_FORMATS,
  104. .rates = USE_RATE,
  105. .rate_min = USE_RATE_MIN,
  106. .rate_max = USE_RATE_MAX,
  107. .channels_min = USE_CHANNELS_MIN,
  108. .channels_max = USE_CHANNELS_MAX,
  109. .buffer_bytes_max = 4800 * 2,
  110. .period_bytes_min = 4800,
  111. .period_bytes_max = 4800,
  112. .periods_min = 2,
  113. .periods_max = 2,
  114. .fifo_size = 0,
  115. };
  116. static struct snd_pcm_hardware msm_pcm_capture_hardware = {
  117. .info = SNDRV_PCM_INFO_INTERLEAVED,
  118. .formats = USE_FORMATS,
  119. .rates = USE_RATE,
  120. .rate_min = USE_RATE_MIN,
  121. .rate_max = USE_RATE_MAX,
  122. .channels_min = USE_CHANNELS_MIN,
  123. .channels_max = USE_CHANNELS_MAX,
  124. .buffer_bytes_max = MAX_BUFFER_CAPTURE_SIZE,
  125. .period_bytes_min = CAPTURE_SIZE,
  126. .period_bytes_max = CAPTURE_SIZE,
  127. .periods_min = USE_PERIODS_MIN,
  128. .periods_max = USE_PERIODS_MAX,
  129. .fifo_size = 0,
  130. };
  131. /* Conventional and unconventional sample rate supported */
  132. static unsigned int supported_sample_rates[] = {
  133. 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
  134. };
  135. static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
  136. .count = ARRAY_SIZE(supported_sample_rates),
  137. .list = supported_sample_rates,
  138. .mask = 0,
  139. };
  140. static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream)
  141. {
  142. struct snd_pcm_runtime *runtime = substream->runtime;
  143. struct msm_audio *prtd = runtime->private_data;
  144. unsigned int period_size;
  145. pr_debug("prtd->out_tail =%d mmap_flag=%d\n",
  146. prtd->out_tail, prtd->mmap_flag);
  147. period_size = snd_pcm_lib_period_bytes(substream);
  148. alsa_dsp_send_buffer(prtd, prtd->out_tail, period_size);
  149. prtd->out_tail ^= 1;
  150. ++copy_count;
  151. prtd->period++;
  152. if (unlikely(prtd->period >= runtime->periods))
  153. prtd->period = 0;
  154. }
  155. static void playback_event_handler(void *data)
  156. {
  157. struct msm_audio *prtd = data;
  158. snd_pcm_period_elapsed(prtd->playback_substream);
  159. if (prtd->mmap_flag) {
  160. if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE)
  161. return;
  162. if (!prtd->stopped)
  163. msm_pcm_enqueue_data(prtd->playback_substream);
  164. else
  165. prtd->out_needed++;
  166. }
  167. }
  168. static void capture_event_handler(void *data)
  169. {
  170. struct msm_audio *prtd = data;
  171. snd_pcm_period_elapsed(prtd->capture_substream);
  172. }
  173. static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
  174. {
  175. struct snd_pcm_runtime *runtime = substream->runtime;
  176. struct msm_audio *prtd = runtime->private_data;
  177. prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
  178. prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
  179. prtd->pcm_irq_pos = 0;
  180. prtd->pcm_buf_pos = 0;
  181. /* rate and channels are sent to audio driver */
  182. prtd->out_sample_rate = runtime->rate;
  183. prtd->out_channel_mode = runtime->channels;
  184. if (prtd->enabled | !(prtd->mmap_flag))
  185. return 0;
  186. prtd->data = substream->dma_buffer.area;
  187. prtd->phys = substream->dma_buffer.addr;
  188. prtd->out[0].data = prtd->data + 0;
  189. prtd->out[0].addr = prtd->phys + 0;
  190. prtd->out[0].size = BUFSZ;
  191. prtd->out[1].data = prtd->data + BUFSZ;
  192. prtd->out[1].addr = prtd->phys + BUFSZ;
  193. prtd->out[1].size = BUFSZ;
  194. prtd->out[0].used = prtd->pcm_count;
  195. prtd->out[1].used = prtd->pcm_count;
  196. mutex_lock(&the_locks.lock);
  197. alsa_audio_configure(prtd);
  198. mutex_unlock(&the_locks.lock);
  199. return 0;
  200. }
  201. static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
  202. {
  203. struct snd_pcm_runtime *runtime = substream->runtime;
  204. struct msm_audio *prtd = runtime->private_data;
  205. struct audmgr_config cfg;
  206. int rc;
  207. prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
  208. prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
  209. prtd->pcm_irq_pos = 0;
  210. prtd->pcm_buf_pos = 0;
  211. /* rate and channels are sent to audio driver */
  212. prtd->samp_rate = convert_samp_rate(runtime->rate);
  213. prtd->samp_rate_index = convert_dsp_samp_index(runtime->rate);
  214. prtd->channel_mode = (runtime->channels - 1);
  215. prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
  216. MONO_DATA_SIZE;
  217. if (prtd->enabled == 1)
  218. return 0;
  219. prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
  220. cfg.tx_rate = convert_samp_rate(runtime->rate);
  221. cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
  222. cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
  223. cfg.codec = RPC_AUD_DEF_CODEC_PCM;
  224. cfg.snd_method = RPC_SND_METHOD_MIDI;
  225. rc = audmgr_enable(&prtd->audmgr, &cfg);
  226. if (rc < 0)
  227. return rc;
  228. if (msm_adsp_enable(prtd->audpre)) {
  229. audmgr_disable(&prtd->audmgr);
  230. return -ENODEV;
  231. }
  232. if (msm_adsp_enable(prtd->audrec)) {
  233. msm_adsp_disable(prtd->audpre);
  234. audmgr_disable(&prtd->audmgr);
  235. return -ENODEV;
  236. }
  237. prtd->enabled = 1;
  238. alsa_rec_dsp_enable(prtd, 1);
  239. return 0;
  240. }
  241. static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  242. {
  243. struct snd_pcm_runtime *runtime = substream->runtime;
  244. struct msm_audio *prtd = runtime->private_data;
  245. unsigned long flag = 0;
  246. int ret = 0;
  247. switch (cmd) {
  248. case SNDRV_PCM_TRIGGER_START:
  249. case SNDRV_PCM_TRIGGER_RESUME:
  250. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  251. if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  252. || !prtd->mmap_flag)
  253. break;
  254. if (!prtd->out_needed) {
  255. prtd->stopped = 0;
  256. break;
  257. }
  258. spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
  259. if (prtd->running == 1) {
  260. if (prtd->stopped == 1) {
  261. prtd->stopped = 0;
  262. prtd->period = 0;
  263. if (prtd->pcm_irq_pos == 0) {
  264. prtd->out_tail = 0;
  265. msm_pcm_enqueue_data(
  266. prtd->playback_substream);
  267. prtd->out_needed--;
  268. } else {
  269. prtd->out_tail = 1;
  270. msm_pcm_enqueue_data(
  271. prtd->playback_substream);
  272. prtd->out_needed--;
  273. }
  274. if (prtd->out_needed) {
  275. prtd->out_tail ^= 1;
  276. msm_pcm_enqueue_data(
  277. prtd->playback_substream);
  278. prtd->out_needed--;
  279. }
  280. }
  281. }
  282. spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
  283. break;
  284. case SNDRV_PCM_TRIGGER_STOP:
  285. case SNDRV_PCM_TRIGGER_SUSPEND:
  286. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  287. if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  288. || !prtd->mmap_flag)
  289. break;
  290. prtd->stopped = 1;
  291. break;
  292. default:
  293. ret = -EINVAL;
  294. }
  295. return ret;
  296. }
  297. static snd_pcm_uframes_t
  298. msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
  299. {
  300. struct snd_pcm_runtime *runtime = substream->runtime;
  301. struct msm_audio *prtd = runtime->private_data;
  302. if (prtd->pcm_irq_pos == prtd->pcm_size)
  303. prtd->pcm_irq_pos = 0;
  304. return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
  305. }
  306. static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
  307. int channel, snd_pcm_uframes_t hwoff, void __user *buf,
  308. snd_pcm_uframes_t frames)
  309. {
  310. int rc = 0, rc1 = 0, rc2 = 0;
  311. int fbytes = 0;
  312. struct snd_pcm_runtime *runtime = substream->runtime;
  313. struct msm_audio *prtd = substream->runtime->private_data;
  314. int monofbytes = 0;
  315. char *bufferp = NULL;
  316. fbytes = frames_to_bytes(runtime, frames);
  317. monofbytes = fbytes / 2;
  318. if (runtime->channels == 2) {
  319. rc = alsa_buffer_read(prtd, buf, fbytes, NULL);
  320. } else {
  321. bufferp = buf;
  322. rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
  323. bufferp = buf + monofbytes ;
  324. rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
  325. rc = rc1 + rc2;
  326. }
  327. prtd->pcm_buf_pos += fbytes;
  328. return rc;
  329. }
  330. static snd_pcm_uframes_t
  331. msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
  332. {
  333. struct snd_pcm_runtime *runtime = substream->runtime;
  334. struct msm_audio *prtd = runtime->private_data;
  335. return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
  336. }
  337. static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
  338. {
  339. struct snd_pcm_runtime *runtime = substream->runtime;
  340. struct msm_audio *prtd = runtime->private_data;
  341. alsa_audrec_disable(prtd);
  342. audmgr_close(&prtd->audmgr);
  343. msm_adsp_put(prtd->audrec);
  344. msm_adsp_put(prtd->audpre);
  345. kfree(prtd);
  346. return 0;
  347. }
  348. struct msm_audio_event_callbacks snd_msm_audio_ops = {
  349. .playback = playback_event_handler,
  350. .capture = capture_event_handler,
  351. };
  352. static int msm_pcm_open(struct snd_pcm_substream *substream)
  353. {
  354. struct snd_pcm_runtime *runtime = substream->runtime;
  355. struct msm_audio *prtd;
  356. int ret = 0;
  357. prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
  358. if (prtd == NULL) {
  359. ret = -ENOMEM;
  360. return ret;
  361. }
  362. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  363. runtime->hw = msm_pcm_playback_hardware;
  364. prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
  365. prtd->playback_substream = substream;
  366. prtd->eos_ack = 0;
  367. ret = msm_audio_volume_update(PCMPLAYBACK_DECODERID,
  368. msm_vol_ctl.volume, msm_vol_ctl.pan);
  369. } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  370. runtime->hw = msm_pcm_capture_hardware;
  371. prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
  372. prtd->capture_substream = substream;
  373. }
  374. ret = snd_pcm_hw_constraint_list(runtime, 0,
  375. SNDRV_PCM_HW_PARAM_RATE,
  376. &constraints_sample_rates);
  377. if (ret < 0)
  378. goto out;
  379. /* Ensure that buffer size is a multiple of period size */
  380. ret = snd_pcm_hw_constraint_integer(runtime,
  381. SNDRV_PCM_HW_PARAM_PERIODS);
  382. if (ret < 0)
  383. goto out;
  384. prtd->ops = &snd_msm_audio_ops;
  385. prtd->out[0].used = BUF_INVALID_LEN;
  386. prtd->out_head = 1; /* point to second buffer on startup */
  387. runtime->private_data = prtd;
  388. ret = alsa_adsp_configure(prtd);
  389. if (ret)
  390. goto out;
  391. copy_count = 0;
  392. return 0;
  393. out:
  394. kfree(prtd);
  395. return ret;
  396. }
  397. static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
  398. snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
  399. {
  400. int rc = 1;
  401. int fbytes = 0;
  402. struct snd_pcm_runtime *runtime = substream->runtime;
  403. struct msm_audio *prtd = runtime->private_data;
  404. fbytes = frames_to_bytes(runtime, frames);
  405. rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
  406. ++copy_count;
  407. if (copy_count == 1) {
  408. mutex_lock(&the_locks.lock);
  409. alsa_audio_configure(prtd);
  410. mutex_unlock(&the_locks.lock);
  411. }
  412. return rc;
  413. }
  414. static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
  415. {
  416. struct snd_pcm_runtime *runtime = substream->runtime;
  417. struct msm_audio *prtd = runtime->private_data;
  418. int rc = 0;
  419. pr_debug("%s()\n", __func__);
  420. /* pcm dmamiss message is sent continously
  421. * when decoder is starved so no race
  422. * condition concern
  423. */
  424. if (prtd->enabled)
  425. rc = wait_event_interruptible(the_locks.eos_wait,
  426. prtd->eos_ack);
  427. alsa_audio_disable(prtd);
  428. audmgr_close(&prtd->audmgr);
  429. kfree(prtd);
  430. return 0;
  431. }
  432. static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
  433. snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
  434. {
  435. int ret = 0;
  436. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  437. ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
  438. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  439. ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
  440. return ret;
  441. }
  442. static int msm_pcm_close(struct snd_pcm_substream *substream)
  443. {
  444. int ret = 0;
  445. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  446. ret = msm_pcm_playback_close(substream);
  447. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  448. ret = msm_pcm_capture_close(substream);
  449. return ret;
  450. }
  451. static int msm_pcm_prepare(struct snd_pcm_substream *substream)
  452. {
  453. int ret = 0;
  454. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  455. ret = msm_pcm_playback_prepare(substream);
  456. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  457. ret = msm_pcm_capture_prepare(substream);
  458. return ret;
  459. }
  460. static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
  461. {
  462. snd_pcm_uframes_t ret = 0;
  463. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  464. ret = msm_pcm_playback_pointer(substream);
  465. else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  466. ret = msm_pcm_capture_pointer(substream);
  467. return ret;
  468. }
  469. int msm_pcm_hw_params(struct snd_pcm_substream *substream,
  470. struct snd_pcm_hw_params *params)
  471. {
  472. struct snd_pcm_runtime *runtime = substream->runtime;
  473. if (substream->pcm->device & 1) {
  474. runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
  475. runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
  476. }
  477. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  478. return 0;
  479. }
  480. int msm_pcm_mmap(struct snd_pcm_substream *substream,
  481. struct vm_area_struct *vma)
  482. {
  483. struct snd_pcm_runtime *runtime = substream->runtime;
  484. struct msm_audio *prtd = runtime->private_data;
  485. prtd->out_head = 0; /* point to First buffer on startup */
  486. prtd->mmap_flag = 1;
  487. runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2;
  488. dma_mmap_coherent(substream->pcm->card->dev, vma,
  489. runtime->dma_area,
  490. runtime->dma_addr,
  491. runtime->dma_bytes);
  492. return 0;
  493. }
  494. static struct snd_pcm_ops msm_pcm_ops = {
  495. .open = msm_pcm_open,
  496. .copy = msm_pcm_copy,
  497. .hw_params = msm_pcm_hw_params,
  498. .close = msm_pcm_close,
  499. .ioctl = snd_pcm_lib_ioctl,
  500. .prepare = msm_pcm_prepare,
  501. .trigger = msm_pcm_trigger,
  502. .pointer = msm_pcm_pointer,
  503. .mmap = msm_pcm_mmap,
  504. };
  505. static int pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
  506. int stream)
  507. {
  508. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  509. struct snd_dma_buffer *buf = &substream->dma_buffer;
  510. size_t size;
  511. if (!stream)
  512. size = PLAYBACK_DMASZ;
  513. else
  514. size = CAPTURE_DMASZ;
  515. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  516. buf->dev.dev = pcm->card->dev;
  517. buf->private_data = NULL;
  518. buf->area = dma_alloc_coherent(pcm->card->dev, size,
  519. &buf->addr, GFP_KERNEL);
  520. if (!buf->area)
  521. return -ENOMEM;
  522. buf->bytes = size;
  523. return 0;
  524. }
  525. static void msm_pcm_free_dma_buffers(struct snd_pcm *pcm)
  526. {
  527. struct snd_pcm_substream *substream;
  528. struct snd_dma_buffer *buf;
  529. int stream;
  530. for (stream = 0; stream < 2; stream++) {
  531. substream = pcm->streams[stream].substream;
  532. if (!substream)
  533. continue;
  534. buf = &substream->dma_buffer;
  535. if (!buf->area)
  536. continue;
  537. dma_free_coherent(pcm->card->dev, buf->bytes,
  538. buf->area, buf->addr);
  539. buf->area = NULL;
  540. }
  541. }
  542. static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
  543. {
  544. int ret;
  545. struct snd_card *card = rtd->card->snd_card;
  546. struct snd_pcm *pcm = rtd->pcm;
  547. if (!card->dev->coherent_dma_mask)
  548. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  549. ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
  550. if (ret)
  551. return ret;
  552. ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
  553. if (ret)
  554. return ret;
  555. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_pcm_ops);
  556. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_pcm_ops);
  557. ret = pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
  558. if (ret)
  559. return ret;
  560. ret = pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
  561. if (ret)
  562. msm_pcm_free_dma_buffers(pcm);
  563. return ret;
  564. }
  565. struct snd_soc_platform_driver msm_soc_platform = {
  566. .ops = &msm_pcm_ops,
  567. .pcm_new = msm_pcm_new,
  568. .pcm_free = msm_pcm_free_dma_buffers,
  569. };
  570. EXPORT_SYMBOL(msm_soc_platform);
  571. static __devinit int msm_pcm_probe(struct platform_device *pdev)
  572. {
  573. return snd_soc_register_platform(&pdev->dev,
  574. &msm_soc_platform);
  575. }
  576. static int msm_pcm_remove(struct platform_device *pdev)
  577. {
  578. snd_soc_unregister_platform(&pdev->dev);
  579. return 0;
  580. }
  581. static struct platform_driver msm_pcm_driver = {
  582. .driver = {
  583. .name = "msm-dsp-audio",
  584. .owner = THIS_MODULE,
  585. },
  586. .probe = msm_pcm_probe,
  587. .remove = __devexit_p(msm_pcm_remove),
  588. };
  589. static int __init msm_soc_platform_init(void)
  590. {
  591. return platform_driver_register(&msm_pcm_driver);
  592. }
  593. module_init(msm_soc_platform_init);
  594. static void __exit msm_soc_platform_exit(void)
  595. {
  596. platform_driver_unregister(&msm_pcm_driver);
  597. }
  598. module_exit(msm_soc_platform_exit);
  599. MODULE_DESCRIPTION("PCM module platform driver");
  600. MODULE_LICENSE("GPL v2");