linux/sound/soc/qcom/lpass-platform.c
<<
>>
Prefs
   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
  21struct 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
  29static 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
  53static 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
 108static 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
 125static 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
 219static 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
 239static 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
 291static 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
 365static 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
 398static 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
 408static 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
 420static 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
 474static 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
 502static 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
 538static 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
 553static 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
 560int 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                dev_err(&pdev->dev, "error getting irq handle: %d\n",
 569                        drvdata->lpaif_irq);
 570                return -ENODEV;
 571        }
 572
 573        /* ensure audio hardware is disabled */
 574        ret = regmap_write(drvdata->lpaif_map,
 575                        LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 576        if (ret) {
 577                dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
 578                return ret;
 579        }
 580
 581        ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
 582                        lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
 583                        "lpass-irq-lpaif", drvdata);
 584        if (ret) {
 585                dev_err(&pdev->dev, "irq request failed: %d\n", ret);
 586                return ret;
 587        }
 588
 589
 590        return devm_snd_soc_register_component(&pdev->dev,
 591                        &lpass_component_driver, NULL, 0);
 592}
 593EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
 594
 595MODULE_DESCRIPTION("QTi LPASS Platform Driver");
 596MODULE_LICENSE("GPL v2");
 597