Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2014 Emilio López <emilio@elopez.com.ar>
0004  * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
0005  * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
0006  * Copyright 2015 Adam Sampson <ats@offog.org>
0007  * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
0008  *
0009  * Based on the Allwinner SDK driver, released under the GPL.
0010  */
0011 
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/delay.h>
0017 #include <linux/slab.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_device.h>
0021 #include <linux/of_platform.h>
0022 #include <linux/clk.h>
0023 #include <linux/regmap.h>
0024 #include <linux/reset.h>
0025 #include <linux/gpio/consumer.h>
0026 
0027 #include <sound/core.h>
0028 #include <sound/pcm.h>
0029 #include <sound/pcm_params.h>
0030 #include <sound/soc.h>
0031 #include <sound/tlv.h>
0032 #include <sound/initval.h>
0033 #include <sound/dmaengine_pcm.h>
0034 
0035 /* Codec DAC digital controls and FIFO registers */
0036 #define SUN4I_CODEC_DAC_DPC         (0x00)
0037 #define SUN4I_CODEC_DAC_DPC_EN_DA           (31)
0038 #define SUN4I_CODEC_DAC_DPC_DVOL            (12)
0039 #define SUN4I_CODEC_DAC_FIFOC           (0x04)
0040 #define SUN4I_CODEC_DAC_FIFOC_DAC_FS            (29)
0041 #define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION       (28)
0042 #define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT        (26)
0043 #define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE      (24)
0044 #define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT       (21)
0045 #define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL     (8)
0046 #define SUN4I_CODEC_DAC_FIFOC_MONO_EN           (6)
0047 #define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS        (5)
0048 #define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN        (4)
0049 #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH        (0)
0050 #define SUN4I_CODEC_DAC_FIFOS           (0x08)
0051 #define SUN4I_CODEC_DAC_TXDATA          (0x0c)
0052 
0053 /* Codec DAC side analog signal controls */
0054 #define SUN4I_CODEC_DAC_ACTL            (0x10)
0055 #define SUN4I_CODEC_DAC_ACTL_DACAENR            (31)
0056 #define SUN4I_CODEC_DAC_ACTL_DACAENL            (30)
0057 #define SUN4I_CODEC_DAC_ACTL_MIXEN          (29)
0058 #define SUN4I_CODEC_DAC_ACTL_LNG            (26)
0059 #define SUN4I_CODEC_DAC_ACTL_FMG            (23)
0060 #define SUN4I_CODEC_DAC_ACTL_MICG           (20)
0061 #define SUN4I_CODEC_DAC_ACTL_LLNS           (19)
0062 #define SUN4I_CODEC_DAC_ACTL_RLNS           (18)
0063 #define SUN4I_CODEC_DAC_ACTL_LFMS           (17)
0064 #define SUN4I_CODEC_DAC_ACTL_RFMS           (16)
0065 #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS          (15)
0066 #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS          (14)
0067 #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS          (13)
0068 #define SUN4I_CODEC_DAC_ACTL_MIC1LS         (12)
0069 #define SUN4I_CODEC_DAC_ACTL_MIC1RS         (11)
0070 #define SUN4I_CODEC_DAC_ACTL_MIC2LS         (10)
0071 #define SUN4I_CODEC_DAC_ACTL_MIC2RS         (9)
0072 #define SUN4I_CODEC_DAC_ACTL_DACPAS         (8)
0073 #define SUN4I_CODEC_DAC_ACTL_MIXPAS         (7)
0074 #define SUN4I_CODEC_DAC_ACTL_PA_MUTE            (6)
0075 #define SUN4I_CODEC_DAC_ACTL_PA_VOL         (0)
0076 #define SUN4I_CODEC_DAC_TUNE            (0x14)
0077 #define SUN4I_CODEC_DAC_DEBUG           (0x18)
0078 
0079 /* Codec ADC digital controls and FIFO registers */
0080 #define SUN4I_CODEC_ADC_FIFOC           (0x1c)
0081 #define SUN4I_CODEC_ADC_FIFOC_ADC_FS            (29)
0082 #define SUN4I_CODEC_ADC_FIFOC_EN_AD         (28)
0083 #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE      (24)
0084 #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL     (8)
0085 #define SUN4I_CODEC_ADC_FIFOC_MONO_EN           (7)
0086 #define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS        (6)
0087 #define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN        (4)
0088 #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH        (0)
0089 #define SUN4I_CODEC_ADC_FIFOS           (0x20)
0090 #define SUN4I_CODEC_ADC_RXDATA          (0x24)
0091 
0092 /* Codec ADC side analog signal controls */
0093 #define SUN4I_CODEC_ADC_ACTL            (0x28)
0094 #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN           (31)
0095 #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN           (30)
0096 #define SUN4I_CODEC_ADC_ACTL_PREG1EN            (29)
0097 #define SUN4I_CODEC_ADC_ACTL_PREG2EN            (28)
0098 #define SUN4I_CODEC_ADC_ACTL_VMICEN         (27)
0099 #define SUN4I_CODEC_ADC_ACTL_PREG1          (25)
0100 #define SUN4I_CODEC_ADC_ACTL_PREG2          (23)
0101 #define SUN4I_CODEC_ADC_ACTL_VADCG          (20)
0102 #define SUN4I_CODEC_ADC_ACTL_ADCIS          (17)
0103 #define SUN4I_CODEC_ADC_ACTL_LNPREG         (13)
0104 #define SUN4I_CODEC_ADC_ACTL_PA_EN          (4)
0105 #define SUN4I_CODEC_ADC_ACTL_DDE            (3)
0106 #define SUN4I_CODEC_ADC_DEBUG           (0x2c)
0107 
0108 /* FIFO counters */
0109 #define SUN4I_CODEC_DAC_TXCNT           (0x30)
0110 #define SUN4I_CODEC_ADC_RXCNT           (0x34)
0111 
0112 /* Calibration register (sun7i only) */
0113 #define SUN7I_CODEC_AC_DAC_CAL          (0x38)
0114 
0115 /* Microphone controls (sun7i only) */
0116 #define SUN7I_CODEC_AC_MIC_PHONE_CAL        (0x3c)
0117 
0118 #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1      (29)
0119 #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2      (26)
0120 
0121 /*
0122  * sun6i specific registers
0123  *
0124  * sun6i shares the same digital control and FIFO registers as sun4i,
0125  * but only the DAC digital controls are at the same offset. The others
0126  * have been moved around to accommodate extra analog controls.
0127  */
0128 
0129 /* Codec DAC digital controls and FIFO registers */
0130 #define SUN6I_CODEC_ADC_FIFOC           (0x10)
0131 #define SUN6I_CODEC_ADC_FIFOC_EN_AD         (28)
0132 #define SUN6I_CODEC_ADC_FIFOS           (0x14)
0133 #define SUN6I_CODEC_ADC_RXDATA          (0x18)
0134 
0135 /* Output mixer and gain controls */
0136 #define SUN6I_CODEC_OM_DACA_CTRL        (0x20)
0137 #define SUN6I_CODEC_OM_DACA_CTRL_DACAREN        (31)
0138 #define SUN6I_CODEC_OM_DACA_CTRL_DACALEN        (30)
0139 #define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN         (29)
0140 #define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN         (28)
0141 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1      (23)
0142 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2      (22)
0143 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE     (21)
0144 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP        (20)
0145 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR       (19)
0146 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR      (18)
0147 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL      (17)
0148 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1      (16)
0149 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2      (15)
0150 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE     (14)
0151 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN        (13)
0152 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL       (12)
0153 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL      (11)
0154 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR      (10)
0155 #define SUN6I_CODEC_OM_DACA_CTRL_RHPIS          (9)
0156 #define SUN6I_CODEC_OM_DACA_CTRL_LHPIS          (8)
0157 #define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE      (7)
0158 #define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE      (6)
0159 #define SUN6I_CODEC_OM_DACA_CTRL_HPVOL          (0)
0160 #define SUN6I_CODEC_OM_PA_CTRL          (0x24)
0161 #define SUN6I_CODEC_OM_PA_CTRL_HPPAEN           (31)
0162 #define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL        (29)
0163 #define SUN6I_CODEC_OM_PA_CTRL_COMPTEN          (28)
0164 #define SUN6I_CODEC_OM_PA_CTRL_MIC1G            (15)
0165 #define SUN6I_CODEC_OM_PA_CTRL_MIC2G            (12)
0166 #define SUN6I_CODEC_OM_PA_CTRL_LINEING          (9)
0167 #define SUN6I_CODEC_OM_PA_CTRL_PHONEG           (6)
0168 #define SUN6I_CODEC_OM_PA_CTRL_PHONEPG          (3)
0169 #define SUN6I_CODEC_OM_PA_CTRL_PHONENG          (0)
0170 
0171 /* Microphone, line out and phone out controls */
0172 #define SUN6I_CODEC_MIC_CTRL            (0x28)
0173 #define SUN6I_CODEC_MIC_CTRL_HBIASEN            (31)
0174 #define SUN6I_CODEC_MIC_CTRL_MBIASEN            (30)
0175 #define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN          (28)
0176 #define SUN6I_CODEC_MIC_CTRL_MIC1BOOST          (25)
0177 #define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN          (24)
0178 #define SUN6I_CODEC_MIC_CTRL_MIC2BOOST          (21)
0179 #define SUN6I_CODEC_MIC_CTRL_MIC2SLT            (20)
0180 #define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN         (19)
0181 #define SUN6I_CODEC_MIC_CTRL_LINEOUTREN         (18)
0182 #define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC        (17)
0183 #define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC        (16)
0184 #define SUN6I_CODEC_MIC_CTRL_LINEOUTVC          (11)
0185 #define SUN6I_CODEC_MIC_CTRL_PHONEPREG          (8)
0186 
0187 /* ADC mixer controls */
0188 #define SUN6I_CODEC_ADC_ACTL            (0x2c)
0189 #define SUN6I_CODEC_ADC_ACTL_ADCREN         (31)
0190 #define SUN6I_CODEC_ADC_ACTL_ADCLEN         (30)
0191 #define SUN6I_CODEC_ADC_ACTL_ADCRG          (27)
0192 #define SUN6I_CODEC_ADC_ACTL_ADCLG          (24)
0193 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1       (13)
0194 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2       (12)
0195 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE      (11)
0196 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP     (10)
0197 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR        (9)
0198 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR      (8)
0199 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL      (7)
0200 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1       (6)
0201 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2       (5)
0202 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE      (4)
0203 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN     (3)
0204 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL        (2)
0205 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL      (1)
0206 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR      (0)
0207 
0208 /* Analog performance tuning controls */
0209 #define SUN6I_CODEC_ADDA_TUNE           (0x30)
0210 
0211 /* Calibration controls */
0212 #define SUN6I_CODEC_CALIBRATION         (0x34)
0213 
0214 /* FIFO counters */
0215 #define SUN6I_CODEC_DAC_TXCNT           (0x40)
0216 #define SUN6I_CODEC_ADC_RXCNT           (0x44)
0217 
0218 /* headset jack detection and button support registers */
0219 #define SUN6I_CODEC_HMIC_CTL            (0x50)
0220 #define SUN6I_CODEC_HMIC_DATA           (0x54)
0221 
0222 /* TODO sun6i DAP (Digital Audio Processing) bits */
0223 
0224 /* FIFO counters moved on A23 */
0225 #define SUN8I_A23_CODEC_DAC_TXCNT       (0x1c)
0226 #define SUN8I_A23_CODEC_ADC_RXCNT       (0x20)
0227 
0228 /* TX FIFO moved on H3 */
0229 #define SUN8I_H3_CODEC_DAC_TXDATA       (0x20)
0230 #define SUN8I_H3_CODEC_DAC_DBG          (0x48)
0231 #define SUN8I_H3_CODEC_ADC_DBG          (0x4c)
0232 
0233 /* TODO H3 DAP (Digital Audio Processing) bits */
0234 
0235 struct sun4i_codec {
0236     struct device   *dev;
0237     struct regmap   *regmap;
0238     struct clk  *clk_apb;
0239     struct clk  *clk_module;
0240     struct reset_control *rst;
0241     struct gpio_desc *gpio_pa;
0242 
0243     /* ADC_FIFOC register is at different offset on different SoCs */
0244     struct regmap_field *reg_adc_fifoc;
0245 
0246     struct snd_dmaengine_dai_dma_data   capture_dma_data;
0247     struct snd_dmaengine_dai_dma_data   playback_dma_data;
0248 };
0249 
0250 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
0251 {
0252     /* Flush TX FIFO */
0253     regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0254             BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
0255 
0256     /* Enable DAC DRQ */
0257     regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0258             BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
0259 }
0260 
0261 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
0262 {
0263     /* Disable DAC DRQ */
0264     regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0265               BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
0266 }
0267 
0268 static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
0269 {
0270     /* Enable ADC DRQ */
0271     regmap_field_set_bits(scodec->reg_adc_fifoc,
0272                   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
0273 }
0274 
0275 static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
0276 {
0277     /* Disable ADC DRQ */
0278     regmap_field_clear_bits(scodec->reg_adc_fifoc,
0279                  BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
0280 }
0281 
0282 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
0283                    struct snd_soc_dai *dai)
0284 {
0285     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0286     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0287 
0288     switch (cmd) {
0289     case SNDRV_PCM_TRIGGER_START:
0290     case SNDRV_PCM_TRIGGER_RESUME:
0291     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0292         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0293             sun4i_codec_start_playback(scodec);
0294         else
0295             sun4i_codec_start_capture(scodec);
0296         break;
0297 
0298     case SNDRV_PCM_TRIGGER_STOP:
0299     case SNDRV_PCM_TRIGGER_SUSPEND:
0300     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0301         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0302             sun4i_codec_stop_playback(scodec);
0303         else
0304             sun4i_codec_stop_capture(scodec);
0305         break;
0306 
0307     default:
0308         return -EINVAL;
0309     }
0310 
0311     return 0;
0312 }
0313 
0314 static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
0315                        struct snd_soc_dai *dai)
0316 {
0317     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0318     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0319 
0320 
0321     /* Flush RX FIFO */
0322     regmap_field_set_bits(scodec->reg_adc_fifoc,
0323                  BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
0324 
0325 
0326     /* Set RX FIFO trigger level */
0327     regmap_field_update_bits(scodec->reg_adc_fifoc,
0328                  0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
0329                  0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
0330 
0331     /*
0332      * FIXME: Undocumented in the datasheet, but
0333      *        Allwinner's code mentions that it is
0334      *        related to microphone gain
0335      */
0336     if (of_device_is_compatible(scodec->dev->of_node,
0337                     "allwinner,sun4i-a10-codec") ||
0338         of_device_is_compatible(scodec->dev->of_node,
0339                     "allwinner,sun7i-a20-codec")) {
0340         regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
0341                    0x3 << 25,
0342                    0x1 << 25);
0343     }
0344 
0345     if (of_device_is_compatible(scodec->dev->of_node,
0346                     "allwinner,sun7i-a20-codec"))
0347         /* FIXME: Undocumented bits */
0348         regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
0349                    0x3 << 8,
0350                    0x1 << 8);
0351 
0352     return 0;
0353 }
0354 
0355 static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
0356                     struct snd_soc_dai *dai)
0357 {
0358     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0359     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0360     u32 val;
0361 
0362     /* Flush the TX FIFO */
0363     regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0364                BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
0365 
0366     /* Set TX FIFO Empty Trigger Level */
0367     regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0368                0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
0369                0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
0370 
0371     if (substream->runtime->rate > 32000)
0372         /* Use 64 bits FIR filter */
0373         val = 0;
0374     else
0375         /* Use 32 bits FIR filter */
0376         val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
0377 
0378     regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0379                BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
0380                val);
0381 
0382     /* Send zeros when we have an underrun */
0383     regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0384                BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT));
0385 
0386     return 0;
0387 };
0388 
0389 static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
0390                    struct snd_soc_dai *dai)
0391 {
0392     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0393         return sun4i_codec_prepare_playback(substream, dai);
0394 
0395     return sun4i_codec_prepare_capture(substream, dai);
0396 }
0397 
0398 static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
0399 {
0400     unsigned int rate = params_rate(params);
0401 
0402     switch (rate) {
0403     case 176400:
0404     case 88200:
0405     case 44100:
0406     case 33075:
0407     case 22050:
0408     case 14700:
0409     case 11025:
0410     case 7350:
0411         return 22579200;
0412 
0413     case 192000:
0414     case 96000:
0415     case 48000:
0416     case 32000:
0417     case 24000:
0418     case 16000:
0419     case 12000:
0420     case 8000:
0421         return 24576000;
0422 
0423     default:
0424         return 0;
0425     }
0426 }
0427 
0428 static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
0429 {
0430     unsigned int rate = params_rate(params);
0431 
0432     switch (rate) {
0433     case 192000:
0434     case 176400:
0435         return 6;
0436 
0437     case 96000:
0438     case 88200:
0439         return 7;
0440 
0441     case 48000:
0442     case 44100:
0443         return 0;
0444 
0445     case 32000:
0446     case 33075:
0447         return 1;
0448 
0449     case 24000:
0450     case 22050:
0451         return 2;
0452 
0453     case 16000:
0454     case 14700:
0455         return 3;
0456 
0457     case 12000:
0458     case 11025:
0459         return 4;
0460 
0461     case 8000:
0462     case 7350:
0463         return 5;
0464 
0465     default:
0466         return -EINVAL;
0467     }
0468 }
0469 
0470 static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
0471                      struct snd_pcm_hw_params *params,
0472                      unsigned int hwrate)
0473 {
0474     /* Set ADC sample rate */
0475     regmap_field_update_bits(scodec->reg_adc_fifoc,
0476                  7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
0477                  hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
0478 
0479     /* Set the number of channels we want to use */
0480     if (params_channels(params) == 1)
0481         regmap_field_set_bits(scodec->reg_adc_fifoc,
0482                      BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
0483     else
0484         regmap_field_clear_bits(scodec->reg_adc_fifoc,
0485                      BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
0486 
0487     /* Set the number of sample bits to either 16 or 24 bits */
0488     if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
0489         regmap_field_set_bits(scodec->reg_adc_fifoc,
0490                    BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
0491 
0492         regmap_field_clear_bits(scodec->reg_adc_fifoc,
0493                    BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
0494 
0495         scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0496     } else {
0497         regmap_field_clear_bits(scodec->reg_adc_fifoc,
0498                    BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
0499 
0500         /* Fill most significant bits with valid data MSB */
0501         regmap_field_set_bits(scodec->reg_adc_fifoc,
0502                    BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
0503 
0504         scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0505     }
0506 
0507     return 0;
0508 }
0509 
0510 static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
0511                       struct snd_pcm_hw_params *params,
0512                       unsigned int hwrate)
0513 {
0514     u32 val;
0515 
0516     /* Set DAC sample rate */
0517     regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0518                7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
0519                hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
0520 
0521     /* Set the number of channels we want to use */
0522     if (params_channels(params) == 1)
0523         val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
0524     else
0525         val = 0;
0526 
0527     regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0528                BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
0529                val);
0530 
0531     /* Set the number of sample bits to either 16 or 24 bits */
0532     if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
0533         regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0534                    BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
0535 
0536         /* Set TX FIFO mode to padding the LSBs with 0 */
0537         regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0538                    BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
0539 
0540         scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0541     } else {
0542         regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0543                    BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
0544 
0545         /* Set TX FIFO mode to repeat the MSB */
0546         regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0547                    BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
0548 
0549         scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0550     }
0551 
0552     return 0;
0553 }
0554 
0555 static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
0556                  struct snd_pcm_hw_params *params,
0557                  struct snd_soc_dai *dai)
0558 {
0559     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0560     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0561     unsigned long clk_freq;
0562     int ret, hwrate;
0563 
0564     clk_freq = sun4i_codec_get_mod_freq(params);
0565     if (!clk_freq)
0566         return -EINVAL;
0567 
0568     ret = clk_set_rate(scodec->clk_module, clk_freq);
0569     if (ret)
0570         return ret;
0571 
0572     hwrate = sun4i_codec_get_hw_rate(params);
0573     if (hwrate < 0)
0574         return hwrate;
0575 
0576     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0577         return sun4i_codec_hw_params_playback(scodec, params,
0578                               hwrate);
0579 
0580     return sun4i_codec_hw_params_capture(scodec, params,
0581                          hwrate);
0582 }
0583 
0584 
0585 static unsigned int sun4i_codec_src_rates[] = {
0586     8000, 11025, 12000, 16000, 22050, 24000, 32000,
0587     44100, 48000, 96000, 192000
0588 };
0589 
0590 
0591 static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
0592     .count  = ARRAY_SIZE(sun4i_codec_src_rates),
0593     .list   = sun4i_codec_src_rates,
0594 };
0595 
0596 
0597 static int sun4i_codec_startup(struct snd_pcm_substream *substream,
0598                    struct snd_soc_dai *dai)
0599 {
0600     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0601     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0602 
0603     snd_pcm_hw_constraint_list(substream->runtime, 0,
0604                 SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
0605 
0606     /*
0607      * Stop issuing DRQ when we have room for less than 16 samples
0608      * in our TX FIFO
0609      */
0610     regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0611                3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
0612 
0613     return clk_prepare_enable(scodec->clk_module);
0614 }
0615 
0616 static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
0617                  struct snd_soc_dai *dai)
0618 {
0619     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0620     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0621 
0622     clk_disable_unprepare(scodec->clk_module);
0623 }
0624 
0625 static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
0626     .startup    = sun4i_codec_startup,
0627     .shutdown   = sun4i_codec_shutdown,
0628     .trigger    = sun4i_codec_trigger,
0629     .hw_params  = sun4i_codec_hw_params,
0630     .prepare    = sun4i_codec_prepare,
0631 };
0632 
0633 static struct snd_soc_dai_driver sun4i_codec_dai = {
0634     .name   = "Codec",
0635     .ops    = &sun4i_codec_dai_ops,
0636     .playback = {
0637         .stream_name    = "Codec Playback",
0638         .channels_min   = 1,
0639         .channels_max   = 2,
0640         .rate_min   = 8000,
0641         .rate_max   = 192000,
0642         .rates      = SNDRV_PCM_RATE_CONTINUOUS,
0643         .formats    = SNDRV_PCM_FMTBIT_S16_LE |
0644                   SNDRV_PCM_FMTBIT_S32_LE,
0645         .sig_bits   = 24,
0646     },
0647     .capture = {
0648         .stream_name    = "Codec Capture",
0649         .channels_min   = 1,
0650         .channels_max   = 2,
0651         .rate_min   = 8000,
0652         .rate_max   = 48000,
0653         .rates      = SNDRV_PCM_RATE_CONTINUOUS,
0654         .formats    = SNDRV_PCM_FMTBIT_S16_LE |
0655                   SNDRV_PCM_FMTBIT_S32_LE,
0656         .sig_bits   = 24,
0657     },
0658 };
0659 
0660 /*** sun4i Codec ***/
0661 static const struct snd_kcontrol_new sun4i_codec_pa_mute =
0662     SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
0663             SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
0664 
0665 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
0666 static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150,
0667                 0);
0668 static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300,
0669                 0);
0670 static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150,
0671                 0);
0672 static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150,
0673                 0);
0674 static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale,
0675                 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
0676                 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0));
0677 static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale,
0678                 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
0679                 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0));
0680 
0681 static const struct snd_kcontrol_new sun4i_codec_controls[] = {
0682     SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
0683                SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
0684                sun4i_codec_pa_volume_scale),
0685     SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
0686                SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
0687                sun4i_codec_linein_loopback_gain_scale),
0688     SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
0689                SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
0690                sun4i_codec_linein_preamp_gain_scale),
0691     SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
0692                SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
0693                sun4i_codec_fmin_loopback_gain_scale),
0694     SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
0695                SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
0696                sun4i_codec_micin_loopback_gain_scale),
0697     SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL,
0698                SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0,
0699                sun4i_codec_micin_preamp_gain_scale),
0700     SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL,
0701                SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0,
0702                sun4i_codec_micin_preamp_gain_scale),
0703 };
0704 
0705 static const struct snd_kcontrol_new sun7i_codec_controls[] = {
0706     SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
0707                SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
0708                sun4i_codec_pa_volume_scale),
0709     SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
0710                SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
0711                sun4i_codec_linein_loopback_gain_scale),
0712     SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
0713                SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
0714                sun4i_codec_linein_preamp_gain_scale),
0715     SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
0716                SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
0717                sun4i_codec_fmin_loopback_gain_scale),
0718     SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
0719                SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
0720                sun4i_codec_micin_loopback_gain_scale),
0721     SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
0722                SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0,
0723                sun7i_codec_micin_preamp_gain_scale),
0724     SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
0725                SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0,
0726                sun7i_codec_micin_preamp_gain_scale),
0727 };
0728 
0729 static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = {
0730     SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch",
0731             SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS,
0732             1, 0),
0733     SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch",
0734             SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS,
0735             1, 0),
0736     SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch",
0737             SUN4I_CODEC_DAC_ACTL,
0738             SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
0739     SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL,
0740             SUN4I_CODEC_DAC_ACTL_LLNS,
0741             SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0),
0742     SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL,
0743             SUN4I_CODEC_DAC_ACTL_LFMS,
0744             SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0),
0745     SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL,
0746             SUN4I_CODEC_DAC_ACTL_MIC1LS,
0747             SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0),
0748     SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL,
0749             SUN4I_CODEC_DAC_ACTL_MIC2LS,
0750             SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0),
0751 };
0752 
0753 static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
0754     SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
0755             SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
0756     SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
0757             SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
0758 };
0759 
0760 static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
0761     /* Digital parts of the ADCs */
0762     SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
0763                 SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
0764                 NULL, 0),
0765 
0766     /* Digital parts of the DACs */
0767     SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
0768                 SUN4I_CODEC_DAC_DPC_EN_DA, 0,
0769                 NULL, 0),
0770 
0771     /* Analog parts of the ADCs */
0772     SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
0773              SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
0774     SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
0775              SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
0776 
0777     /* Analog parts of the DACs */
0778     SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
0779              SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
0780     SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
0781              SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
0782 
0783     /* Mixers */
0784     SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
0785                sun4i_codec_mixer_controls,
0786                ARRAY_SIZE(sun4i_codec_mixer_controls)),
0787     SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
0788                sun4i_codec_mixer_controls,
0789                ARRAY_SIZE(sun4i_codec_mixer_controls)),
0790 
0791     /* Global Mixer Enable */
0792     SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
0793                 SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
0794 
0795     /* VMIC */
0796     SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
0797                 SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
0798 
0799     /* Mic Pre-Amplifiers */
0800     SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
0801              SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
0802     SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
0803              SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0),
0804 
0805     /* Power Amplifier */
0806     SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
0807                SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
0808                sun4i_codec_pa_mixer_controls,
0809                ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
0810     SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
0811                 &sun4i_codec_pa_mute),
0812 
0813     SND_SOC_DAPM_INPUT("Line Right"),
0814     SND_SOC_DAPM_INPUT("Line Left"),
0815     SND_SOC_DAPM_INPUT("FM Right"),
0816     SND_SOC_DAPM_INPUT("FM Left"),
0817     SND_SOC_DAPM_INPUT("Mic1"),
0818     SND_SOC_DAPM_INPUT("Mic2"),
0819 
0820     SND_SOC_DAPM_OUTPUT("HP Right"),
0821     SND_SOC_DAPM_OUTPUT("HP Left"),
0822 };
0823 
0824 static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
0825     /* Left ADC / DAC Routes */
0826     { "Left ADC", NULL, "ADC" },
0827     { "Left DAC", NULL, "DAC" },
0828 
0829     /* Right ADC / DAC Routes */
0830     { "Right ADC", NULL, "ADC" },
0831     { "Right DAC", NULL, "DAC" },
0832 
0833     /* Right Mixer Routes */
0834     { "Right Mixer", NULL, "Mixer Enable" },
0835     { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" },
0836     { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" },
0837     { "Right Mixer", "Line Playback Switch", "Line Right" },
0838     { "Right Mixer", "FM Playback Switch", "FM Right" },
0839     { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
0840     { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
0841 
0842     /* Left Mixer Routes */
0843     { "Left Mixer", NULL, "Mixer Enable" },
0844     { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" },
0845     { "Left Mixer", "Line Playback Switch", "Line Left" },
0846     { "Left Mixer", "FM Playback Switch", "FM Left" },
0847     { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
0848     { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
0849 
0850     /* Power Amplifier Routes */
0851     { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
0852     { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
0853     { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
0854     { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
0855 
0856     /* Headphone Output Routes */
0857     { "Power Amplifier Mute", "Switch", "Power Amplifier" },
0858     { "HP Right", NULL, "Power Amplifier Mute" },
0859     { "HP Left", NULL, "Power Amplifier Mute" },
0860 
0861     /* Mic1 Routes */
0862     { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
0863     { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
0864     { "MIC1 Pre-Amplifier", NULL, "Mic1"},
0865     { "Mic1", NULL, "VMIC" },
0866 
0867     /* Mic2 Routes */
0868     { "Left ADC", NULL, "MIC2 Pre-Amplifier" },
0869     { "Right ADC", NULL, "MIC2 Pre-Amplifier" },
0870     { "MIC2 Pre-Amplifier", NULL, "Mic2"},
0871     { "Mic2", NULL, "VMIC" },
0872 };
0873 
0874 static const struct snd_soc_component_driver sun4i_codec_codec = {
0875     .controls       = sun4i_codec_controls,
0876     .num_controls       = ARRAY_SIZE(sun4i_codec_controls),
0877     .dapm_widgets       = sun4i_codec_codec_dapm_widgets,
0878     .num_dapm_widgets   = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
0879     .dapm_routes        = sun4i_codec_codec_dapm_routes,
0880     .num_dapm_routes    = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
0881     .idle_bias_on       = 1,
0882     .use_pmdown_time    = 1,
0883     .endianness     = 1,
0884 };
0885 
0886 static const struct snd_soc_component_driver sun7i_codec_codec = {
0887     .controls       = sun7i_codec_controls,
0888     .num_controls       = ARRAY_SIZE(sun7i_codec_controls),
0889     .dapm_widgets       = sun4i_codec_codec_dapm_widgets,
0890     .num_dapm_widgets   = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
0891     .dapm_routes        = sun4i_codec_codec_dapm_routes,
0892     .num_dapm_routes    = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
0893     .idle_bias_on       = 1,
0894     .use_pmdown_time    = 1,
0895     .endianness     = 1,
0896 };
0897 
0898 /*** sun6i Codec ***/
0899 
0900 /* mixer controls */
0901 static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
0902     SOC_DAPM_DOUBLE("DAC Playback Switch",
0903             SUN6I_CODEC_OM_DACA_CTRL,
0904             SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
0905             SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
0906     SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
0907             SUN6I_CODEC_OM_DACA_CTRL,
0908             SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
0909             SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
0910     SOC_DAPM_DOUBLE("Line In Playback Switch",
0911             SUN6I_CODEC_OM_DACA_CTRL,
0912             SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
0913             SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
0914     SOC_DAPM_DOUBLE("Mic1 Playback Switch",
0915             SUN6I_CODEC_OM_DACA_CTRL,
0916             SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
0917             SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
0918     SOC_DAPM_DOUBLE("Mic2 Playback Switch",
0919             SUN6I_CODEC_OM_DACA_CTRL,
0920             SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
0921             SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
0922 };
0923 
0924 /* ADC mixer controls */
0925 static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
0926     SOC_DAPM_DOUBLE("Mixer Capture Switch",
0927             SUN6I_CODEC_ADC_ACTL,
0928             SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
0929             SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
0930     SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
0931             SUN6I_CODEC_ADC_ACTL,
0932             SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
0933             SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
0934     SOC_DAPM_DOUBLE("Line In Capture Switch",
0935             SUN6I_CODEC_ADC_ACTL,
0936             SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
0937             SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
0938     SOC_DAPM_DOUBLE("Mic1 Capture Switch",
0939             SUN6I_CODEC_ADC_ACTL,
0940             SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
0941             SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
0942     SOC_DAPM_DOUBLE("Mic2 Capture Switch",
0943             SUN6I_CODEC_ADC_ACTL,
0944             SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
0945             SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
0946 };
0947 
0948 /* headphone controls */
0949 static const char * const sun6i_codec_hp_src_enum_text[] = {
0950     "DAC", "Mixer",
0951 };
0952 
0953 static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
0954                 SUN6I_CODEC_OM_DACA_CTRL,
0955                 SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
0956                 SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
0957                 sun6i_codec_hp_src_enum_text);
0958 
0959 static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
0960     SOC_DAPM_ENUM("Headphone Source Playback Route",
0961               sun6i_codec_hp_src_enum),
0962 };
0963 
0964 /* microphone controls */
0965 static const char * const sun6i_codec_mic2_src_enum_text[] = {
0966     "Mic2", "Mic3",
0967 };
0968 
0969 static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
0970                 SUN6I_CODEC_MIC_CTRL,
0971                 SUN6I_CODEC_MIC_CTRL_MIC2SLT,
0972                 sun6i_codec_mic2_src_enum_text);
0973 
0974 static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
0975     SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
0976               sun6i_codec_mic2_src_enum),
0977 };
0978 
0979 /* line out controls */
0980 static const char * const sun6i_codec_lineout_src_enum_text[] = {
0981     "Stereo", "Mono Differential",
0982 };
0983 
0984 static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
0985                 SUN6I_CODEC_MIC_CTRL,
0986                 SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
0987                 SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
0988                 sun6i_codec_lineout_src_enum_text);
0989 
0990 static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
0991     SOC_DAPM_ENUM("Line Out Source Playback Route",
0992               sun6i_codec_lineout_src_enum),
0993 };
0994 
0995 /* volume / mute controls */
0996 static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
0997 static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
0998 static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
0999                   -450, 150, 0);
1000 static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
1001     0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
1002     2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
1003 );
1004 static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
1005     0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1006     1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
1007 );
1008 
1009 static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
1010     SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1011                SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1012                sun6i_codec_dvol_scale),
1013     SOC_SINGLE_TLV("Headphone Playback Volume",
1014                SUN6I_CODEC_OM_DACA_CTRL,
1015                SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
1016                sun6i_codec_hp_vol_scale),
1017     SOC_SINGLE_TLV("Line Out Playback Volume",
1018                SUN6I_CODEC_MIC_CTRL,
1019                SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
1020                sun6i_codec_lineout_vol_scale),
1021     SOC_DOUBLE("Headphone Playback Switch",
1022            SUN6I_CODEC_OM_DACA_CTRL,
1023            SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
1024            SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
1025     SOC_DOUBLE("Line Out Playback Switch",
1026            SUN6I_CODEC_MIC_CTRL,
1027            SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
1028            SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
1029     /* Mixer pre-gains */
1030     SOC_SINGLE_TLV("Line In Playback Volume",
1031                SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
1032                0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1033     SOC_SINGLE_TLV("Mic1 Playback Volume",
1034                SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
1035                0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1036     SOC_SINGLE_TLV("Mic2 Playback Volume",
1037                SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
1038                0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1039 
1040     /* Microphone Amp boost gains */
1041     SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1042                SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
1043                sun6i_codec_mic_gain_scale),
1044     SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1045                SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
1046                sun6i_codec_mic_gain_scale),
1047     SOC_DOUBLE_TLV("ADC Capture Volume",
1048                SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
1049                SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
1050                sun6i_codec_out_mixer_pregain_scale),
1051 };
1052 
1053 static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
1054     /* Microphone inputs */
1055     SND_SOC_DAPM_INPUT("MIC1"),
1056     SND_SOC_DAPM_INPUT("MIC2"),
1057     SND_SOC_DAPM_INPUT("MIC3"),
1058 
1059     /* Microphone Bias */
1060     SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
1061                 SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
1062     SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
1063                 SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
1064 
1065     /* Mic input path */
1066     SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
1067              SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
1068     SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
1069              SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
1070     SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
1071              SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
1072 
1073     /* Line In */
1074     SND_SOC_DAPM_INPUT("LINEIN"),
1075 
1076     /* Digital parts of the ADCs */
1077     SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1078                 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
1079                 NULL, 0),
1080 
1081     /* Analog parts of the ADCs */
1082     SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1083              SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
1084     SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1085              SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
1086 
1087     /* ADC Mixers */
1088     SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
1089             sun6i_codec_adc_mixer_controls),
1090     SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
1091             sun6i_codec_adc_mixer_controls),
1092 
1093     /* Digital parts of the DACs */
1094     SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1095                 SUN4I_CODEC_DAC_DPC_EN_DA, 0,
1096                 NULL, 0),
1097 
1098     /* Analog parts of the DACs */
1099     SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
1100              SUN6I_CODEC_OM_DACA_CTRL,
1101              SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
1102     SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
1103              SUN6I_CODEC_OM_DACA_CTRL,
1104              SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
1105 
1106     /* Mixers */
1107     SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1108             SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
1109             sun6i_codec_mixer_controls),
1110     SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1111             SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
1112             sun6i_codec_mixer_controls),
1113 
1114     /* Headphone output path */
1115     SND_SOC_DAPM_MUX("Headphone Source Playback Route",
1116              SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
1117     SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
1118                  SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
1119     SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
1120                 SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
1121     SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
1122              SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
1123     SND_SOC_DAPM_OUTPUT("HP"),
1124 
1125     /* Line Out path */
1126     SND_SOC_DAPM_MUX("Line Out Source Playback Route",
1127              SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
1128     SND_SOC_DAPM_OUTPUT("LINEOUT"),
1129 };
1130 
1131 static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1132     /* DAC Routes */
1133     { "Left DAC", NULL, "DAC Enable" },
1134     { "Right DAC", NULL, "DAC Enable" },
1135 
1136     /* Microphone Routes */
1137     { "Mic1 Amplifier", NULL, "MIC1"},
1138     { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
1139     { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
1140     { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
1141 
1142     /* Left Mixer Routes */
1143     { "Left Mixer", "DAC Playback Switch", "Left DAC" },
1144     { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
1145     { "Left Mixer", "Line In Playback Switch", "LINEIN" },
1146     { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1147     { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1148 
1149     /* Right Mixer Routes */
1150     { "Right Mixer", "DAC Playback Switch", "Right DAC" },
1151     { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
1152     { "Right Mixer", "Line In Playback Switch", "LINEIN" },
1153     { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1154     { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1155 
1156     /* Left ADC Mixer Routes */
1157     { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
1158     { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
1159     { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
1160     { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1161     { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1162 
1163     /* Right ADC Mixer Routes */
1164     { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
1165     { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
1166     { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
1167     { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1168     { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1169 
1170     /* Headphone Routes */
1171     { "Headphone Source Playback Route", "DAC", "Left DAC" },
1172     { "Headphone Source Playback Route", "DAC", "Right DAC" },
1173     { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
1174     { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
1175     { "Headphone Amp", NULL, "Headphone Source Playback Route" },
1176     { "HP", NULL, "Headphone Amp" },
1177     { "HPCOM", NULL, "HPCOM Protection" },
1178 
1179     /* Line Out Routes */
1180     { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
1181     { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
1182     { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
1183     { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
1184     { "LINEOUT", NULL, "Line Out Source Playback Route" },
1185 
1186     /* ADC Routes */
1187     { "Left ADC", NULL, "ADC Enable" },
1188     { "Right ADC", NULL, "ADC Enable" },
1189     { "Left ADC", NULL, "Left ADC Mixer" },
1190     { "Right ADC", NULL, "Right ADC Mixer" },
1191 };
1192 
1193 static const struct snd_soc_component_driver sun6i_codec_codec = {
1194     .controls       = sun6i_codec_codec_widgets,
1195     .num_controls       = ARRAY_SIZE(sun6i_codec_codec_widgets),
1196     .dapm_widgets       = sun6i_codec_codec_dapm_widgets,
1197     .num_dapm_widgets   = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
1198     .dapm_routes        = sun6i_codec_codec_dapm_routes,
1199     .num_dapm_routes    = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
1200     .idle_bias_on       = 1,
1201     .use_pmdown_time    = 1,
1202     .endianness     = 1,
1203 };
1204 
1205 /* sun8i A23 codec */
1206 static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
1207     SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1208                SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1209                sun6i_codec_dvol_scale),
1210 };
1211 
1212 static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1213     /* Digital parts of the ADCs */
1214     SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1215                 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
1216     /* Digital parts of the DACs */
1217     SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1218                 SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
1219 
1220 };
1221 
1222 static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
1223     .controls       = sun8i_a23_codec_codec_controls,
1224     .num_controls       = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
1225     .dapm_widgets       = sun8i_a23_codec_codec_widgets,
1226     .num_dapm_widgets   = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
1227     .idle_bias_on       = 1,
1228     .use_pmdown_time    = 1,
1229     .endianness     = 1,
1230 };
1231 
1232 static const struct snd_soc_component_driver sun4i_codec_component = {
1233     .name           = "sun4i-codec",
1234     .legacy_dai_naming  = 1,
1235 };
1236 
1237 #define SUN4I_CODEC_RATES   SNDRV_PCM_RATE_CONTINUOUS
1238 #define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
1239                  SNDRV_PCM_FMTBIT_S32_LE)
1240 
1241 static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
1242 {
1243     struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
1244     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1245 
1246     snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
1247                   &scodec->capture_dma_data);
1248 
1249     return 0;
1250 }
1251 
1252 static struct snd_soc_dai_driver dummy_cpu_dai = {
1253     .name   = "sun4i-codec-cpu-dai",
1254     .probe  = sun4i_codec_dai_probe,
1255     .playback = {
1256         .stream_name    = "Playback",
1257         .channels_min   = 1,
1258         .channels_max   = 2,
1259         .rates      = SUN4I_CODEC_RATES,
1260         .formats    = SUN4I_CODEC_FORMATS,
1261         .sig_bits   = 24,
1262     },
1263     .capture = {
1264         .stream_name    = "Capture",
1265         .channels_min   = 1,
1266         .channels_max   = 2,
1267         .rates      = SUN4I_CODEC_RATES,
1268         .formats    = SUN4I_CODEC_FORMATS,
1269         .sig_bits   = 24,
1270      },
1271 };
1272 
1273 static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
1274                             int *num_links)
1275 {
1276     struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
1277                              GFP_KERNEL);
1278     struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev,
1279                         3 * sizeof(*dlc), GFP_KERNEL);
1280     if (!link || !dlc)
1281         return NULL;
1282 
1283     link->cpus  = &dlc[0];
1284     link->codecs    = &dlc[1];
1285     link->platforms = &dlc[2];
1286 
1287     link->num_cpus      = 1;
1288     link->num_codecs    = 1;
1289     link->num_platforms = 1;
1290 
1291     link->name      = "cdc";
1292     link->stream_name   = "CDC PCM";
1293     link->codecs->dai_name  = "Codec";
1294     link->cpus->dai_name    = dev_name(dev);
1295     link->codecs->name  = dev_name(dev);
1296     link->platforms->name   = dev_name(dev);
1297     link->dai_fmt       = SND_SOC_DAIFMT_I2S;
1298 
1299     *num_links = 1;
1300 
1301     return link;
1302 };
1303 
1304 static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
1305                  struct snd_kcontrol *k, int event)
1306 {
1307     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
1308 
1309     gpiod_set_value_cansleep(scodec->gpio_pa,
1310                  !!SND_SOC_DAPM_EVENT_ON(event));
1311 
1312     if (SND_SOC_DAPM_EVENT_ON(event)) {
1313         /*
1314          * Need a delay to wait for DAC to push the data. 700ms seems
1315          * to be the best compromise not to feel this delay while
1316          * playing a sound.
1317          */
1318         msleep(700);
1319     }
1320 
1321     return 0;
1322 }
1323 
1324 static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
1325     SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1326 };
1327 
1328 static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
1329     { "Speaker", NULL, "HP Right" },
1330     { "Speaker", NULL, "HP Left" },
1331 };
1332 
1333 static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
1334 {
1335     struct snd_soc_card *card;
1336 
1337     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1338     if (!card)
1339         return ERR_PTR(-ENOMEM);
1340 
1341     card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1342     if (!card->dai_link)
1343         return ERR_PTR(-ENOMEM);
1344 
1345     card->dev       = dev;
1346     card->owner     = THIS_MODULE;
1347     card->name      = "sun4i-codec";
1348     card->dapm_widgets  = sun4i_codec_card_dapm_widgets;
1349     card->num_dapm_widgets  = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
1350     card->dapm_routes   = sun4i_codec_card_dapm_routes;
1351     card->num_dapm_routes   = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
1352 
1353     return card;
1354 };
1355 
1356 static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
1357     SND_SOC_DAPM_HP("Headphone", NULL),
1358     SND_SOC_DAPM_LINE("Line In", NULL),
1359     SND_SOC_DAPM_LINE("Line Out", NULL),
1360     SND_SOC_DAPM_MIC("Headset Mic", NULL),
1361     SND_SOC_DAPM_MIC("Mic", NULL),
1362     SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1363 };
1364 
1365 static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
1366 {
1367     struct snd_soc_card *card;
1368     int ret;
1369 
1370     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1371     if (!card)
1372         return ERR_PTR(-ENOMEM);
1373 
1374     card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1375     if (!card->dai_link)
1376         return ERR_PTR(-ENOMEM);
1377 
1378     card->dev       = dev;
1379     card->owner     = THIS_MODULE;
1380     card->name      = "A31 Audio Codec";
1381     card->dapm_widgets  = sun6i_codec_card_dapm_widgets;
1382     card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1383     card->fully_routed  = true;
1384 
1385     ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1386     if (ret)
1387         dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1388 
1389     return card;
1390 };
1391 
1392 /* Connect digital side enables to analog side widgets */
1393 static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
1394     /* ADC Routes */
1395     { "Left ADC", NULL, "ADC Enable" },
1396     { "Right ADC", NULL, "ADC Enable" },
1397     { "Codec Capture", NULL, "Left ADC" },
1398     { "Codec Capture", NULL, "Right ADC" },
1399 
1400     /* DAC Routes */
1401     { "Left DAC", NULL, "DAC Enable" },
1402     { "Right DAC", NULL, "DAC Enable" },
1403     { "Left DAC", NULL, "Codec Playback" },
1404     { "Right DAC", NULL, "Codec Playback" },
1405 };
1406 
1407 static struct snd_soc_aux_dev aux_dev = {
1408     .dlc = COMP_EMPTY(),
1409 };
1410 
1411 static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
1412 {
1413     struct snd_soc_card *card;
1414     int ret;
1415 
1416     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1417     if (!card)
1418         return ERR_PTR(-ENOMEM);
1419 
1420     aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1421                          "allwinner,codec-analog-controls",
1422                          0);
1423     if (!aux_dev.dlc.of_node) {
1424         dev_err(dev, "Can't find analog controls for codec.\n");
1425         return ERR_PTR(-EINVAL);
1426     }
1427 
1428     card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1429     if (!card->dai_link)
1430         return ERR_PTR(-ENOMEM);
1431 
1432     card->dev       = dev;
1433     card->owner     = THIS_MODULE;
1434     card->name      = "A23 Audio Codec";
1435     card->dapm_widgets  = sun6i_codec_card_dapm_widgets;
1436     card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1437     card->dapm_routes   = sun8i_codec_card_routes;
1438     card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1439     card->aux_dev       = &aux_dev;
1440     card->num_aux_devs  = 1;
1441     card->fully_routed  = true;
1442 
1443     ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1444     if (ret)
1445         dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1446 
1447     return card;
1448 };
1449 
1450 static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
1451 {
1452     struct snd_soc_card *card;
1453     int ret;
1454 
1455     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1456     if (!card)
1457         return ERR_PTR(-ENOMEM);
1458 
1459     aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1460                          "allwinner,codec-analog-controls",
1461                          0);
1462     if (!aux_dev.dlc.of_node) {
1463         dev_err(dev, "Can't find analog controls for codec.\n");
1464         return ERR_PTR(-EINVAL);
1465     }
1466 
1467     card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1468     if (!card->dai_link)
1469         return ERR_PTR(-ENOMEM);
1470 
1471     card->dev       = dev;
1472     card->owner     = THIS_MODULE;
1473     card->name      = "H3 Audio Codec";
1474     card->dapm_widgets  = sun6i_codec_card_dapm_widgets;
1475     card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1476     card->dapm_routes   = sun8i_codec_card_routes;
1477     card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1478     card->aux_dev       = &aux_dev;
1479     card->num_aux_devs  = 1;
1480     card->fully_routed  = true;
1481 
1482     ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1483     if (ret)
1484         dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1485 
1486     return card;
1487 };
1488 
1489 static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
1490 {
1491     struct snd_soc_card *card;
1492     int ret;
1493 
1494     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1495     if (!card)
1496         return ERR_PTR(-ENOMEM);
1497 
1498     aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1499                          "allwinner,codec-analog-controls",
1500                          0);
1501     if (!aux_dev.dlc.of_node) {
1502         dev_err(dev, "Can't find analog controls for codec.\n");
1503         return ERR_PTR(-EINVAL);
1504     }
1505 
1506     card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1507     if (!card->dai_link)
1508         return ERR_PTR(-ENOMEM);
1509 
1510     card->dev       = dev;
1511     card->owner     = THIS_MODULE;
1512     card->name      = "V3s Audio Codec";
1513     card->dapm_widgets  = sun6i_codec_card_dapm_widgets;
1514     card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1515     card->dapm_routes   = sun8i_codec_card_routes;
1516     card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1517     card->aux_dev       = &aux_dev;
1518     card->num_aux_devs  = 1;
1519     card->fully_routed  = true;
1520 
1521     ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1522     if (ret)
1523         dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1524 
1525     return card;
1526 };
1527 
1528 static const struct regmap_config sun4i_codec_regmap_config = {
1529     .reg_bits   = 32,
1530     .reg_stride = 4,
1531     .val_bits   = 32,
1532     .max_register   = SUN4I_CODEC_ADC_RXCNT,
1533 };
1534 
1535 static const struct regmap_config sun6i_codec_regmap_config = {
1536     .reg_bits   = 32,
1537     .reg_stride = 4,
1538     .val_bits   = 32,
1539     .max_register   = SUN6I_CODEC_HMIC_DATA,
1540 };
1541 
1542 static const struct regmap_config sun7i_codec_regmap_config = {
1543     .reg_bits   = 32,
1544     .reg_stride = 4,
1545     .val_bits   = 32,
1546     .max_register   = SUN7I_CODEC_AC_MIC_PHONE_CAL,
1547 };
1548 
1549 static const struct regmap_config sun8i_a23_codec_regmap_config = {
1550     .reg_bits   = 32,
1551     .reg_stride = 4,
1552     .val_bits   = 32,
1553     .max_register   = SUN8I_A23_CODEC_ADC_RXCNT,
1554 };
1555 
1556 static const struct regmap_config sun8i_h3_codec_regmap_config = {
1557     .reg_bits   = 32,
1558     .reg_stride = 4,
1559     .val_bits   = 32,
1560     .max_register   = SUN8I_H3_CODEC_ADC_DBG,
1561 };
1562 
1563 static const struct regmap_config sun8i_v3s_codec_regmap_config = {
1564     .reg_bits   = 32,
1565     .reg_stride = 4,
1566     .val_bits   = 32,
1567     .max_register   = SUN8I_H3_CODEC_ADC_DBG,
1568 };
1569 
1570 struct sun4i_codec_quirks {
1571     const struct regmap_config *regmap_config;
1572     const struct snd_soc_component_driver *codec;
1573     struct snd_soc_card * (*create_card)(struct device *dev);
1574     struct reg_field reg_adc_fifoc; /* used for regmap_field */
1575     unsigned int reg_dac_txdata;    /* TX FIFO offset for DMA config */
1576     unsigned int reg_adc_rxdata;    /* RX FIFO offset for DMA config */
1577     bool has_reset;
1578 };
1579 
1580 static const struct sun4i_codec_quirks sun4i_codec_quirks = {
1581     .regmap_config  = &sun4i_codec_regmap_config,
1582     .codec      = &sun4i_codec_codec,
1583     .create_card    = sun4i_codec_create_card,
1584     .reg_adc_fifoc  = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1585     .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1586     .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1587 };
1588 
1589 static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
1590     .regmap_config  = &sun6i_codec_regmap_config,
1591     .codec      = &sun6i_codec_codec,
1592     .create_card    = sun6i_codec_create_card,
1593     .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1594     .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1595     .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1596     .has_reset  = true,
1597 };
1598 
1599 static const struct sun4i_codec_quirks sun7i_codec_quirks = {
1600     .regmap_config  = &sun7i_codec_regmap_config,
1601     .codec      = &sun7i_codec_codec,
1602     .create_card    = sun4i_codec_create_card,
1603     .reg_adc_fifoc  = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1604     .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1605     .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1606 };
1607 
1608 static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
1609     .regmap_config  = &sun8i_a23_codec_regmap_config,
1610     .codec      = &sun8i_a23_codec_codec,
1611     .create_card    = sun8i_a23_codec_create_card,
1612     .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1613     .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1614     .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1615     .has_reset  = true,
1616 };
1617 
1618 static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
1619     .regmap_config  = &sun8i_h3_codec_regmap_config,
1620     /*
1621      * TODO Share the codec structure with A23 for now.
1622      * This should be split out when adding digital audio
1623      * processing support for the H3.
1624      */
1625     .codec      = &sun8i_a23_codec_codec,
1626     .create_card    = sun8i_h3_codec_create_card,
1627     .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1628     .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1629     .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1630     .has_reset  = true,
1631 };
1632 
1633 static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
1634     .regmap_config  = &sun8i_v3s_codec_regmap_config,
1635     /*
1636      * TODO The codec structure should be split out, like
1637      * H3, when adding digital audio processing support.
1638      */
1639     .codec      = &sun8i_a23_codec_codec,
1640     .create_card    = sun8i_v3s_codec_create_card,
1641     .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1642     .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1643     .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1644     .has_reset  = true,
1645 };
1646 
1647 static const struct of_device_id sun4i_codec_of_match[] = {
1648     {
1649         .compatible = "allwinner,sun4i-a10-codec",
1650         .data = &sun4i_codec_quirks,
1651     },
1652     {
1653         .compatible = "allwinner,sun6i-a31-codec",
1654         .data = &sun6i_a31_codec_quirks,
1655     },
1656     {
1657         .compatible = "allwinner,sun7i-a20-codec",
1658         .data = &sun7i_codec_quirks,
1659     },
1660     {
1661         .compatible = "allwinner,sun8i-a23-codec",
1662         .data = &sun8i_a23_codec_quirks,
1663     },
1664     {
1665         .compatible = "allwinner,sun8i-h3-codec",
1666         .data = &sun8i_h3_codec_quirks,
1667     },
1668     {
1669         .compatible = "allwinner,sun8i-v3s-codec",
1670         .data = &sun8i_v3s_codec_quirks,
1671     },
1672     {}
1673 };
1674 MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
1675 
1676 static int sun4i_codec_probe(struct platform_device *pdev)
1677 {
1678     struct snd_soc_card *card;
1679     struct sun4i_codec *scodec;
1680     const struct sun4i_codec_quirks *quirks;
1681     struct resource *res;
1682     void __iomem *base;
1683     int ret;
1684 
1685     scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
1686     if (!scodec)
1687         return -ENOMEM;
1688 
1689     scodec->dev = &pdev->dev;
1690 
1691     base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1692     if (IS_ERR(base))
1693         return PTR_ERR(base);
1694 
1695     quirks = of_device_get_match_data(&pdev->dev);
1696     if (quirks == NULL) {
1697         dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
1698         return -ENODEV;
1699     }
1700 
1701     scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
1702                            quirks->regmap_config);
1703     if (IS_ERR(scodec->regmap)) {
1704         dev_err(&pdev->dev, "Failed to create our regmap\n");
1705         return PTR_ERR(scodec->regmap);
1706     }
1707 
1708     /* Get the clocks from the DT */
1709     scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
1710     if (IS_ERR(scodec->clk_apb)) {
1711         dev_err(&pdev->dev, "Failed to get the APB clock\n");
1712         return PTR_ERR(scodec->clk_apb);
1713     }
1714 
1715     scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
1716     if (IS_ERR(scodec->clk_module)) {
1717         dev_err(&pdev->dev, "Failed to get the module clock\n");
1718         return PTR_ERR(scodec->clk_module);
1719     }
1720 
1721     if (quirks->has_reset) {
1722         scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
1723                                    NULL);
1724         if (IS_ERR(scodec->rst)) {
1725             dev_err(&pdev->dev, "Failed to get reset control\n");
1726             return PTR_ERR(scodec->rst);
1727         }
1728     }
1729 
1730     scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
1731                           GPIOD_OUT_LOW);
1732     if (IS_ERR(scodec->gpio_pa)) {
1733         ret = PTR_ERR(scodec->gpio_pa);
1734         dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
1735         return ret;
1736     }
1737 
1738     /* reg_field setup */
1739     scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
1740                             scodec->regmap,
1741                             quirks->reg_adc_fifoc);
1742     if (IS_ERR(scodec->reg_adc_fifoc)) {
1743         ret = PTR_ERR(scodec->reg_adc_fifoc);
1744         dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
1745             ret);
1746         return ret;
1747     }
1748 
1749     /* Enable the bus clock */
1750     if (clk_prepare_enable(scodec->clk_apb)) {
1751         dev_err(&pdev->dev, "Failed to enable the APB clock\n");
1752         return -EINVAL;
1753     }
1754 
1755     /* Deassert the reset control */
1756     if (scodec->rst) {
1757         ret = reset_control_deassert(scodec->rst);
1758         if (ret) {
1759             dev_err(&pdev->dev,
1760                 "Failed to deassert the reset control\n");
1761             goto err_clk_disable;
1762         }
1763     }
1764 
1765     /* DMA configuration for TX FIFO */
1766     scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
1767     scodec->playback_dma_data.maxburst = 8;
1768     scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1769 
1770     /* DMA configuration for RX FIFO */
1771     scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
1772     scodec->capture_dma_data.maxburst = 8;
1773     scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1774 
1775     ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
1776                      &sun4i_codec_dai, 1);
1777     if (ret) {
1778         dev_err(&pdev->dev, "Failed to register our codec\n");
1779         goto err_assert_reset;
1780     }
1781 
1782     ret = devm_snd_soc_register_component(&pdev->dev,
1783                           &sun4i_codec_component,
1784                           &dummy_cpu_dai, 1);
1785     if (ret) {
1786         dev_err(&pdev->dev, "Failed to register our DAI\n");
1787         goto err_assert_reset;
1788     }
1789 
1790     ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1791     if (ret) {
1792         dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
1793         goto err_assert_reset;
1794     }
1795 
1796     card = quirks->create_card(&pdev->dev);
1797     if (IS_ERR(card)) {
1798         ret = PTR_ERR(card);
1799         dev_err(&pdev->dev, "Failed to create our card\n");
1800         goto err_assert_reset;
1801     }
1802 
1803     snd_soc_card_set_drvdata(card, scodec);
1804 
1805     ret = snd_soc_register_card(card);
1806     if (ret) {
1807         dev_err(&pdev->dev, "Failed to register our card\n");
1808         goto err_assert_reset;
1809     }
1810 
1811     return 0;
1812 
1813 err_assert_reset:
1814     if (scodec->rst)
1815         reset_control_assert(scodec->rst);
1816 err_clk_disable:
1817     clk_disable_unprepare(scodec->clk_apb);
1818     return ret;
1819 }
1820 
1821 static int sun4i_codec_remove(struct platform_device *pdev)
1822 {
1823     struct snd_soc_card *card = platform_get_drvdata(pdev);
1824     struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1825 
1826     snd_soc_unregister_card(card);
1827     if (scodec->rst)
1828         reset_control_assert(scodec->rst);
1829     clk_disable_unprepare(scodec->clk_apb);
1830 
1831     return 0;
1832 }
1833 
1834 static struct platform_driver sun4i_codec_driver = {
1835     .driver = {
1836         .name = "sun4i-codec",
1837         .of_match_table = sun4i_codec_of_match,
1838     },
1839     .probe = sun4i_codec_probe,
1840     .remove = sun4i_codec_remove,
1841 };
1842 module_platform_driver(sun4i_codec_driver);
1843 
1844 MODULE_DESCRIPTION("Allwinner A10 codec driver");
1845 MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
1846 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
1847 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1848 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
1849 MODULE_LICENSE("GPL");