Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
0004 //
0005 // Copyright (c) 2010 Samsung Electronics Co. Ltd
0006 //      http://www.samsung.com/
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 /* Registers */
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  * struct samsung_spdif_info - Samsung S/PDIF Controller information
0067  * @lock: Spin lock for S/PDIF.
0068  * @dev: The parent device passed to use from the probe.
0069  * @regs: The pointer to the device register block.
0070  * @clk_rate: Current clock rate for calcurate ratio.
0071  * @pclk: The peri-clock pointer for spdif master operation.
0072  * @sclk: The source clock pointer for making sync signals.
0073  * @saved_clkcon: Backup clkcon reg. in suspend.
0074  * @saved_con: Backup con reg. in suspend.
0075  * @saved_cstas: Backup cstas reg. in suspend.
0076  * @dma_playback: DMA information for playback channel.
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     /* Request S/PDIF Register's memory region */
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");