lpass-platform.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /*
  2. * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
  14. */
  15. #include <linux/dma-mapping.h>
  16. #include <linux/export.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/platform_device.h>
  20. #include <sound/pcm_params.h>
  21. #include <linux/regmap.h>
  22. #include <sound/soc.h>
  23. #include "lpass-lpaif-reg.h"
  24. #include "lpass.h"
  25. struct lpass_pcm_data {
  26. int rdma_ch;
  27. int wrdma_ch;
  28. int i2s_port;
  29. };
  30. #define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)
  31. #define LPASS_PLATFORM_PERIODS 2
  32. static struct snd_pcm_hardware lpass_platform_pcm_hardware = {
  33. .info = SNDRV_PCM_INFO_MMAP |
  34. SNDRV_PCM_INFO_MMAP_VALID |
  35. SNDRV_PCM_INFO_INTERLEAVED |
  36. SNDRV_PCM_INFO_PAUSE |
  37. SNDRV_PCM_INFO_RESUME,
  38. .formats = SNDRV_PCM_FMTBIT_S16 |
  39. SNDRV_PCM_FMTBIT_S24 |
  40. SNDRV_PCM_FMTBIT_S32,
  41. .rates = SNDRV_PCM_RATE_8000_192000,
  42. .rate_min = 8000,
  43. .rate_max = 192000,
  44. .channels_min = 1,
  45. .channels_max = 8,
  46. .buffer_bytes_max = LPASS_PLATFORM_BUFFER_SIZE,
  47. .period_bytes_max = LPASS_PLATFORM_BUFFER_SIZE /
  48. LPASS_PLATFORM_PERIODS,
  49. .period_bytes_min = LPASS_PLATFORM_BUFFER_SIZE /
  50. LPASS_PLATFORM_PERIODS,
  51. .periods_min = LPASS_PLATFORM_PERIODS,
  52. .periods_max = LPASS_PLATFORM_PERIODS,
  53. .fifo_size = 0,
  54. };
  55. static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
  56. {
  57. struct snd_pcm_runtime *runtime = substream->runtime;
  58. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  59. struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
  60. struct lpass_data *drvdata =
  61. snd_soc_platform_get_drvdata(soc_runtime->platform);
  62. struct lpass_variant *v = drvdata->variant;
  63. int ret, dma_ch, dir = substream->stream;
  64. struct lpass_pcm_data *data;
  65. data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
  66. if (!data)
  67. return -ENOMEM;
  68. data->i2s_port = cpu_dai->driver->id;
  69. runtime->private_data = data;
  70. dma_ch = 0;
  71. if (v->alloc_dma_channel)
  72. dma_ch = v->alloc_dma_channel(drvdata, dir);
  73. else
  74. dma_ch = 0;
  75. if (dma_ch < 0)
  76. return dma_ch;
  77. drvdata->substream[dma_ch] = substream;
  78. ret = regmap_write(drvdata->lpaif_map,
  79. LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
  80. if (ret) {
  81. dev_err(soc_runtime->dev,
  82. "%s() error writing to rdmactl reg: %d\n",
  83. __func__, ret);
  84. return ret;
  85. }
  86. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  87. data->rdma_ch = dma_ch;
  88. else
  89. data->wrdma_ch = dma_ch;
  90. snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
  91. runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
  92. ret = snd_pcm_hw_constraint_integer(runtime,
  93. SNDRV_PCM_HW_PARAM_PERIODS);
  94. if (ret < 0) {
  95. dev_err(soc_runtime->dev, "%s() setting constraints failed: %d\n",
  96. __func__, ret);
  97. return -EINVAL;
  98. }
  99. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  100. return 0;
  101. }
  102. static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
  103. {
  104. struct snd_pcm_runtime *runtime = substream->runtime;
  105. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  106. struct lpass_data *drvdata =
  107. snd_soc_platform_get_drvdata(soc_runtime->platform);
  108. struct lpass_variant *v = drvdata->variant;
  109. struct lpass_pcm_data *data;
  110. int dma_ch, dir = substream->stream;
  111. data = runtime->private_data;
  112. v = drvdata->variant;
  113. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  114. dma_ch = data->rdma_ch;
  115. else
  116. dma_ch = data->wrdma_ch;
  117. drvdata->substream[dma_ch] = NULL;
  118. if (v->free_dma_channel)
  119. v->free_dma_channel(drvdata, dma_ch);
  120. return 0;
  121. }
  122. static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
  123. struct snd_pcm_hw_params *params)
  124. {
  125. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  126. struct lpass_data *drvdata =
  127. snd_soc_platform_get_drvdata(soc_runtime->platform);
  128. struct snd_pcm_runtime *rt = substream->runtime;
  129. struct lpass_pcm_data *pcm_data = rt->private_data;
  130. struct lpass_variant *v = drvdata->variant;
  131. snd_pcm_format_t format = params_format(params);
  132. unsigned int channels = params_channels(params);
  133. unsigned int regval;
  134. int ch, dir = substream->stream;
  135. int bitwidth;
  136. int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
  137. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  138. ch = pcm_data->rdma_ch;
  139. else
  140. ch = pcm_data->wrdma_ch;
  141. bitwidth = snd_pcm_format_width(format);
  142. if (bitwidth < 0) {
  143. dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n",
  144. __func__, bitwidth);
  145. return bitwidth;
  146. }
  147. regval = LPAIF_DMACTL_BURSTEN_INCR4 |
  148. LPAIF_DMACTL_AUDINTF(dma_port) |
  149. LPAIF_DMACTL_FIFOWM_8;
  150. switch (bitwidth) {
  151. case 16:
  152. switch (channels) {
  153. case 1:
  154. case 2:
  155. regval |= LPAIF_DMACTL_WPSCNT_ONE;
  156. break;
  157. case 4:
  158. regval |= LPAIF_DMACTL_WPSCNT_TWO;
  159. break;
  160. case 6:
  161. regval |= LPAIF_DMACTL_WPSCNT_THREE;
  162. break;
  163. case 8:
  164. regval |= LPAIF_DMACTL_WPSCNT_FOUR;
  165. break;
  166. default:
  167. dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
  168. __func__, bitwidth, channels);
  169. return -EINVAL;
  170. }
  171. break;
  172. case 24:
  173. case 32:
  174. switch (channels) {
  175. case 1:
  176. regval |= LPAIF_DMACTL_WPSCNT_ONE;
  177. break;
  178. case 2:
  179. regval |= LPAIF_DMACTL_WPSCNT_TWO;
  180. break;
  181. case 4:
  182. regval |= LPAIF_DMACTL_WPSCNT_FOUR;
  183. break;
  184. case 6:
  185. regval |= LPAIF_DMACTL_WPSCNT_SIX;
  186. break;
  187. case 8:
  188. regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
  189. break;
  190. default:
  191. dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
  192. __func__, bitwidth, channels);
  193. return -EINVAL;
  194. }
  195. break;
  196. default:
  197. dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
  198. __func__, bitwidth, channels);
  199. return -EINVAL;
  200. }
  201. ret = regmap_write(drvdata->lpaif_map,
  202. LPAIF_DMACTL_REG(v, ch, dir), regval);
  203. if (ret) {
  204. dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
  205. __func__, ret);
  206. return ret;
  207. }
  208. return 0;
  209. }
  210. static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
  211. {
  212. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  213. struct lpass_data *drvdata =
  214. snd_soc_platform_get_drvdata(soc_runtime->platform);
  215. struct snd_pcm_runtime *rt = substream->runtime;
  216. struct lpass_pcm_data *pcm_data = rt->private_data;
  217. struct lpass_variant *v = drvdata->variant;
  218. unsigned int reg;
  219. int ret;
  220. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  221. reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch);
  222. else
  223. reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch);
  224. ret = regmap_write(drvdata->lpaif_map, reg, 0);
  225. if (ret)
  226. dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
  227. __func__, ret);
  228. return ret;
  229. }
  230. static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
  231. {
  232. struct snd_pcm_runtime *runtime = substream->runtime;
  233. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  234. struct lpass_data *drvdata =
  235. snd_soc_platform_get_drvdata(soc_runtime->platform);
  236. struct snd_pcm_runtime *rt = substream->runtime;
  237. struct lpass_pcm_data *pcm_data = rt->private_data;
  238. struct lpass_variant *v = drvdata->variant;
  239. int ret, ch, dir = substream->stream;
  240. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  241. ch = pcm_data->rdma_ch;
  242. else
  243. ch = pcm_data->wrdma_ch;
  244. ret = regmap_write(drvdata->lpaif_map,
  245. LPAIF_DMABASE_REG(v, ch, dir),
  246. runtime->dma_addr);
  247. if (ret) {
  248. dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
  249. __func__, ret);
  250. return ret;
  251. }
  252. ret = regmap_write(drvdata->lpaif_map,
  253. LPAIF_DMABUFF_REG(v, ch, dir),
  254. (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
  255. if (ret) {
  256. dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
  257. __func__, ret);
  258. return ret;
  259. }
  260. ret = regmap_write(drvdata->lpaif_map,
  261. LPAIF_DMAPER_REG(v, ch, dir),
  262. (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
  263. if (ret) {
  264. dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
  265. __func__, ret);
  266. return ret;
  267. }
  268. ret = regmap_update_bits(drvdata->lpaif_map,
  269. LPAIF_DMACTL_REG(v, ch, dir),
  270. LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
  271. if (ret) {
  272. dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
  273. __func__, ret);
  274. return ret;
  275. }
  276. return 0;
  277. }
  278. static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
  279. int cmd)
  280. {
  281. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  282. struct lpass_data *drvdata =
  283. snd_soc_platform_get_drvdata(soc_runtime->platform);
  284. struct snd_pcm_runtime *rt = substream->runtime;
  285. struct lpass_pcm_data *pcm_data = rt->private_data;
  286. struct lpass_variant *v = drvdata->variant;
  287. int ret, ch, dir = substream->stream;
  288. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  289. ch = pcm_data->rdma_ch;
  290. else
  291. ch = pcm_data->wrdma_ch;
  292. switch (cmd) {
  293. case SNDRV_PCM_TRIGGER_START:
  294. case SNDRV_PCM_TRIGGER_RESUME:
  295. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  296. /* clear status before enabling interrupts */
  297. ret = regmap_write(drvdata->lpaif_map,
  298. LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
  299. LPAIF_IRQ_ALL(ch));
  300. if (ret) {
  301. dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
  302. __func__, ret);
  303. return ret;
  304. }
  305. ret = regmap_update_bits(drvdata->lpaif_map,
  306. LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
  307. LPAIF_IRQ_ALL(ch),
  308. LPAIF_IRQ_ALL(ch));
  309. if (ret) {
  310. dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
  311. __func__, ret);
  312. return ret;
  313. }
  314. ret = regmap_update_bits(drvdata->lpaif_map,
  315. LPAIF_DMACTL_REG(v, ch, dir),
  316. LPAIF_DMACTL_ENABLE_MASK,
  317. LPAIF_DMACTL_ENABLE_ON);
  318. if (ret) {
  319. dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
  320. __func__, ret);
  321. return ret;
  322. }
  323. break;
  324. case SNDRV_PCM_TRIGGER_STOP:
  325. case SNDRV_PCM_TRIGGER_SUSPEND:
  326. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  327. ret = regmap_update_bits(drvdata->lpaif_map,
  328. LPAIF_DMACTL_REG(v, ch, dir),
  329. LPAIF_DMACTL_ENABLE_MASK,
  330. LPAIF_DMACTL_ENABLE_OFF);
  331. if (ret) {
  332. dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
  333. __func__, ret);
  334. return ret;
  335. }
  336. ret = regmap_update_bits(drvdata->lpaif_map,
  337. LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
  338. LPAIF_IRQ_ALL(ch), 0);
  339. if (ret) {
  340. dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
  341. __func__, ret);
  342. return ret;
  343. }
  344. break;
  345. }
  346. return 0;
  347. }
  348. static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
  349. struct snd_pcm_substream *substream)
  350. {
  351. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  352. struct lpass_data *drvdata =
  353. snd_soc_platform_get_drvdata(soc_runtime->platform);
  354. struct snd_pcm_runtime *rt = substream->runtime;
  355. struct lpass_pcm_data *pcm_data = rt->private_data;
  356. struct lpass_variant *v = drvdata->variant;
  357. unsigned int base_addr, curr_addr;
  358. int ret, ch, dir = substream->stream;
  359. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  360. ch = pcm_data->rdma_ch;
  361. else
  362. ch = pcm_data->wrdma_ch;
  363. ret = regmap_read(drvdata->lpaif_map,
  364. LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
  365. if (ret) {
  366. dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
  367. __func__, ret);
  368. return ret;
  369. }
  370. ret = regmap_read(drvdata->lpaif_map,
  371. LPAIF_DMACURR_REG(v, ch, dir), &curr_addr);
  372. if (ret) {
  373. dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
  374. __func__, ret);
  375. return ret;
  376. }
  377. return bytes_to_frames(substream->runtime, curr_addr - base_addr);
  378. }
  379. static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
  380. struct vm_area_struct *vma)
  381. {
  382. struct snd_pcm_runtime *runtime = substream->runtime;
  383. return dma_mmap_coherent(substream->pcm->card->dev, vma,
  384. runtime->dma_area, runtime->dma_addr,
  385. runtime->dma_bytes);
  386. }
  387. static const struct snd_pcm_ops lpass_platform_pcm_ops = {
  388. .open = lpass_platform_pcmops_open,
  389. .close = lpass_platform_pcmops_close,
  390. .ioctl = snd_pcm_lib_ioctl,
  391. .hw_params = lpass_platform_pcmops_hw_params,
  392. .hw_free = lpass_platform_pcmops_hw_free,
  393. .prepare = lpass_platform_pcmops_prepare,
  394. .trigger = lpass_platform_pcmops_trigger,
  395. .pointer = lpass_platform_pcmops_pointer,
  396. .mmap = lpass_platform_pcmops_mmap,
  397. };
  398. static irqreturn_t lpass_dma_interrupt_handler(
  399. struct snd_pcm_substream *substream,
  400. struct lpass_data *drvdata,
  401. int chan, u32 interrupts)
  402. {
  403. struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  404. struct lpass_variant *v = drvdata->variant;
  405. irqreturn_t ret = IRQ_NONE;
  406. int rv;
  407. if (interrupts & LPAIF_IRQ_PER(chan)) {
  408. rv = regmap_write(drvdata->lpaif_map,
  409. LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
  410. LPAIF_IRQ_PER(chan));
  411. if (rv) {
  412. dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
  413. __func__, rv);
  414. return IRQ_NONE;
  415. }
  416. snd_pcm_period_elapsed(substream);
  417. ret = IRQ_HANDLED;
  418. }
  419. if (interrupts & LPAIF_IRQ_XRUN(chan)) {
  420. rv = regmap_write(drvdata->lpaif_map,
  421. LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
  422. LPAIF_IRQ_XRUN(chan));
  423. if (rv) {
  424. dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
  425. __func__, rv);
  426. return IRQ_NONE;
  427. }
  428. dev_warn(soc_runtime->dev, "%s() xrun warning\n", __func__);
  429. snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
  430. ret = IRQ_HANDLED;
  431. }
  432. if (interrupts & LPAIF_IRQ_ERR(chan)) {
  433. rv = regmap_write(drvdata->lpaif_map,
  434. LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
  435. LPAIF_IRQ_ERR(chan));
  436. if (rv) {
  437. dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
  438. __func__, rv);
  439. return IRQ_NONE;
  440. }
  441. dev_err(soc_runtime->dev, "%s() bus access error\n", __func__);
  442. snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
  443. ret = IRQ_HANDLED;
  444. }
  445. return ret;
  446. }
  447. static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
  448. {
  449. struct lpass_data *drvdata = data;
  450. struct lpass_variant *v = drvdata->variant;
  451. unsigned int irqs;
  452. int rv, chan;
  453. rv = regmap_read(drvdata->lpaif_map,
  454. LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
  455. if (rv) {
  456. pr_err("%s() error reading from irqstat reg: %d\n",
  457. __func__, rv);
  458. return IRQ_NONE;
  459. }
  460. /* Handle per channel interrupts */
  461. for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
  462. if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
  463. rv = lpass_dma_interrupt_handler(
  464. drvdata->substream[chan],
  465. drvdata, chan, irqs);
  466. if (rv != IRQ_HANDLED)
  467. return rv;
  468. }
  469. }
  470. return IRQ_HANDLED;
  471. }
  472. static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
  473. {
  474. struct snd_pcm *pcm = soc_runtime->pcm;
  475. struct snd_pcm_substream *psubstream, *csubstream;
  476. int ret = -EINVAL;
  477. size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
  478. psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
  479. if (psubstream) {
  480. ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
  481. soc_runtime->platform->dev,
  482. size, &psubstream->dma_buffer);
  483. if (ret) {
  484. dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
  485. return ret;
  486. }
  487. }
  488. csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
  489. if (csubstream) {
  490. ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
  491. soc_runtime->platform->dev,
  492. size, &csubstream->dma_buffer);
  493. if (ret) {
  494. dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
  495. if (psubstream)
  496. snd_dma_free_pages(&psubstream->dma_buffer);
  497. return ret;
  498. }
  499. }
  500. return 0;
  501. }
  502. static void lpass_platform_pcm_free(struct snd_pcm *pcm)
  503. {
  504. struct snd_pcm_substream *substream;
  505. int i;
  506. for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
  507. substream = pcm->streams[i].substream;
  508. if (substream) {
  509. snd_dma_free_pages(&substream->dma_buffer);
  510. substream->dma_buffer.area = NULL;
  511. substream->dma_buffer.addr = 0;
  512. }
  513. }
  514. }
  515. static struct snd_soc_platform_driver lpass_platform_driver = {
  516. .pcm_new = lpass_platform_pcm_new,
  517. .pcm_free = lpass_platform_pcm_free,
  518. .ops = &lpass_platform_pcm_ops,
  519. };
  520. int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
  521. {
  522. struct lpass_data *drvdata = platform_get_drvdata(pdev);
  523. struct lpass_variant *v = drvdata->variant;
  524. int ret;
  525. drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
  526. if (drvdata->lpaif_irq < 0) {
  527. dev_err(&pdev->dev, "%s() error getting irq handle: %d\n",
  528. __func__, drvdata->lpaif_irq);
  529. return -ENODEV;
  530. }
  531. /* ensure audio hardware is disabled */
  532. ret = regmap_write(drvdata->lpaif_map,
  533. LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
  534. if (ret) {
  535. dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
  536. __func__, ret);
  537. return ret;
  538. }
  539. ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
  540. lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
  541. "lpass-irq-lpaif", drvdata);
  542. if (ret) {
  543. dev_err(&pdev->dev, "%s() irq request failed: %d\n",
  544. __func__, ret);
  545. return ret;
  546. }
  547. return devm_snd_soc_register_platform(&pdev->dev,
  548. &lpass_platform_driver);
  549. }
  550. EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
  551. MODULE_DESCRIPTION("QTi LPASS Platform Driver");
  552. MODULE_LICENSE("GPL v2");