0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/delay.h>
0012 #include <linux/clk.h>
0013 #include <linux/slab.h>
0014 #include <linux/io.h>
0015 #include <linux/dmaengine.h>
0016 #include <linux/pm_runtime.h>
0017
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/initval.h>
0021 #include <sound/pcm_params.h>
0022 #include <sound/soc.h>
0023 #include <sound/pxa2xx-lib.h>
0024 #include <sound/dmaengine_pcm.h>
0025 #include "mmp-sspa.h"
0026
0027
0028
0029
0030 struct sspa_priv {
0031 void __iomem *tx_base;
0032 void __iomem *rx_base;
0033
0034 struct snd_dmaengine_dai_dma_data playback_dma_data;
0035 struct snd_dmaengine_dai_dma_data capture_dma_data;
0036 struct clk *clk;
0037 struct clk *audio_clk;
0038 struct clk *sysclk;
0039
0040 int running_cnt;
0041 u32 sp;
0042 u32 ctrl;
0043 };
0044
0045 static void mmp_sspa_tx_enable(struct sspa_priv *sspa)
0046 {
0047 unsigned int sspa_sp = sspa->sp;
0048
0049 sspa_sp &= ~SSPA_SP_MSL;
0050 sspa_sp |= SSPA_SP_S_EN;
0051 sspa_sp |= SSPA_SP_WEN;
0052 __raw_writel(sspa_sp, sspa->tx_base + SSPA_SP);
0053 }
0054
0055 static void mmp_sspa_tx_disable(struct sspa_priv *sspa)
0056 {
0057 unsigned int sspa_sp = sspa->sp;
0058
0059 sspa_sp &= ~SSPA_SP_MSL;
0060 sspa_sp &= ~SSPA_SP_S_EN;
0061 sspa_sp |= SSPA_SP_WEN;
0062 __raw_writel(sspa_sp, sspa->tx_base + SSPA_SP);
0063 }
0064
0065 static void mmp_sspa_rx_enable(struct sspa_priv *sspa)
0066 {
0067 unsigned int sspa_sp = sspa->sp;
0068
0069 sspa_sp |= SSPA_SP_S_EN;
0070 sspa_sp |= SSPA_SP_WEN;
0071 __raw_writel(sspa_sp, sspa->rx_base + SSPA_SP);
0072 }
0073
0074 static void mmp_sspa_rx_disable(struct sspa_priv *sspa)
0075 {
0076 unsigned int sspa_sp = sspa->sp;
0077
0078 sspa_sp &= ~SSPA_SP_S_EN;
0079 sspa_sp |= SSPA_SP_WEN;
0080 __raw_writel(sspa_sp, sspa->rx_base + SSPA_SP);
0081 }
0082
0083 static int mmp_sspa_startup(struct snd_pcm_substream *substream,
0084 struct snd_soc_dai *dai)
0085 {
0086 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
0087
0088 clk_prepare_enable(sspa->sysclk);
0089 clk_prepare_enable(sspa->clk);
0090
0091 return 0;
0092 }
0093
0094 static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
0095 struct snd_soc_dai *dai)
0096 {
0097 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
0098
0099 clk_disable_unprepare(sspa->clk);
0100 clk_disable_unprepare(sspa->sysclk);
0101 }
0102
0103
0104
0105
0106 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
0107 int clk_id, unsigned int freq, int dir)
0108 {
0109 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
0110 struct device *dev = cpu_dai->component->dev;
0111 int ret = 0;
0112
0113 if (dev->of_node)
0114 return -ENOTSUPP;
0115
0116 switch (clk_id) {
0117 case MMP_SSPA_CLK_AUDIO:
0118 ret = clk_set_rate(sspa->audio_clk, freq);
0119 if (ret)
0120 return ret;
0121 break;
0122 case MMP_SSPA_CLK_PLL:
0123 case MMP_SSPA_CLK_VCXO:
0124
0125 return -EINVAL;
0126 default:
0127 return -EINVAL;
0128 }
0129
0130 return 0;
0131 }
0132
0133 static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
0134 int source, unsigned int freq_in,
0135 unsigned int freq_out)
0136 {
0137 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
0138 struct device *dev = cpu_dai->component->dev;
0139 int ret = 0;
0140
0141 if (dev->of_node)
0142 return -ENOTSUPP;
0143
0144 switch (pll_id) {
0145 case MMP_SYSCLK:
0146 ret = clk_set_rate(sspa->sysclk, freq_out);
0147 if (ret)
0148 return ret;
0149 break;
0150 case MMP_SSPA_CLK:
0151 ret = clk_set_rate(sspa->clk, freq_out);
0152 if (ret)
0153 return ret;
0154 break;
0155 default:
0156 return -ENODEV;
0157 }
0158
0159 return 0;
0160 }
0161
0162
0163
0164
0165 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
0166 unsigned int fmt)
0167 {
0168 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
0169
0170
0171 sspa->sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
0172 sspa->ctrl = 0;
0173
0174 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0175 case SND_SOC_DAIFMT_BP_FP:
0176 sspa->sp |= SSPA_SP_MSL;
0177 break;
0178 case SND_SOC_DAIFMT_BC_FC:
0179 break;
0180 default:
0181 return -EINVAL;
0182 }
0183
0184 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0185 case SND_SOC_DAIFMT_NB_NF:
0186 sspa->sp |= SSPA_SP_FSP;
0187 break;
0188 default:
0189 return -EINVAL;
0190 }
0191
0192 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0193 case SND_SOC_DAIFMT_I2S:
0194 sspa->ctrl |= SSPA_CTL_XDATDLY(1);
0195 break;
0196 default:
0197 return -EINVAL;
0198 }
0199
0200
0201
0202
0203
0204 return 0;
0205 }
0206
0207
0208
0209
0210
0211 static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
0212 struct snd_pcm_hw_params *params,
0213 struct snd_soc_dai *dai)
0214 {
0215 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
0216 struct device *dev = dai->component->dev;
0217 u32 sspa_ctrl = sspa->ctrl;
0218 int bits;
0219 int bitval;
0220
0221 switch (params_format(params)) {
0222 case SNDRV_PCM_FORMAT_S8:
0223 bits = 8;
0224 bitval = SSPA_CTL_8_BITS;
0225 break;
0226 case SNDRV_PCM_FORMAT_S16_LE:
0227 bits = 16;
0228 bitval = SSPA_CTL_16_BITS;
0229 break;
0230 case SNDRV_PCM_FORMAT_S24_3LE:
0231 bits = 24;
0232 bitval = SSPA_CTL_24_BITS;
0233 break;
0234 case SNDRV_PCM_FORMAT_S32_LE:
0235 bits = 32;
0236 bitval = SSPA_CTL_32_BITS;
0237 break;
0238 default:
0239 return -EINVAL;
0240 }
0241
0242 sspa_ctrl &= ~SSPA_CTL_XPH;
0243 if (dev->of_node || params_channels(params) == 2)
0244 sspa_ctrl |= SSPA_CTL_XPH;
0245
0246 sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
0247 sspa_ctrl |= SSPA_CTL_XWDLEN1(bitval);
0248
0249 sspa_ctrl &= ~SSPA_CTL_XWDLEN2_MASK;
0250 sspa_ctrl |= SSPA_CTL_XWDLEN2(bitval);
0251
0252 sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
0253 sspa_ctrl |= SSPA_CTL_XSSZ1(bitval);
0254
0255 sspa_ctrl &= ~SSPA_CTL_XSSZ2_MASK;
0256 sspa_ctrl |= SSPA_CTL_XSSZ2(bitval);
0257
0258 sspa->sp &= ~SSPA_SP_FWID_MASK;
0259 sspa->sp |= SSPA_SP_FWID(bits - 1);
0260
0261 sspa->sp &= ~SSPA_TXSP_FPER_MASK;
0262 sspa->sp |= SSPA_TXSP_FPER(bits * 2 - 1);
0263
0264 if (dev->of_node) {
0265 clk_set_rate(sspa->clk, params_rate(params) *
0266 params_channels(params) * bits);
0267 }
0268
0269 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0270 __raw_writel(sspa_ctrl, sspa->tx_base + SSPA_CTL);
0271 __raw_writel(0x1, sspa->tx_base + SSPA_FIFO_UL);
0272 } else {
0273 __raw_writel(sspa_ctrl, sspa->rx_base + SSPA_CTL);
0274 __raw_writel(0x0, sspa->rx_base + SSPA_FIFO_UL);
0275 }
0276
0277 return 0;
0278 }
0279
0280 static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
0281 struct snd_soc_dai *dai)
0282 {
0283 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
0284 int ret = 0;
0285
0286 switch (cmd) {
0287 case SNDRV_PCM_TRIGGER_START:
0288 case SNDRV_PCM_TRIGGER_RESUME:
0289 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0290
0291
0292
0293
0294
0295
0296 if (!sspa->running_cnt)
0297 mmp_sspa_rx_enable(sspa);
0298
0299 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0300 mmp_sspa_tx_enable(sspa);
0301
0302 sspa->running_cnt++;
0303 break;
0304
0305 case SNDRV_PCM_TRIGGER_STOP:
0306 case SNDRV_PCM_TRIGGER_SUSPEND:
0307 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0308 sspa->running_cnt--;
0309
0310 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0311 mmp_sspa_tx_disable(sspa);
0312
0313
0314 if (!sspa->running_cnt)
0315 mmp_sspa_rx_disable(sspa);
0316 break;
0317
0318 default:
0319 ret = -EINVAL;
0320 }
0321
0322 return ret;
0323 }
0324
0325 static int mmp_sspa_probe(struct snd_soc_dai *dai)
0326 {
0327 struct sspa_priv *sspa = dev_get_drvdata(dai->dev);
0328
0329 snd_soc_dai_init_dma_data(dai,
0330 &sspa->playback_dma_data,
0331 &sspa->capture_dma_data);
0332
0333 return 0;
0334 }
0335
0336 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
0337 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
0338 SNDRV_PCM_FMTBIT_S16_LE | \
0339 SNDRV_PCM_FMTBIT_S24_3LE | \
0340 SNDRV_PCM_FMTBIT_S32_LE)
0341
0342 static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
0343 .startup = mmp_sspa_startup,
0344 .shutdown = mmp_sspa_shutdown,
0345 .trigger = mmp_sspa_trigger,
0346 .hw_params = mmp_sspa_hw_params,
0347 .set_sysclk = mmp_sspa_set_dai_sysclk,
0348 .set_pll = mmp_sspa_set_dai_pll,
0349 .set_fmt = mmp_sspa_set_dai_fmt,
0350 };
0351
0352 static struct snd_soc_dai_driver mmp_sspa_dai = {
0353 .probe = mmp_sspa_probe,
0354 .playback = {
0355 .channels_min = 1,
0356 .channels_max = 128,
0357 .rates = MMP_SSPA_RATES,
0358 .formats = MMP_SSPA_FORMATS,
0359 },
0360 .capture = {
0361 .channels_min = 1,
0362 .channels_max = 2,
0363 .rates = MMP_SSPA_RATES,
0364 .formats = MMP_SSPA_FORMATS,
0365 },
0366 .ops = &mmp_sspa_dai_ops,
0367 };
0368
0369 #define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
0370 SNDRV_PCM_INFO_MMAP_VALID | \
0371 SNDRV_PCM_INFO_INTERLEAVED | \
0372 SNDRV_PCM_INFO_PAUSE | \
0373 SNDRV_PCM_INFO_RESUME | \
0374 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
0375
0376 static const struct snd_pcm_hardware mmp_pcm_hardware[] = {
0377 {
0378 .info = MMP_PCM_INFO,
0379 .period_bytes_min = 1024,
0380 .period_bytes_max = 2048,
0381 .periods_min = 2,
0382 .periods_max = 32,
0383 .buffer_bytes_max = 4096,
0384 .fifo_size = 32,
0385 },
0386 {
0387 .info = MMP_PCM_INFO,
0388 .period_bytes_min = 1024,
0389 .period_bytes_max = 2048,
0390 .periods_min = 2,
0391 .periods_max = 32,
0392 .buffer_bytes_max = 4096,
0393 .fifo_size = 32,
0394 },
0395 };
0396
0397 static const struct snd_dmaengine_pcm_config mmp_pcm_config = {
0398 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
0399 .pcm_hardware = mmp_pcm_hardware,
0400 .prealloc_buffer_size = 4096,
0401 };
0402
0403 static int mmp_pcm_mmap(struct snd_soc_component *component,
0404 struct snd_pcm_substream *substream,
0405 struct vm_area_struct *vma)
0406 {
0407 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
0408 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0409 return remap_pfn_range(vma, vma->vm_start,
0410 substream->dma_buffer.addr >> PAGE_SHIFT,
0411 vma->vm_end - vma->vm_start, vma->vm_page_prot);
0412 }
0413
0414 static int mmp_sspa_open(struct snd_soc_component *component,
0415 struct snd_pcm_substream *substream)
0416 {
0417 struct sspa_priv *sspa = snd_soc_component_get_drvdata(component);
0418
0419 pm_runtime_get_sync(component->dev);
0420
0421
0422 if ((__raw_readl(sspa->tx_base + SSPA_SP) & SSPA_SP_S_EN) ||
0423 (__raw_readl(sspa->rx_base + SSPA_SP) & SSPA_SP_S_EN)) {
0424 dev_err(component->dev,
0425 "can't change hardware dai format: stream is in use\n");
0426 return -EBUSY;
0427 }
0428
0429 __raw_writel(sspa->sp, sspa->tx_base + SSPA_SP);
0430 __raw_writel(sspa->sp, sspa->rx_base + SSPA_SP);
0431
0432 sspa->sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
0433 __raw_writel(sspa->sp, sspa->tx_base + SSPA_SP);
0434 __raw_writel(sspa->sp, sspa->rx_base + SSPA_SP);
0435
0436
0437
0438
0439
0440
0441
0442
0443 __raw_writel(sspa->sp & ~SSPA_SP_MSL, sspa->tx_base + SSPA_SP);
0444
0445 __raw_writel(sspa->ctrl, sspa->tx_base + SSPA_CTL);
0446 __raw_writel(sspa->ctrl, sspa->rx_base + SSPA_CTL);
0447
0448 return 0;
0449 }
0450
0451 static int mmp_sspa_close(struct snd_soc_component *component,
0452 struct snd_pcm_substream *substream)
0453 {
0454 pm_runtime_put_sync(component->dev);
0455 return 0;
0456 }
0457
0458 static const struct snd_soc_component_driver mmp_sspa_component = {
0459 .name = "mmp-sspa",
0460 .mmap = mmp_pcm_mmap,
0461 .open = mmp_sspa_open,
0462 .close = mmp_sspa_close,
0463 .legacy_dai_naming = 1,
0464 };
0465
0466 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
0467 {
0468 struct sspa_priv *sspa;
0469 int ret;
0470
0471 sspa = devm_kzalloc(&pdev->dev,
0472 sizeof(struct sspa_priv), GFP_KERNEL);
0473 if (!sspa)
0474 return -ENOMEM;
0475
0476 if (pdev->dev.of_node) {
0477 sspa->rx_base = devm_platform_ioremap_resource(pdev, 0);
0478 if (IS_ERR(sspa->rx_base))
0479 return PTR_ERR(sspa->rx_base);
0480
0481 sspa->tx_base = devm_platform_ioremap_resource(pdev, 1);
0482 if (IS_ERR(sspa->tx_base))
0483 return PTR_ERR(sspa->tx_base);
0484
0485 sspa->clk = devm_clk_get(&pdev->dev, "bitclk");
0486 if (IS_ERR(sspa->clk))
0487 return PTR_ERR(sspa->clk);
0488
0489 sspa->audio_clk = devm_clk_get(&pdev->dev, "audio");
0490 if (IS_ERR(sspa->audio_clk))
0491 return PTR_ERR(sspa->audio_clk);
0492 } else {
0493 struct resource *res;
0494
0495 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
0496 if (res == NULL)
0497 return -ENODEV;
0498
0499 sspa->rx_base = devm_ioremap(&pdev->dev, res->start, 0x30);
0500 if (!sspa->rx_base)
0501 return -ENOMEM;
0502
0503 sspa->tx_base = devm_ioremap(&pdev->dev,
0504 res->start + 0x80, 0x30);
0505 if (!sspa->tx_base)
0506 return -ENOMEM;
0507
0508 sspa->clk = devm_clk_get(&pdev->dev, NULL);
0509 if (IS_ERR(sspa->clk))
0510 return PTR_ERR(sspa->clk);
0511
0512 sspa->audio_clk = clk_get(NULL, "mmp-audio");
0513 if (IS_ERR(sspa->audio_clk))
0514 return PTR_ERR(sspa->audio_clk);
0515
0516 sspa->sysclk = clk_get(NULL, "mmp-sysclk");
0517 if (IS_ERR(sspa->sysclk)) {
0518 clk_put(sspa->audio_clk);
0519 return PTR_ERR(sspa->sysclk);
0520 }
0521 }
0522 platform_set_drvdata(pdev, sspa);
0523
0524 sspa->playback_dma_data.maxburst = 4;
0525 sspa->capture_dma_data.maxburst = 4;
0526
0527 sspa->capture_dma_data.addr = SSPA_D;
0528 sspa->playback_dma_data.addr = 0x80 + SSPA_D;
0529
0530 if (pdev->dev.of_node) {
0531 ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
0532 &mmp_pcm_config, 0);
0533 if (ret)
0534 return ret;
0535 }
0536
0537 ret = devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
0538 &mmp_sspa_dai, 1);
0539 if (ret)
0540 return ret;
0541
0542 pm_runtime_enable(&pdev->dev);
0543 clk_prepare_enable(sspa->audio_clk);
0544
0545 return 0;
0546 }
0547
0548 static int asoc_mmp_sspa_remove(struct platform_device *pdev)
0549 {
0550 struct sspa_priv *sspa = platform_get_drvdata(pdev);
0551
0552 clk_disable_unprepare(sspa->audio_clk);
0553 pm_runtime_disable(&pdev->dev);
0554
0555 if (pdev->dev.of_node)
0556 return 0;
0557
0558 clk_put(sspa->audio_clk);
0559 clk_put(sspa->sysclk);
0560 return 0;
0561 }
0562
0563 #ifdef CONFIG_OF
0564 static const struct of_device_id mmp_sspa_of_match[] = {
0565 { .compatible = "marvell,mmp-sspa" },
0566 {},
0567 };
0568
0569 MODULE_DEVICE_TABLE(of, mmp_sspa_of_match);
0570 #endif
0571
0572 static struct platform_driver asoc_mmp_sspa_driver = {
0573 .driver = {
0574 .name = "mmp-sspa-dai",
0575 .of_match_table = of_match_ptr(mmp_sspa_of_match),
0576 },
0577 .probe = asoc_mmp_sspa_probe,
0578 .remove = asoc_mmp_sspa_remove,
0579 };
0580
0581 module_platform_driver(asoc_mmp_sspa_driver);
0582
0583 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
0584 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
0585 MODULE_LICENSE("GPL");
0586 MODULE_ALIAS("platform:mmp-sspa-dai");