GNU Linux-libre 4.9.337-gnu1
[releases.git] / sound / soc / sunxi / sun4i-spdif.c
1 /*
2  * ALSA SoC SPDIF Audio Layer
3  *
4  * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
5  * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
6  *
7  * Based on the Allwinner SDK driver, released under the GPL.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19
20 #include <linux/clk.h>
21 #include <linux/delay.h>
22 #include <linux/device.h>
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25 #include <linux/regmap.h>
26 #include <linux/of_address.h>
27 #include <linux/of_device.h>
28 #include <linux/ioport.h>
29 #include <linux/module.h>
30 #include <linux/platform_device.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/reset.h>
33 #include <sound/dmaengine_pcm.h>
34 #include <sound/pcm_params.h>
35 #include <sound/soc.h>
36
37 #define SUN4I_SPDIF_CTL         (0x00)
38         #define SUN4I_SPDIF_CTL_MCLKDIV(v)              ((v) << 4) /* v even */
39         #define SUN4I_SPDIF_CTL_MCLKOUTEN               BIT(2)
40         #define SUN4I_SPDIF_CTL_GEN                     BIT(1)
41         #define SUN4I_SPDIF_CTL_RESET                   BIT(0)
42
43 #define SUN4I_SPDIF_TXCFG       (0x04)
44         #define SUN4I_SPDIF_TXCFG_SINGLEMOD             BIT(31)
45         #define SUN4I_SPDIF_TXCFG_ASS                   BIT(17)
46         #define SUN4I_SPDIF_TXCFG_NONAUDIO              BIT(16)
47         #define SUN4I_SPDIF_TXCFG_TXRATIO(v)            ((v) << 4)
48         #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK          GENMASK(8, 4)
49         #define SUN4I_SPDIF_TXCFG_FMTRVD                GENMASK(3, 2)
50         #define SUN4I_SPDIF_TXCFG_FMT16BIT              (0 << 2)
51         #define SUN4I_SPDIF_TXCFG_FMT20BIT              (1 << 2)
52         #define SUN4I_SPDIF_TXCFG_FMT24BIT              (2 << 2)
53         #define SUN4I_SPDIF_TXCFG_CHSTMODE              BIT(1)
54         #define SUN4I_SPDIF_TXCFG_TXEN                  BIT(0)
55
56 #define SUN4I_SPDIF_RXCFG       (0x08)
57         #define SUN4I_SPDIF_RXCFG_LOCKFLAG              BIT(4)
58         #define SUN4I_SPDIF_RXCFG_CHSTSRC               BIT(3)
59         #define SUN4I_SPDIF_RXCFG_CHSTCP                BIT(1)
60         #define SUN4I_SPDIF_RXCFG_RXEN                  BIT(0)
61
62 #define SUN4I_SPDIF_TXFIFO      (0x0C)
63
64 #define SUN4I_SPDIF_RXFIFO      (0x10)
65
66 #define SUN4I_SPDIF_FCTL        (0x14)
67         #define SUN4I_SPDIF_FCTL_FIFOSRC                BIT(31)
68         #define SUN4I_SPDIF_FCTL_FTX                    BIT(17)
69         #define SUN4I_SPDIF_FCTL_FRX                    BIT(16)
70         #define SUN4I_SPDIF_FCTL_TXTL(v)                ((v) << 8)
71         #define SUN4I_SPDIF_FCTL_TXTL_MASK              GENMASK(12, 8)
72         #define SUN4I_SPDIF_FCTL_RXTL(v)                ((v) << 3)
73         #define SUN4I_SPDIF_FCTL_RXTL_MASK              GENMASK(7, 3)
74         #define SUN4I_SPDIF_FCTL_TXIM                   BIT(2)
75         #define SUN4I_SPDIF_FCTL_RXOM(v)                ((v) << 0)
76         #define SUN4I_SPDIF_FCTL_RXOM_MASK              GENMASK(1, 0)
77
78 #define SUN4I_SPDIF_FSTA        (0x18)
79         #define SUN4I_SPDIF_FSTA_TXE                    BIT(14)
80         #define SUN4I_SPDIF_FSTA_TXECNTSHT              (8)
81         #define SUN4I_SPDIF_FSTA_RXA                    BIT(6)
82         #define SUN4I_SPDIF_FSTA_RXACNTSHT              (0)
83
84 #define SUN4I_SPDIF_INT         (0x1C)
85         #define SUN4I_SPDIF_INT_RXLOCKEN                BIT(18)
86         #define SUN4I_SPDIF_INT_RXUNLOCKEN              BIT(17)
87         #define SUN4I_SPDIF_INT_RXPARERREN              BIT(16)
88         #define SUN4I_SPDIF_INT_TXDRQEN                 BIT(7)
89         #define SUN4I_SPDIF_INT_TXUIEN                  BIT(6)
90         #define SUN4I_SPDIF_INT_TXOIEN                  BIT(5)
91         #define SUN4I_SPDIF_INT_TXEIEN                  BIT(4)
92         #define SUN4I_SPDIF_INT_RXDRQEN                 BIT(2)
93         #define SUN4I_SPDIF_INT_RXOIEN                  BIT(1)
94         #define SUN4I_SPDIF_INT_RXAIEN                  BIT(0)
95
96 #define SUN4I_SPDIF_ISTA        (0x20)
97         #define SUN4I_SPDIF_ISTA_RXLOCKSTA              BIT(18)
98         #define SUN4I_SPDIF_ISTA_RXUNLOCKSTA            BIT(17)
99         #define SUN4I_SPDIF_ISTA_RXPARERRSTA            BIT(16)
100         #define SUN4I_SPDIF_ISTA_TXUSTA                 BIT(6)
101         #define SUN4I_SPDIF_ISTA_TXOSTA                 BIT(5)
102         #define SUN4I_SPDIF_ISTA_TXESTA                 BIT(4)
103         #define SUN4I_SPDIF_ISTA_RXOSTA                 BIT(1)
104         #define SUN4I_SPDIF_ISTA_RXASTA                 BIT(0)
105
106 #define SUN4I_SPDIF_TXCNT       (0x24)
107
108 #define SUN4I_SPDIF_RXCNT       (0x28)
109
110 #define SUN4I_SPDIF_TXCHSTA0    (0x2C)
111         #define SUN4I_SPDIF_TXCHSTA0_CLK(v)             ((v) << 28)
112         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)         ((v) << 24)
113         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK       GENMASK(27, 24)
114         #define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)           ((v) << 20)
115         #define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK         GENMASK(23, 20)
116         #define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)          ((v) << 16)
117         #define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)         ((v) << 8)
118         #define SUN4I_SPDIF_TXCHSTA0_MODE(v)            ((v) << 6)
119         #define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)        ((v) << 3)
120         #define SUN4I_SPDIF_TXCHSTA0_CP                 BIT(2)
121         #define SUN4I_SPDIF_TXCHSTA0_AUDIO              BIT(1)
122         #define SUN4I_SPDIF_TXCHSTA0_PRO                BIT(0)
123
124 #define SUN4I_SPDIF_TXCHSTA1    (0x30)
125         #define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)           ((v) << 8)
126         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
127         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK    GENMASK(7, 4)
128         #define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
129         #define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN         BIT(0)
130
131 #define SUN4I_SPDIF_RXCHSTA0    (0x34)
132         #define SUN4I_SPDIF_RXCHSTA0_CLK(v)             ((v) << 28)
133         #define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)         ((v) << 24)
134         #define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)           ((v) << 20)
135         #define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)          ((v) << 16)
136         #define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)         ((v) << 8)
137         #define SUN4I_SPDIF_RXCHSTA0_MODE(v)            ((v) << 6)
138         #define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)        ((v) << 3)
139         #define SUN4I_SPDIF_RXCHSTA0_CP                 BIT(2)
140         #define SUN4I_SPDIF_RXCHSTA0_AUDIO              BIT(1)
141         #define SUN4I_SPDIF_RXCHSTA0_PRO                BIT(0)
142
143 #define SUN4I_SPDIF_RXCHSTA1    (0x38)
144         #define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)           ((v) << 8)
145         #define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
146         #define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
147         #define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN         BIT(0)
148
149 /* Defines for Sampling Frequency */
150 #define SUN4I_SPDIF_SAMFREQ_44_1KHZ             0x0
151 #define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED       0x1
152 #define SUN4I_SPDIF_SAMFREQ_48KHZ               0x2
153 #define SUN4I_SPDIF_SAMFREQ_32KHZ               0x3
154 #define SUN4I_SPDIF_SAMFREQ_22_05KHZ            0x4
155 #define SUN4I_SPDIF_SAMFREQ_24KHZ               0x6
156 #define SUN4I_SPDIF_SAMFREQ_88_2KHZ             0x8
157 #define SUN4I_SPDIF_SAMFREQ_76_8KHZ             0x9
158 #define SUN4I_SPDIF_SAMFREQ_96KHZ               0xa
159 #define SUN4I_SPDIF_SAMFREQ_176_4KHZ            0xc
160 #define SUN4I_SPDIF_SAMFREQ_192KHZ              0xe
161
162 struct sun4i_spdif_dev {
163         struct platform_device *pdev;
164         struct clk *spdif_clk;
165         struct clk *apb_clk;
166         struct reset_control *rst;
167         struct snd_soc_dai_driver cpu_dai_drv;
168         struct regmap *regmap;
169         struct snd_dmaengine_dai_dma_data dma_params_tx;
170 };
171
172 static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
173 {
174         /* soft reset SPDIF */
175         regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
176
177         /* flush TX FIFO */
178         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
179                            SUN4I_SPDIF_FCTL_FTX, SUN4I_SPDIF_FCTL_FTX);
180
181         /* clear TX counter */
182         regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
183 }
184
185 static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
186                                 struct sun4i_spdif_dev *host)
187 {
188         if (substream->runtime->channels == 1)
189                 regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
190                                    SUN4I_SPDIF_TXCFG_SINGLEMOD,
191                                    SUN4I_SPDIF_TXCFG_SINGLEMOD);
192
193         /* SPDIF TX ENABLE */
194         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
195                            SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
196
197         /* DRQ ENABLE */
198         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
199                            SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
200
201         /* Global enable */
202         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
203                            SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
204 }
205
206 static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
207                                  struct sun4i_spdif_dev *host)
208 {
209         /* SPDIF TX DISABLE */
210         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
211                            SUN4I_SPDIF_TXCFG_TXEN, 0);
212
213         /* DRQ DISABLE */
214         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
215                            SUN4I_SPDIF_INT_TXDRQEN, 0);
216
217         /* Global disable */
218         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
219                            SUN4I_SPDIF_CTL_GEN, 0);
220 }
221
222 static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
223                                struct snd_soc_dai *cpu_dai)
224 {
225         struct snd_soc_pcm_runtime *rtd = substream->private_data;
226         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(rtd->cpu_dai);
227
228         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
229                 return -EINVAL;
230
231         sun4i_spdif_configure(host);
232
233         return 0;
234 }
235
236 static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
237                                  struct snd_pcm_hw_params *params,
238                                  struct snd_soc_dai *cpu_dai)
239 {
240         int ret = 0;
241         int fmt;
242         unsigned long rate = params_rate(params);
243         u32 mclk_div = 0;
244         unsigned int mclk = 0;
245         u32 reg_val;
246         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
247         struct platform_device *pdev = host->pdev;
248
249         /* Add the PCM and raw data select interface */
250         switch (params_channels(params)) {
251         case 1: /* PCM mode */
252         case 2:
253                 fmt = 0;
254                 break;
255         case 4: /* raw data mode */
256                 fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
257                 break;
258         default:
259                 return -EINVAL;
260         }
261
262         switch (params_format(params)) {
263         case SNDRV_PCM_FORMAT_S16_LE:
264                 fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
265                 break;
266         case SNDRV_PCM_FORMAT_S20_3LE:
267                 fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
268                 break;
269         case SNDRV_PCM_FORMAT_S24_LE:
270                 fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
271                 break;
272         default:
273                 return -EINVAL;
274         }
275
276         switch (rate) {
277         case 22050:
278         case 44100:
279         case 88200:
280         case 176400:
281                 mclk = 22579200;
282                 break;
283         case 24000:
284         case 32000:
285         case 48000:
286         case 96000:
287         case 192000:
288                 mclk = 24576000;
289                 break;
290         default:
291                 return -EINVAL;
292         }
293
294         ret = clk_set_rate(host->spdif_clk, mclk);
295         if (ret < 0) {
296                 dev_err(&pdev->dev,
297                         "Setting SPDIF clock rate for %d Hz failed!\n", mclk);
298                 return ret;
299         }
300
301         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
302                            SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
303
304         switch (rate) {
305         case 22050:
306         case 24000:
307                 mclk_div = 8;
308                 break;
309         case 32000:
310                 mclk_div = 6;
311                 break;
312         case 44100:
313         case 48000:
314                 mclk_div = 4;
315                 break;
316         case 88200:
317         case 96000:
318                 mclk_div = 2;
319                 break;
320         case 176400:
321         case 192000:
322                 mclk_div = 1;
323                 break;
324         default:
325                 return -EINVAL;
326         }
327
328         reg_val = 0;
329         reg_val |= SUN4I_SPDIF_TXCFG_ASS;
330         reg_val |= fmt; /* set non audio and bit depth */
331         reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
332         reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
333         regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
334
335         return 0;
336 }
337
338 static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
339                                struct snd_soc_dai *dai)
340 {
341         int ret = 0;
342         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
343
344         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
345                 return -EINVAL;
346
347         switch (cmd) {
348         case SNDRV_PCM_TRIGGER_START:
349         case SNDRV_PCM_TRIGGER_RESUME:
350         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
351                 sun4i_snd_txctrl_on(substream, host);
352                 break;
353
354         case SNDRV_PCM_TRIGGER_STOP:
355         case SNDRV_PCM_TRIGGER_SUSPEND:
356         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
357                 sun4i_snd_txctrl_off(substream, host);
358                 break;
359
360         default:
361                 ret = -EINVAL;
362                 break;
363         }
364         return ret;
365 }
366
367 static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
368 {
369         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
370
371         snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
372         return 0;
373 }
374
375 static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
376         .startup        = sun4i_spdif_startup,
377         .trigger        = sun4i_spdif_trigger,
378         .hw_params      = sun4i_spdif_hw_params,
379 };
380
381 static const struct regmap_config sun4i_spdif_regmap_config = {
382         .reg_bits = 32,
383         .reg_stride = 4,
384         .val_bits = 32,
385         .max_register = SUN4I_SPDIF_RXCHSTA1,
386 };
387
388 #define SUN4I_RATES     SNDRV_PCM_RATE_8000_192000
389
390 #define SUN4I_FORMATS   (SNDRV_PCM_FORMAT_S16_LE | \
391                                 SNDRV_PCM_FORMAT_S20_3LE | \
392                                 SNDRV_PCM_FORMAT_S24_LE)
393
394 static struct snd_soc_dai_driver sun4i_spdif_dai = {
395         .playback = {
396                 .channels_min = 1,
397                 .channels_max = 2,
398                 .rates = SUN4I_RATES,
399                 .formats = SUN4I_FORMATS,
400         },
401         .probe = sun4i_spdif_soc_dai_probe,
402         .ops = &sun4i_spdif_dai_ops,
403         .name = "spdif",
404 };
405
406 static const struct of_device_id sun4i_spdif_of_match[] = {
407         { .compatible = "allwinner,sun4i-a10-spdif", },
408         { .compatible = "allwinner,sun6i-a31-spdif", },
409         { /* sentinel */ }
410 };
411 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
412
413 static const struct snd_soc_component_driver sun4i_spdif_component = {
414         .name           = "sun4i-spdif",
415 };
416
417 static int sun4i_spdif_runtime_suspend(struct device *dev)
418 {
419         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
420
421         clk_disable_unprepare(host->spdif_clk);
422         clk_disable_unprepare(host->apb_clk);
423
424         return 0;
425 }
426
427 static int sun4i_spdif_runtime_resume(struct device *dev)
428 {
429         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
430
431         clk_prepare_enable(host->spdif_clk);
432         clk_prepare_enable(host->apb_clk);
433
434         return 0;
435 }
436
437 static int sun4i_spdif_probe(struct platform_device *pdev)
438 {
439         struct sun4i_spdif_dev *host;
440         struct resource *res;
441         int ret;
442         void __iomem *base;
443
444         dev_dbg(&pdev->dev, "Entered %s\n", __func__);
445
446         host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
447         if (!host)
448                 return -ENOMEM;
449
450         host->pdev = pdev;
451
452         /* Initialize this copy of the CPU DAI driver structure */
453         memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
454         host->cpu_dai_drv.name = dev_name(&pdev->dev);
455
456         /* Get the addresses */
457         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
458         base = devm_ioremap_resource(&pdev->dev, res);
459         if (IS_ERR(base))
460                 return PTR_ERR(base);
461
462         host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
463                                                 &sun4i_spdif_regmap_config);
464
465         /* Clocks */
466         host->apb_clk = devm_clk_get(&pdev->dev, "apb");
467         if (IS_ERR(host->apb_clk)) {
468                 dev_err(&pdev->dev, "failed to get a apb clock.\n");
469                 return PTR_ERR(host->apb_clk);
470         }
471
472         host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
473         if (IS_ERR(host->spdif_clk)) {
474                 dev_err(&pdev->dev, "failed to get a spdif clock.\n");
475                 ret = PTR_ERR(host->spdif_clk);
476                 goto err_disable_apb_clk;
477         }
478
479         host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO;
480         host->dma_params_tx.maxburst = 8;
481         host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
482
483         platform_set_drvdata(pdev, host);
484
485         if (of_device_is_compatible(pdev->dev.of_node,
486                                     "allwinner,sun6i-a31-spdif")) {
487                 host->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
488                 if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
489                         ret = -EPROBE_DEFER;
490                         dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
491                         goto err_disable_apb_clk;
492                 }
493                 if (!IS_ERR(host->rst))
494                         reset_control_deassert(host->rst);
495         }
496
497         ret = devm_snd_soc_register_component(&pdev->dev,
498                                 &sun4i_spdif_component, &sun4i_spdif_dai, 1);
499         if (ret)
500                 goto err_disable_apb_clk;
501
502         pm_runtime_enable(&pdev->dev);
503         if (!pm_runtime_enabled(&pdev->dev)) {
504                 ret = sun4i_spdif_runtime_resume(&pdev->dev);
505                 if (ret)
506                         goto err_unregister;
507         }
508
509         ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
510         if (ret)
511                 goto err_suspend;
512         return 0;
513 err_suspend:
514         if (!pm_runtime_status_suspended(&pdev->dev))
515                 sun4i_spdif_runtime_suspend(&pdev->dev);
516 err_unregister:
517         pm_runtime_disable(&pdev->dev);
518         snd_soc_unregister_component(&pdev->dev);
519 err_disable_apb_clk:
520         clk_disable_unprepare(host->apb_clk);
521         return ret;
522 }
523
524 static int sun4i_spdif_remove(struct platform_device *pdev)
525 {
526         pm_runtime_disable(&pdev->dev);
527         if (!pm_runtime_status_suspended(&pdev->dev))
528                 sun4i_spdif_runtime_suspend(&pdev->dev);
529
530         snd_soc_unregister_platform(&pdev->dev);
531         snd_soc_unregister_component(&pdev->dev);
532
533         return 0;
534 }
535
536 static const struct dev_pm_ops sun4i_spdif_pm = {
537         SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
538                            sun4i_spdif_runtime_resume, NULL)
539 };
540
541 static struct platform_driver sun4i_spdif_driver = {
542         .driver         = {
543                 .name   = "sun4i-spdif",
544                 .of_match_table = of_match_ptr(sun4i_spdif_of_match),
545                 .pm     = &sun4i_spdif_pm,
546         },
547         .probe          = sun4i_spdif_probe,
548         .remove         = sun4i_spdif_remove,
549 };
550
551 module_platform_driver(sun4i_spdif_driver);
552
553 MODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
554 MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
555 MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
556 MODULE_LICENSE("GPL");
557 MODULE_ALIAS("platform:sun4i-spdif");