0001
0002
0003
0004
0005
0006
0007 #include <linux/dma-mapping.h>
0008 #include <linux/io.h>
0009 #include <linux/irq.h>
0010 #include <linux/module.h>
0011 #include <sound/pcm_params.h>
0012 #include <linux/regmap.h>
0013 #include <linux/of_device.h>
0014 #include <sound/soc.h>
0015 #include "bcm63xx-i2s.h"
0016
0017
0018 struct i2s_dma_desc {
0019 unsigned char *dma_area;
0020 dma_addr_t dma_addr;
0021 unsigned int dma_len;
0022 };
0023
0024 struct bcm63xx_runtime_data {
0025 int dma_len;
0026 dma_addr_t dma_addr;
0027 dma_addr_t dma_addr_next;
0028 };
0029
0030 static const struct snd_pcm_hardware bcm63xx_pcm_hardware = {
0031 .info = SNDRV_PCM_INFO_MMAP |
0032 SNDRV_PCM_INFO_MMAP_VALID |
0033 SNDRV_PCM_INFO_INTERLEAVED |
0034 SNDRV_PCM_INFO_PAUSE |
0035 SNDRV_PCM_INFO_RESUME,
0036 .formats = SNDRV_PCM_FMTBIT_S32_LE,
0037 .period_bytes_max = 8192 - 32,
0038 .periods_min = 1,
0039 .periods_max = PAGE_SIZE/sizeof(struct i2s_dma_desc),
0040 .buffer_bytes_max = 128 * 1024,
0041 .fifo_size = 32,
0042 };
0043
0044 static int bcm63xx_pcm_hw_params(struct snd_soc_component *component,
0045 struct snd_pcm_substream *substream,
0046 struct snd_pcm_hw_params *params)
0047 {
0048 struct i2s_dma_desc *dma_desc;
0049 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0050
0051 dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
0052 if (!dma_desc)
0053 return -ENOMEM;
0054
0055 snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_desc);
0056
0057 return 0;
0058 }
0059
0060 static int bcm63xx_pcm_hw_free(struct snd_soc_component *component,
0061 struct snd_pcm_substream *substream)
0062 {
0063 struct i2s_dma_desc *dma_desc;
0064 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0065
0066 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0067 kfree(dma_desc);
0068
0069 return 0;
0070 }
0071
0072 static int bcm63xx_pcm_trigger(struct snd_soc_component *component,
0073 struct snd_pcm_substream *substream, int cmd)
0074 {
0075 int ret = 0;
0076 struct snd_soc_pcm_runtime *rtd;
0077 struct bcm_i2s_priv *i2s_priv;
0078 struct regmap *regmap_i2s;
0079
0080 rtd = asoc_substream_to_rtd(substream);
0081 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
0082 regmap_i2s = i2s_priv->regmap_i2s;
0083
0084 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0085 switch (cmd) {
0086 case SNDRV_PCM_TRIGGER_START:
0087 regmap_update_bits(regmap_i2s,
0088 I2S_TX_IRQ_EN,
0089 I2S_TX_DESC_OFF_INTR_EN,
0090 I2S_TX_DESC_OFF_INTR_EN);
0091 regmap_update_bits(regmap_i2s,
0092 I2S_TX_CFG,
0093 I2S_TX_ENABLE_MASK,
0094 I2S_TX_ENABLE);
0095 break;
0096 case SNDRV_PCM_TRIGGER_STOP:
0097 case SNDRV_PCM_TRIGGER_SUSPEND:
0098 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0099 regmap_write(regmap_i2s,
0100 I2S_TX_IRQ_EN,
0101 0);
0102 regmap_update_bits(regmap_i2s,
0103 I2S_TX_CFG,
0104 I2S_TX_ENABLE_MASK,
0105 0);
0106 break;
0107 default:
0108 ret = -EINVAL;
0109 }
0110 } else {
0111 switch (cmd) {
0112 case SNDRV_PCM_TRIGGER_START:
0113 regmap_update_bits(regmap_i2s,
0114 I2S_RX_IRQ_EN,
0115 I2S_RX_DESC_OFF_INTR_EN_MSK,
0116 I2S_RX_DESC_OFF_INTR_EN);
0117 regmap_update_bits(regmap_i2s,
0118 I2S_RX_CFG,
0119 I2S_RX_ENABLE_MASK,
0120 I2S_RX_ENABLE);
0121 break;
0122 case SNDRV_PCM_TRIGGER_STOP:
0123 case SNDRV_PCM_TRIGGER_SUSPEND:
0124 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0125 regmap_update_bits(regmap_i2s,
0126 I2S_RX_IRQ_EN,
0127 I2S_RX_DESC_OFF_INTR_EN_MSK,
0128 0);
0129 regmap_update_bits(regmap_i2s,
0130 I2S_RX_CFG,
0131 I2S_RX_ENABLE_MASK,
0132 0);
0133 break;
0134 default:
0135 ret = -EINVAL;
0136 }
0137 }
0138 return ret;
0139 }
0140
0141 static int bcm63xx_pcm_prepare(struct snd_soc_component *component,
0142 struct snd_pcm_substream *substream)
0143 {
0144 struct i2s_dma_desc *dma_desc;
0145 struct regmap *regmap_i2s;
0146 struct bcm_i2s_priv *i2s_priv;
0147 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0148 struct snd_pcm_runtime *runtime = substream->runtime;
0149 uint32_t regaddr_desclen, regaddr_descaddr;
0150
0151 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0152 dma_desc->dma_len = snd_pcm_lib_period_bytes(substream);
0153 dma_desc->dma_addr = runtime->dma_addr;
0154 dma_desc->dma_area = runtime->dma_area;
0155
0156 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0157 regaddr_desclen = I2S_TX_DESC_IFF_LEN;
0158 regaddr_descaddr = I2S_TX_DESC_IFF_ADDR;
0159 } else {
0160 regaddr_desclen = I2S_RX_DESC_IFF_LEN;
0161 regaddr_descaddr = I2S_RX_DESC_IFF_ADDR;
0162 }
0163
0164 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
0165 regmap_i2s = i2s_priv->regmap_i2s;
0166
0167 regmap_write(regmap_i2s, regaddr_desclen, dma_desc->dma_len);
0168 regmap_write(regmap_i2s, regaddr_descaddr, dma_desc->dma_addr);
0169
0170 return 0;
0171 }
0172
0173 static snd_pcm_uframes_t
0174 bcm63xx_pcm_pointer(struct snd_soc_component *component,
0175 struct snd_pcm_substream *substream)
0176 {
0177 snd_pcm_uframes_t x;
0178 struct bcm63xx_runtime_data *prtd = substream->runtime->private_data;
0179
0180 if (!prtd->dma_addr_next)
0181 prtd->dma_addr_next = substream->runtime->dma_addr;
0182
0183 x = bytes_to_frames(substream->runtime,
0184 prtd->dma_addr_next - substream->runtime->dma_addr);
0185
0186 return x == substream->runtime->buffer_size ? 0 : x;
0187 }
0188
0189 static int bcm63xx_pcm_open(struct snd_soc_component *component,
0190 struct snd_pcm_substream *substream)
0191 {
0192 int ret = 0;
0193 struct snd_pcm_runtime *runtime = substream->runtime;
0194 struct bcm63xx_runtime_data *prtd;
0195
0196 runtime->hw = bcm63xx_pcm_hardware;
0197 ret = snd_pcm_hw_constraint_step(runtime, 0,
0198 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
0199 if (ret)
0200 goto out;
0201
0202 ret = snd_pcm_hw_constraint_step(runtime, 0,
0203 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
0204 if (ret)
0205 goto out;
0206
0207 ret = snd_pcm_hw_constraint_integer(runtime,
0208 SNDRV_PCM_HW_PARAM_PERIODS);
0209 if (ret < 0)
0210 goto out;
0211
0212 ret = -ENOMEM;
0213 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
0214 if (!prtd)
0215 goto out;
0216
0217 runtime->private_data = prtd;
0218 return 0;
0219 out:
0220 return ret;
0221 }
0222
0223 static int bcm63xx_pcm_close(struct snd_soc_component *component,
0224 struct snd_pcm_substream *substream)
0225 {
0226 struct snd_pcm_runtime *runtime = substream->runtime;
0227 struct bcm63xx_runtime_data *prtd = runtime->private_data;
0228
0229 kfree(prtd);
0230 return 0;
0231 }
0232
0233 static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv)
0234 {
0235 unsigned int availdepth, ifflevel, offlevel, int_status, val_1, val_2;
0236 struct bcm63xx_runtime_data *prtd;
0237 struct snd_pcm_substream *substream;
0238 struct snd_pcm_runtime *runtime;
0239 struct regmap *regmap_i2s;
0240 struct i2s_dma_desc *dma_desc;
0241 struct snd_soc_pcm_runtime *rtd;
0242 struct bcm_i2s_priv *i2s_priv;
0243
0244 i2s_priv = (struct bcm_i2s_priv *)bcm_i2s_priv;
0245 regmap_i2s = i2s_priv->regmap_i2s;
0246
0247
0248 regmap_read(regmap_i2s, I2S_RX_IRQ_CTL, &int_status);
0249
0250 if (int_status & I2S_RX_DESC_OFF_INTR_EN_MSK) {
0251 substream = i2s_priv->capture_substream;
0252 runtime = substream->runtime;
0253 rtd = asoc_substream_to_rtd(substream);
0254 prtd = runtime->private_data;
0255 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0256
0257 offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >>
0258 I2S_RX_DESC_OFF_LEVEL_SHIFT;
0259 while (offlevel) {
0260 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1);
0261 regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2);
0262 offlevel--;
0263 }
0264 prtd->dma_addr_next = val_1 + val_2;
0265 ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >>
0266 I2S_RX_DESC_IFF_LEVEL_SHIFT;
0267
0268 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel;
0269 while (availdepth) {
0270 dma_desc->dma_addr +=
0271 snd_pcm_lib_period_bytes(substream);
0272 dma_desc->dma_area +=
0273 snd_pcm_lib_period_bytes(substream);
0274 if (dma_desc->dma_addr - runtime->dma_addr >=
0275 runtime->dma_bytes) {
0276 dma_desc->dma_addr = runtime->dma_addr;
0277 dma_desc->dma_area = runtime->dma_area;
0278 }
0279
0280 prtd->dma_addr = dma_desc->dma_addr;
0281 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_LEN,
0282 snd_pcm_lib_period_bytes(substream));
0283 regmap_write(regmap_i2s, I2S_RX_DESC_IFF_ADDR,
0284 dma_desc->dma_addr);
0285 availdepth--;
0286 }
0287
0288 snd_pcm_period_elapsed(substream);
0289
0290
0291 regmap_update_bits(regmap_i2s, I2S_RX_IRQ_CTL,
0292 I2S_RX_INTR_MASK, 0);
0293 }
0294
0295
0296 regmap_read(regmap_i2s, I2S_TX_IRQ_CTL, &int_status);
0297
0298 if (int_status & I2S_TX_DESC_OFF_INTR_EN_MSK) {
0299 substream = i2s_priv->play_substream;
0300 runtime = substream->runtime;
0301 rtd = asoc_substream_to_rtd(substream);
0302 prtd = runtime->private_data;
0303 dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0304
0305 offlevel = (int_status & I2S_TX_DESC_OFF_LEVEL_MASK) >>
0306 I2S_TX_DESC_OFF_LEVEL_SHIFT;
0307 while (offlevel) {
0308 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_ADDR, &val_1);
0309 regmap_read(regmap_i2s, I2S_TX_DESC_OFF_LEN, &val_2);
0310 prtd->dma_addr_next = val_1 + val_2;
0311 offlevel--;
0312 }
0313
0314 ifflevel = (int_status & I2S_TX_DESC_IFF_LEVEL_MASK) >>
0315 I2S_TX_DESC_IFF_LEVEL_SHIFT;
0316 availdepth = I2S_DESC_FIFO_DEPTH - ifflevel;
0317
0318 while (availdepth) {
0319 dma_desc->dma_addr +=
0320 snd_pcm_lib_period_bytes(substream);
0321 dma_desc->dma_area +=
0322 snd_pcm_lib_period_bytes(substream);
0323
0324 if (dma_desc->dma_addr - runtime->dma_addr >=
0325 runtime->dma_bytes) {
0326 dma_desc->dma_addr = runtime->dma_addr;
0327 dma_desc->dma_area = runtime->dma_area;
0328 }
0329
0330 prtd->dma_addr = dma_desc->dma_addr;
0331 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_LEN,
0332 snd_pcm_lib_period_bytes(substream));
0333 regmap_write(regmap_i2s, I2S_TX_DESC_IFF_ADDR,
0334 dma_desc->dma_addr);
0335 availdepth--;
0336 }
0337
0338 snd_pcm_period_elapsed(substream);
0339
0340
0341 regmap_update_bits(regmap_i2s, I2S_TX_IRQ_CTL,
0342 I2S_TX_INTR_MASK, 0);
0343 }
0344
0345 return IRQ_HANDLED;
0346 }
0347
0348 static int bcm63xx_soc_pcm_new(struct snd_soc_component *component,
0349 struct snd_soc_pcm_runtime *rtd)
0350 {
0351 struct snd_pcm *pcm = rtd->pcm;
0352 struct bcm_i2s_priv *i2s_priv;
0353 int ret;
0354
0355 i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
0356
0357 of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1);
0358
0359 ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32));
0360 if (ret)
0361 return ret;
0362
0363 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
0364 i2s_priv->play_substream =
0365 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
0366 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
0367 i2s_priv->capture_substream =
0368 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
0369
0370 return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
0371 pcm->card->dev,
0372 bcm63xx_pcm_hardware.buffer_bytes_max);
0373 }
0374
0375 static const struct snd_soc_component_driver bcm63xx_soc_platform = {
0376 .open = bcm63xx_pcm_open,
0377 .close = bcm63xx_pcm_close,
0378 .hw_params = bcm63xx_pcm_hw_params,
0379 .hw_free = bcm63xx_pcm_hw_free,
0380 .prepare = bcm63xx_pcm_prepare,
0381 .trigger = bcm63xx_pcm_trigger,
0382 .pointer = bcm63xx_pcm_pointer,
0383 .pcm_construct = bcm63xx_soc_pcm_new,
0384 };
0385
0386 int bcm63xx_soc_platform_probe(struct platform_device *pdev,
0387 struct bcm_i2s_priv *i2s_priv)
0388 {
0389 int ret;
0390
0391 ret = platform_get_irq(pdev, 0);
0392 if (ret < 0)
0393 return ret;
0394
0395 ret = devm_request_irq(&pdev->dev, ret, i2s_dma_isr,
0396 irq_get_trigger_type(ret), "i2s_dma", (void *)i2s_priv);
0397 if (ret) {
0398 dev_err(&pdev->dev,
0399 "i2s_init: failed to request interrupt.ret=%d\n", ret);
0400 return ret;
0401 }
0402
0403 return devm_snd_soc_register_component(&pdev->dev,
0404 &bcm63xx_soc_platform, NULL, 0);
0405 }
0406
0407 int bcm63xx_soc_platform_remove(struct platform_device *pdev)
0408 {
0409 return 0;
0410 }
0411
0412 MODULE_AUTHOR("Kevin,Li <kevin-ke.li@broadcom.com>");
0413 MODULE_DESCRIPTION("Broadcom DSL XPON ASOC PCM Interface");
0414 MODULE_LICENSE("GPL v2");