2 * ALSA SoC SPDIF In Audio Layer for spear processors
4 * Copyright (C) 2012 ST Microelectronics
5 * Vipin Kumar <vipin.kumar@st.com>
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
18 #include <linux/ioport.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24 #include <sound/spear_dma.h>
25 #include <sound/spear_spdif.h>
26 #include "spdif_in_regs.h"
28 struct spdif_in_params
{
34 struct spear_dma_data dma_params
;
35 struct spdif_in_params saved_params
;
38 void (*reset_perip
)(void);
42 static void spdif_in_configure(struct spdif_in_dev
*host
)
44 u32 ctrl
= SPDIF_IN_PRTYEN
| SPDIF_IN_STATEN
| SPDIF_IN_USREN
|
45 SPDIF_IN_VALEN
| SPDIF_IN_BLKEN
;
46 ctrl
|= SPDIF_MODE_16BIT
| SPDIF_FIFO_THRES_16
;
48 writel(ctrl
, host
->io_base
+ SPDIF_IN_CTRL
);
49 writel(0xF, host
->io_base
+ SPDIF_IN_IRQ_MASK
);
52 static int spdif_in_dai_probe(struct snd_soc_dai
*dai
)
54 struct spdif_in_dev
*host
= snd_soc_dai_get_drvdata(dai
);
56 dai
->capture_dma_data
= &host
->dma_params
;
61 static void spdif_in_shutdown(struct snd_pcm_substream
*substream
,
62 struct snd_soc_dai
*dai
)
64 struct spdif_in_dev
*host
= snd_soc_dai_get_drvdata(dai
);
66 if (substream
->stream
!= SNDRV_PCM_STREAM_CAPTURE
)
69 writel(0x0, host
->io_base
+ SPDIF_IN_IRQ_MASK
);
72 static void spdif_in_format(struct spdif_in_dev
*host
, u32 format
)
74 u32 ctrl
= readl(host
->io_base
+ SPDIF_IN_CTRL
);
77 case SNDRV_PCM_FORMAT_S16_LE
:
78 ctrl
|= SPDIF_XTRACT_16BIT
;
81 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
:
82 ctrl
&= ~SPDIF_XTRACT_16BIT
;
86 writel(ctrl
, host
->io_base
+ SPDIF_IN_CTRL
);
89 static int spdif_in_hw_params(struct snd_pcm_substream
*substream
,
90 struct snd_pcm_hw_params
*params
,
91 struct snd_soc_dai
*dai
)
93 struct spdif_in_dev
*host
= snd_soc_dai_get_drvdata(dai
);
96 if (substream
->stream
!= SNDRV_PCM_STREAM_CAPTURE
)
99 format
= params_format(params
);
100 host
->saved_params
.format
= format
;
105 static int spdif_in_trigger(struct snd_pcm_substream
*substream
, int cmd
,
106 struct snd_soc_dai
*dai
)
108 struct spdif_in_dev
*host
= snd_soc_dai_get_drvdata(dai
);
112 if (substream
->stream
!= SNDRV_PCM_STREAM_CAPTURE
)
116 case SNDRV_PCM_TRIGGER_START
:
117 case SNDRV_PCM_TRIGGER_RESUME
:
118 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
119 clk_enable(host
->clk
);
120 spdif_in_configure(host
);
121 spdif_in_format(host
, host
->saved_params
.format
);
123 ctrl
= readl(host
->io_base
+ SPDIF_IN_CTRL
);
124 ctrl
|= SPDIF_IN_SAMPLE
| SPDIF_IN_ENB
;
125 writel(ctrl
, host
->io_base
+ SPDIF_IN_CTRL
);
126 writel(0xF, host
->io_base
+ SPDIF_IN_IRQ_MASK
);
129 case SNDRV_PCM_TRIGGER_STOP
:
130 case SNDRV_PCM_TRIGGER_SUSPEND
:
131 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
132 ctrl
= readl(host
->io_base
+ SPDIF_IN_CTRL
);
133 ctrl
&= ~(SPDIF_IN_SAMPLE
| SPDIF_IN_ENB
);
134 writel(ctrl
, host
->io_base
+ SPDIF_IN_CTRL
);
135 writel(0x0, host
->io_base
+ SPDIF_IN_IRQ_MASK
);
137 if (host
->reset_perip
)
139 clk_disable(host
->clk
);
149 static struct snd_soc_dai_ops spdif_in_dai_ops
= {
150 .shutdown
= spdif_in_shutdown
,
151 .trigger
= spdif_in_trigger
,
152 .hw_params
= spdif_in_hw_params
,
155 static struct snd_soc_dai_driver spdif_in_dai
= {
156 .probe
= spdif_in_dai_probe
,
160 .rates
= (SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
| \
161 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_96000
| \
162 SNDRV_PCM_RATE_192000
),
163 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| \
164 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
,
166 .ops
= &spdif_in_dai_ops
,
169 static const struct snd_soc_component_driver spdif_in_component
= {
173 static irqreturn_t
spdif_in_irq(int irq
, void *arg
)
175 struct spdif_in_dev
*host
= (struct spdif_in_dev
*)arg
;
177 u32 irq_status
= readl(host
->io_base
+ SPDIF_IN_IRQ
);
182 if (irq_status
& SPDIF_IRQ_FIFOWRITE
)
183 dev_err(host
->dev
, "spdif in: fifo write error");
184 if (irq_status
& SPDIF_IRQ_EMPTYFIFOREAD
)
185 dev_err(host
->dev
, "spdif in: empty fifo read error");
186 if (irq_status
& SPDIF_IRQ_FIFOFULL
)
187 dev_err(host
->dev
, "spdif in: fifo full error");
188 if (irq_status
& SPDIF_IRQ_OUTOFRANGE
)
189 dev_err(host
->dev
, "spdif in: out of range error");
191 writel(0, host
->io_base
+ SPDIF_IN_IRQ
);
196 static int spdif_in_probe(struct platform_device
*pdev
)
198 struct spdif_in_dev
*host
;
199 struct spear_spdif_platform_data
*pdata
;
200 struct resource
*res
, *res_fifo
;
203 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
207 res_fifo
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
211 if (!devm_request_mem_region(&pdev
->dev
, res
->start
,
212 resource_size(res
), pdev
->name
)) {
213 dev_warn(&pdev
->dev
, "Failed to get memory resourse\n");
217 host
= devm_kzalloc(&pdev
->dev
, sizeof(*host
), GFP_KERNEL
);
219 dev_warn(&pdev
->dev
, "kzalloc fail\n");
223 host
->io_base
= devm_ioremap(&pdev
->dev
, res
->start
,
225 if (!host
->io_base
) {
226 dev_warn(&pdev
->dev
, "ioremap failed\n");
230 host
->irq
= platform_get_irq(pdev
, 0);
234 host
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
235 if (IS_ERR(host
->clk
))
236 return PTR_ERR(host
->clk
);
238 pdata
= dev_get_platdata(&pdev
->dev
);
243 host
->dma_params
.data
= pdata
->dma_params
;
244 host
->dma_params
.addr
= res_fifo
->start
;
245 host
->dma_params
.max_burst
= 16;
246 host
->dma_params
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
247 host
->dma_params
.filter
= pdata
->filter
;
248 host
->reset_perip
= pdata
->reset_perip
;
250 host
->dev
= &pdev
->dev
;
251 dev_set_drvdata(&pdev
->dev
, host
);
253 ret
= devm_request_irq(&pdev
->dev
, host
->irq
, spdif_in_irq
, 0,
256 dev_warn(&pdev
->dev
, "request_irq failed\n");
260 return snd_soc_register_component(&pdev
->dev
, &spdif_in_component
,
264 static int spdif_in_remove(struct platform_device
*pdev
)
266 snd_soc_unregister_component(&pdev
->dev
);
271 static struct platform_driver spdif_in_driver
= {
272 .probe
= spdif_in_probe
,
273 .remove
= spdif_in_remove
,
276 .owner
= THIS_MODULE
,
280 module_platform_driver(spdif_in_driver
);
282 MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
283 MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface");
284 MODULE_LICENSE("GPL");
285 MODULE_ALIAS("platform:spdif_in");