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 50 dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT); 51 if (!dma_desc) 52 return -ENOMEM; 53 54 snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_desc); 55 56 return 0; 57 } 58 59 static int bcm63xx_pcm_hw_free(struct snd_soc_component *component, 60 struct snd_pcm_substream *substream) 61 { 62 struct i2s_dma_desc *dma_desc; 63 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 64 65 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 66 kfree(dma_desc); 67 68 return 0; 69 } 70 71 static int bcm63xx_pcm_trigger(struct snd_soc_component *component, 72 struct snd_pcm_substream *substream, int cmd) 73 { 74 int ret = 0; 75 struct snd_soc_pcm_runtime *rtd; 76 struct bcm_i2s_priv *i2s_priv; 77 struct regmap *regmap_i2s; 78 79 rtd = asoc_substream_to_rtd(substream); 80 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 81 regmap_i2s = i2s_priv->regmap_i2s; 82 83 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 84 switch (cmd) { 85 case SNDRV_PCM_TRIGGER_START: 86 regmap_update_bits(regmap_i2s, 87 I2S_TX_IRQ_EN, 88 I2S_TX_DESC_OFF_INTR_EN, 89 I2S_TX_DESC_OFF_INTR_EN); 90 regmap_update_bits(regmap_i2s, 91 I2S_TX_CFG, 92 I2S_TX_ENABLE_MASK, 93 I2S_TX_ENABLE); 94 break; 95 case SNDRV_PCM_TRIGGER_STOP: 96 case SNDRV_PCM_TRIGGER_SUSPEND: 97 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 98 regmap_write(regmap_i2s, 99 I2S_TX_IRQ_EN, 100 0); 101 regmap_update_bits(regmap_i2s, 102 I2S_TX_CFG, 103 I2S_TX_ENABLE_MASK, 104 0); 105 break; 106 default: 107 ret = -EINVAL; 108 } 109 } else { 110 switch (cmd) { 111 case SNDRV_PCM_TRIGGER_START: 112 regmap_update_bits(regmap_i2s, 113 I2S_RX_IRQ_EN, 114 I2S_RX_DESC_OFF_INTR_EN_MSK, 115 I2S_RX_DESC_OFF_INTR_EN); 116 regmap_update_bits(regmap_i2s, 117 I2S_RX_CFG, 118 I2S_RX_ENABLE_MASK, 119 I2S_RX_ENABLE); 120 break; 121 case SNDRV_PCM_TRIGGER_STOP: 122 case SNDRV_PCM_TRIGGER_SUSPEND: 123 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 124 regmap_update_bits(regmap_i2s, 125 I2S_RX_IRQ_EN, 126 I2S_RX_DESC_OFF_INTR_EN_MSK, 127 0); 128 regmap_update_bits(regmap_i2s, 129 I2S_RX_CFG, 130 I2S_RX_ENABLE_MASK, 131 0); 132 break; 133 default: 134 ret = -EINVAL; 135 } 136 } 137 return ret; 138 } 139 140 static int bcm63xx_pcm_prepare(struct snd_soc_component *component, 141 struct snd_pcm_substream *substream) 142 { 143 struct i2s_dma_desc *dma_desc; 144 struct regmap *regmap_i2s; 145 struct bcm_i2s_priv *i2s_priv; 146 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 147 struct snd_pcm_runtime *runtime = substream->runtime; 148 uint32_t regaddr_desclen, regaddr_descaddr; 149 150 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 151 dma_desc->dma_len = snd_pcm_lib_period_bytes(substream); 152 dma_desc->dma_addr = runtime->dma_addr; 153 dma_desc->dma_area = runtime->dma_area; 154 155 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 156 regaddr_desclen = I2S_TX_DESC_IFF_LEN; 157 regaddr_descaddr = I2S_TX_DESC_IFF_ADDR; 158 } else { 159 regaddr_desclen = I2S_RX_DESC_IFF_LEN; 160 regaddr_descaddr = I2S_RX_DESC_IFF_ADDR; 161 } 162 163 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 164 regmap_i2s = i2s_priv->regmap_i2s; 165 166 regmap_write(regmap_i2s, regaddr_desclen, dma_desc->dma_len); 167 regmap_write(regmap_i2s, regaddr_descaddr, dma_desc->dma_addr); 168 169 return 0; 170 } 171 172 static snd_pcm_uframes_t 173 bcm63xx_pcm_pointer(struct snd_soc_component *component, 174 struct snd_pcm_substream *substream) 175 { 176 snd_pcm_uframes_t x; 177 struct bcm63xx_runtime_data *prtd = substream->runtime->private_data; 178 179 if (!prtd->dma_addr_next) 180 prtd->dma_addr_next = substream->runtime->dma_addr; 181 182 x = bytes_to_frames(substream->runtime, 183 prtd->dma_addr_next - substream->runtime->dma_addr); 184 185 return x == substream->runtime->buffer_size ? 0 : x; 186 } 187 188 static int bcm63xx_pcm_open(struct snd_soc_component *component, 189 struct snd_pcm_substream *substream) 190 { 191 int ret = 0; 192 struct snd_pcm_runtime *runtime = substream->runtime; 193 struct bcm63xx_runtime_data *prtd; 194 195 runtime->hw = bcm63xx_pcm_hardware; 196 ret = snd_pcm_hw_constraint_step(runtime, 0, 197 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); 198 if (ret) 199 goto out; 200 201 ret = snd_pcm_hw_constraint_step(runtime, 0, 202 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); 203 if (ret) 204 goto out; 205 206 ret = snd_pcm_hw_constraint_integer(runtime, 207 SNDRV_PCM_HW_PARAM_PERIODS); 208 if (ret < 0) 209 goto out; 210 211 ret = -ENOMEM; 212 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 213 if (!prtd) 214 goto out; 215 216 runtime->private_data = prtd; 217 return 0; 218 out: 219 return ret; 220 } 221 222 static int bcm63xx_pcm_close(struct snd_soc_component *component, 223 struct snd_pcm_substream *substream) 224 { 225 struct snd_pcm_runtime *runtime = substream->runtime; 226 struct bcm63xx_runtime_data *prtd = runtime->private_data; 227 228 kfree(prtd); 229 return 0; 230 } 231 232 static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv) 233 { 234 unsigned int availdepth, ifflevel, offlevel, int_status, val_1, val_2; 235 struct bcm63xx_runtime_data *prtd; 236 struct snd_pcm_substream *substream; 237 struct snd_pcm_runtime *runtime; 238 struct regmap *regmap_i2s; 239 struct i2s_dma_desc *dma_desc; 240 struct snd_soc_pcm_runtime *rtd; 241 struct bcm_i2s_priv *i2s_priv; 242 243 i2s_priv = (struct bcm_i2s_priv *)bcm_i2s_priv; 244 regmap_i2s = i2s_priv->regmap_i2s; 245 246 /* rx */ 247 regmap_read(regmap_i2s, I2S_RX_IRQ_CTL, &int_status); 248 249 if (int_status & I2S_RX_DESC_OFF_INTR_EN_MSK) { 250 substream = i2s_priv->capture_substream; 251 runtime = substream->runtime; 252 rtd = asoc_substream_to_rtd(substream); 253 prtd = runtime->private_data; 254 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 255 256 offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >> 257 I2S_RX_DESC_OFF_LEVEL_SHIFT; 258 while (offlevel) { 259 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1); 260 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2); 261 offlevel--; 262 } 263 prtd->dma_addr_next = val_1 + val_2; 264 ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >> 265 I2S_RX_DESC_IFF_LEVEL_SHIFT; 266 267 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel; 268 while (availdepth) { 269 dma_desc->dma_addr += 270 snd_pcm_lib_period_bytes(substream); 271 dma_desc->dma_area += 272 snd_pcm_lib_period_bytes(substream); 273 if (dma_desc->dma_addr - runtime->dma_addr >= 274 runtime->dma_bytes) { 275 dma_desc->dma_addr = runtime->dma_addr; 276 dma_desc->dma_area = runtime->dma_area; 277 } 278 279 prtd->dma_addr = dma_desc->dma_addr; 280 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_LEN, 281 snd_pcm_lib_period_bytes(substream)); 282 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_ADDR, 283 dma_desc->dma_addr); 284 availdepth--; 285 } 286 287 snd_pcm_period_elapsed(substream); 288 289 /* Clear interrupt by writing 0 */ 290 regmap_update_bits(regmap_i2s, I2S_RX_IRQ_CTL, 291 I2S_RX_INTR_MASK, 0); 292 } 293 294 /* tx */ 295 regmap_read(regmap_i2s, I2S_TX_IRQ_CTL, &int_status); 296 297 if (int_status & I2S_TX_DESC_OFF_INTR_EN_MSK) { 298 substream = i2s_priv->play_substream; 299 runtime = substream->runtime; 300 rtd = asoc_substream_to_rtd(substream); 301 prtd = runtime->private_data; 302 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 303 304 offlevel = (int_status & I2S_TX_DESC_OFF_LEVEL_MASK) >> 305 I2S_TX_DESC_OFF_LEVEL_SHIFT; 306 while (offlevel) { 307 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_ADDR, &val_1); 308 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_LEN, &val_2); 309 prtd->dma_addr_next = val_1 + val_2; 310 offlevel--; 311 } 312 313 ifflevel = (int_status & I2S_TX_DESC_IFF_LEVEL_MASK) >> 314 I2S_TX_DESC_IFF_LEVEL_SHIFT; 315 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel; 316 317 while (availdepth) { 318 dma_desc->dma_addr += 319 snd_pcm_lib_period_bytes(substream); 320 dma_desc->dma_area += 321 snd_pcm_lib_period_bytes(substream); 322 323 if (dma_desc->dma_addr - runtime->dma_addr >= 324 runtime->dma_bytes) { 325 dma_desc->dma_addr = runtime->dma_addr; 326 dma_desc->dma_area = runtime->dma_area; 327 } 328 329 prtd->dma_addr = dma_desc->dma_addr; 330 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_LEN, 331 snd_pcm_lib_period_bytes(substream)); 332 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_ADDR, 333 dma_desc->dma_addr); 334 availdepth--; 335 } 336 337 snd_pcm_period_elapsed(substream); 338 339 /* Clear interrupt by writing 0 */ 340 regmap_update_bits(regmap_i2s, I2S_TX_IRQ_CTL, 341 I2S_TX_INTR_MASK, 0); 342 } 343 344 return IRQ_HANDLED; 345 } 346 347 static int bcm63xx_soc_pcm_new(struct snd_soc_component *component, 348 struct snd_soc_pcm_runtime *rtd) 349 { 350 struct snd_pcm *pcm = rtd->pcm; 351 struct bcm_i2s_priv *i2s_priv; 352 int ret; 353 354 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev); 355 356 of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); 357 358 ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32)); 359 if (ret) 360 return ret; 361 362 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) 363 i2s_priv->play_substream = 364 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 365 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) 366 i2s_priv->capture_substream = 367 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 368 369 return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC, 370 pcm->card->dev, 371 bcm63xx_pcm_hardware.buffer_bytes_max); 372 } 373 374 static const struct snd_soc_component_driver bcm63xx_soc_platform = { 375 .open = bcm63xx_pcm_open, 376 .close = bcm63xx_pcm_close, 377 .hw_params = bcm63xx_pcm_hw_params, 378 .hw_free = bcm63xx_pcm_hw_free, 379 .prepare = bcm63xx_pcm_prepare, 380 .trigger = bcm63xx_pcm_trigger, 381 .pointer = bcm63xx_pcm_pointer, 382 .pcm_construct = bcm63xx_soc_pcm_new, 383 }; 384 385 int bcm63xx_soc_platform_probe(struct platform_device *pdev, 386 struct bcm_i2s_priv *i2s_priv) 387 { 388 int ret; 389 390 i2s_priv->r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 391 if (!i2s_priv->r_irq) { 392 dev_err(&pdev->dev, "Unable to get register irq resource.\n"); 393 return -ENODEV; 394 } 395 396 ret = devm_request_irq(&pdev->dev, i2s_priv->r_irq->start, i2s_dma_isr, 397 i2s_priv->r_irq->flags, "i2s_dma", (void *)i2s_priv); 398 if (ret) { 399 dev_err(&pdev->dev, 400 "i2s_init: failed to request interrupt.ret=%d\n", ret); 401 return ret; 402 } 403 404 return devm_snd_soc_register_component(&pdev->dev, 405 &bcm63xx_soc_platform, NULL, 0); 406 } 407 408 int bcm63xx_soc_platform_remove(struct platform_device *pdev) 409 { 410 return 0; 411 } 412 413 MODULE_AUTHOR("Kevin,Li <kevin-ke.li@broadcom.com>"); 414 MODULE_DESCRIPTION("Broadcom DSL XPON ASOC PCM Interface"); 415 MODULE_LICENSE("GPL v2"); 416