1 // SPDX-License-Identifier: GPL-2.0-or-later 2 // linux/sound/bcm/bcm63xx-pcm-whistler.c 3 // BCM63xx whistler pcm interface 4 // Copyright (c) 2020 Broadcom Corporation 5 // Author: Kevin-Ke Li <kevin-ke.li@broadcom.com> 6 7 #include <linux/dma-mapping.h> 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <sound/pcm_params.h> 11 #include <linux/regmap.h> 12 #include <linux/of_device.h> 13 #include <sound/soc.h> 14 #include "bcm63xx-i2s.h" 15 16 17 struct i2s_dma_desc { 18 unsigned char *dma_area; 19 dma_addr_t dma_addr; 20 unsigned int dma_len; 21 }; 22 23 struct bcm63xx_runtime_data { 24 int dma_len; 25 dma_addr_t dma_addr; 26 dma_addr_t dma_addr_next; 27 }; 28 29 static const struct snd_pcm_hardware bcm63xx_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_S32_LE, /* support S32 only */ 36 .period_bytes_max = 8192 - 32, 37 .periods_min = 1, 38 .periods_max = PAGE_SIZE/sizeof(struct i2s_dma_desc), 39 .buffer_bytes_max = 128 * 1024, 40 .fifo_size = 32, 41 }; 42 43 static int bcm63xx_pcm_hw_params(struct snd_soc_component *component, 44 struct snd_pcm_substream *substream, 45 struct snd_pcm_hw_params *params) 46 { 47 struct i2s_dma_desc *dma_desc; 48 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 49 struct snd_pcm_runtime *runtime = substream->runtime; 50 51 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 52 runtime->dma_bytes = params_buffer_bytes(params); 53 54 dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT); 55 if (!dma_desc) 56 return -ENOMEM; 57 58 snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_desc); 59 60 return 0; 61 } 62 63 static int bcm63xx_pcm_hw_free(struct snd_soc_component *component, 64 struct snd_pcm_substream *substream) 65 { 66 struct i2s_dma_desc *dma_desc; 67 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 68 69 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 70 kfree(dma_desc); 71 snd_pcm_set_runtime_buffer(substream, NULL); 72 73 return 0; 74 } 75 76 static int bcm63xx_pcm_trigger(struct snd_soc_component *component, 77 struct snd_pcm_substream *substream, int cmd) 78 { 79 int ret = 0; 80 struct snd_soc_pcm_runtime *rtd; 81 struct bcm_i2s_priv *i2s_priv; 82 struct regmap *regmap_i2s; 83 84 rtd = asoc_substream_to_rtd(substream); 85 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 86 regmap_i2s = i2s_priv->regmap_i2s; 87 88 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 89 switch (cmd) { 90 case SNDRV_PCM_TRIGGER_START: 91 regmap_update_bits(regmap_i2s, 92 I2S_TX_IRQ_EN, 93 I2S_TX_DESC_OFF_INTR_EN, 94 I2S_TX_DESC_OFF_INTR_EN); 95 regmap_update_bits(regmap_i2s, 96 I2S_TX_CFG, 97 I2S_TX_ENABLE_MASK, 98 I2S_TX_ENABLE); 99 break; 100 case SNDRV_PCM_TRIGGER_STOP: 101 case SNDRV_PCM_TRIGGER_SUSPEND: 102 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 103 regmap_write(regmap_i2s, 104 I2S_TX_IRQ_EN, 105 0); 106 regmap_update_bits(regmap_i2s, 107 I2S_TX_CFG, 108 I2S_TX_ENABLE_MASK, 109 0); 110 break; 111 default: 112 ret = -EINVAL; 113 } 114 } else { 115 switch (cmd) { 116 case SNDRV_PCM_TRIGGER_START: 117 regmap_update_bits(regmap_i2s, 118 I2S_RX_IRQ_EN, 119 I2S_RX_DESC_OFF_INTR_EN_MSK, 120 I2S_RX_DESC_OFF_INTR_EN); 121 regmap_update_bits(regmap_i2s, 122 I2S_RX_CFG, 123 I2S_RX_ENABLE_MASK, 124 I2S_RX_ENABLE); 125 break; 126 case SNDRV_PCM_TRIGGER_STOP: 127 case SNDRV_PCM_TRIGGER_SUSPEND: 128 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 129 regmap_update_bits(regmap_i2s, 130 I2S_RX_IRQ_EN, 131 I2S_RX_DESC_OFF_INTR_EN_MSK, 132 0); 133 regmap_update_bits(regmap_i2s, 134 I2S_RX_CFG, 135 I2S_RX_ENABLE_MASK, 136 0); 137 break; 138 default: 139 ret = -EINVAL; 140 } 141 } 142 return ret; 143 } 144 145 static int bcm63xx_pcm_prepare(struct snd_soc_component *component, 146 struct snd_pcm_substream *substream) 147 { 148 struct i2s_dma_desc *dma_desc; 149 struct regmap *regmap_i2s; 150 struct bcm_i2s_priv *i2s_priv; 151 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 152 struct snd_pcm_runtime *runtime = substream->runtime; 153 uint32_t regaddr_desclen, regaddr_descaddr; 154 155 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 156 dma_desc->dma_len = snd_pcm_lib_period_bytes(substream); 157 dma_desc->dma_addr = runtime->dma_addr; 158 dma_desc->dma_area = runtime->dma_area; 159 160 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 161 regaddr_desclen = I2S_TX_DESC_IFF_LEN; 162 regaddr_descaddr = I2S_TX_DESC_IFF_ADDR; 163 } else { 164 regaddr_desclen = I2S_RX_DESC_IFF_LEN; 165 regaddr_descaddr = I2S_RX_DESC_IFF_ADDR; 166 } 167 168 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 169 regmap_i2s = i2s_priv->regmap_i2s; 170 171 regmap_write(regmap_i2s, regaddr_desclen, dma_desc->dma_len); 172 regmap_write(regmap_i2s, regaddr_descaddr, dma_desc->dma_addr); 173 174 return 0; 175 } 176 177 static snd_pcm_uframes_t 178 bcm63xx_pcm_pointer(struct snd_soc_component *component, 179 struct snd_pcm_substream *substream) 180 { 181 snd_pcm_uframes_t x; 182 struct bcm63xx_runtime_data *prtd = substream->runtime->private_data; 183 184 if (!prtd->dma_addr_next) 185 prtd->dma_addr_next = substream->runtime->dma_addr; 186 187 x = bytes_to_frames(substream->runtime, 188 prtd->dma_addr_next - substream->runtime->dma_addr); 189 190 return x == substream->runtime->buffer_size ? 0 : x; 191 } 192 193 static int bcm63xx_pcm_mmap(struct snd_soc_component *component, 194 struct snd_pcm_substream *substream, 195 struct vm_area_struct *vma) 196 { 197 struct snd_pcm_runtime *runtime = substream->runtime; 198 199 return dma_mmap_wc(substream->pcm->card->dev, vma, 200 runtime->dma_area, 201 runtime->dma_addr, 202 runtime->dma_bytes); 203 204 } 205 206 static int bcm63xx_pcm_open(struct snd_soc_component *component, 207 struct snd_pcm_substream *substream) 208 { 209 int ret = 0; 210 struct snd_pcm_runtime *runtime = substream->runtime; 211 struct bcm63xx_runtime_data *prtd; 212 213 runtime->hw = bcm63xx_pcm_hardware; 214 ret = snd_pcm_hw_constraint_step(runtime, 0, 215 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); 216 if (ret) 217 goto out; 218 219 ret = snd_pcm_hw_constraint_step(runtime, 0, 220 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); 221 if (ret) 222 goto out; 223 224 ret = snd_pcm_hw_constraint_integer(runtime, 225 SNDRV_PCM_HW_PARAM_PERIODS); 226 if (ret < 0) 227 goto out; 228 229 ret = -ENOMEM; 230 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 231 if (!prtd) 232 goto out; 233 234 runtime->private_data = prtd; 235 return 0; 236 out: 237 return ret; 238 } 239 240 static int bcm63xx_pcm_close(struct snd_soc_component *component, 241 struct snd_pcm_substream *substream) 242 { 243 struct snd_pcm_runtime *runtime = substream->runtime; 244 struct bcm63xx_runtime_data *prtd = runtime->private_data; 245 246 kfree(prtd); 247 return 0; 248 } 249 250 static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv) 251 { 252 unsigned int availdepth, ifflevel, offlevel, int_status, val_1, val_2; 253 struct bcm63xx_runtime_data *prtd; 254 struct snd_pcm_substream *substream; 255 struct snd_pcm_runtime *runtime; 256 struct regmap *regmap_i2s; 257 struct i2s_dma_desc *dma_desc; 258 struct snd_soc_pcm_runtime *rtd; 259 struct bcm_i2s_priv *i2s_priv; 260 261 i2s_priv = (struct bcm_i2s_priv *)bcm_i2s_priv; 262 regmap_i2s = i2s_priv->regmap_i2s; 263 264 /* rx */ 265 regmap_read(regmap_i2s, I2S_RX_IRQ_CTL, &int_status); 266 267 if (int_status & I2S_RX_DESC_OFF_INTR_EN_MSK) { 268 substream = i2s_priv->capture_substream; 269 runtime = substream->runtime; 270 rtd = asoc_substream_to_rtd(substream); 271 prtd = runtime->private_data; 272 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 273 274 offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >> 275 I2S_RX_DESC_OFF_LEVEL_SHIFT; 276 while (offlevel) { 277 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1); 278 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2); 279 offlevel--; 280 } 281 prtd->dma_addr_next = val_1 + val_2; 282 ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >> 283 I2S_RX_DESC_IFF_LEVEL_SHIFT; 284 285 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel; 286 while (availdepth) { 287 dma_desc->dma_addr += 288 snd_pcm_lib_period_bytes(substream); 289 dma_desc->dma_area += 290 snd_pcm_lib_period_bytes(substream); 291 if (dma_desc->dma_addr - runtime->dma_addr >= 292 runtime->dma_bytes) { 293 dma_desc->dma_addr = runtime->dma_addr; 294 dma_desc->dma_area = runtime->dma_area; 295 } 296 297 prtd->dma_addr = dma_desc->dma_addr; 298 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_LEN, 299 snd_pcm_lib_period_bytes(substream)); 300 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_ADDR, 301 dma_desc->dma_addr); 302 availdepth--; 303 } 304 305 snd_pcm_period_elapsed(substream); 306 307 /* Clear interrupt by writing 0 */ 308 regmap_update_bits(regmap_i2s, I2S_RX_IRQ_CTL, 309 I2S_RX_INTR_MASK, 0); 310 } 311 312 /* tx */ 313 regmap_read(regmap_i2s, I2S_TX_IRQ_CTL, &int_status); 314 315 if (int_status & I2S_TX_DESC_OFF_INTR_EN_MSK) { 316 substream = i2s_priv->play_substream; 317 runtime = substream->runtime; 318 rtd = asoc_substream_to_rtd(substream); 319 prtd = runtime->private_data; 320 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 321 322 offlevel = (int_status & I2S_TX_DESC_OFF_LEVEL_MASK) >> 323 I2S_TX_DESC_OFF_LEVEL_SHIFT; 324 while (offlevel) { 325 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_ADDR, &val_1); 326 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_LEN, &val_2); 327 prtd->dma_addr_next = val_1 + val_2; 328 offlevel--; 329 } 330 331 ifflevel = (int_status & I2S_TX_DESC_IFF_LEVEL_MASK) >> 332 I2S_TX_DESC_IFF_LEVEL_SHIFT; 333 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel; 334 335 while (availdepth) { 336 dma_desc->dma_addr += 337 snd_pcm_lib_period_bytes(substream); 338 dma_desc->dma_area += 339 snd_pcm_lib_period_bytes(substream); 340 341 if (dma_desc->dma_addr - runtime->dma_addr >= 342 runtime->dma_bytes) { 343 dma_desc->dma_addr = runtime->dma_addr; 344 dma_desc->dma_area = runtime->dma_area; 345 } 346 347 prtd->dma_addr = dma_desc->dma_addr; 348 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_LEN, 349 snd_pcm_lib_period_bytes(substream)); 350 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_ADDR, 351 dma_desc->dma_addr); 352 availdepth--; 353 } 354 355 snd_pcm_period_elapsed(substream); 356 357 /* Clear interrupt by writing 0 */ 358 regmap_update_bits(regmap_i2s, I2S_TX_IRQ_CTL, 359 I2S_TX_INTR_MASK, 0); 360 } 361 362 return IRQ_HANDLED; 363 } 364 365 static int bcm63xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 366 { 367 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 368 struct snd_dma_buffer *buf = &substream->dma_buffer; 369 size_t size = bcm63xx_pcm_hardware.buffer_bytes_max; 370 371 buf->dev.type = SNDRV_DMA_TYPE_DEV; 372 buf->dev.dev = pcm->card->dev; 373 buf->private_data = NULL; 374 375 buf->area = dma_alloc_wc(pcm->card->dev, 376 size, &buf->addr, 377 GFP_KERNEL); 378 if (!buf->area) 379 return -ENOMEM; 380 buf->bytes = size; 381 return 0; 382 } 383 384 static int bcm63xx_soc_pcm_new(struct snd_soc_component *component, 385 struct snd_soc_pcm_runtime *rtd) 386 { 387 struct snd_pcm *pcm = rtd->pcm; 388 struct bcm_i2s_priv *i2s_priv; 389 int ret; 390 391 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 392 393 of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); 394 395 ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32)); 396 if (ret) 397 goto out; 398 399 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 400 ret = bcm63xx_pcm_preallocate_dma_buffer(pcm, 401 SNDRV_PCM_STREAM_PLAYBACK); 402 if (ret) 403 goto out; 404 405 i2s_priv->play_substream = 406 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 407 } 408 409 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 410 ret = bcm63xx_pcm_preallocate_dma_buffer(pcm, 411 SNDRV_PCM_STREAM_CAPTURE); 412 if (ret) 413 goto out; 414 i2s_priv->capture_substream = 415 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 416 } 417 418 out: 419 return ret; 420 } 421 422 static void bcm63xx_pcm_free_dma_buffers(struct snd_soc_component *component, 423 struct snd_pcm *pcm) 424 { 425 int stream; 426 struct snd_dma_buffer *buf; 427 struct snd_pcm_substream *substream; 428 429 for (stream = 0; stream < 2; stream++) { 430 substream = pcm->streams[stream].substream; 431 if (!substream) 432 continue; 433 buf = &substream->dma_buffer; 434 if (!buf->area) 435 continue; 436 dma_free_wc(pcm->card->dev, buf->bytes, 437 buf->area, buf->addr); 438 buf->area = NULL; 439 } 440 } 441 442 static const struct snd_soc_component_driver bcm63xx_soc_platform = { 443 .open = bcm63xx_pcm_open, 444 .close = bcm63xx_pcm_close, 445 .hw_params = bcm63xx_pcm_hw_params, 446 .hw_free = bcm63xx_pcm_hw_free, 447 .prepare = bcm63xx_pcm_prepare, 448 .trigger = bcm63xx_pcm_trigger, 449 .pointer = bcm63xx_pcm_pointer, 450 .mmap = bcm63xx_pcm_mmap, 451 .pcm_construct = bcm63xx_soc_pcm_new, 452 .pcm_destruct = bcm63xx_pcm_free_dma_buffers, 453 }; 454 455 int bcm63xx_soc_platform_probe(struct platform_device *pdev, 456 struct bcm_i2s_priv *i2s_priv) 457 { 458 int ret; 459 460 i2s_priv->r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 461 if (!i2s_priv->r_irq) { 462 dev_err(&pdev->dev, "Unable to get register irq resource.\n"); 463 return -ENODEV; 464 } 465 466 ret = devm_request_irq(&pdev->dev, i2s_priv->r_irq->start, i2s_dma_isr, 467 i2s_priv->r_irq->flags, "i2s_dma", (void *)i2s_priv); 468 if (ret) { 469 dev_err(&pdev->dev, 470 "i2s_init: failed to request interrupt.ret=%d\n", ret); 471 return ret; 472 } 473 474 return devm_snd_soc_register_component(&pdev->dev, 475 &bcm63xx_soc_platform, NULL, 0); 476 } 477 478 int bcm63xx_soc_platform_remove(struct platform_device *pdev) 479 { 480 return 0; 481 } 482 483 MODULE_AUTHOR("Kevin,Li <kevin-ke.li@broadcom.com>"); 484 MODULE_DESCRIPTION("Broadcom DSL XPON ASOC PCM Interface"); 485 MODULE_LICENSE("GPL v2"); 486