linux/sound/soc/qcom/lpass-platform.c
<<
>>
Prefs
   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
  27struct lpass_pcm_data {
  28        int dma_ch;
  29        int i2s_port;
  30};
  31
  32#define LPASS_PLATFORM_BUFFER_SIZE      (16 * 1024)
  33#define LPASS_PLATFORM_PERIODS          2
  34
  35static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
  36        .info                   =       SNDRV_PCM_INFO_MMAP |
  37                                        SNDRV_PCM_INFO_MMAP_VALID |
  38                                        SNDRV_PCM_INFO_INTERLEAVED |
  39                                        SNDRV_PCM_INFO_PAUSE |
  40                                        SNDRV_PCM_INFO_RESUME,
  41        .formats                =       SNDRV_PCM_FMTBIT_S16 |
  42                                        SNDRV_PCM_FMTBIT_S24 |
  43                                        SNDRV_PCM_FMTBIT_S32,
  44        .rates                  =       SNDRV_PCM_RATE_8000_192000,
  45        .rate_min               =       8000,
  46        .rate_max               =       192000,
  47        .channels_min           =       1,
  48        .channels_max           =       8,
  49        .buffer_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE,
  50        .period_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE /
  51                                                LPASS_PLATFORM_PERIODS,
  52        .period_bytes_min       =       LPASS_PLATFORM_BUFFER_SIZE /
  53                                                LPASS_PLATFORM_PERIODS,
  54        .periods_min            =       LPASS_PLATFORM_PERIODS,
  55        .periods_max            =       LPASS_PLATFORM_PERIODS,
  56        .fifo_size              =       0,
  57};
  58
  59static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
  60{
  61        struct snd_pcm_runtime *runtime = substream->runtime;
  62        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
  63        struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
  64        struct lpass_data *drvdata =
  65                snd_soc_platform_get_drvdata(soc_runtime->platform);
  66        struct lpass_variant *v = drvdata->variant;
  67        int ret, dma_ch, dir = substream->stream;
  68        struct lpass_pcm_data *data;
  69
  70        data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
  71        if (!data)
  72                return -ENOMEM;
  73
  74        data->i2s_port = cpu_dai->driver->id;
  75        runtime->private_data = data;
  76
  77        dma_ch = 0;
  78        if (v->alloc_dma_channel)
  79                dma_ch = v->alloc_dma_channel(drvdata, dir);
  80        else
  81                dma_ch = 0;
  82
  83        if (dma_ch < 0)
  84                return dma_ch;
  85
  86        drvdata->substream[dma_ch] = substream;
  87
  88        ret = regmap_write(drvdata->lpaif_map,
  89                        LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
  90        if (ret) {
  91                dev_err(soc_runtime->dev,
  92                        "error writing to rdmactl reg: %d\n", ret);
  93                        return ret;
  94        }
  95
  96        data->dma_ch = dma_ch;
  97
  98        snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
  99
 100        runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
 101
 102        ret = snd_pcm_hw_constraint_integer(runtime,
 103                        SNDRV_PCM_HW_PARAM_PERIODS);
 104        if (ret < 0) {
 105                dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
 106                        ret);
 107                return -EINVAL;
 108        }
 109
 110        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 111
 112        return 0;
 113}
 114
 115static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
 116{
 117        struct snd_pcm_runtime *runtime = substream->runtime;
 118        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 119        struct lpass_data *drvdata =
 120                snd_soc_platform_get_drvdata(soc_runtime->platform);
 121        struct lpass_variant *v = drvdata->variant;
 122        struct lpass_pcm_data *data;
 123
 124        data = runtime->private_data;
 125        v = drvdata->variant;
 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
 133static 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 lpass_data *drvdata =
 138                snd_soc_platform_get_drvdata(soc_runtime->platform);
 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
 227static 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 lpass_data *drvdata =
 231                snd_soc_platform_get_drvdata(soc_runtime->platform);
 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
 247static 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 lpass_data *drvdata =
 252                snd_soc_platform_get_drvdata(soc_runtime->platform);
 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
 299static 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 lpass_data *drvdata =
 304                snd_soc_platform_get_drvdata(soc_runtime->platform);
 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
 373static 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 lpass_data *drvdata =
 378                        snd_soc_platform_get_drvdata(soc_runtime->platform);
 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
 406static 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
 416static 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
 428static 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
 482static 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
 510static 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        int ret = -EINVAL;
 515        size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 516
 517        psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 518        if (psubstream) {
 519                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
 520                                        soc_runtime->platform->dev,
 521                                        size, &psubstream->dma_buffer);
 522                if (ret) {
 523                        dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 524                        return ret;
 525                }
 526        }
 527
 528        csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 529        if (csubstream) {
 530                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
 531                                        soc_runtime->platform->dev,
 532                                        size, &csubstream->dma_buffer);
 533                if (ret) {
 534                        dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 535                        if (psubstream)
 536                                snd_dma_free_pages(&psubstream->dma_buffer);
 537                        return ret;
 538                }
 539
 540        }
 541
 542        return 0;
 543}
 544
 545static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 546{
 547        struct snd_pcm_substream *substream;
 548        int i;
 549
 550        for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
 551                substream = pcm->streams[i].substream;
 552                if (substream) {
 553                        snd_dma_free_pages(&substream->dma_buffer);
 554                        substream->dma_buffer.area = NULL;
 555                        substream->dma_buffer.addr = 0;
 556                }
 557        }
 558}
 559
 560static const struct snd_soc_platform_driver lpass_platform_driver = {
 561        .pcm_new        = lpass_platform_pcm_new,
 562        .pcm_free       = lpass_platform_pcm_free,
 563        .ops            = &lpass_platform_pcm_ops,
 564};
 565
 566int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 567{
 568        struct lpass_data *drvdata = platform_get_drvdata(pdev);
 569        struct lpass_variant *v = drvdata->variant;
 570        int ret;
 571
 572        drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
 573        if (drvdata->lpaif_irq < 0) {
 574                dev_err(&pdev->dev, "error getting irq handle: %d\n",
 575                        drvdata->lpaif_irq);
 576                return -ENODEV;
 577        }
 578
 579        /* ensure audio hardware is disabled */
 580        ret = regmap_write(drvdata->lpaif_map,
 581                        LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 582        if (ret) {
 583                dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
 584                return ret;
 585        }
 586
 587        ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
 588                        lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
 589                        "lpass-irq-lpaif", drvdata);
 590        if (ret) {
 591                dev_err(&pdev->dev, "irq request failed: %d\n", ret);
 592                return ret;
 593        }
 594
 595
 596        return devm_snd_soc_register_platform(&pdev->dev,
 597                        &lpass_platform_driver);
 598}
 599EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
 600
 601MODULE_DESCRIPTION("QTi LPASS Platform Driver");
 602MODULE_LICENSE("GPL v2");
 603