1 // SPDX-License-Identifier: GPL-2.0
3 // Xilinx ASoC SPDIF audio support
5 // Copyright (C) 2018 Xilinx, Inc.
7 // Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
10 #include <linux/clk.h>
12 #include <linux/module.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16 #include <sound/pcm_params.h>
17 #include <sound/soc.h>
19 #define XLNX_SPDIF_RATES \
20 (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
21 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
22 SNDRV_PCM_RATE_192000)
24 #define XLNX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
26 #define XSPDIF_IRQ_STS_REG 0x20
27 #define XSPDIF_IRQ_ENABLE_REG 0x28
28 #define XSPDIF_SOFT_RESET_REG 0x40
29 #define XSPDIF_CONTROL_REG 0x44
30 #define XSPDIF_CHAN_0_STS_REG 0x4C
31 #define XSPDIF_GLOBAL_IRQ_ENABLE_REG 0x1C
32 #define XSPDIF_CH_A_USER_DATA_REG_0 0x64
34 #define XSPDIF_CORE_ENABLE_MASK BIT(0)
35 #define XSPDIF_FIFO_FLUSH_MASK BIT(1)
36 #define XSPDIF_CH_STS_MASK BIT(5)
37 #define XSPDIF_GLOBAL_IRQ_ENABLE BIT(31)
38 #define XSPDIF_CLOCK_CONFIG_BITS_MASK GENMASK(5, 2)
39 #define XSPDIF_CLOCK_CONFIG_BITS_SHIFT 2
40 #define XSPDIF_SOFT_RESET_VALUE 0xA
42 #define MAX_CHANNELS 2
43 #define AES_SAMPLE_WIDTH 32
44 #define CH_STATUS_UPDATE_TIMEOUT 40
46 struct spdif_dev_data
{
49 bool rx_chsts_updated
;
52 wait_queue_head_t chsts_q
;
55 static irqreturn_t
xlnx_spdifrx_irq_handler(int irq
, void *arg
)
58 struct spdif_dev_data
*ctx
= arg
;
60 val
= readl(ctx
->base
+ XSPDIF_IRQ_STS_REG
);
61 if (val
& XSPDIF_CH_STS_MASK
) {
62 writel(val
& XSPDIF_CH_STS_MASK
,
63 ctx
->base
+ XSPDIF_IRQ_STS_REG
);
64 val
= readl(ctx
->base
+
65 XSPDIF_IRQ_ENABLE_REG
);
66 writel(val
& ~XSPDIF_CH_STS_MASK
,
67 ctx
->base
+ XSPDIF_IRQ_ENABLE_REG
);
69 ctx
->rx_chsts_updated
= true;
70 wake_up_interruptible(&ctx
->chsts_q
);
77 static int xlnx_spdif_startup(struct snd_pcm_substream
*substream
,
78 struct snd_soc_dai
*dai
)
81 struct spdif_dev_data
*ctx
= dev_get_drvdata(dai
->dev
);
83 val
= readl(ctx
->base
+ XSPDIF_CONTROL_REG
);
84 val
|= XSPDIF_FIFO_FLUSH_MASK
;
85 writel(val
, ctx
->base
+ XSPDIF_CONTROL_REG
);
87 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
88 writel(XSPDIF_CH_STS_MASK
,
89 ctx
->base
+ XSPDIF_IRQ_ENABLE_REG
);
90 writel(XSPDIF_GLOBAL_IRQ_ENABLE
,
91 ctx
->base
+ XSPDIF_GLOBAL_IRQ_ENABLE_REG
);
97 static void xlnx_spdif_shutdown(struct snd_pcm_substream
*substream
,
98 struct snd_soc_dai
*dai
)
100 struct spdif_dev_data
*ctx
= dev_get_drvdata(dai
->dev
);
102 writel(XSPDIF_SOFT_RESET_VALUE
, ctx
->base
+ XSPDIF_SOFT_RESET_REG
);
105 static int xlnx_spdif_hw_params(struct snd_pcm_substream
*substream
,
106 struct snd_pcm_hw_params
*params
,
107 struct snd_soc_dai
*dai
)
109 u32 val
, clk_div
, clk_cfg
;
110 struct spdif_dev_data
*ctx
= dev_get_drvdata(dai
->dev
);
112 clk_div
= DIV_ROUND_CLOSEST(ctx
->aclk
, MAX_CHANNELS
* AES_SAMPLE_WIDTH
*
113 params_rate(params
));
141 val
= readl(ctx
->base
+ XSPDIF_CONTROL_REG
);
142 val
&= ~XSPDIF_CLOCK_CONFIG_BITS_MASK
;
143 val
|= clk_cfg
<< XSPDIF_CLOCK_CONFIG_BITS_SHIFT
;
144 writel(val
, ctx
->base
+ XSPDIF_CONTROL_REG
);
149 static int rx_stream_detect(struct snd_soc_dai
*dai
)
152 struct spdif_dev_data
*ctx
= dev_get_drvdata(dai
->dev
);
153 unsigned long jiffies
= msecs_to_jiffies(CH_STATUS_UPDATE_TIMEOUT
);
155 /* start capture only if stream is detected within 40ms timeout */
156 err
= wait_event_interruptible_timeout(ctx
->chsts_q
,
157 ctx
->rx_chsts_updated
,
160 dev_err(dai
->dev
, "No streaming audio detected!\n");
163 ctx
->rx_chsts_updated
= false;
168 static int xlnx_spdif_trigger(struct snd_pcm_substream
*substream
, int cmd
,
169 struct snd_soc_dai
*dai
)
173 struct spdif_dev_data
*ctx
= dev_get_drvdata(dai
->dev
);
175 val
= readl(ctx
->base
+ XSPDIF_CONTROL_REG
);
177 case SNDRV_PCM_TRIGGER_START
:
178 case SNDRV_PCM_TRIGGER_RESUME
:
179 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
180 val
|= XSPDIF_CORE_ENABLE_MASK
;
181 writel(val
, ctx
->base
+ XSPDIF_CONTROL_REG
);
182 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
183 ret
= rx_stream_detect(dai
);
185 case SNDRV_PCM_TRIGGER_STOP
:
186 case SNDRV_PCM_TRIGGER_SUSPEND
:
187 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
188 val
&= ~XSPDIF_CORE_ENABLE_MASK
;
189 writel(val
, ctx
->base
+ XSPDIF_CONTROL_REG
);
198 static const struct snd_soc_dai_ops xlnx_spdif_dai_ops
= {
199 .startup
= xlnx_spdif_startup
,
200 .shutdown
= xlnx_spdif_shutdown
,
201 .trigger
= xlnx_spdif_trigger
,
202 .hw_params
= xlnx_spdif_hw_params
,
205 static struct snd_soc_dai_driver xlnx_spdif_tx_dai
= {
206 .name
= "xlnx_spdif_tx",
210 .rates
= XLNX_SPDIF_RATES
,
211 .formats
= XLNX_SPDIF_FORMATS
,
213 .ops
= &xlnx_spdif_dai_ops
,
216 static struct snd_soc_dai_driver xlnx_spdif_rx_dai
= {
217 .name
= "xlnx_spdif_rx",
221 .rates
= XLNX_SPDIF_RATES
,
222 .formats
= XLNX_SPDIF_FORMATS
,
224 .ops
= &xlnx_spdif_dai_ops
,
227 static const struct snd_soc_component_driver xlnx_spdif_component
= {
228 .name
= "xlnx-spdif",
229 .legacy_dai_naming
= 1,
232 static const struct of_device_id xlnx_spdif_of_match
[] = {
233 { .compatible
= "xlnx,spdif-2.0", },
236 MODULE_DEVICE_TABLE(of
, xlnx_spdif_of_match
);
238 static int xlnx_spdif_probe(struct platform_device
*pdev
)
241 struct snd_soc_dai_driver
*dai_drv
;
242 struct spdif_dev_data
*ctx
;
244 struct device
*dev
= &pdev
->dev
;
245 struct device_node
*node
= dev
->of_node
;
247 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
251 ctx
->axi_clk
= devm_clk_get(dev
, "s_axi_aclk");
252 if (IS_ERR(ctx
->axi_clk
)) {
253 ret
= PTR_ERR(ctx
->axi_clk
);
254 dev_err(dev
, "failed to get s_axi_aclk(%d)\n", ret
);
257 ret
= clk_prepare_enable(ctx
->axi_clk
);
259 dev_err(dev
, "failed to enable s_axi_aclk(%d)\n", ret
);
263 ctx
->base
= devm_platform_ioremap_resource(pdev
, 0);
264 if (IS_ERR(ctx
->base
)) {
265 ret
= PTR_ERR(ctx
->base
);
268 ret
= of_property_read_u32(node
, "xlnx,spdif-mode", &ctx
->mode
);
270 dev_err(dev
, "cannot get SPDIF mode\n");
274 dai_drv
= &xlnx_spdif_tx_dai
;
276 ret
= platform_get_irq(pdev
, 0);
279 ret
= devm_request_irq(dev
, ret
,
280 xlnx_spdifrx_irq_handler
,
281 0, "XLNX_SPDIF_RX", ctx
);
283 dev_err(dev
, "spdif rx irq request failed\n");
288 init_waitqueue_head(&ctx
->chsts_q
);
289 dai_drv
= &xlnx_spdif_rx_dai
;
292 ret
= of_property_read_u32(node
, "xlnx,aud_clk_i", &ctx
->aclk
);
294 dev_err(dev
, "cannot get aud_clk_i value\n");
298 dev_set_drvdata(dev
, ctx
);
300 ret
= devm_snd_soc_register_component(dev
, &xlnx_spdif_component
,
303 dev_err(dev
, "SPDIF component registration failed\n");
307 writel(XSPDIF_SOFT_RESET_VALUE
, ctx
->base
+ XSPDIF_SOFT_RESET_REG
);
308 dev_info(dev
, "%s DAI registered\n", dai_drv
->name
);
311 clk_disable_unprepare(ctx
->axi_clk
);
315 static void xlnx_spdif_remove(struct platform_device
*pdev
)
317 struct spdif_dev_data
*ctx
= dev_get_drvdata(&pdev
->dev
);
319 clk_disable_unprepare(ctx
->axi_clk
);
322 static struct platform_driver xlnx_spdif_driver
= {
324 .name
= "xlnx-spdif",
325 .of_match_table
= xlnx_spdif_of_match
,
327 .probe
= xlnx_spdif_probe
,
328 .remove
= xlnx_spdif_remove
,
330 module_platform_driver(xlnx_spdif_driver
);
332 MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
333 MODULE_DESCRIPTION("XILINX SPDIF driver");
334 MODULE_LICENSE("GPL v2");