0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011
0012 #include <sound/soc.h>
0013 #include <sound/pcm_params.h>
0014
0015 #include <linux/platform_data/asoc-s3c.h>
0016
0017 #include "dma.h"
0018 #include "spdif.h"
0019
0020
0021 #define CLKCON 0x00
0022 #define CON 0x04
0023 #define BSTAS 0x08
0024 #define CSTAS 0x0C
0025 #define DATA_OUTBUF 0x10
0026 #define DCNT 0x14
0027 #define BSTAS_S 0x18
0028 #define DCNT_S 0x1C
0029
0030 #define CLKCTL_MASK 0x7
0031 #define CLKCTL_MCLK_EXT (0x1 << 2)
0032 #define CLKCTL_PWR_ON (0x1 << 0)
0033
0034 #define CON_MASK 0x3ffffff
0035 #define CON_FIFO_TH_SHIFT 19
0036 #define CON_FIFO_TH_MASK (0x7 << 19)
0037 #define CON_USERDATA_23RDBIT (0x1 << 12)
0038
0039 #define CON_SW_RESET (0x1 << 5)
0040
0041 #define CON_MCLKDIV_MASK (0x3 << 3)
0042 #define CON_MCLKDIV_256FS (0x0 << 3)
0043 #define CON_MCLKDIV_384FS (0x1 << 3)
0044 #define CON_MCLKDIV_512FS (0x2 << 3)
0045
0046 #define CON_PCM_MASK (0x3 << 1)
0047 #define CON_PCM_16BIT (0x0 << 1)
0048 #define CON_PCM_20BIT (0x1 << 1)
0049 #define CON_PCM_24BIT (0x2 << 1)
0050
0051 #define CON_PCM_DATA (0x1 << 0)
0052
0053 #define CSTAS_MASK 0x3fffffff
0054 #define CSTAS_SAMP_FREQ_MASK (0xF << 24)
0055 #define CSTAS_SAMP_FREQ_44 (0x0 << 24)
0056 #define CSTAS_SAMP_FREQ_48 (0x2 << 24)
0057 #define CSTAS_SAMP_FREQ_32 (0x3 << 24)
0058 #define CSTAS_SAMP_FREQ_96 (0xA << 24)
0059
0060 #define CSTAS_CATEGORY_MASK (0xFF << 8)
0061 #define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
0062
0063 #define CSTAS_NO_COPYRIGHT (0x1 << 2)
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 struct samsung_spdif_info {
0079 spinlock_t lock;
0080 struct device *dev;
0081 void __iomem *regs;
0082 unsigned long clk_rate;
0083 struct clk *pclk;
0084 struct clk *sclk;
0085 u32 saved_clkcon;
0086 u32 saved_con;
0087 u32 saved_cstas;
0088 struct snd_dmaengine_dai_dma_data *dma_playback;
0089 };
0090
0091 static struct snd_dmaengine_dai_dma_data spdif_stereo_out;
0092 static struct samsung_spdif_info spdif_info;
0093
0094 static inline struct samsung_spdif_info
0095 *component_to_info(struct snd_soc_component *component)
0096 {
0097 return snd_soc_component_get_drvdata(component);
0098 }
0099
0100 static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
0101 {
0102 return snd_soc_dai_get_drvdata(cpu_dai);
0103 }
0104
0105 static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
0106 {
0107 void __iomem *regs = spdif->regs;
0108 u32 clkcon;
0109
0110 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0111
0112 clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
0113 if (on)
0114 writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
0115 else
0116 writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
0117 }
0118
0119 static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
0120 int clk_id, unsigned int freq, int dir)
0121 {
0122 struct samsung_spdif_info *spdif = to_info(cpu_dai);
0123 u32 clkcon;
0124
0125 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0126
0127 clkcon = readl(spdif->regs + CLKCON);
0128
0129 if (clk_id == SND_SOC_SPDIF_INT_MCLK)
0130 clkcon &= ~CLKCTL_MCLK_EXT;
0131 else
0132 clkcon |= CLKCTL_MCLK_EXT;
0133
0134 writel(clkcon, spdif->regs + CLKCON);
0135
0136 spdif->clk_rate = freq;
0137
0138 return 0;
0139 }
0140
0141 static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
0142 struct snd_soc_dai *dai)
0143 {
0144 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0145 struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
0146 unsigned long flags;
0147
0148 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0149
0150 switch (cmd) {
0151 case SNDRV_PCM_TRIGGER_START:
0152 case SNDRV_PCM_TRIGGER_RESUME:
0153 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0154 spin_lock_irqsave(&spdif->lock, flags);
0155 spdif_snd_txctrl(spdif, 1);
0156 spin_unlock_irqrestore(&spdif->lock, flags);
0157 break;
0158 case SNDRV_PCM_TRIGGER_STOP:
0159 case SNDRV_PCM_TRIGGER_SUSPEND:
0160 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0161 spin_lock_irqsave(&spdif->lock, flags);
0162 spdif_snd_txctrl(spdif, 0);
0163 spin_unlock_irqrestore(&spdif->lock, flags);
0164 break;
0165 default:
0166 return -EINVAL;
0167 }
0168
0169 return 0;
0170 }
0171
0172 static int spdif_sysclk_ratios[] = {
0173 512, 384, 256,
0174 };
0175
0176 static int spdif_hw_params(struct snd_pcm_substream *substream,
0177 struct snd_pcm_hw_params *params,
0178 struct snd_soc_dai *socdai)
0179 {
0180 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0181 struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
0182 void __iomem *regs = spdif->regs;
0183 struct snd_dmaengine_dai_dma_data *dma_data;
0184 u32 con, clkcon, cstas;
0185 unsigned long flags;
0186 int i, ratio;
0187
0188 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0189
0190 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0191 dma_data = spdif->dma_playback;
0192 else {
0193 dev_err(spdif->dev, "Capture is not supported\n");
0194 return -EINVAL;
0195 }
0196
0197 snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_data);
0198
0199 spin_lock_irqsave(&spdif->lock, flags);
0200
0201 con = readl(regs + CON) & CON_MASK;
0202 cstas = readl(regs + CSTAS) & CSTAS_MASK;
0203 clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
0204
0205 con &= ~CON_FIFO_TH_MASK;
0206 con |= (0x7 << CON_FIFO_TH_SHIFT);
0207 con |= CON_USERDATA_23RDBIT;
0208 con |= CON_PCM_DATA;
0209
0210 con &= ~CON_PCM_MASK;
0211 switch (params_width(params)) {
0212 case 16:
0213 con |= CON_PCM_16BIT;
0214 break;
0215 default:
0216 dev_err(spdif->dev, "Unsupported data size.\n");
0217 goto err;
0218 }
0219
0220 ratio = spdif->clk_rate / params_rate(params);
0221 for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
0222 if (ratio == spdif_sysclk_ratios[i])
0223 break;
0224 if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
0225 dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
0226 spdif->clk_rate, params_rate(params));
0227 goto err;
0228 }
0229
0230 con &= ~CON_MCLKDIV_MASK;
0231 switch (ratio) {
0232 case 256:
0233 con |= CON_MCLKDIV_256FS;
0234 break;
0235 case 384:
0236 con |= CON_MCLKDIV_384FS;
0237 break;
0238 case 512:
0239 con |= CON_MCLKDIV_512FS;
0240 break;
0241 }
0242
0243 cstas &= ~CSTAS_SAMP_FREQ_MASK;
0244 switch (params_rate(params)) {
0245 case 44100:
0246 cstas |= CSTAS_SAMP_FREQ_44;
0247 break;
0248 case 48000:
0249 cstas |= CSTAS_SAMP_FREQ_48;
0250 break;
0251 case 32000:
0252 cstas |= CSTAS_SAMP_FREQ_32;
0253 break;
0254 case 96000:
0255 cstas |= CSTAS_SAMP_FREQ_96;
0256 break;
0257 default:
0258 dev_err(spdif->dev, "Invalid sampling rate %d\n",
0259 params_rate(params));
0260 goto err;
0261 }
0262
0263 cstas &= ~CSTAS_CATEGORY_MASK;
0264 cstas |= CSTAS_CATEGORY_CODE_CDP;
0265 cstas |= CSTAS_NO_COPYRIGHT;
0266
0267 writel(con, regs + CON);
0268 writel(cstas, regs + CSTAS);
0269 writel(clkcon, regs + CLKCON);
0270
0271 spin_unlock_irqrestore(&spdif->lock, flags);
0272
0273 return 0;
0274 err:
0275 spin_unlock_irqrestore(&spdif->lock, flags);
0276 return -EINVAL;
0277 }
0278
0279 static void spdif_shutdown(struct snd_pcm_substream *substream,
0280 struct snd_soc_dai *dai)
0281 {
0282 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0283 struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
0284 void __iomem *regs = spdif->regs;
0285 u32 con, clkcon;
0286
0287 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0288
0289 con = readl(regs + CON) & CON_MASK;
0290 clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
0291
0292 writel(con | CON_SW_RESET, regs + CON);
0293 cpu_relax();
0294
0295 writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
0296 }
0297
0298 #ifdef CONFIG_PM
0299 static int spdif_suspend(struct snd_soc_component *component)
0300 {
0301 struct samsung_spdif_info *spdif = component_to_info(component);
0302 u32 con = spdif->saved_con;
0303
0304 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0305
0306 spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
0307 spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
0308 spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
0309
0310 writel(con | CON_SW_RESET, spdif->regs + CON);
0311 cpu_relax();
0312
0313 return 0;
0314 }
0315
0316 static int spdif_resume(struct snd_soc_component *component)
0317 {
0318 struct samsung_spdif_info *spdif = component_to_info(component);
0319
0320 dev_dbg(spdif->dev, "Entered %s\n", __func__);
0321
0322 writel(spdif->saved_clkcon, spdif->regs + CLKCON);
0323 writel(spdif->saved_con, spdif->regs + CON);
0324 writel(spdif->saved_cstas, spdif->regs + CSTAS);
0325
0326 return 0;
0327 }
0328 #else
0329 #define spdif_suspend NULL
0330 #define spdif_resume NULL
0331 #endif
0332
0333 static const struct snd_soc_dai_ops spdif_dai_ops = {
0334 .set_sysclk = spdif_set_sysclk,
0335 .trigger = spdif_trigger,
0336 .hw_params = spdif_hw_params,
0337 .shutdown = spdif_shutdown,
0338 };
0339
0340 static struct snd_soc_dai_driver samsung_spdif_dai = {
0341 .name = "samsung-spdif",
0342 .playback = {
0343 .stream_name = "S/PDIF Playback",
0344 .channels_min = 2,
0345 .channels_max = 2,
0346 .rates = (SNDRV_PCM_RATE_32000 |
0347 SNDRV_PCM_RATE_44100 |
0348 SNDRV_PCM_RATE_48000 |
0349 SNDRV_PCM_RATE_96000),
0350 .formats = SNDRV_PCM_FMTBIT_S16_LE, },
0351 .ops = &spdif_dai_ops,
0352 };
0353
0354 static const struct snd_soc_component_driver samsung_spdif_component = {
0355 .name = "samsung-spdif",
0356 .suspend = spdif_suspend,
0357 .resume = spdif_resume,
0358 .legacy_dai_naming = 1,
0359 };
0360
0361 static int spdif_probe(struct platform_device *pdev)
0362 {
0363 struct s3c_audio_pdata *spdif_pdata;
0364 struct resource *mem_res;
0365 struct samsung_spdif_info *spdif;
0366 dma_filter_fn filter;
0367 int ret;
0368
0369 spdif_pdata = pdev->dev.platform_data;
0370
0371 dev_dbg(&pdev->dev, "Entered %s\n", __func__);
0372
0373 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0374 if (!mem_res) {
0375 dev_err(&pdev->dev, "Unable to get register resource.\n");
0376 return -ENXIO;
0377 }
0378
0379 if (spdif_pdata && spdif_pdata->cfg_gpio
0380 && spdif_pdata->cfg_gpio(pdev)) {
0381 dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
0382 return -EINVAL;
0383 }
0384
0385 spdif = &spdif_info;
0386 spdif->dev = &pdev->dev;
0387
0388 spin_lock_init(&spdif->lock);
0389
0390 spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
0391 if (IS_ERR(spdif->pclk)) {
0392 dev_err(&pdev->dev, "failed to get peri-clock\n");
0393 ret = -ENOENT;
0394 goto err0;
0395 }
0396 ret = clk_prepare_enable(spdif->pclk);
0397 if (ret)
0398 goto err0;
0399
0400 spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
0401 if (IS_ERR(spdif->sclk)) {
0402 dev_err(&pdev->dev, "failed to get internal source clock\n");
0403 ret = -ENOENT;
0404 goto err1;
0405 }
0406 ret = clk_prepare_enable(spdif->sclk);
0407 if (ret)
0408 goto err1;
0409
0410
0411 if (!request_mem_region(mem_res->start,
0412 resource_size(mem_res), "samsung-spdif")) {
0413 dev_err(&pdev->dev, "Unable to request register region\n");
0414 ret = -EBUSY;
0415 goto err2;
0416 }
0417
0418 spdif->regs = ioremap(mem_res->start, 0x100);
0419 if (spdif->regs == NULL) {
0420 dev_err(&pdev->dev, "Cannot ioremap registers\n");
0421 ret = -ENXIO;
0422 goto err3;
0423 }
0424
0425 spdif_stereo_out.addr_width = 2;
0426 spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF;
0427 filter = NULL;
0428 if (spdif_pdata) {
0429 spdif_stereo_out.filter_data = spdif_pdata->dma_playback;
0430 filter = spdif_pdata->dma_filter;
0431 }
0432 spdif->dma_playback = &spdif_stereo_out;
0433
0434 ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
0435 NULL, NULL, NULL);
0436 if (ret) {
0437 dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
0438 goto err4;
0439 }
0440
0441 dev_set_drvdata(&pdev->dev, spdif);
0442
0443 ret = devm_snd_soc_register_component(&pdev->dev,
0444 &samsung_spdif_component, &samsung_spdif_dai, 1);
0445 if (ret != 0) {
0446 dev_err(&pdev->dev, "fail to register dai\n");
0447 goto err4;
0448 }
0449
0450 return 0;
0451 err4:
0452 iounmap(spdif->regs);
0453 err3:
0454 release_mem_region(mem_res->start, resource_size(mem_res));
0455 err2:
0456 clk_disable_unprepare(spdif->sclk);
0457 err1:
0458 clk_disable_unprepare(spdif->pclk);
0459 err0:
0460 return ret;
0461 }
0462
0463 static int spdif_remove(struct platform_device *pdev)
0464 {
0465 struct samsung_spdif_info *spdif = &spdif_info;
0466 struct resource *mem_res;
0467
0468 iounmap(spdif->regs);
0469
0470 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0471 release_mem_region(mem_res->start, resource_size(mem_res));
0472
0473 clk_disable_unprepare(spdif->sclk);
0474 clk_disable_unprepare(spdif->pclk);
0475
0476 return 0;
0477 }
0478
0479 static struct platform_driver samsung_spdif_driver = {
0480 .probe = spdif_probe,
0481 .remove = spdif_remove,
0482 .driver = {
0483 .name = "samsung-spdif",
0484 },
0485 };
0486
0487 module_platform_driver(samsung_spdif_driver);
0488
0489 MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
0490 MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
0491 MODULE_LICENSE("GPL");
0492 MODULE_ALIAS("platform:samsung-spdif");