Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * ALSA SoC SPDIF In Audio Layer for spear processors
0003  *
0004  * Copyright (C) 2012 ST Microelectronics
0005  * Vipin Kumar <vipin.kumar@st.com>
0006  *
0007  * This file is licensed under the terms of the GNU General Public
0008  * License version 2. This program is licensed "as is" without any
0009  * warranty of any kind, whether express or implied.
0010  */
0011 
0012 #include <linux/clk.h>
0013 #include <linux/delay.h>
0014 #include <linux/device.h>
0015 #include <linux/kernel.h>
0016 #include <linux/init.h>
0017 #include <linux/io.h>
0018 #include <linux/ioport.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_device.h>
0021 #include <sound/dmaengine_pcm.h>
0022 #include <sound/pcm.h>
0023 #include <sound/pcm_params.h>
0024 #include <sound/soc.h>
0025 #include <sound/spear_dma.h>
0026 #include <sound/spear_spdif.h>
0027 #include "spdif_in_regs.h"
0028 #include "spear_pcm.h"
0029 
0030 struct spdif_in_params {
0031     u32 format;
0032 };
0033 
0034 struct spdif_in_dev {
0035     struct clk *clk;
0036     struct spear_dma_data dma_params;
0037     struct spdif_in_params saved_params;
0038     void *io_base;
0039     struct device *dev;
0040     void (*reset_perip)(void);
0041     int irq;
0042     struct snd_dmaengine_dai_dma_data dma_params_rx;
0043     struct snd_dmaengine_pcm_config config;
0044 };
0045 
0046 static void spdif_in_configure(struct spdif_in_dev *host)
0047 {
0048     u32 ctrl = SPDIF_IN_PRTYEN | SPDIF_IN_STATEN | SPDIF_IN_USREN |
0049         SPDIF_IN_VALEN | SPDIF_IN_BLKEN;
0050     ctrl |= SPDIF_MODE_16BIT | SPDIF_FIFO_THRES_16;
0051 
0052     writel(ctrl, host->io_base + SPDIF_IN_CTRL);
0053     writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
0054 }
0055 
0056 static int spdif_in_dai_probe(struct snd_soc_dai *dai)
0057 {
0058     struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
0059 
0060     host->dma_params_rx.filter_data = &host->dma_params;
0061     dai->capture_dma_data = &host->dma_params_rx;
0062 
0063     return 0;
0064 }
0065 
0066 static void spdif_in_shutdown(struct snd_pcm_substream *substream,
0067         struct snd_soc_dai *dai)
0068 {
0069     struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
0070 
0071     if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
0072         return;
0073 
0074     writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
0075 }
0076 
0077 static void spdif_in_format(struct spdif_in_dev *host, u32 format)
0078 {
0079     u32 ctrl = readl(host->io_base + SPDIF_IN_CTRL);
0080 
0081     switch (format) {
0082     case SNDRV_PCM_FORMAT_S16_LE:
0083         ctrl |= SPDIF_XTRACT_16BIT;
0084         break;
0085 
0086     case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
0087         ctrl &= ~SPDIF_XTRACT_16BIT;
0088         break;
0089     }
0090 
0091     writel(ctrl, host->io_base + SPDIF_IN_CTRL);
0092 }
0093 
0094 static int spdif_in_hw_params(struct snd_pcm_substream *substream,
0095         struct snd_pcm_hw_params *params,
0096         struct snd_soc_dai *dai)
0097 {
0098     struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
0099     u32 format;
0100 
0101     if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
0102         return -EINVAL;
0103 
0104     format = params_format(params);
0105     host->saved_params.format = format;
0106 
0107     return 0;
0108 }
0109 
0110 static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
0111         struct snd_soc_dai *dai)
0112 {
0113     struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
0114     u32 ctrl;
0115     int ret = 0;
0116 
0117     if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
0118         return -EINVAL;
0119 
0120     switch (cmd) {
0121     case SNDRV_PCM_TRIGGER_START:
0122     case SNDRV_PCM_TRIGGER_RESUME:
0123     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0124         clk_enable(host->clk);
0125         spdif_in_configure(host);
0126         spdif_in_format(host, host->saved_params.format);
0127 
0128         ctrl = readl(host->io_base + SPDIF_IN_CTRL);
0129         ctrl |= SPDIF_IN_SAMPLE | SPDIF_IN_ENB;
0130         writel(ctrl, host->io_base + SPDIF_IN_CTRL);
0131         writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
0132         break;
0133 
0134     case SNDRV_PCM_TRIGGER_STOP:
0135     case SNDRV_PCM_TRIGGER_SUSPEND:
0136     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0137         ctrl = readl(host->io_base + SPDIF_IN_CTRL);
0138         ctrl &= ~(SPDIF_IN_SAMPLE | SPDIF_IN_ENB);
0139         writel(ctrl, host->io_base + SPDIF_IN_CTRL);
0140         writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
0141 
0142         if (host->reset_perip)
0143             host->reset_perip();
0144         clk_disable(host->clk);
0145         break;
0146 
0147     default:
0148         ret = -EINVAL;
0149         break;
0150     }
0151     return ret;
0152 }
0153 
0154 static const struct snd_soc_dai_ops spdif_in_dai_ops = {
0155     .shutdown   = spdif_in_shutdown,
0156     .trigger    = spdif_in_trigger,
0157     .hw_params  = spdif_in_hw_params,
0158 };
0159 
0160 static struct snd_soc_dai_driver spdif_in_dai = {
0161     .probe = spdif_in_dai_probe,
0162     .capture = {
0163         .channels_min = 2,
0164         .channels_max = 2,
0165         .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
0166                  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
0167                  SNDRV_PCM_RATE_192000),
0168         .formats = SNDRV_PCM_FMTBIT_S16_LE | \
0169                SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
0170     },
0171     .ops = &spdif_in_dai_ops,
0172 };
0173 
0174 static const struct snd_soc_component_driver spdif_in_component = {
0175     .name           = "spdif-in",
0176     .legacy_dai_naming  = 1,
0177 };
0178 
0179 static irqreturn_t spdif_in_irq(int irq, void *arg)
0180 {
0181     struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
0182 
0183     u32 irq_status = readl(host->io_base + SPDIF_IN_IRQ);
0184 
0185     if (!irq_status)
0186         return IRQ_NONE;
0187 
0188     if (irq_status & SPDIF_IRQ_FIFOWRITE)
0189         dev_err(host->dev, "spdif in: fifo write error");
0190     if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD)
0191         dev_err(host->dev, "spdif in: empty fifo read error");
0192     if (irq_status & SPDIF_IRQ_FIFOFULL)
0193         dev_err(host->dev, "spdif in: fifo full error");
0194     if (irq_status & SPDIF_IRQ_OUTOFRANGE)
0195         dev_err(host->dev, "spdif in: out of range error");
0196 
0197     writel(0, host->io_base + SPDIF_IN_IRQ);
0198 
0199     return IRQ_HANDLED;
0200 }
0201 
0202 static int spdif_in_probe(struct platform_device *pdev)
0203 {
0204     struct spdif_in_dev *host;
0205     struct spear_spdif_platform_data *pdata;
0206     struct resource *res_fifo;
0207     void __iomem *io_base;
0208     int ret;
0209 
0210     io_base = devm_platform_ioremap_resource(pdev, 0);
0211     if (IS_ERR(io_base))
0212         return PTR_ERR(io_base);
0213 
0214     res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0);
0215     if (!res_fifo)
0216         return -EINVAL;
0217 
0218     host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
0219     if (!host)
0220         return -ENOMEM;
0221 
0222     host->io_base = io_base;
0223     host->irq = platform_get_irq(pdev, 0);
0224     if (host->irq < 0) {
0225         dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq);
0226         return host->irq;
0227     }
0228 
0229     host->clk = devm_clk_get(&pdev->dev, NULL);
0230     if (IS_ERR(host->clk))
0231         return PTR_ERR(host->clk);
0232 
0233     pdata = dev_get_platdata(&pdev->dev);
0234 
0235     if (!pdata)
0236         return -EINVAL;
0237 
0238     host->dma_params.data = pdata->dma_params;
0239     host->dma_params.addr = res_fifo->start;
0240     host->dma_params.max_burst = 16;
0241     host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0242     host->reset_perip = pdata->reset_perip;
0243 
0244     host->dev = &pdev->dev;
0245     dev_set_drvdata(&pdev->dev, host);
0246 
0247     ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
0248             "spdif-in", host);
0249     if (ret) {
0250         dev_warn(&pdev->dev, "request_irq failed\n");
0251         return ret;
0252     }
0253 
0254     ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
0255                           &spdif_in_dai, 1);
0256     if (ret)
0257         return ret;
0258 
0259     return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
0260                         pdata->filter);
0261 }
0262 
0263 static struct platform_driver spdif_in_driver = {
0264     .probe      = spdif_in_probe,
0265     .driver     = {
0266         .name   = "spdif-in",
0267     },
0268 };
0269 
0270 module_platform_driver(spdif_in_driver);
0271 
0272 MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
0273 MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface");
0274 MODULE_LICENSE("GPL");
0275 MODULE_ALIAS("platform:spdif_in");