ASoC: sun8i-codec: Generalize AIF clock control
[linux-2.6-microblaze.git] / sound / soc / sunxi / sun8i-codec.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * This driver supports the digital controls for the internal codec
4  * found in Allwinner's A33 SoCs.
5  *
6  * (C) Copyright 2010-2016
7  * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
8  * huangxin <huangxin@Reuuimllatech.com>
9  * Mylène Josserand <mylene.josserand@free-electrons.com>
10  */
11
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/of_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/regmap.h>
19 #include <linux/log2.h>
20
21 #include <sound/pcm_params.h>
22 #include <sound/soc.h>
23 #include <sound/soc-dapm.h>
24
25 #define SUN8I_SYSCLK_CTL                                0x00c
26 #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA                    11
27 #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL                (0x2 << 8)
28 #define SUN8I_SYSCLK_CTL_AIF2CLK_ENA                    7
29 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL                (0x2 << 4)
30 #define SUN8I_SYSCLK_CTL_SYSCLK_ENA                     3
31 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC                     0
32 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK             (0x0 << 0)
33 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK             (0x1 << 0)
34 #define SUN8I_MOD_CLK_ENA                               0x010
35 #define SUN8I_MOD_CLK_ENA_AIF1                          15
36 #define SUN8I_MOD_CLK_ENA_ADC                           3
37 #define SUN8I_MOD_CLK_ENA_DAC                           2
38 #define SUN8I_MOD_RST_CTL                               0x014
39 #define SUN8I_MOD_RST_CTL_AIF1                          15
40 #define SUN8I_MOD_RST_CTL_ADC                           3
41 #define SUN8I_MOD_RST_CTL_DAC                           2
42 #define SUN8I_SYS_SR_CTRL                               0x018
43 #define SUN8I_SYS_SR_CTRL_AIF1_FS                       12
44 #define SUN8I_SYS_SR_CTRL_AIF2_FS                       8
45 #define SUN8I_AIF_CLK_CTRL(n)                           (0x040 * (1 + (n)))
46 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD                     15
47 #define SUN8I_AIF_CLK_CTRL_CLK_INV                      13
48 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV                     9
49 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV                     6
50 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ                     4
51 #define SUN8I_AIF_CLK_CTRL_DATA_FMT                     2
52 #define SUN8I_AIF1_ADCDAT_CTRL                          0x044
53 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA            15
54 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA            14
55 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC            10
56 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC            8
57 #define SUN8I_AIF1_DACDAT_CTRL                          0x048
58 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA            15
59 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA            14
60 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC            10
61 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC            8
62 #define SUN8I_AIF1_MXR_SRC                              0x04c
63 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L        15
64 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL        14
65 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL            13
66 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR        12
67 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R        11
68 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR        10
69 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR            9
70 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL        8
71 #define SUN8I_ADC_DIG_CTRL                              0x100
72 #define SUN8I_ADC_DIG_CTRL_ENAD                         15
73 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS                    2
74 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY                    1
75 #define SUN8I_DAC_DIG_CTRL                              0x120
76 #define SUN8I_DAC_DIG_CTRL_ENDA                         15
77 #define SUN8I_DAC_MXR_SRC                               0x130
78 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L         15
79 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L         14
80 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL         13
81 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL             12
82 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R         11
83 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R         10
84 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR         9
85 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR             8
86
87 #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK       GENMASK(9, 8)
88 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK       GENMASK(5, 4)
89 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK          GENMASK(15, 12)
90 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK          GENMASK(11, 8)
91 #define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK         GENMASK(14, 13)
92 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK        GENMASK(12, 9)
93 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK        GENMASK(8, 6)
94 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK        GENMASK(5, 4)
95 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK        GENMASK(3, 2)
96
97 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
98
99 #define SUN8I_CODEC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8     |\
100                                  SNDRV_PCM_FMTBIT_S16_LE |\
101                                  SNDRV_PCM_FMTBIT_S20_LE |\
102                                  SNDRV_PCM_FMTBIT_S24_LE |\
103                                  SNDRV_PCM_FMTBIT_S20_3LE|\
104                                  SNDRV_PCM_FMTBIT_S24_3LE)
105
106 #define SUN8I_CODEC_PCM_RATES   (SNDRV_PCM_RATE_8000_48000|\
107                                  SNDRV_PCM_RATE_88200     |\
108                                  SNDRV_PCM_RATE_96000     |\
109                                  SNDRV_PCM_RATE_176400    |\
110                                  SNDRV_PCM_RATE_192000    |\
111                                  SNDRV_PCM_RATE_KNOT)
112
113 enum {
114         SUN8I_CODEC_AIF1,
115         SUN8I_CODEC_NAIFS
116 };
117
118 struct sun8i_codec_aif {
119         unsigned int    sample_rate;
120         unsigned int    slots;
121         unsigned int    slot_width;
122         unsigned int    active_streams  : 2;
123         unsigned int    open_streams    : 2;
124 };
125
126 struct sun8i_codec_quirks {
127         bool legacy_widgets     : 1;
128         bool lrck_inversion     : 1;
129 };
130
131 struct sun8i_codec {
132         struct regmap                   *regmap;
133         struct clk                      *clk_module;
134         const struct sun8i_codec_quirks *quirks;
135         struct sun8i_codec_aif          aifs[SUN8I_CODEC_NAIFS];
136         unsigned int                    sysclk_rate;
137         int                             sysclk_refcnt;
138 };
139
140 static int sun8i_codec_runtime_resume(struct device *dev)
141 {
142         struct sun8i_codec *scodec = dev_get_drvdata(dev);
143         int ret;
144
145         regcache_cache_only(scodec->regmap, false);
146
147         ret = regcache_sync(scodec->regmap);
148         if (ret) {
149                 dev_err(dev, "Failed to sync regmap cache\n");
150                 return ret;
151         }
152
153         return 0;
154 }
155
156 static int sun8i_codec_runtime_suspend(struct device *dev)
157 {
158         struct sun8i_codec *scodec = dev_get_drvdata(dev);
159
160         regcache_cache_only(scodec->regmap, true);
161         regcache_mark_dirty(scodec->regmap);
162
163         return 0;
164 }
165
166 static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
167 {
168         switch (sample_rate) {
169         case 7350:
170         case 8000:
171                 return 0x0;
172         case 11025:
173                 return 0x1;
174         case 12000:
175                 return 0x2;
176         case 14700:
177         case 16000:
178                 return 0x3;
179         case 22050:
180                 return 0x4;
181         case 24000:
182                 return 0x5;
183         case 29400:
184         case 32000:
185                 return 0x6;
186         case 44100:
187                 return 0x7;
188         case 48000:
189                 return 0x8;
190         case 88200:
191         case 96000:
192                 return 0x9;
193         case 176400:
194         case 192000:
195                 return 0xa;
196         default:
197                 return -EINVAL;
198         }
199 }
200
201 static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
202 {
203         unsigned int max_rate = 0;
204         int hw_rate, i;
205
206         for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
207                 struct sun8i_codec_aif *aif = &scodec->aifs[i];
208
209                 if (aif->active_streams)
210                         max_rate = max(max_rate, aif->sample_rate);
211         }
212
213         /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
214         if (!max_rate)
215                 max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
216
217         hw_rate = sun8i_codec_get_hw_rate(max_rate);
218         if (hw_rate < 0)
219                 return hw_rate;
220
221         regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
222                            SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
223                            hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
224
225         return 0;
226 }
227
228 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
229 {
230         struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
231         u32 dsp_format, format, invert, value;
232
233         /* clock masters */
234         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
235         case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
236                 value = 0x1;
237                 break;
238         case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
239                 value = 0x0;
240                 break;
241         default:
242                 return -EINVAL;
243         }
244
245         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
246                            BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
247                            value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
248
249         /* DAI format */
250         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
251         case SND_SOC_DAIFMT_I2S:
252                 format = 0x0;
253                 break;
254         case SND_SOC_DAIFMT_LEFT_J:
255                 format = 0x1;
256                 break;
257         case SND_SOC_DAIFMT_RIGHT_J:
258                 format = 0x2;
259                 break;
260         case SND_SOC_DAIFMT_DSP_A:
261                 format = 0x3;
262                 dsp_format = 0x0; /* Set LRCK_INV to 0 */
263                 break;
264         case SND_SOC_DAIFMT_DSP_B:
265                 format = 0x3;
266                 dsp_format = 0x1; /* Set LRCK_INV to 1 */
267                 break;
268         default:
269                 return -EINVAL;
270         }
271
272         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
273                            SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
274                            format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
275
276         /* clock inversion */
277         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
278         case SND_SOC_DAIFMT_NB_NF: /* Normal */
279                 invert = 0x0;
280                 break;
281         case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
282                 invert = 0x1;
283                 break;
284         case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
285                 invert = 0x2;
286                 break;
287         case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
288                 invert = 0x3;
289                 break;
290         default:
291                 return -EINVAL;
292         }
293
294         if (format == 0x3) {
295                 /* Inverted LRCK is not available in DSP mode. */
296                 if (invert & BIT(0))
297                         return -EINVAL;
298
299                 /* Instead, the bit selects between DSP A/B formats. */
300                 invert |= dsp_format;
301         } else {
302                 /*
303                  * It appears that the DAI and the codec in the A33 SoC don't
304                  * share the same polarity for the LRCK signal when they mean
305                  * 'normal' and 'inverted' in the datasheet.
306                  *
307                  * Since the DAI here is our regular i2s driver that have been
308                  * tested with way more codecs than just this one, it means
309                  * that the codec probably gets it backward, and we have to
310                  * invert the value here.
311                  */
312                 invert ^= scodec->quirks->lrck_inversion;
313         }
314
315         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
316                            SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
317                            invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
318
319         return 0;
320 }
321
322 static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
323                                     unsigned int tx_mask, unsigned int rx_mask,
324                                     int slots, int slot_width)
325 {
326         struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
327         struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
328
329         if (slot_width && !is_power_of_2(slot_width))
330                 return -EINVAL;
331
332         aif->slots = slots;
333         aif->slot_width = slot_width;
334
335         return 0;
336 }
337
338 static const unsigned int sun8i_codec_rates[] = {
339           7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
340          29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
341 };
342
343 static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
344         .list   = sun8i_codec_rates,
345         .count  = ARRAY_SIZE(sun8i_codec_rates),
346 };
347
348 static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
349         .list   = sun8i_codec_rates,
350         .count  = ARRAY_SIZE(sun8i_codec_rates),
351         .mask   = 0x5555,
352 };
353
354 static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
355         .list   = sun8i_codec_rates,
356         .count  = ARRAY_SIZE(sun8i_codec_rates),
357         .mask   = 0xaaaa,
358 };
359
360 static int sun8i_codec_startup(struct snd_pcm_substream *substream,
361                                struct snd_soc_dai *dai)
362 {
363         struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
364         const struct snd_pcm_hw_constraint_list *list;
365
366         if (!scodec->sysclk_refcnt)
367                 list = &sun8i_codec_all_rates;
368         else if (scodec->sysclk_rate == 22579200)
369                 list = &sun8i_codec_22M_rates;
370         else if (scodec->sysclk_rate == 24576000)
371                 list = &sun8i_codec_24M_rates;
372         else
373                 return -EINVAL;
374
375         return snd_pcm_hw_constraint_list(substream->runtime, 0,
376                                           SNDRV_PCM_HW_PARAM_RATE, list);
377 }
378
379 struct sun8i_codec_clk_div {
380         u8      div;
381         u8      val;
382 };
383
384 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
385         { .div = 1,     .val = 0 },
386         { .div = 2,     .val = 1 },
387         { .div = 4,     .val = 2 },
388         { .div = 6,     .val = 3 },
389         { .div = 8,     .val = 4 },
390         { .div = 12,    .val = 5 },
391         { .div = 16,    .val = 6 },
392         { .div = 24,    .val = 7 },
393         { .div = 32,    .val = 8 },
394         { .div = 48,    .val = 9 },
395         { .div = 64,    .val = 10 },
396         { .div = 96,    .val = 11 },
397         { .div = 128,   .val = 12 },
398         { .div = 192,   .val = 13 },
399 };
400
401 static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
402                                     unsigned int lrck_div_order,
403                                     unsigned int sample_rate)
404 {
405         unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
406         int i;
407
408         for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
409                 const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
410
411                 if (bdiv->div == div)
412                         return bdiv->val;
413         }
414
415         return -EINVAL;
416 }
417
418 static int sun8i_codec_get_lrck_div_order(unsigned int slots,
419                                           unsigned int slot_width)
420 {
421         unsigned int div = slots * slot_width;
422
423         if (div < 16 || div > 256)
424                 return -EINVAL;
425
426         return order_base_2(div);
427 }
428
429 static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
430 {
431         return sample_rate % 4000 ? 22579200 : 24576000;
432 }
433
434 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
435                                  struct snd_pcm_hw_params *params,
436                                  struct snd_soc_dai *dai)
437 {
438         struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
439         struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
440         unsigned int sample_rate = params_rate(params);
441         unsigned int slots = aif->slots ?: params_channels(params);
442         unsigned int slot_width = aif->slot_width ?: params_width(params);
443         unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
444         int bclk_div, lrck_div_order, ret, word_size;
445
446         /* word size */
447         switch (params_width(params)) {
448         case 8:
449                 word_size = 0x0;
450                 break;
451         case 16:
452                 word_size = 0x1;
453                 break;
454         case 20:
455                 word_size = 0x2;
456                 break;
457         case 24:
458                 word_size = 0x3;
459                 break;
460         default:
461                 return -EINVAL;
462         }
463
464         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
465                            SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
466                            word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
467
468         /* LRCK divider (BCLK/LRCK ratio) */
469         lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
470         if (lrck_div_order < 0)
471                 return lrck_div_order;
472
473         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
474                            SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
475                            (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
476
477         /* BCLK divider (SYSCLK/BCLK ratio) */
478         bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
479         if (bclk_div < 0)
480                 return bclk_div;
481
482         regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
483                            SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
484                            bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
485
486         /*
487          * SYSCLK rate
488          *
489          * Clock rate protection is reference counted; but hw_params may be
490          * called many times per substream, without matching calls to hw_free.
491          * Protect the clock rate once per AIF, on the first hw_params call
492          * for the first substream. clk_set_rate() will allow clock rate
493          * changes on subsequent calls if only one AIF has open streams.
494          */
495         ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
496                                                                           sysclk_rate);
497         if (ret == -EBUSY)
498                 dev_err(dai->dev,
499                         "%s sample rate (%u Hz) conflicts with other audio streams\n",
500                         dai->name, sample_rate);
501         if (ret < 0)
502                 return ret;
503
504         if (!aif->open_streams)
505                 scodec->sysclk_refcnt++;
506         scodec->sysclk_rate = sysclk_rate;
507
508         aif->sample_rate = sample_rate;
509         aif->open_streams |= BIT(substream->stream);
510
511         return sun8i_codec_update_sample_rate(scodec);
512 }
513
514 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
515                                struct snd_soc_dai *dai)
516 {
517         struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
518         struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
519
520         /* Drop references when the last substream for the AIF is freed. */
521         if (aif->open_streams != BIT(substream->stream))
522                 goto done;
523
524         clk_rate_exclusive_put(scodec->clk_module);
525         scodec->sysclk_refcnt--;
526         aif->sample_rate = 0;
527
528 done:
529         aif->open_streams &= ~BIT(substream->stream);
530         return 0;
531 }
532
533 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
534         .set_fmt        = sun8i_codec_set_fmt,
535         .set_tdm_slot   = sun8i_codec_set_tdm_slot,
536         .startup        = sun8i_codec_startup,
537         .hw_params      = sun8i_codec_hw_params,
538         .hw_free        = sun8i_codec_hw_free,
539 };
540
541 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
542         {
543                 .name   = "sun8i-codec-aif1",
544                 .id     = SUN8I_CODEC_AIF1,
545                 .ops    = &sun8i_codec_dai_ops,
546                 /* capture capabilities */
547                 .capture = {
548                         .stream_name    = "AIF1 Capture",
549                         .channels_min   = 1,
550                         .channels_max   = 2,
551                         .rates          = SUN8I_CODEC_PCM_RATES,
552                         .formats        = SUN8I_CODEC_PCM_FORMATS,
553                         .sig_bits       = 24,
554                 },
555                 /* playback capabilities */
556                 .playback = {
557                         .stream_name    = "AIF1 Playback",
558                         .channels_min   = 1,
559                         .channels_max   = 2,
560                         .rates          = SUN8I_CODEC_PCM_RATES,
561                         .formats        = SUN8I_CODEC_PCM_FORMATS,
562                 },
563                 .symmetric_rates        = true,
564                 .symmetric_channels     = true,
565                 .symmetric_samplebits   = true,
566         },
567 };
568
569 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
570                                  struct snd_kcontrol *kcontrol, int event)
571 {
572         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
573         struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
574         struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
575         int stream = w->id == snd_soc_dapm_aif_out;
576
577         if (SND_SOC_DAPM_EVENT_ON(event))
578                 aif->active_streams |= BIT(stream);
579         else
580                 aif->active_streams &= ~BIT(stream);
581
582         return sun8i_codec_update_sample_rate(scodec);
583 }
584
585 static const char *const sun8i_aif_stereo_mux_enum_values[] = {
586         "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
587 };
588
589 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
590                             SUN8I_AIF1_ADCDAT_CTRL,
591                             SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
592                             SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
593                             sun8i_aif_stereo_mux_enum_values);
594
595 static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
596         SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
597                       sun8i_aif1_ad0_stereo_mux_enum);
598
599 static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
600         SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
601                         SUN8I_AIF1_MXR_SRC,
602                         SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
603                         SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
604         SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
605                         SUN8I_AIF1_MXR_SRC,
606                         SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
607                         SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
608         SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
609                         SUN8I_AIF1_MXR_SRC,
610                         SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
611                         SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
612         SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
613                         SUN8I_AIF1_MXR_SRC,
614                         SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
615                         SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
616 };
617
618 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
619                             SUN8I_AIF1_DACDAT_CTRL,
620                             SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
621                             SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
622                             sun8i_aif_stereo_mux_enum_values);
623
624 static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
625         SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
626                       sun8i_aif1_da0_stereo_mux_enum);
627
628 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
629         SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
630                         SUN8I_DAC_MXR_SRC,
631                         SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
632                         SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
633         SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
634                         SUN8I_DAC_MXR_SRC,
635                         SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
636                         SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
637         SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
638                         SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
639                         SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
640         SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
641                         SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
642                         SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
643 };
644
645 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
646         /* System Clocks */
647         SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
648
649         SND_SOC_DAPM_SUPPLY("AIF1CLK",
650                             SUN8I_SYSCLK_CTL,
651                             SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
652         SND_SOC_DAPM_SUPPLY("SYSCLK",
653                             SUN8I_SYSCLK_CTL,
654                             SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
655
656         /* Module Clocks */
657         SND_SOC_DAPM_SUPPLY("CLK AIF1",
658                             SUN8I_MOD_CLK_ENA,
659                             SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
660         SND_SOC_DAPM_SUPPLY("CLK ADC",
661                             SUN8I_MOD_CLK_ENA,
662                             SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
663         SND_SOC_DAPM_SUPPLY("CLK DAC",
664                             SUN8I_MOD_CLK_ENA,
665                             SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
666
667         /* Module Resets */
668         SND_SOC_DAPM_SUPPLY("RST AIF1",
669                             SUN8I_MOD_RST_CTL,
670                             SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
671         SND_SOC_DAPM_SUPPLY("RST ADC",
672                             SUN8I_MOD_RST_CTL,
673                             SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
674         SND_SOC_DAPM_SUPPLY("RST DAC",
675                             SUN8I_MOD_RST_CTL,
676                             SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
677
678         /* Module Supplies */
679         SND_SOC_DAPM_SUPPLY("ADC",
680                             SUN8I_ADC_DIG_CTRL,
681                             SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
682         SND_SOC_DAPM_SUPPLY("DAC",
683                             SUN8I_DAC_DIG_CTRL,
684                             SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
685
686         /* AIF "ADC" Outputs */
687         SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
688                                SUN8I_AIF1_ADCDAT_CTRL,
689                                SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
690                                sun8i_codec_aif_event,
691                                SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
692         SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
693                              SUN8I_AIF1_ADCDAT_CTRL,
694                              SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
695
696         /* AIF "ADC" Mono/Stereo Muxes */
697         SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
698                          &sun8i_aif1_ad0_stereo_mux_control),
699         SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
700                          &sun8i_aif1_ad0_stereo_mux_control),
701
702         /* AIF "ADC" Mixers */
703         SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
704                         sun8i_aif1_ad0_mixer_controls),
705         SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
706                         sun8i_aif1_ad0_mixer_controls),
707
708         /* AIF "DAC" Mono/Stereo Muxes */
709         SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
710                          &sun8i_aif1_da0_stereo_mux_control),
711         SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
712                          &sun8i_aif1_da0_stereo_mux_control),
713
714         /* AIF "DAC" Inputs */
715         SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
716                               SUN8I_AIF1_DACDAT_CTRL,
717                               SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
718                               sun8i_codec_aif_event,
719                               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
720         SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
721                             SUN8I_AIF1_DACDAT_CTRL,
722                             SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
723
724         /* ADC Inputs (connected to analog codec DAPM context) */
725         SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
726         SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
727
728         /* DAC Outputs (connected to analog codec DAPM context) */
729         SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
730         SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
731
732         /* DAC Mixers */
733         SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
734                         sun8i_dac_mixer_controls),
735         SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
736                         sun8i_dac_mixer_controls),
737 };
738
739 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
740         /* Clock Routes */
741         { "AIF1CLK", NULL, "mod" },
742
743         { "SYSCLK", NULL, "AIF1CLK" },
744
745         { "CLK AIF1", NULL, "AIF1CLK" },
746         { "CLK AIF1", NULL, "SYSCLK" },
747         { "RST AIF1", NULL, "CLK AIF1" },
748         { "AIF1 AD0L", NULL, "RST AIF1" },
749         { "AIF1 AD0R", NULL, "RST AIF1" },
750         { "AIF1 DA0L", NULL, "RST AIF1" },
751         { "AIF1 DA0R", NULL, "RST AIF1" },
752
753         { "CLK ADC", NULL, "SYSCLK" },
754         { "RST ADC", NULL, "CLK ADC" },
755         { "ADC", NULL, "RST ADC" },
756         { "ADCL", NULL, "ADC" },
757         { "ADCR", NULL, "ADC" },
758
759         { "CLK DAC", NULL, "SYSCLK" },
760         { "RST DAC", NULL, "CLK DAC" },
761         { "DAC", NULL, "RST DAC" },
762         { "DACL", NULL, "DAC" },
763         { "DACR", NULL, "DAC" },
764
765         /* AIF "ADC" Output Routes */
766         { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
767         { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
768
769         /* AIF "ADC" Mono/Stereo Mux Routes */
770         { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
771         { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
772         { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
773         { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
774         { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
775         { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
776
777         { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
778         { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
779         { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
780         { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
781         { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
782         { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
783
784         /* AIF "ADC" Mixer Routes */
785         { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
786         { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
787
788         { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
789         { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
790
791         /* AIF "DAC" Mono/Stereo Mux Routes */
792         { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
793         { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
794         { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
795         { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
796         { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
797         { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
798
799         { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
800         { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
801         { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
802         { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
803         { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
804         { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
805
806         /* DAC Output Routes */
807         { "DACL", NULL, "DACL Mixer" },
808         { "DACR", NULL, "DACR Mixer" },
809
810         /* DAC Mixer Routes */
811         { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
812         { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
813
814         { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
815         { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
816 };
817
818 static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
819         /* Legacy ADC Inputs (connected to analog codec DAPM context) */
820         SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
821         SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
822
823         /* Legacy DAC Outputs (connected to analog codec DAPM context) */
824         SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
825         SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
826 };
827
828 static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
829         /* Legacy ADC Routes */
830         { "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
831         { "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
832
833         /* Legacy DAC Routes */
834         { "AIF1 Slot 0 Left", NULL, "DACL" },
835         { "AIF1 Slot 0 Right", NULL, "DACR" },
836 };
837
838 static int sun8i_codec_component_probe(struct snd_soc_component *component)
839 {
840         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
841         struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
842         int ret;
843
844         /* Add widgets for backward compatibility with old device trees. */
845         if (scodec->quirks->legacy_widgets) {
846                 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
847                                                 ARRAY_SIZE(sun8i_codec_legacy_widgets));
848                 if (ret)
849                         return ret;
850
851                 ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
852                                               ARRAY_SIZE(sun8i_codec_legacy_routes));
853                 if (ret)
854                         return ret;
855         }
856
857         /*
858          * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
859          * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
860          * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
861          * directly to simplify the clock tree.
862          */
863         regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
864                            SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
865                            SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
866                            SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
867                            SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
868
869         /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
870         regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
871                            BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
872                            SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
873
874         /* Program the default sample rate. */
875         sun8i_codec_update_sample_rate(scodec);
876
877         return 0;
878 }
879
880 static const struct snd_soc_component_driver sun8i_soc_component = {
881         .dapm_widgets           = sun8i_codec_dapm_widgets,
882         .num_dapm_widgets       = ARRAY_SIZE(sun8i_codec_dapm_widgets),
883         .dapm_routes            = sun8i_codec_dapm_routes,
884         .num_dapm_routes        = ARRAY_SIZE(sun8i_codec_dapm_routes),
885         .probe                  = sun8i_codec_component_probe,
886         .idle_bias_on           = 1,
887         .endianness             = 1,
888         .non_legacy_dai_naming  = 1,
889 };
890
891 static const struct regmap_config sun8i_codec_regmap_config = {
892         .reg_bits       = 32,
893         .reg_stride     = 4,
894         .val_bits       = 32,
895         .max_register   = SUN8I_DAC_MXR_SRC,
896
897         .cache_type     = REGCACHE_FLAT,
898 };
899
900 static int sun8i_codec_probe(struct platform_device *pdev)
901 {
902         struct sun8i_codec *scodec;
903         void __iomem *base;
904         int ret;
905
906         scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
907         if (!scodec)
908                 return -ENOMEM;
909
910         scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
911         if (IS_ERR(scodec->clk_module)) {
912                 dev_err(&pdev->dev, "Failed to get the module clock\n");
913                 return PTR_ERR(scodec->clk_module);
914         }
915
916         base = devm_platform_ioremap_resource(pdev, 0);
917         if (IS_ERR(base)) {
918                 dev_err(&pdev->dev, "Failed to map the registers\n");
919                 return PTR_ERR(base);
920         }
921
922         scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
923                                                    &sun8i_codec_regmap_config);
924         if (IS_ERR(scodec->regmap)) {
925                 dev_err(&pdev->dev, "Failed to create our regmap\n");
926                 return PTR_ERR(scodec->regmap);
927         }
928
929         scodec->quirks = of_device_get_match_data(&pdev->dev);
930
931         platform_set_drvdata(pdev, scodec);
932
933         pm_runtime_enable(&pdev->dev);
934         if (!pm_runtime_enabled(&pdev->dev)) {
935                 ret = sun8i_codec_runtime_resume(&pdev->dev);
936                 if (ret)
937                         goto err_pm_disable;
938         }
939
940         ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
941                                               sun8i_codec_dais,
942                                               ARRAY_SIZE(sun8i_codec_dais));
943         if (ret) {
944                 dev_err(&pdev->dev, "Failed to register codec\n");
945                 goto err_suspend;
946         }
947
948         return ret;
949
950 err_suspend:
951         if (!pm_runtime_status_suspended(&pdev->dev))
952                 sun8i_codec_runtime_suspend(&pdev->dev);
953
954 err_pm_disable:
955         pm_runtime_disable(&pdev->dev);
956
957         return ret;
958 }
959
960 static int sun8i_codec_remove(struct platform_device *pdev)
961 {
962         pm_runtime_disable(&pdev->dev);
963         if (!pm_runtime_status_suspended(&pdev->dev))
964                 sun8i_codec_runtime_suspend(&pdev->dev);
965
966         return 0;
967 }
968
969 static const struct sun8i_codec_quirks sun8i_a33_quirks = {
970         .legacy_widgets = true,
971         .lrck_inversion = true,
972 };
973
974 static const struct sun8i_codec_quirks sun50i_a64_quirks = {
975 };
976
977 static const struct of_device_id sun8i_codec_of_match[] = {
978         { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
979         { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
980         {}
981 };
982 MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
983
984 static const struct dev_pm_ops sun8i_codec_pm_ops = {
985         SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
986                            sun8i_codec_runtime_resume, NULL)
987 };
988
989 static struct platform_driver sun8i_codec_driver = {
990         .driver = {
991                 .name = "sun8i-codec",
992                 .of_match_table = sun8i_codec_of_match,
993                 .pm = &sun8i_codec_pm_ops,
994         },
995         .probe = sun8i_codec_probe,
996         .remove = sun8i_codec_remove,
997 };
998 module_platform_driver(sun8i_codec_driver);
999
1000 MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
1001 MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
1002 MODULE_LICENSE("GPL");
1003 MODULE_ALIAS("platform:sun8i-codec");