0001
0002
0003
0004
0005
0006
0007
0008
0009
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");