~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/qcom/lpass-platform.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp