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