Mention branches and keyring.
[releases.git] / sunxi / sun4i-spdif.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * ALSA SoC SPDIF Audio Layer
4  *
5  * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
6  * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
7  *
8  * Based on the Allwinner SDK driver, released under the GPL.
9  */
10
11 #include <linux/clk.h>
12 #include <linux/delay.h>
13 #include <linux/device.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/regmap.h>
17 #include <linux/of_address.h>
18 #include <linux/of_device.h>
19 #include <linux/ioport.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/reset.h>
24 #include <linux/spinlock.h>
25 #include <sound/asoundef.h>
26 #include <sound/dmaengine_pcm.h>
27 #include <sound/pcm_params.h>
28 #include <sound/soc.h>
29
30 #define SUN4I_SPDIF_CTL         (0x00)
31         #define SUN4I_SPDIF_CTL_MCLKDIV(v)              ((v) << 4) /* v even */
32         #define SUN4I_SPDIF_CTL_MCLKOUTEN               BIT(2)
33         #define SUN4I_SPDIF_CTL_GEN                     BIT(1)
34         #define SUN4I_SPDIF_CTL_RESET                   BIT(0)
35
36 #define SUN4I_SPDIF_TXCFG       (0x04)
37         #define SUN4I_SPDIF_TXCFG_SINGLEMOD             BIT(31)
38         #define SUN4I_SPDIF_TXCFG_ASS                   BIT(17)
39         #define SUN4I_SPDIF_TXCFG_NONAUDIO              BIT(16)
40         #define SUN4I_SPDIF_TXCFG_TXRATIO(v)            ((v) << 4)
41         #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK          GENMASK(8, 4)
42         #define SUN4I_SPDIF_TXCFG_FMTRVD                GENMASK(3, 2)
43         #define SUN4I_SPDIF_TXCFG_FMT16BIT              (0 << 2)
44         #define SUN4I_SPDIF_TXCFG_FMT20BIT              (1 << 2)
45         #define SUN4I_SPDIF_TXCFG_FMT24BIT              (2 << 2)
46         #define SUN4I_SPDIF_TXCFG_CHSTMODE              BIT(1)
47         #define SUN4I_SPDIF_TXCFG_TXEN                  BIT(0)
48
49 #define SUN4I_SPDIF_RXCFG       (0x08)
50         #define SUN4I_SPDIF_RXCFG_LOCKFLAG              BIT(4)
51         #define SUN4I_SPDIF_RXCFG_CHSTSRC               BIT(3)
52         #define SUN4I_SPDIF_RXCFG_CHSTCP                BIT(1)
53         #define SUN4I_SPDIF_RXCFG_RXEN                  BIT(0)
54
55 #define SUN4I_SPDIF_TXFIFO      (0x0C)
56
57 #define SUN4I_SPDIF_RXFIFO      (0x10)
58
59 #define SUN4I_SPDIF_FCTL        (0x14)
60         #define SUN4I_SPDIF_FCTL_FIFOSRC                BIT(31)
61         #define SUN4I_SPDIF_FCTL_FTX                    BIT(17)
62         #define SUN4I_SPDIF_FCTL_FRX                    BIT(16)
63         #define SUN4I_SPDIF_FCTL_TXTL(v)                ((v) << 8)
64         #define SUN4I_SPDIF_FCTL_TXTL_MASK              GENMASK(12, 8)
65         #define SUN4I_SPDIF_FCTL_RXTL(v)                ((v) << 3)
66         #define SUN4I_SPDIF_FCTL_RXTL_MASK              GENMASK(7, 3)
67         #define SUN4I_SPDIF_FCTL_TXIM                   BIT(2)
68         #define SUN4I_SPDIF_FCTL_RXOM(v)                ((v) << 0)
69         #define SUN4I_SPDIF_FCTL_RXOM_MASK              GENMASK(1, 0)
70
71 #define SUN50I_H6_SPDIF_FCTL (0x14)
72         #define SUN50I_H6_SPDIF_FCTL_HUB_EN             BIT(31)
73         #define SUN50I_H6_SPDIF_FCTL_FTX                BIT(30)
74         #define SUN50I_H6_SPDIF_FCTL_FRX                BIT(29)
75         #define SUN50I_H6_SPDIF_FCTL_TXTL(v)            ((v) << 12)
76         #define SUN50I_H6_SPDIF_FCTL_TXTL_MASK          GENMASK(19, 12)
77         #define SUN50I_H6_SPDIF_FCTL_RXTL(v)            ((v) << 4)
78         #define SUN50I_H6_SPDIF_FCTL_RXTL_MASK          GENMASK(10, 4)
79         #define SUN50I_H6_SPDIF_FCTL_TXIM               BIT(2)
80         #define SUN50I_H6_SPDIF_FCTL_RXOM(v)            ((v) << 0)
81         #define SUN50I_H6_SPDIF_FCTL_RXOM_MASK          GENMASK(1, 0)
82
83 #define SUN4I_SPDIF_FSTA        (0x18)
84         #define SUN4I_SPDIF_FSTA_TXE                    BIT(14)
85         #define SUN4I_SPDIF_FSTA_TXECNTSHT              (8)
86         #define SUN4I_SPDIF_FSTA_RXA                    BIT(6)
87         #define SUN4I_SPDIF_FSTA_RXACNTSHT              (0)
88
89 #define SUN4I_SPDIF_INT         (0x1C)
90         #define SUN4I_SPDIF_INT_RXLOCKEN                BIT(18)
91         #define SUN4I_SPDIF_INT_RXUNLOCKEN              BIT(17)
92         #define SUN4I_SPDIF_INT_RXPARERREN              BIT(16)
93         #define SUN4I_SPDIF_INT_TXDRQEN                 BIT(7)
94         #define SUN4I_SPDIF_INT_TXUIEN                  BIT(6)
95         #define SUN4I_SPDIF_INT_TXOIEN                  BIT(5)
96         #define SUN4I_SPDIF_INT_TXEIEN                  BIT(4)
97         #define SUN4I_SPDIF_INT_RXDRQEN                 BIT(2)
98         #define SUN4I_SPDIF_INT_RXOIEN                  BIT(1)
99         #define SUN4I_SPDIF_INT_RXAIEN                  BIT(0)
100
101 #define SUN4I_SPDIF_ISTA        (0x20)
102         #define SUN4I_SPDIF_ISTA_RXLOCKSTA              BIT(18)
103         #define SUN4I_SPDIF_ISTA_RXUNLOCKSTA            BIT(17)
104         #define SUN4I_SPDIF_ISTA_RXPARERRSTA            BIT(16)
105         #define SUN4I_SPDIF_ISTA_TXUSTA                 BIT(6)
106         #define SUN4I_SPDIF_ISTA_TXOSTA                 BIT(5)
107         #define SUN4I_SPDIF_ISTA_TXESTA                 BIT(4)
108         #define SUN4I_SPDIF_ISTA_RXOSTA                 BIT(1)
109         #define SUN4I_SPDIF_ISTA_RXASTA                 BIT(0)
110
111 #define SUN8I_SPDIF_TXFIFO      (0x20)
112
113 #define SUN4I_SPDIF_TXCNT       (0x24)
114
115 #define SUN4I_SPDIF_RXCNT       (0x28)
116
117 #define SUN4I_SPDIF_TXCHSTA0    (0x2C)
118         #define SUN4I_SPDIF_TXCHSTA0_CLK(v)             ((v) << 28)
119         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)         ((v) << 24)
120         #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK       GENMASK(27, 24)
121         #define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)           ((v) << 20)
122         #define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK         GENMASK(23, 20)
123         #define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)          ((v) << 16)
124         #define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)         ((v) << 8)
125         #define SUN4I_SPDIF_TXCHSTA0_MODE(v)            ((v) << 6)
126         #define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)        ((v) << 3)
127         #define SUN4I_SPDIF_TXCHSTA0_CP                 BIT(2)
128         #define SUN4I_SPDIF_TXCHSTA0_AUDIO              BIT(1)
129         #define SUN4I_SPDIF_TXCHSTA0_PRO                BIT(0)
130
131 #define SUN4I_SPDIF_TXCHSTA1    (0x30)
132         #define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)           ((v) << 8)
133         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
134         #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK    GENMASK(7, 4)
135         #define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
136         #define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN         BIT(0)
137
138 #define SUN4I_SPDIF_RXCHSTA0    (0x34)
139         #define SUN4I_SPDIF_RXCHSTA0_CLK(v)             ((v) << 28)
140         #define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)         ((v) << 24)
141         #define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)           ((v) << 20)
142         #define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)          ((v) << 16)
143         #define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)         ((v) << 8)
144         #define SUN4I_SPDIF_RXCHSTA0_MODE(v)            ((v) << 6)
145         #define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)        ((v) << 3)
146         #define SUN4I_SPDIF_RXCHSTA0_CP                 BIT(2)
147         #define SUN4I_SPDIF_RXCHSTA0_AUDIO              BIT(1)
148         #define SUN4I_SPDIF_RXCHSTA0_PRO                BIT(0)
149
150 #define SUN4I_SPDIF_RXCHSTA1    (0x38)
151         #define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)           ((v) << 8)
152         #define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)      ((v) << 4)
153         #define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)      ((v) << 1)
154         #define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN         BIT(0)
155
156 /* Defines for Sampling Frequency */
157 #define SUN4I_SPDIF_SAMFREQ_44_1KHZ             0x0
158 #define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED       0x1
159 #define SUN4I_SPDIF_SAMFREQ_48KHZ               0x2
160 #define SUN4I_SPDIF_SAMFREQ_32KHZ               0x3
161 #define SUN4I_SPDIF_SAMFREQ_22_05KHZ            0x4
162 #define SUN4I_SPDIF_SAMFREQ_24KHZ               0x6
163 #define SUN4I_SPDIF_SAMFREQ_88_2KHZ             0x8
164 #define SUN4I_SPDIF_SAMFREQ_76_8KHZ             0x9
165 #define SUN4I_SPDIF_SAMFREQ_96KHZ               0xa
166 #define SUN4I_SPDIF_SAMFREQ_176_4KHZ            0xc
167 #define SUN4I_SPDIF_SAMFREQ_192KHZ              0xe
168
169 /**
170  * struct sun4i_spdif_quirks - Differences between SoC variants.
171  *
172  * @reg_dac_txdata: TX FIFO offset for DMA config.
173  * @has_reset: SoC needs reset deasserted.
174  * @val_fctl_ftx: TX FIFO flush bitmask.
175  */
176 struct sun4i_spdif_quirks {
177         unsigned int reg_dac_txdata;
178         bool has_reset;
179         unsigned int val_fctl_ftx;
180 };
181
182 struct sun4i_spdif_dev {
183         struct platform_device *pdev;
184         struct clk *spdif_clk;
185         struct clk *apb_clk;
186         struct reset_control *rst;
187         struct snd_soc_dai_driver cpu_dai_drv;
188         struct regmap *regmap;
189         struct snd_dmaengine_dai_dma_data dma_params_tx;
190         const struct sun4i_spdif_quirks *quirks;
191         spinlock_t lock;
192 };
193
194 static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
195 {
196         const struct sun4i_spdif_quirks *quirks = host->quirks;
197
198         /* soft reset SPDIF */
199         regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
200
201         /* flush TX FIFO */
202         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
203                            quirks->val_fctl_ftx, quirks->val_fctl_ftx);
204
205         /* clear TX counter */
206         regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
207 }
208
209 static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
210                                 struct sun4i_spdif_dev *host)
211 {
212         if (substream->runtime->channels == 1)
213                 regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
214                                    SUN4I_SPDIF_TXCFG_SINGLEMOD,
215                                    SUN4I_SPDIF_TXCFG_SINGLEMOD);
216
217         /* SPDIF TX ENABLE */
218         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
219                            SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
220
221         /* DRQ ENABLE */
222         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
223                            SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
224
225         /* Global enable */
226         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
227                            SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
228 }
229
230 static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
231                                  struct sun4i_spdif_dev *host)
232 {
233         /* SPDIF TX DISABLE */
234         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
235                            SUN4I_SPDIF_TXCFG_TXEN, 0);
236
237         /* DRQ DISABLE */
238         regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
239                            SUN4I_SPDIF_INT_TXDRQEN, 0);
240
241         /* Global disable */
242         regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
243                            SUN4I_SPDIF_CTL_GEN, 0);
244 }
245
246 static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
247                                struct snd_soc_dai *cpu_dai)
248 {
249         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
250         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
251
252         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
253                 return -EINVAL;
254
255         sun4i_spdif_configure(host);
256
257         return 0;
258 }
259
260 static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
261                                  struct snd_pcm_hw_params *params,
262                                  struct snd_soc_dai *cpu_dai)
263 {
264         int ret = 0;
265         int fmt;
266         unsigned long rate = params_rate(params);
267         u32 mclk_div = 0;
268         unsigned int mclk = 0;
269         u32 reg_val;
270         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
271         struct platform_device *pdev = host->pdev;
272
273         /* Add the PCM and raw data select interface */
274         switch (params_channels(params)) {
275         case 1: /* PCM mode */
276         case 2:
277                 fmt = 0;
278                 break;
279         case 4: /* raw data mode */
280                 fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
281                 break;
282         default:
283                 return -EINVAL;
284         }
285
286         switch (params_format(params)) {
287         case SNDRV_PCM_FORMAT_S16_LE:
288                 fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
289                 break;
290         case SNDRV_PCM_FORMAT_S20_3LE:
291                 fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
292                 break;
293         case SNDRV_PCM_FORMAT_S24_LE:
294                 fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
295                 break;
296         default:
297                 return -EINVAL;
298         }
299
300         switch (rate) {
301         case 22050:
302         case 44100:
303         case 88200:
304         case 176400:
305                 mclk = 22579200;
306                 break;
307         case 24000:
308         case 32000:
309         case 48000:
310         case 96000:
311         case 192000:
312                 mclk = 24576000;
313                 break;
314         default:
315                 return -EINVAL;
316         }
317
318         ret = clk_set_rate(host->spdif_clk, mclk);
319         if (ret < 0) {
320                 dev_err(&pdev->dev,
321                         "Setting SPDIF clock rate for %d Hz failed!\n", mclk);
322                 return ret;
323         }
324
325         regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
326                            SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
327
328         switch (rate) {
329         case 22050:
330         case 24000:
331                 mclk_div = 8;
332                 break;
333         case 32000:
334                 mclk_div = 6;
335                 break;
336         case 44100:
337         case 48000:
338                 mclk_div = 4;
339                 break;
340         case 88200:
341         case 96000:
342                 mclk_div = 2;
343                 break;
344         case 176400:
345         case 192000:
346                 mclk_div = 1;
347                 break;
348         default:
349                 return -EINVAL;
350         }
351
352         reg_val = 0;
353         reg_val |= SUN4I_SPDIF_TXCFG_ASS;
354         reg_val |= fmt; /* set non audio and bit depth */
355         reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
356         reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
357         regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
358
359         return 0;
360 }
361
362 static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
363                                struct snd_soc_dai *dai)
364 {
365         int ret = 0;
366         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
367
368         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
369                 return -EINVAL;
370
371         switch (cmd) {
372         case SNDRV_PCM_TRIGGER_START:
373         case SNDRV_PCM_TRIGGER_RESUME:
374         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
375                 sun4i_snd_txctrl_on(substream, host);
376                 break;
377
378         case SNDRV_PCM_TRIGGER_STOP:
379         case SNDRV_PCM_TRIGGER_SUSPEND:
380         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
381                 sun4i_snd_txctrl_off(substream, host);
382                 break;
383
384         default:
385                 ret = -EINVAL;
386                 break;
387         }
388         return ret;
389 }
390
391 static int sun4i_spdif_info(struct snd_kcontrol *kcontrol,
392                             struct snd_ctl_elem_info *uinfo)
393 {
394         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
395         uinfo->count = 1;
396
397         return 0;
398 }
399
400 static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol,
401                                        struct snd_ctl_elem_value *ucontrol)
402 {
403         u8 *status = ucontrol->value.iec958.status;
404
405         status[0] = 0xff;
406         status[1] = 0xff;
407         status[2] = 0xff;
408         status[3] = 0xff;
409         status[4] = 0xff;
410         status[5] = 0x03;
411
412         return 0;
413 }
414
415 static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
416                                   struct snd_ctl_elem_value *ucontrol)
417 {
418         struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
419         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
420         u8 *status = ucontrol->value.iec958.status;
421         unsigned long flags;
422         unsigned int reg;
423
424         spin_lock_irqsave(&host->lock, flags);
425
426         regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, &reg);
427
428         status[0] = reg & 0xff;
429         status[1] = (reg >> 8) & 0xff;
430         status[2] = (reg >> 16) & 0xff;
431         status[3] = (reg >> 24) & 0xff;
432
433         regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, &reg);
434
435         status[4] = reg & 0xff;
436         status[5] = (reg >> 8) & 0x3;
437
438         spin_unlock_irqrestore(&host->lock, flags);
439
440         return 0;
441 }
442
443 static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
444                                   struct snd_ctl_elem_value *ucontrol)
445 {
446         struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
447         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
448         u8 *status = ucontrol->value.iec958.status;
449         unsigned long flags;
450         unsigned int reg;
451         bool chg0, chg1;
452
453         spin_lock_irqsave(&host->lock, flags);
454
455         reg = (u32)status[3] << 24;
456         reg |= (u32)status[2] << 16;
457         reg |= (u32)status[1] << 8;
458         reg |= (u32)status[0];
459
460         regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
461                                  GENMASK(31,0), reg, &chg0);
462
463         reg = (u32)status[5] << 8;
464         reg |= (u32)status[4];
465
466         regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
467                                  GENMASK(9,0), reg, &chg1);
468
469         reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
470         if (status[0] & IEC958_AES0_NONAUDIO)
471                 reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
472
473         regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
474                            SUN4I_SPDIF_TXCFG_CHSTMODE |
475                            SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
476
477         spin_unlock_irqrestore(&host->lock, flags);
478
479         return chg0 || chg1;
480 }
481
482 static struct snd_kcontrol_new sun4i_spdif_controls[] = {
483         {
484                 .access = SNDRV_CTL_ELEM_ACCESS_READ,
485                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
486                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
487                 .info = sun4i_spdif_info,
488                 .get = sun4i_spdif_get_status_mask
489         },
490         {
491                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
492                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
493                 .info = sun4i_spdif_info,
494                 .get = sun4i_spdif_get_status,
495                 .put = sun4i_spdif_set_status
496         }
497 };
498
499 static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
500 {
501         struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
502
503         snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
504         snd_soc_add_dai_controls(dai, sun4i_spdif_controls,
505                                  ARRAY_SIZE(sun4i_spdif_controls));
506
507         return 0;
508 }
509
510 static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
511         .startup        = sun4i_spdif_startup,
512         .trigger        = sun4i_spdif_trigger,
513         .hw_params      = sun4i_spdif_hw_params,
514 };
515
516 static const struct regmap_config sun4i_spdif_regmap_config = {
517         .reg_bits = 32,
518         .reg_stride = 4,
519         .val_bits = 32,
520         .max_register = SUN4I_SPDIF_RXCHSTA1,
521 };
522
523 #define SUN4I_RATES     SNDRV_PCM_RATE_8000_192000
524
525 #define SUN4I_FORMATS   (SNDRV_PCM_FORMAT_S16_LE | \
526                                 SNDRV_PCM_FORMAT_S20_3LE | \
527                                 SNDRV_PCM_FORMAT_S24_LE)
528
529 static struct snd_soc_dai_driver sun4i_spdif_dai = {
530         .playback = {
531                 .channels_min = 1,
532                 .channels_max = 2,
533                 .rates = SUN4I_RATES,
534                 .formats = SUN4I_FORMATS,
535         },
536         .probe = sun4i_spdif_soc_dai_probe,
537         .ops = &sun4i_spdif_dai_ops,
538         .name = "spdif",
539 };
540
541 static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
542         .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
543         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
544 };
545
546 static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
547         .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
548         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
549         .has_reset      = true,
550 };
551
552 static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
553         .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
554         .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
555         .has_reset      = true,
556 };
557
558 static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
559         .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
560         .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
561         .has_reset      = true,
562 };
563
564 static const struct of_device_id sun4i_spdif_of_match[] = {
565         {
566                 .compatible = "allwinner,sun4i-a10-spdif",
567                 .data = &sun4i_a10_spdif_quirks,
568         },
569         {
570                 .compatible = "allwinner,sun6i-a31-spdif",
571                 .data = &sun6i_a31_spdif_quirks,
572         },
573         {
574                 .compatible = "allwinner,sun8i-h3-spdif",
575                 .data = &sun8i_h3_spdif_quirks,
576         },
577         {
578                 .compatible = "allwinner,sun50i-h6-spdif",
579                 .data = &sun50i_h6_spdif_quirks,
580         },
581         {
582                 .compatible = "allwinner,sun50i-h616-spdif",
583                 /* Essentially the same as the H6, but without RX */
584                 .data = &sun50i_h6_spdif_quirks,
585         },
586         { /* sentinel */ }
587 };
588 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
589
590 static const struct snd_soc_component_driver sun4i_spdif_component = {
591         .name                   = "sun4i-spdif",
592         .legacy_dai_naming      = 1,
593 };
594
595 static int sun4i_spdif_runtime_suspend(struct device *dev)
596 {
597         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
598
599         clk_disable_unprepare(host->spdif_clk);
600         clk_disable_unprepare(host->apb_clk);
601
602         return 0;
603 }
604
605 static int sun4i_spdif_runtime_resume(struct device *dev)
606 {
607         struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
608         int ret;
609
610         ret = clk_prepare_enable(host->spdif_clk);
611         if (ret)
612                 return ret;
613         ret = clk_prepare_enable(host->apb_clk);
614         if (ret)
615                 clk_disable_unprepare(host->spdif_clk);
616
617         return ret;
618 }
619
620 static int sun4i_spdif_probe(struct platform_device *pdev)
621 {
622         struct sun4i_spdif_dev *host;
623         struct resource *res;
624         const struct sun4i_spdif_quirks *quirks;
625         int ret;
626         void __iomem *base;
627
628         dev_dbg(&pdev->dev, "Entered %s\n", __func__);
629
630         host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
631         if (!host)
632                 return -ENOMEM;
633
634         host->pdev = pdev;
635         spin_lock_init(&host->lock);
636
637         /* Initialize this copy of the CPU DAI driver structure */
638         memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
639         host->cpu_dai_drv.name = dev_name(&pdev->dev);
640
641         /* Get the addresses */
642         base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
643         if (IS_ERR(base))
644                 return PTR_ERR(base);
645
646         quirks = of_device_get_match_data(&pdev->dev);
647         if (quirks == NULL) {
648                 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
649                 return -ENODEV;
650         }
651         host->quirks = quirks;
652
653         host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
654                                                 &sun4i_spdif_regmap_config);
655
656         /* Clocks */
657         host->apb_clk = devm_clk_get(&pdev->dev, "apb");
658         if (IS_ERR(host->apb_clk)) {
659                 dev_err(&pdev->dev, "failed to get a apb clock.\n");
660                 return PTR_ERR(host->apb_clk);
661         }
662
663         host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
664         if (IS_ERR(host->spdif_clk)) {
665                 dev_err(&pdev->dev, "failed to get a spdif clock.\n");
666                 return PTR_ERR(host->spdif_clk);
667         }
668
669         host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
670         host->dma_params_tx.maxburst = 8;
671         host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
672
673         platform_set_drvdata(pdev, host);
674
675         if (quirks->has_reset) {
676                 host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
677                                                                       NULL);
678                 if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
679                         ret = -EPROBE_DEFER;
680                         dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
681                         return ret;
682                 }
683                 if (!IS_ERR(host->rst))
684                         reset_control_deassert(host->rst);
685         }
686
687         ret = devm_snd_soc_register_component(&pdev->dev,
688                                 &sun4i_spdif_component, &sun4i_spdif_dai, 1);
689         if (ret)
690                 return ret;
691
692         pm_runtime_enable(&pdev->dev);
693         if (!pm_runtime_enabled(&pdev->dev)) {
694                 ret = sun4i_spdif_runtime_resume(&pdev->dev);
695                 if (ret)
696                         goto err_unregister;
697         }
698
699         ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
700         if (ret)
701                 goto err_suspend;
702         return 0;
703 err_suspend:
704         if (!pm_runtime_status_suspended(&pdev->dev))
705                 sun4i_spdif_runtime_suspend(&pdev->dev);
706 err_unregister:
707         pm_runtime_disable(&pdev->dev);
708         return ret;
709 }
710
711 static int sun4i_spdif_remove(struct platform_device *pdev)
712 {
713         pm_runtime_disable(&pdev->dev);
714         if (!pm_runtime_status_suspended(&pdev->dev))
715                 sun4i_spdif_runtime_suspend(&pdev->dev);
716
717         return 0;
718 }
719
720 static const struct dev_pm_ops sun4i_spdif_pm = {
721         SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
722                            sun4i_spdif_runtime_resume, NULL)
723 };
724
725 static struct platform_driver sun4i_spdif_driver = {
726         .driver         = {
727                 .name   = "sun4i-spdif",
728                 .of_match_table = of_match_ptr(sun4i_spdif_of_match),
729                 .pm     = &sun4i_spdif_pm,
730         },
731         .probe          = sun4i_spdif_probe,
732         .remove         = sun4i_spdif_remove,
733 };
734
735 module_platform_driver(sun4i_spdif_driver);
736
737 MODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
738 MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
739 MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
740 MODULE_LICENSE("GPL");
741 MODULE_ALIAS("platform:sun4i-spdif");