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 (24 * 2 * 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_alloc_dmactl_fields(struct device *dev, 54 struct regmap *map) 55 { 56 struct lpass_data *drvdata = dev_get_drvdata(dev); 57 struct lpass_variant *v = drvdata->variant; 58 struct lpaif_dmactl *rd_dmactl, *wr_dmactl; 59 int rval; 60 61 drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), 62 GFP_KERNEL); 63 if (drvdata->rd_dmactl == NULL) 64 return -ENOMEM; 65 66 drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), 67 GFP_KERNEL); 68 if (drvdata->wr_dmactl == NULL) 69 return -ENOMEM; 70 71 rd_dmactl = drvdata->rd_dmactl; 72 wr_dmactl = drvdata->wr_dmactl; 73 74 rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf, 75 &v->rdma_intf, 6); 76 if (rval) 77 return rval; 78 79 return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf, 80 &v->wrdma_intf, 6); 81 } 82 83 static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev, 84 struct regmap *map) 85 { 86 struct lpass_data *drvdata = dev_get_drvdata(dev); 87 struct lpass_variant *v = drvdata->variant; 88 struct lpaif_dmactl *rd_dmactl; 89 90 rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL); 91 if (rd_dmactl == NULL) 92 return -ENOMEM; 93 94 drvdata->hdmi_rd_dmactl = rd_dmactl; 95 96 return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten, 97 &v->hdmi_rdma_bursten, 8); 98 } 99 100 static int lpass_platform_pcmops_open(struct snd_soc_component *component, 101 struct snd_pcm_substream *substream) 102 { 103 struct snd_pcm_runtime *runtime = substream->runtime; 104 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 105 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 106 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 107 struct lpass_variant *v = drvdata->variant; 108 int ret, dma_ch, dir = substream->stream; 109 struct lpass_pcm_data *data; 110 struct regmap *map; 111 unsigned int dai_id = cpu_dai->driver->id; 112 113 component->id = dai_id; 114 data = kzalloc(sizeof(*data), GFP_KERNEL); 115 if (!data) 116 return -ENOMEM; 117 118 data->i2s_port = cpu_dai->driver->id; 119 runtime->private_data = data; 120 121 if (v->alloc_dma_channel) 122 dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id); 123 else 124 dma_ch = 0; 125 126 if (dma_ch < 0) { 127 kfree(data); 128 return dma_ch; 129 } 130 131 if (cpu_dai->driver->id == LPASS_DP_RX) { 132 map = drvdata->hdmiif_map; 133 drvdata->hdmi_substream[dma_ch] = substream; 134 } else { 135 map = drvdata->lpaif_map; 136 drvdata->substream[dma_ch] = substream; 137 } 138 data->dma_ch = dma_ch; 139 ret = regmap_write(map, 140 LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0); 141 if (ret) { 142 dev_err(soc_runtime->dev, 143 "error writing to rdmactl reg: %d\n", ret); 144 return ret; 145 } 146 snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); 147 148 runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max; 149 150 ret = snd_pcm_hw_constraint_integer(runtime, 151 SNDRV_PCM_HW_PARAM_PERIODS); 152 if (ret < 0) { 153 kfree(data); 154 dev_err(soc_runtime->dev, "setting constraints failed: %d\n", 155 ret); 156 return -EINVAL; 157 } 158 159 return 0; 160 } 161 162 static int lpass_platform_pcmops_close(struct snd_soc_component *component, 163 struct snd_pcm_substream *substream) 164 { 165 struct snd_pcm_runtime *runtime = substream->runtime; 166 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 167 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 168 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 169 struct lpass_variant *v = drvdata->variant; 170 struct lpass_pcm_data *data; 171 unsigned int dai_id = cpu_dai->driver->id; 172 173 data = runtime->private_data; 174 if (dai_id == LPASS_DP_RX) 175 drvdata->hdmi_substream[data->dma_ch] = NULL; 176 else 177 drvdata->substream[data->dma_ch] = NULL; 178 if (v->free_dma_channel) 179 v->free_dma_channel(drvdata, data->dma_ch, dai_id); 180 181 kfree(data); 182 return 0; 183 } 184 185 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, 186 struct snd_pcm_substream *substream, 187 struct snd_pcm_hw_params *params) 188 { 189 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 190 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 191 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 192 struct snd_pcm_runtime *rt = substream->runtime; 193 struct lpass_pcm_data *pcm_data = rt->private_data; 194 struct lpass_variant *v = drvdata->variant; 195 snd_pcm_format_t format = params_format(params); 196 unsigned int channels = params_channels(params); 197 unsigned int regval; 198 struct lpaif_dmactl *dmactl; 199 int id, dir = substream->stream; 200 int bitwidth; 201 int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; 202 unsigned int dai_id = cpu_dai->driver->id; 203 204 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 205 id = pcm_data->dma_ch; 206 if (dai_id == LPASS_DP_RX) 207 dmactl = drvdata->hdmi_rd_dmactl; 208 else 209 dmactl = drvdata->rd_dmactl; 210 211 } else { 212 dmactl = drvdata->wr_dmactl; 213 id = pcm_data->dma_ch - v->wrdma_channel_start; 214 } 215 216 bitwidth = snd_pcm_format_width(format); 217 if (bitwidth < 0) { 218 dev_err(soc_runtime->dev, "invalid bit width given: %d\n", 219 bitwidth); 220 return bitwidth; 221 } 222 223 ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4); 224 if (ret) { 225 dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret); 226 return ret; 227 } 228 229 ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8); 230 if (ret) { 231 dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret); 232 return ret; 233 } 234 235 switch (dai_id) { 236 case LPASS_DP_RX: 237 ret = regmap_fields_write(dmactl->burst8, id, 238 LPAIF_DMACTL_BURSTEN_INCR4); 239 if (ret) { 240 dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret); 241 return ret; 242 } 243 ret = regmap_fields_write(dmactl->burst16, id, 244 LPAIF_DMACTL_BURSTEN_INCR4); 245 if (ret) { 246 dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret); 247 return ret; 248 } 249 ret = regmap_fields_write(dmactl->dynburst, id, 250 LPAIF_DMACTL_BURSTEN_INCR4); 251 if (ret) { 252 dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret); 253 return ret; 254 } 255 break; 256 case MI2S_PRIMARY: 257 case MI2S_SECONDARY: 258 case MI2S_TERTIARY: 259 case MI2S_QUATERNARY: 260 case MI2S_QUINARY: 261 ret = regmap_fields_write(dmactl->intf, id, 262 LPAIF_DMACTL_AUDINTF(dma_port)); 263 if (ret) { 264 dev_err(soc_runtime->dev, "error updating audio interface field: %d\n", 265 ret); 266 return ret; 267 } 268 269 break; 270 default: 271 dev_err(soc_runtime->dev, "%s: invalid interface: %d\n", __func__, dai_id); 272 break; 273 } 274 switch (bitwidth) { 275 case 16: 276 switch (channels) { 277 case 1: 278 case 2: 279 regval = LPAIF_DMACTL_WPSCNT_ONE; 280 break; 281 case 4: 282 regval = LPAIF_DMACTL_WPSCNT_TWO; 283 break; 284 case 6: 285 regval = LPAIF_DMACTL_WPSCNT_THREE; 286 break; 287 case 8: 288 regval = LPAIF_DMACTL_WPSCNT_FOUR; 289 break; 290 default: 291 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", 292 bitwidth, channels); 293 return -EINVAL; 294 } 295 break; 296 case 24: 297 case 32: 298 switch (channels) { 299 case 1: 300 regval = LPAIF_DMACTL_WPSCNT_ONE; 301 break; 302 case 2: 303 regval = (dai_id == LPASS_DP_RX ? 304 LPAIF_DMACTL_WPSCNT_ONE : 305 LPAIF_DMACTL_WPSCNT_TWO); 306 break; 307 case 4: 308 regval = (dai_id == LPASS_DP_RX ? 309 LPAIF_DMACTL_WPSCNT_TWO : 310 LPAIF_DMACTL_WPSCNT_FOUR); 311 break; 312 case 6: 313 regval = (dai_id == LPASS_DP_RX ? 314 LPAIF_DMACTL_WPSCNT_THREE : 315 LPAIF_DMACTL_WPSCNT_SIX); 316 break; 317 case 8: 318 regval = (dai_id == LPASS_DP_RX ? 319 LPAIF_DMACTL_WPSCNT_FOUR : 320 LPAIF_DMACTL_WPSCNT_EIGHT); 321 break; 322 default: 323 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", 324 bitwidth, channels); 325 return -EINVAL; 326 } 327 break; 328 default: 329 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", 330 bitwidth, channels); 331 return -EINVAL; 332 } 333 334 ret = regmap_fields_write(dmactl->wpscnt, id, regval); 335 if (ret) { 336 dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n", 337 ret); 338 return ret; 339 } 340 341 return 0; 342 } 343 344 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component, 345 struct snd_pcm_substream *substream) 346 { 347 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 348 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 349 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 350 struct snd_pcm_runtime *rt = substream->runtime; 351 struct lpass_pcm_data *pcm_data = rt->private_data; 352 struct lpass_variant *v = drvdata->variant; 353 unsigned int reg; 354 int ret; 355 struct regmap *map; 356 unsigned int dai_id = cpu_dai->driver->id; 357 358 if (dai_id == LPASS_DP_RX) 359 map = drvdata->hdmiif_map; 360 else 361 map = drvdata->lpaif_map; 362 363 reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id); 364 ret = regmap_write(map, reg, 0); 365 if (ret) 366 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", 367 ret); 368 369 return ret; 370 } 371 372 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, 373 struct snd_pcm_substream *substream) 374 { 375 struct snd_pcm_runtime *runtime = substream->runtime; 376 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 377 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 378 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 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 struct lpaif_dmactl *dmactl; 383 struct regmap *map; 384 int ret, id, ch, dir = substream->stream; 385 unsigned int dai_id = cpu_dai->driver->id; 386 387 388 ch = pcm_data->dma_ch; 389 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 390 if (dai_id == LPASS_DP_RX) { 391 dmactl = drvdata->hdmi_rd_dmactl; 392 map = drvdata->hdmiif_map; 393 } else { 394 dmactl = drvdata->rd_dmactl; 395 map = drvdata->lpaif_map; 396 } 397 398 id = pcm_data->dma_ch; 399 } else { 400 dmactl = drvdata->wr_dmactl; 401 id = pcm_data->dma_ch - v->wrdma_channel_start; 402 map = drvdata->lpaif_map; 403 } 404 405 ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id), 406 runtime->dma_addr); 407 if (ret) { 408 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n", 409 ret); 410 return ret; 411 } 412 413 ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id), 414 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); 415 if (ret) { 416 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n", 417 ret); 418 return ret; 419 } 420 421 ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id), 422 (snd_pcm_lib_period_bytes(substream) >> 2) - 1); 423 if (ret) { 424 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n", 425 ret); 426 return ret; 427 } 428 429 ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON); 430 if (ret) { 431 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", 432 ret); 433 return ret; 434 } 435 436 return 0; 437 } 438 439 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, 440 struct snd_pcm_substream *substream, 441 int cmd) 442 { 443 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 444 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 445 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 446 struct snd_pcm_runtime *rt = substream->runtime; 447 struct lpass_pcm_data *pcm_data = rt->private_data; 448 struct lpass_variant *v = drvdata->variant; 449 struct lpaif_dmactl *dmactl; 450 struct regmap *map; 451 int ret, ch, id; 452 int dir = substream->stream; 453 unsigned int reg_irqclr = 0, val_irqclr = 0; 454 unsigned int reg_irqen = 0, val_irqen = 0, val_mask = 0; 455 unsigned int dai_id = cpu_dai->driver->id; 456 457 ch = pcm_data->dma_ch; 458 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 459 id = pcm_data->dma_ch; 460 if (dai_id == LPASS_DP_RX) { 461 dmactl = drvdata->hdmi_rd_dmactl; 462 map = drvdata->hdmiif_map; 463 } else { 464 dmactl = drvdata->rd_dmactl; 465 map = drvdata->lpaif_map; 466 } 467 } else { 468 dmactl = drvdata->wr_dmactl; 469 id = pcm_data->dma_ch - v->wrdma_channel_start; 470 map = drvdata->lpaif_map; 471 } 472 473 switch (cmd) { 474 case SNDRV_PCM_TRIGGER_START: 475 case SNDRV_PCM_TRIGGER_RESUME: 476 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 477 ret = regmap_fields_write(dmactl->enable, id, 478 LPAIF_DMACTL_ENABLE_ON); 479 if (ret) { 480 dev_err(soc_runtime->dev, 481 "error writing to rdmactl reg: %d\n", ret); 482 return ret; 483 } 484 switch (dai_id) { 485 case LPASS_DP_RX: 486 ret = regmap_fields_write(dmactl->dyncclk, id, 487 LPAIF_DMACTL_DYNCLK_ON); 488 if (ret) { 489 dev_err(soc_runtime->dev, 490 "error writing to rdmactl reg: %d\n", ret); 491 return ret; 492 } 493 reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v); 494 val_irqclr = (LPAIF_IRQ_ALL(ch) | 495 LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) | 496 LPAIF_IRQ_HDMI_METADONE | 497 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch)); 498 499 reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v); 500 val_mask = (LPAIF_IRQ_ALL(ch) | 501 LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) | 502 LPAIF_IRQ_HDMI_METADONE | 503 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch)); 504 val_irqen = (LPAIF_IRQ_ALL(ch) | 505 LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) | 506 LPAIF_IRQ_HDMI_METADONE | 507 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch)); 508 break; 509 case MI2S_PRIMARY: 510 case MI2S_SECONDARY: 511 case MI2S_TERTIARY: 512 case MI2S_QUATERNARY: 513 case MI2S_QUINARY: 514 reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST); 515 val_irqclr = LPAIF_IRQ_ALL(ch); 516 517 518 reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST); 519 val_mask = LPAIF_IRQ_ALL(ch); 520 val_irqen = LPAIF_IRQ_ALL(ch); 521 break; 522 default: 523 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); 524 return -EINVAL; 525 } 526 527 ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr); 528 if (ret) { 529 dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret); 530 return ret; 531 } 532 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen); 533 if (ret) { 534 dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret); 535 return ret; 536 } 537 break; 538 case SNDRV_PCM_TRIGGER_STOP: 539 case SNDRV_PCM_TRIGGER_SUSPEND: 540 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 541 ret = regmap_fields_write(dmactl->enable, id, 542 LPAIF_DMACTL_ENABLE_OFF); 543 if (ret) { 544 dev_err(soc_runtime->dev, 545 "error writing to rdmactl reg: %d\n", ret); 546 return ret; 547 } 548 switch (dai_id) { 549 case LPASS_DP_RX: 550 ret = regmap_fields_write(dmactl->dyncclk, id, 551 LPAIF_DMACTL_DYNCLK_OFF); 552 if (ret) { 553 dev_err(soc_runtime->dev, 554 "error writing to rdmactl reg: %d\n", ret); 555 return ret; 556 } 557 reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v); 558 val_mask = (LPAIF_IRQ_ALL(ch) | 559 LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) | 560 LPAIF_IRQ_HDMI_METADONE | 561 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch)); 562 val_irqen = 0; 563 break; 564 case MI2S_PRIMARY: 565 case MI2S_SECONDARY: 566 case MI2S_TERTIARY: 567 case MI2S_QUATERNARY: 568 case MI2S_QUINARY: 569 reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST); 570 val_mask = LPAIF_IRQ_ALL(ch); 571 val_irqen = 0; 572 break; 573 default: 574 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); 575 return -EINVAL; 576 } 577 578 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen); 579 if (ret) { 580 dev_err(soc_runtime->dev, 581 "error writing to irqen reg: %d\n", ret); 582 return ret; 583 } 584 break; 585 } 586 587 return 0; 588 } 589 590 static snd_pcm_uframes_t lpass_platform_pcmops_pointer( 591 struct snd_soc_component *component, 592 struct snd_pcm_substream *substream) 593 { 594 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 595 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 596 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 597 struct snd_pcm_runtime *rt = substream->runtime; 598 struct lpass_pcm_data *pcm_data = rt->private_data; 599 struct lpass_variant *v = drvdata->variant; 600 unsigned int base_addr, curr_addr; 601 int ret, ch, dir = substream->stream; 602 struct regmap *map; 603 unsigned int dai_id = cpu_dai->driver->id; 604 605 if (dai_id == LPASS_DP_RX) 606 map = drvdata->hdmiif_map; 607 else 608 map = drvdata->lpaif_map; 609 610 ch = pcm_data->dma_ch; 611 612 ret = regmap_read(map, 613 LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr); 614 if (ret) { 615 dev_err(soc_runtime->dev, 616 "error reading from rdmabase reg: %d\n", ret); 617 return ret; 618 } 619 620 ret = regmap_read(map, 621 LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr); 622 if (ret) { 623 dev_err(soc_runtime->dev, 624 "error reading from rdmacurr reg: %d\n", ret); 625 return ret; 626 } 627 628 return bytes_to_frames(substream->runtime, curr_addr - base_addr); 629 } 630 631 static irqreturn_t lpass_dma_interrupt_handler( 632 struct snd_pcm_substream *substream, 633 struct lpass_data *drvdata, 634 int chan, u32 interrupts) 635 { 636 struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); 637 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); 638 struct lpass_variant *v = drvdata->variant; 639 irqreturn_t ret = IRQ_NONE; 640 int rv; 641 unsigned int reg, val, mask; 642 struct regmap *map; 643 unsigned int dai_id = cpu_dai->driver->id; 644 645 mask = LPAIF_IRQ_ALL(chan); 646 switch (dai_id) { 647 case LPASS_DP_RX: 648 map = drvdata->hdmiif_map; 649 reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v); 650 val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) | 651 LPAIF_IRQ_HDMI_METADONE | 652 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan)); 653 break; 654 case MI2S_PRIMARY: 655 case MI2S_SECONDARY: 656 case MI2S_TERTIARY: 657 case MI2S_QUATERNARY: 658 case MI2S_QUINARY: 659 map = drvdata->lpaif_map; 660 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST); 661 val = 0; 662 break; 663 default: 664 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); 665 return -EINVAL; 666 } 667 if (interrupts & LPAIF_IRQ_PER(chan)) { 668 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val)); 669 if (rv) { 670 dev_err(soc_runtime->dev, 671 "error writing to irqclear reg: %d\n", rv); 672 return IRQ_NONE; 673 } 674 snd_pcm_period_elapsed(substream); 675 ret = IRQ_HANDLED; 676 } 677 678 if (interrupts & LPAIF_IRQ_XRUN(chan)) { 679 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val)); 680 if (rv) { 681 dev_err(soc_runtime->dev, 682 "error writing to irqclear reg: %d\n", rv); 683 return IRQ_NONE; 684 } 685 dev_warn(soc_runtime->dev, "xrun warning\n"); 686 snd_pcm_stop_xrun(substream); 687 ret = IRQ_HANDLED; 688 } 689 690 if (interrupts & LPAIF_IRQ_ERR(chan)) { 691 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val)); 692 if (rv) { 693 dev_err(soc_runtime->dev, 694 "error writing to irqclear reg: %d\n", rv); 695 return IRQ_NONE; 696 } 697 dev_err(soc_runtime->dev, "bus access error\n"); 698 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); 699 ret = IRQ_HANDLED; 700 } 701 702 if (interrupts & val) { 703 rv = regmap_write(map, reg, val); 704 if (rv) { 705 dev_err(soc_runtime->dev, 706 "error writing to irqclear reg: %d\n", rv); 707 return IRQ_NONE; 708 } 709 ret = IRQ_HANDLED; 710 } 711 712 return ret; 713 } 714 715 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) 716 { 717 struct lpass_data *drvdata = data; 718 struct lpass_variant *v = drvdata->variant; 719 unsigned int irqs; 720 int rv, chan; 721 722 rv = regmap_read(drvdata->lpaif_map, 723 LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs); 724 if (rv) { 725 pr_err("error reading from irqstat reg: %d\n", rv); 726 return IRQ_NONE; 727 } 728 729 /* Handle per channel interrupts */ 730 for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) { 731 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) { 732 rv = lpass_dma_interrupt_handler( 733 drvdata->substream[chan], 734 drvdata, chan, irqs); 735 if (rv != IRQ_HANDLED) 736 return rv; 737 } 738 } 739 740 return IRQ_HANDLED; 741 } 742 743 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data) 744 { 745 struct lpass_data *drvdata = data; 746 struct lpass_variant *v = drvdata->variant; 747 unsigned int irqs; 748 int rv, chan; 749 750 rv = regmap_read(drvdata->hdmiif_map, 751 LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs); 752 if (rv) { 753 pr_err("error reading from irqstat reg: %d\n", rv); 754 return IRQ_NONE; 755 } 756 757 /* Handle per channel interrupts */ 758 for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) { 759 if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) | 760 LPAIF_IRQ_HDMI_METADONE | 761 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan)) 762 && drvdata->hdmi_substream[chan]) { 763 rv = lpass_dma_interrupt_handler( 764 drvdata->hdmi_substream[chan], 765 drvdata, chan, irqs); 766 if (rv != IRQ_HANDLED) 767 return rv; 768 } 769 } 770 771 return IRQ_HANDLED; 772 } 773 774 static int lpass_platform_pcm_new(struct snd_soc_component *component, 775 struct snd_soc_pcm_runtime *soc_runtime) 776 { 777 struct snd_pcm *pcm = soc_runtime->pcm; 778 size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; 779 780 return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 781 component->dev, size); 782 } 783 784 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component) 785 { 786 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 787 struct regmap *map; 788 unsigned int dai_id = component->id; 789 790 if (dai_id == LPASS_DP_RX) 791 map = drvdata->hdmiif_map; 792 else 793 map = drvdata->lpaif_map; 794 795 regcache_cache_only(map, true); 796 regcache_mark_dirty(map); 797 798 return 0; 799 } 800 801 static int lpass_platform_pcmops_resume(struct snd_soc_component *component) 802 { 803 struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); 804 struct regmap *map; 805 unsigned int dai_id = component->id; 806 807 if (dai_id == LPASS_DP_RX) 808 map = drvdata->hdmiif_map; 809 else 810 map = drvdata->lpaif_map; 811 812 regcache_cache_only(map, false); 813 return regcache_sync(map); 814 } 815 816 817 static const struct snd_soc_component_driver lpass_component_driver = { 818 .name = DRV_NAME, 819 .open = lpass_platform_pcmops_open, 820 .close = lpass_platform_pcmops_close, 821 .hw_params = lpass_platform_pcmops_hw_params, 822 .hw_free = lpass_platform_pcmops_hw_free, 823 .prepare = lpass_platform_pcmops_prepare, 824 .trigger = lpass_platform_pcmops_trigger, 825 .pointer = lpass_platform_pcmops_pointer, 826 .pcm_construct = lpass_platform_pcm_new, 827 .suspend = lpass_platform_pcmops_suspend, 828 .resume = lpass_platform_pcmops_resume, 829 830 }; 831 832 int asoc_qcom_lpass_platform_register(struct platform_device *pdev) 833 { 834 struct lpass_data *drvdata = platform_get_drvdata(pdev); 835 struct lpass_variant *v = drvdata->variant; 836 int ret; 837 838 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); 839 if (drvdata->lpaif_irq < 0) 840 return -ENODEV; 841 842 /* ensure audio hardware is disabled */ 843 ret = regmap_write(drvdata->lpaif_map, 844 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0); 845 if (ret) { 846 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret); 847 return ret; 848 } 849 850 ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq, 851 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING, 852 "lpass-irq-lpaif", drvdata); 853 if (ret) { 854 dev_err(&pdev->dev, "irq request failed: %d\n", ret); 855 return ret; 856 } 857 858 ret = lpass_platform_alloc_dmactl_fields(&pdev->dev, 859 drvdata->lpaif_map); 860 if (ret) { 861 dev_err(&pdev->dev, 862 "error initializing dmactl fields: %d\n", ret); 863 return ret; 864 } 865 866 if (drvdata->hdmi_port_enable) { 867 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi"); 868 if (drvdata->hdmiif_irq < 0) 869 return -ENODEV; 870 871 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq, 872 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata); 873 if (ret) { 874 dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret); 875 return ret; 876 } 877 ret = regmap_write(drvdata->hdmiif_map, 878 LPASS_HDMITX_APP_IRQEN_REG(v), 0); 879 if (ret) { 880 dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret); 881 return ret; 882 } 883 884 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev, 885 drvdata->hdmiif_map); 886 if (ret) { 887 dev_err(&pdev->dev, 888 "error initializing hdmidmactl fields: %d\n", ret); 889 return ret; 890 } 891 } 892 return devm_snd_soc_register_component(&pdev->dev, 893 &lpass_component_driver, NULL, 0); 894 } 895 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); 896 897 MODULE_DESCRIPTION("QTi LPASS Platform Driver"); 898 MODULE_LICENSE("GPL v2"); 899