root/sound/soc/qcom/lpass-platform.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lpass_platform_pcmops_open
  2. lpass_platform_pcmops_close
  3. lpass_platform_pcmops_hw_params
  4. lpass_platform_pcmops_hw_free
  5. lpass_platform_pcmops_prepare
  6. lpass_platform_pcmops_trigger
  7. lpass_platform_pcmops_pointer
  8. lpass_platform_pcmops_mmap
  9. lpass_dma_interrupt_handler
  10. lpass_platform_lpaif_irq
  11. lpass_platform_pcm_new
  12. lpass_platform_pcm_free
  13. asoc_qcom_lpass_platform_register

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

/* [<][>][^][v][top][bottom][index][help] */