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