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_soc_component *component, 54 struct snd_pcm_substream *substream) 55 { 56 struct snd_pcm_runtime *runtime = substream->runtime; 57 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 58 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 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_soc_component *component, 109 struct snd_pcm_substream *substream) 110 { 111 struct snd_pcm_runtime *runtime = substream->runtime; 112 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 113 struct lpass_variant *v = drvdata->variant; 114 struct lpass_pcm_data *data; 115 116 data = runtime->private_data; 117 drvdata->substream[data->dma_ch] = NULL; 118 if (v->free_dma_channel) 119 v->free_dma_channel(drvdata, data->dma_ch); 120 121 return 0; 122 } 123 124 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, 125 struct snd_pcm_substream *substream, 126 struct snd_pcm_hw_params *params) 127 { 128 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 129 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 130 struct snd_pcm_runtime *rt = substream->runtime; 131 struct lpass_pcm_data *pcm_data = rt->private_data; 132 struct lpass_variant *v = drvdata->variant; 133 snd_pcm_format_t format = params_format(params); 134 unsigned int channels = params_channels(params); 135 unsigned int regval; 136 int ch, dir = substream->stream; 137 int bitwidth; 138 int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; 139 140 ch = pcm_data->dma_ch; 141 142 bitwidth = snd_pcm_format_width(format); 143 if (bitwidth < 0) { 144 dev_err(soc_runtime->dev, "invalid bit width given: %d\n", 145 bitwidth); 146 return bitwidth; 147 } 148 149 regval = LPAIF_DMACTL_BURSTEN_INCR4 | 150 LPAIF_DMACTL_AUDINTF(dma_port) | 151 LPAIF_DMACTL_FIFOWM_8; 152 153 switch (bitwidth) { 154 case 16: 155 switch (channels) { 156 case 1: 157 case 2: 158 regval |= LPAIF_DMACTL_WPSCNT_ONE; 159 break; 160 case 4: 161 regval |= LPAIF_DMACTL_WPSCNT_TWO; 162 break; 163 case 6: 164 regval |= LPAIF_DMACTL_WPSCNT_THREE; 165 break; 166 case 8: 167 regval |= LPAIF_DMACTL_WPSCNT_FOUR; 168 break; 169 default: 170 dev_err(soc_runtime->dev, 171 "invalid PCM config given: bw=%d, ch=%u\n", 172 bitwidth, channels); 173 return -EINVAL; 174 } 175 break; 176 case 24: 177 case 32: 178 switch (channels) { 179 case 1: 180 regval |= LPAIF_DMACTL_WPSCNT_ONE; 181 break; 182 case 2: 183 regval |= LPAIF_DMACTL_WPSCNT_TWO; 184 break; 185 case 4: 186 regval |= LPAIF_DMACTL_WPSCNT_FOUR; 187 break; 188 case 6: 189 regval |= LPAIF_DMACTL_WPSCNT_SIX; 190 break; 191 case 8: 192 regval |= LPAIF_DMACTL_WPSCNT_EIGHT; 193 break; 194 default: 195 dev_err(soc_runtime->dev, 196 "invalid PCM config given: bw=%d, ch=%u\n", 197 bitwidth, channels); 198 return -EINVAL; 199 } 200 break; 201 default: 202 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", 203 bitwidth, channels); 204 return -EINVAL; 205 } 206 207 ret = regmap_write(drvdata->lpaif_map, 208 LPAIF_DMACTL_REG(v, ch, dir), regval); 209 if (ret) { 210 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", 211 ret); 212 return ret; 213 } 214 215 return 0; 216 } 217 218 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component, 219 struct snd_pcm_substream *substream) 220 { 221 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 222 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 223 struct snd_pcm_runtime *rt = substream->runtime; 224 struct lpass_pcm_data *pcm_data = rt->private_data; 225 struct lpass_variant *v = drvdata->variant; 226 unsigned int reg; 227 int ret; 228 229 reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream); 230 ret = regmap_write(drvdata->lpaif_map, reg, 0); 231 if (ret) 232 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", 233 ret); 234 235 return ret; 236 } 237 238 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, 239 struct snd_pcm_substream *substream) 240 { 241 struct snd_pcm_runtime *runtime = substream->runtime; 242 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 243 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 244 struct snd_pcm_runtime *rt = substream->runtime; 245 struct lpass_pcm_data *pcm_data = rt->private_data; 246 struct lpass_variant *v = drvdata->variant; 247 int ret, ch, dir = substream->stream; 248 249 ch = pcm_data->dma_ch; 250 251 ret = regmap_write(drvdata->lpaif_map, 252 LPAIF_DMABASE_REG(v, ch, dir), 253 runtime->dma_addr); 254 if (ret) { 255 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n", 256 ret); 257 return ret; 258 } 259 260 ret = regmap_write(drvdata->lpaif_map, 261 LPAIF_DMABUFF_REG(v, ch, dir), 262 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); 263 if (ret) { 264 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n", 265 ret); 266 return ret; 267 } 268 269 ret = regmap_write(drvdata->lpaif_map, 270 LPAIF_DMAPER_REG(v, ch, dir), 271 (snd_pcm_lib_period_bytes(substream) >> 2) - 1); 272 if (ret) { 273 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n", 274 ret); 275 return ret; 276 } 277 278 ret = regmap_update_bits(drvdata->lpaif_map, 279 LPAIF_DMACTL_REG(v, ch, dir), 280 LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON); 281 if (ret) { 282 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", 283 ret); 284 return ret; 285 } 286 287 return 0; 288 } 289 290 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, 291 struct snd_pcm_substream *substream, 292 int cmd) 293 { 294 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 295 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 296 struct snd_pcm_runtime *rt = substream->runtime; 297 struct lpass_pcm_data *pcm_data = rt->private_data; 298 struct lpass_variant *v = drvdata->variant; 299 int ret, ch, dir = substream->stream; 300 301 ch = pcm_data->dma_ch; 302 303 switch (cmd) { 304 case SNDRV_PCM_TRIGGER_START: 305 case SNDRV_PCM_TRIGGER_RESUME: 306 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 307 /* clear status before enabling interrupts */ 308 ret = regmap_write(drvdata->lpaif_map, 309 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), 310 LPAIF_IRQ_ALL(ch)); 311 if (ret) { 312 dev_err(soc_runtime->dev, 313 "error writing to irqclear reg: %d\n", ret); 314 return ret; 315 } 316 317 ret = regmap_update_bits(drvdata->lpaif_map, 318 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 319 LPAIF_IRQ_ALL(ch), 320 LPAIF_IRQ_ALL(ch)); 321 if (ret) { 322 dev_err(soc_runtime->dev, 323 "error writing to irqen reg: %d\n", ret); 324 return ret; 325 } 326 327 ret = regmap_update_bits(drvdata->lpaif_map, 328 LPAIF_DMACTL_REG(v, ch, dir), 329 LPAIF_DMACTL_ENABLE_MASK, 330 LPAIF_DMACTL_ENABLE_ON); 331 if (ret) { 332 dev_err(soc_runtime->dev, 333 "error writing to rdmactl reg: %d\n", ret); 334 return ret; 335 } 336 break; 337 case SNDRV_PCM_TRIGGER_STOP: 338 case SNDRV_PCM_TRIGGER_SUSPEND: 339 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 340 ret = regmap_update_bits(drvdata->lpaif_map, 341 LPAIF_DMACTL_REG(v, ch, dir), 342 LPAIF_DMACTL_ENABLE_MASK, 343 LPAIF_DMACTL_ENABLE_OFF); 344 if (ret) { 345 dev_err(soc_runtime->dev, 346 "error writing to rdmactl reg: %d\n", ret); 347 return ret; 348 } 349 350 ret = regmap_update_bits(drvdata->lpaif_map, 351 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 352 LPAIF_IRQ_ALL(ch), 0); 353 if (ret) { 354 dev_err(soc_runtime->dev, 355 "error writing to irqen reg: %d\n", ret); 356 return ret; 357 } 358 break; 359 } 360 361 return 0; 362 } 363 364 static snd_pcm_uframes_t lpass_platform_pcmops_pointer( 365 struct snd_soc_component *component, 366 struct snd_pcm_substream *substream) 367 { 368 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 369 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 370 struct snd_pcm_runtime *rt = substream->runtime; 371 struct lpass_pcm_data *pcm_data = rt->private_data; 372 struct lpass_variant *v = drvdata->variant; 373 unsigned int base_addr, curr_addr; 374 int ret, ch, dir = substream->stream; 375 376 ch = pcm_data->dma_ch; 377 378 ret = regmap_read(drvdata->lpaif_map, 379 LPAIF_DMABASE_REG(v, ch, dir), &base_addr); 380 if (ret) { 381 dev_err(soc_runtime->dev, 382 "error reading from rdmabase reg: %d\n", ret); 383 return ret; 384 } 385 386 ret = regmap_read(drvdata->lpaif_map, 387 LPAIF_DMACURR_REG(v, ch, dir), &curr_addr); 388 if (ret) { 389 dev_err(soc_runtime->dev, 390 "error reading from rdmacurr reg: %d\n", ret); 391 return ret; 392 } 393 394 return bytes_to_frames(substream->runtime, curr_addr - base_addr); 395 } 396 397 static int lpass_platform_pcmops_mmap(struct snd_soc_component *component, 398 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 irqreturn_t lpass_dma_interrupt_handler( 409 struct snd_pcm_substream *substream, 410 struct lpass_data *drvdata, 411 int chan, u32 interrupts) 412 { 413 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 414 struct lpass_variant *v = drvdata->variant; 415 irqreturn_t ret = IRQ_NONE; 416 int rv; 417 418 if (interrupts & LPAIF_IRQ_PER(chan)) { 419 rv = regmap_write(drvdata->lpaif_map, 420 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), 421 LPAIF_IRQ_PER(chan)); 422 if (rv) { 423 dev_err(soc_runtime->dev, 424 "error writing to irqclear reg: %d\n", rv); 425 return IRQ_NONE; 426 } 427 snd_pcm_period_elapsed(substream); 428 ret = IRQ_HANDLED; 429 } 430 431 if (interrupts & LPAIF_IRQ_XRUN(chan)) { 432 rv = regmap_write(drvdata->lpaif_map, 433 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), 434 LPAIF_IRQ_XRUN(chan)); 435 if (rv) { 436 dev_err(soc_runtime->dev, 437 "error writing to irqclear reg: %d\n", rv); 438 return IRQ_NONE; 439 } 440 dev_warn(soc_runtime->dev, "xrun warning\n"); 441 snd_pcm_stop_xrun(substream); 442 ret = IRQ_HANDLED; 443 } 444 445 if (interrupts & LPAIF_IRQ_ERR(chan)) { 446 rv = regmap_write(drvdata->lpaif_map, 447 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), 448 LPAIF_IRQ_ERR(chan)); 449 if (rv) { 450 dev_err(soc_runtime->dev, 451 "error writing to irqclear reg: %d\n", rv); 452 return IRQ_NONE; 453 } 454 dev_err(soc_runtime->dev, "bus access error\n"); 455 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); 456 ret = IRQ_HANDLED; 457 } 458 459 return ret; 460 } 461 462 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) 463 { 464 struct lpass_data *drvdata = data; 465 struct lpass_variant *v = drvdata->variant; 466 unsigned int irqs; 467 int rv, chan; 468 469 rv = regmap_read(drvdata->lpaif_map, 470 LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs); 471 if (rv) { 472 pr_err("error reading from irqstat reg: %d\n", rv); 473 return IRQ_NONE; 474 } 475 476 /* Handle per channel interrupts */ 477 for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) { 478 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) { 479 rv = lpass_dma_interrupt_handler( 480 drvdata->substream[chan], 481 drvdata, chan, irqs); 482 if (rv != IRQ_HANDLED) 483 return rv; 484 } 485 } 486 487 return IRQ_HANDLED; 488 } 489 490 static int lpass_platform_pcm_new(struct snd_soc_component *component, 491 struct snd_soc_pcm_runtime *soc_runtime) 492 { 493 struct snd_pcm *pcm = soc_runtime->pcm; 494 struct snd_pcm_substream *psubstream, *csubstream; 495 int ret = -EINVAL; 496 size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; 497 498 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 499 if (psubstream) { 500 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 501 component->dev, 502 size, &psubstream->dma_buffer); 503 if (ret) { 504 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); 505 return ret; 506 } 507 } 508 509 csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 510 if (csubstream) { 511 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 512 component->dev, 513 size, &csubstream->dma_buffer); 514 if (ret) { 515 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); 516 if (psubstream) 517 snd_dma_free_pages(&psubstream->dma_buffer); 518 return ret; 519 } 520 521 } 522 523 return 0; 524 } 525 526 static void lpass_platform_pcm_free(struct snd_soc_component *component, 527 struct snd_pcm *pcm) 528 { 529 struct snd_pcm_substream *substream; 530 int i; 531 532 for_each_pcm_streams(i) { 533 substream = pcm->streams[i].substream; 534 if (substream) { 535 snd_dma_free_pages(&substream->dma_buffer); 536 substream->dma_buffer.area = NULL; 537 substream->dma_buffer.addr = 0; 538 } 539 } 540 } 541 542 static const struct snd_soc_component_driver lpass_component_driver = { 543 .name = DRV_NAME, 544 .open = lpass_platform_pcmops_open, 545 .close = lpass_platform_pcmops_close, 546 .hw_params = lpass_platform_pcmops_hw_params, 547 .hw_free = lpass_platform_pcmops_hw_free, 548 .prepare = lpass_platform_pcmops_prepare, 549 .trigger = lpass_platform_pcmops_trigger, 550 .pointer = lpass_platform_pcmops_pointer, 551 .mmap = lpass_platform_pcmops_mmap, 552 .pcm_construct = lpass_platform_pcm_new, 553 .pcm_destruct = lpass_platform_pcm_free, 554 555 }; 556 557 int asoc_qcom_lpass_platform_register(struct platform_device *pdev) 558 { 559 struct lpass_data *drvdata = platform_get_drvdata(pdev); 560 struct lpass_variant *v = drvdata->variant; 561 int ret; 562 563 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); 564 if (drvdata->lpaif_irq < 0) 565 return -ENODEV; 566 567 /* ensure audio hardware is disabled */ 568 ret = regmap_write(drvdata->lpaif_map, 569 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0); 570 if (ret) { 571 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret); 572 return ret; 573 } 574 575 ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq, 576 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING, 577 "lpass-irq-lpaif", drvdata); 578 if (ret) { 579 dev_err(&pdev->dev, "irq request failed: %d\n", ret); 580 return ret; 581 } 582 583 584 return devm_snd_soc_register_component(&pdev->dev, 585 &lpass_component_driver, NULL, 0); 586 } 587 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); 588 589 MODULE_DESCRIPTION("QTi LPASS Platform Driver"); 590 MODULE_LICENSE("GPL v2"); 591