1
2
3
4
5
6
7
8
9
10#include <linux/clk.h>
11#include <linux/io.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_platform.h>
15#include <linux/platform_device.h>
16#include <sound/pcm_params.h>
17#include <sound/soc.h>
18
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)
23
24#define XLNX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
25
26#define XSPDIF_IRQ_STS_REG 0x20
27#define XSPDIF_IRQ_STS_CH_STS_MASK BIT(5)
28#define XSPDIF_IRQ_ENABLE_REG 0x28
29#define XSPDIF_SOFT_RESET_REG 0x40
30#define XSPDIF_SOFT_RESET_VAL 0xA
31#define XSPDIF_CONTROL_REG 0x44
32#define XSPDIF_CONTROL_ENABLE_MASK BIT(0)
33#define XSPDIF_CONTROL_FIFO_FLUSH_MASK BIT(1)
34#define XSPDIF_CONTROL_CLK_CFG_MASK GENMASK(5, 2)
35#define XSPDIF_CONTROL_CLK_CFG_SHIFT 2
36#define XSPDIF_CHAN_0_STS_REG 0x4C
37#define XSPDIF_GLOBAL_IRQ_REG 0x1C
38#define XSPDIF_GLOBAL_IRQ_ENABLE_MASK BIT(31)
39#define XSPDIF_CH_A_USER_DATA_REG_0 0x64
40
41#define XSPDIF_MAX_CHANNELS 2
42#define XSPDIF_AES_SAMPLE_WIDTH 32
43#define XSPDIF_CH_STS_UPDATE_TIMEOUT 40
44
45enum {
46 CLK_DIV_BY_4,
47 CLK_DIV_BY_8,
48 CLK_DIV_BY_16,
49 CLK_DIV_BY_24,
50 CLK_DIV_BY_32,
51 CLK_DIV_BY_48,
52 CLK_DIV_BY_64,
53};
54
55struct spdif_dev_data {
56 wait_queue_head_t chsts_q;
57 void __iomem *base;
58 struct clk *axi_clk;
59 struct clk *axis_clk;
60 struct clk *aud_clk;
61 u32 mode;
62 unsigned long aclk;
63 bool rx_chsts_updated;
64};
65
66static irqreturn_t xlnx_spdifrx_irq_handler(int irq, void *arg)
67{
68 u32 val;
69 struct spdif_dev_data *ctx = arg;
70
71 val = ioread32(ctx->base + XSPDIF_IRQ_STS_REG);
72 if (val & XSPDIF_IRQ_STS_CH_STS_MASK) {
73 writel(val & XSPDIF_IRQ_STS_CH_STS_MASK,
74 ctx->base + XSPDIF_IRQ_STS_REG);
75 val = ioread32(ctx->base +
76 XSPDIF_IRQ_ENABLE_REG);
77 writel(val & ~XSPDIF_IRQ_STS_CH_STS_MASK,
78 ctx->base + XSPDIF_IRQ_ENABLE_REG);
79
80 ctx->rx_chsts_updated = true;
81 wake_up_interruptible(&ctx->chsts_q);
82 return IRQ_HANDLED;
83 }
84
85 return IRQ_NONE;
86}
87
88static int xlnx_spdif_startup(struct snd_pcm_substream *substream,
89 struct snd_soc_dai *dai)
90{
91 u32 val;
92 struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
93
94 val = ioread32(ctx->base + XSPDIF_CONTROL_REG);
95 val |= XSPDIF_CONTROL_FIFO_FLUSH_MASK;
96 writel(val, ctx->base + XSPDIF_CONTROL_REG);
97
98 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
99 writel(XSPDIF_IRQ_STS_CH_STS_MASK,
100 ctx->base + XSPDIF_IRQ_ENABLE_REG);
101 writel(XSPDIF_GLOBAL_IRQ_ENABLE_MASK,
102 ctx->base + XSPDIF_GLOBAL_IRQ_REG);
103 }
104
105 return 0;
106}
107
108static void xlnx_spdif_shutdown(struct snd_pcm_substream *substream,
109 struct snd_soc_dai *dai)
110{
111 struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
112
113 writel(XSPDIF_SOFT_RESET_VAL, ctx->base + XSPDIF_SOFT_RESET_REG);
114}
115
116static int xlnx_spdif_hw_params(struct snd_pcm_substream *substream,
117 struct snd_pcm_hw_params *params,
118 struct snd_soc_dai *dai)
119{
120 u32 val, clk_div, clk_cfg;
121 struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
122
123 ctx->aclk = clk_get_rate(ctx->aud_clk);
124 clk_div = DIV_ROUND_CLOSEST(ctx->aclk, XSPDIF_MAX_CHANNELS *
125 XSPDIF_AES_SAMPLE_WIDTH *
126 params_rate(params));
127
128 switch (clk_div) {
129 case 4:
130 clk_cfg = CLK_DIV_BY_4;
131 break;
132 case 8:
133 clk_cfg = CLK_DIV_BY_8;
134 break;
135 case 16:
136 clk_cfg = CLK_DIV_BY_16;
137 break;
138 case 24:
139 clk_cfg = CLK_DIV_BY_24;
140 break;
141 case 32:
142 clk_cfg = CLK_DIV_BY_32;
143 break;
144 case 48:
145 clk_cfg = CLK_DIV_BY_48;
146 break;
147 case 64:
148 clk_cfg = CLK_DIV_BY_64;
149 break;
150 default:
151 return -EINVAL;
152 }
153
154 val = ioread32(ctx->base + XSPDIF_CONTROL_REG);
155 val &= ~XSPDIF_CONTROL_CLK_CFG_MASK;
156 val |= clk_cfg << XSPDIF_CONTROL_CLK_CFG_SHIFT;
157 writel(val, ctx->base + XSPDIF_CONTROL_REG);
158
159 return 0;
160}
161
162static int rx_stream_detect(struct snd_soc_dai *dai)
163{
164 int err;
165 struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
166 unsigned long jiffies = msecs_to_jiffies(XSPDIF_CH_STS_UPDATE_TIMEOUT);
167
168
169 err = wait_event_interruptible_timeout(ctx->chsts_q,
170 ctx->rx_chsts_updated,
171 jiffies);
172 if (!err) {
173 dev_err(dai->dev, "No streaming audio detected!\n");
174 return -EINVAL;
175 }
176 ctx->rx_chsts_updated = false;
177
178 return 0;
179}
180
181static int xlnx_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
182 struct snd_soc_dai *dai)
183{
184 u32 val;
185 int ret = 0;
186 struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
187
188 val = ioread32(ctx->base + XSPDIF_CONTROL_REG);
189 switch (cmd) {
190 case SNDRV_PCM_TRIGGER_START:
191 case SNDRV_PCM_TRIGGER_RESUME:
192 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
193 val |= XSPDIF_CONTROL_ENABLE_MASK;
194 writel(val, ctx->base + XSPDIF_CONTROL_REG);
195 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
196 ret = rx_stream_detect(dai);
197 break;
198 case SNDRV_PCM_TRIGGER_STOP:
199 case SNDRV_PCM_TRIGGER_SUSPEND:
200 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
201 val &= ~XSPDIF_CONTROL_ENABLE_MASK;
202 writel(val, ctx->base + XSPDIF_CONTROL_REG);
203 break;
204 default:
205 ret = -EINVAL;
206 }
207
208 return ret;
209}
210
211static const struct snd_soc_dai_ops xlnx_spdif_dai_ops = {
212 .startup = xlnx_spdif_startup,
213 .shutdown = xlnx_spdif_shutdown,
214 .trigger = xlnx_spdif_trigger,
215 .hw_params = xlnx_spdif_hw_params,
216};
217
218static struct snd_soc_dai_driver xlnx_spdif_tx_dai = {
219 .name = "xlnx_spdif_tx",
220 .playback = {
221 .channels_min = 2,
222 .channels_max = 2,
223 .rates = XLNX_SPDIF_RATES,
224 .formats = XLNX_SPDIF_FORMATS,
225 },
226 .ops = &xlnx_spdif_dai_ops,
227};
228
229static struct snd_soc_dai_driver xlnx_spdif_rx_dai = {
230 .name = "xlnx_spdif_rx",
231 .capture = {
232 .channels_min = 2,
233 .channels_max = 2,
234 .rates = XLNX_SPDIF_RATES,
235 .formats = XLNX_SPDIF_FORMATS,
236 },
237 .ops = &xlnx_spdif_dai_ops,
238};
239
240static const struct snd_soc_component_driver xlnx_spdif_component = {
241 .name = "xlnx-spdif",
242};
243
244static const struct of_device_id xlnx_spdif_of_match[] = {
245 { .compatible = "xlnx,spdif-2.0", },
246 {},
247};
248MODULE_DEVICE_TABLE(of, xlnx_spdif_of_match);
249
250static int xlnx_spdif_probe(struct platform_device *pdev)
251{
252 int ret;
253 struct resource *res;
254 struct snd_soc_dai_driver *dai_drv;
255 struct spdif_dev_data *ctx;
256
257 struct device *dev = &pdev->dev;
258 struct device_node *node = dev->of_node;
259
260 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
261 if (!ctx)
262 return -ENOMEM;
263
264 ctx->axi_clk = devm_clk_get(dev, "s_axi_aclk");
265 if (IS_ERR(ctx->axi_clk)) {
266 ret = PTR_ERR(ctx->axi_clk);
267 dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret);
268 return ret;
269 }
270 ret = clk_prepare_enable(ctx->axi_clk);
271 if (ret) {
272 dev_err(dev, "failed to enable s_axi_aclk(%d)\n", ret);
273 return ret;
274 }
275
276 ctx->base = devm_platform_ioremap_resource(pdev, 0);
277 if (IS_ERR(ctx->base)) {
278 ret = PTR_ERR(ctx->base);
279 goto axi_clk_err;
280 }
281 ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode);
282 if (ret < 0) {
283 dev_err(dev, "cannot get SPDIF mode\n");
284 goto axi_clk_err;
285 }
286 if (ctx->mode) {
287 ctx->axis_clk = devm_clk_get(dev, "s_axis_aclk");
288 if (IS_ERR(ctx->axis_clk)) {
289 ret = PTR_ERR(ctx->axis_clk);
290 dev_err(dev, "failed to get s_axis_aclk(%d)\n", ret);
291 goto axi_clk_err;
292 }
293 dai_drv = &xlnx_spdif_tx_dai;
294 } else {
295 ctx->axis_clk = devm_clk_get(dev, "m_axis_aclk");
296 if (IS_ERR(ctx->axis_clk)) {
297 ret = PTR_ERR(ctx->axis_clk);
298 dev_err(dev, "failed to get m_axis_aclk(%d)\n", ret);
299 goto axi_clk_err;
300 }
301
302 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
303 if (!res) {
304 dev_err(dev, "No IRQ resource found\n");
305 ret = -ENODEV;
306 goto axi_clk_err;
307 }
308 ret = devm_request_irq(dev, res->start,
309 xlnx_spdifrx_irq_handler,
310 0, "XLNX_SPDIF_RX", ctx);
311 if (ret) {
312 dev_err(dev, "spdif rx irq request failed\n");
313 ret = -ENODEV;
314 goto axi_clk_err;
315 }
316
317 init_waitqueue_head(&ctx->chsts_q);
318 dai_drv = &xlnx_spdif_rx_dai;
319 }
320
321 ctx->aud_clk = devm_clk_get(dev, "aud_clk_i");
322 if (IS_ERR(ctx->aud_clk)) {
323 ret = PTR_ERR(ctx->aud_clk);
324 dev_err(dev, "failed to get aud_aclk(%d)\n", ret);
325 goto axi_clk_err;
326 }
327
328 ret = clk_prepare_enable(ctx->axis_clk);
329 if (ret) {
330 dev_err(dev, "failed to enable axis_aclk(%d)\n", ret);
331 goto axi_clk_err;
332 }
333
334 ret = clk_prepare_enable(ctx->aud_clk);
335 if (ret) {
336 dev_err(dev, "failed to enable aud_aclk(%d)\n", ret);
337 goto axis_clk_err;
338 }
339
340 dev_set_drvdata(dev, ctx);
341
342 ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component,
343 dai_drv, 1);
344 if (ret) {
345 dev_err(dev, "SPDIF component registration failed\n");
346 goto clk_err;
347 }
348
349 writel(XSPDIF_SOFT_RESET_VAL, ctx->base + XSPDIF_SOFT_RESET_REG);
350 dev_info(dev, "%s DAI registered\n", dai_drv->name);
351 return 0;
352
353clk_err:
354 clk_disable_unprepare(ctx->aud_clk);
355axis_clk_err:
356 clk_disable_unprepare(ctx->axis_clk);
357axi_clk_err:
358 clk_disable_unprepare(ctx->axi_clk);
359
360 return ret;
361}
362
363static int xlnx_spdif_remove(struct platform_device *pdev)
364{
365 struct spdif_dev_data *ctx = dev_get_drvdata(&pdev->dev);
366
367 clk_disable_unprepare(ctx->aud_clk);
368 clk_disable_unprepare(ctx->axis_clk);
369 clk_disable_unprepare(ctx->axi_clk);
370 return 0;
371}
372
373static struct platform_driver xlnx_spdif_driver = {
374 .driver = {
375 .name = "xlnx-spdif",
376 .of_match_table = xlnx_spdif_of_match,
377 },
378 .probe = xlnx_spdif_probe,
379 .remove = xlnx_spdif_remove,
380};
381module_platform_driver(xlnx_spdif_driver);
382
383MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
384MODULE_DESCRIPTION("XILINX SPDIF driver");
385MODULE_LICENSE("GPL v2");
386