Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * This driver supports the analog controls for the internal codec
0004  * found in Allwinner's A64 SoC.
0005  *
0006  * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
0007  * Copyright (C) 2017 Marcus Cooper <codekipper@gmail.com>
0008  * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com>
0009  *
0010  * Based on sun8i-codec-analog.c
0011  *
0012  */
0013 
0014 #include <linux/io.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021 
0022 #include <sound/soc.h>
0023 #include <sound/soc-dapm.h>
0024 #include <sound/tlv.h>
0025 
0026 #include "sun8i-adda-pr-regmap.h"
0027 
0028 /* Codec analog control register offsets and bit fields */
0029 #define SUN50I_ADDA_HP_CTRL     0x00
0030 #define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE     7
0031 #define SUN50I_ADDA_HP_CTRL_HPPA_EN     6
0032 #define SUN50I_ADDA_HP_CTRL_HPVOL       0
0033 
0034 #define SUN50I_ADDA_OL_MIX_CTRL     0x01
0035 #define SUN50I_ADDA_OL_MIX_CTRL_MIC1        6
0036 #define SUN50I_ADDA_OL_MIX_CTRL_MIC2        5
0037 #define SUN50I_ADDA_OL_MIX_CTRL_PHONE       4
0038 #define SUN50I_ADDA_OL_MIX_CTRL_PHONEN      3
0039 #define SUN50I_ADDA_OL_MIX_CTRL_LINEINL     2
0040 #define SUN50I_ADDA_OL_MIX_CTRL_DACL        1
0041 #define SUN50I_ADDA_OL_MIX_CTRL_DACR        0
0042 
0043 #define SUN50I_ADDA_OR_MIX_CTRL     0x02
0044 #define SUN50I_ADDA_OR_MIX_CTRL_MIC1        6
0045 #define SUN50I_ADDA_OR_MIX_CTRL_MIC2        5
0046 #define SUN50I_ADDA_OR_MIX_CTRL_PHONE       4
0047 #define SUN50I_ADDA_OR_MIX_CTRL_PHONEP      3
0048 #define SUN50I_ADDA_OR_MIX_CTRL_LINEINR     2
0049 #define SUN50I_ADDA_OR_MIX_CTRL_DACR        1
0050 #define SUN50I_ADDA_OR_MIX_CTRL_DACL        0
0051 
0052 #define SUN50I_ADDA_EARPIECE_CTRL0  0x03
0053 #define SUN50I_ADDA_EARPIECE_CTRL0_EAR_RAMP_TIME    4
0054 #define SUN50I_ADDA_EARPIECE_CTRL0_ESPSR        0
0055 
0056 #define SUN50I_ADDA_EARPIECE_CTRL1  0x04
0057 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN 7
0058 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE   6
0059 #define SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL  0
0060 
0061 #define SUN50I_ADDA_LINEOUT_CTRL0   0x05
0062 #define SUN50I_ADDA_LINEOUT_CTRL0_LEN       7
0063 #define SUN50I_ADDA_LINEOUT_CTRL0_REN       6
0064 #define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL  5
0065 #define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL  4
0066 
0067 #define SUN50I_ADDA_LINEOUT_CTRL1   0x06
0068 #define SUN50I_ADDA_LINEOUT_CTRL1_VOL       0
0069 
0070 #define SUN50I_ADDA_MIC1_CTRL       0x07
0071 #define SUN50I_ADDA_MIC1_CTRL_MIC1G     4
0072 #define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN     3
0073 #define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST     0
0074 
0075 #define SUN50I_ADDA_MIC2_CTRL       0x08
0076 #define SUN50I_ADDA_MIC2_CTRL_MIC2G     4
0077 #define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN     3
0078 #define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST     0
0079 
0080 #define SUN50I_ADDA_LINEIN_CTRL     0x09
0081 #define SUN50I_ADDA_LINEIN_CTRL_LINEING     0
0082 
0083 #define SUN50I_ADDA_MIX_DAC_CTRL    0x0a
0084 #define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN    7
0085 #define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN    6
0086 #define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN     5
0087 #define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN     4
0088 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE  3
0089 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE  2
0090 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS      1
0091 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS      0
0092 
0093 #define SUN50I_ADDA_L_ADCMIX_SRC    0x0b
0094 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC1       6
0095 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC2       5
0096 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONE      4
0097 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN     3
0098 #define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL    2
0099 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL     1
0100 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR     0
0101 
0102 #define SUN50I_ADDA_R_ADCMIX_SRC    0x0c
0103 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC1       6
0104 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC2       5
0105 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONE      4
0106 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP     3
0107 #define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR    2
0108 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR      1
0109 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL      0
0110 
0111 #define SUN50I_ADDA_ADC_CTRL        0x0d
0112 #define SUN50I_ADDA_ADC_CTRL_ADCREN     7
0113 #define SUN50I_ADDA_ADC_CTRL_ADCLEN     6
0114 #define SUN50I_ADDA_ADC_CTRL_ADCG       0
0115 
0116 #define SUN50I_ADDA_HS_MBIAS_CTRL   0x0e
0117 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN    7
0118 
0119 #define SUN50I_ADDA_JACK_MIC_CTRL   0x1d
0120 #define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN    6
0121 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN    5
0122 
0123 /* mixer controls */
0124 static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
0125     SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
0126               SUN50I_ADDA_OL_MIX_CTRL,
0127               SUN50I_ADDA_OR_MIX_CTRL,
0128               SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
0129     SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
0130               SUN50I_ADDA_OL_MIX_CTRL,
0131               SUN50I_ADDA_OR_MIX_CTRL,
0132               SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
0133     SOC_DAPM_DOUBLE_R("Line In Playback Switch",
0134               SUN50I_ADDA_OL_MIX_CTRL,
0135               SUN50I_ADDA_OR_MIX_CTRL,
0136               SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),
0137     SOC_DAPM_DOUBLE_R("DAC Playback Switch",
0138               SUN50I_ADDA_OL_MIX_CTRL,
0139               SUN50I_ADDA_OR_MIX_CTRL,
0140               SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
0141     SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
0142               SUN50I_ADDA_OL_MIX_CTRL,
0143               SUN50I_ADDA_OR_MIX_CTRL,
0144               SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
0145 };
0146 
0147 /* ADC mixer controls */
0148 static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {
0149     SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
0150               SUN50I_ADDA_L_ADCMIX_SRC,
0151               SUN50I_ADDA_R_ADCMIX_SRC,
0152               SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
0153     SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
0154               SUN50I_ADDA_L_ADCMIX_SRC,
0155               SUN50I_ADDA_R_ADCMIX_SRC,
0156               SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
0157     SOC_DAPM_DOUBLE_R("Line In Capture Switch",
0158               SUN50I_ADDA_L_ADCMIX_SRC,
0159               SUN50I_ADDA_R_ADCMIX_SRC,
0160               SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),
0161     SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
0162               SUN50I_ADDA_L_ADCMIX_SRC,
0163               SUN50I_ADDA_R_ADCMIX_SRC,
0164               SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
0165     SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
0166               SUN50I_ADDA_L_ADCMIX_SRC,
0167               SUN50I_ADDA_R_ADCMIX_SRC,
0168               SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
0169 };
0170 
0171 static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,
0172                   -450, 150, 0);
0173 static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale,
0174     0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
0175     1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
0176 );
0177 
0178 static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1);
0179 
0180 static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale,
0181     0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
0182     2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
0183 );
0184 
0185 static const DECLARE_TLV_DB_RANGE(sun50i_codec_earpiece_vol_scale,
0186     0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
0187     2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
0188 );
0189 
0190 /* volume / mute controls */
0191 static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
0192     SOC_SINGLE_TLV("Headphone Playback Volume",
0193                SUN50I_ADDA_HP_CTRL,
0194                SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,
0195                sun50i_codec_hp_vol_scale),
0196 
0197     /* Mixer pre-gain */
0198     SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
0199                SUN50I_ADDA_MIC1_CTRL_MIC1G,
0200                0x7, 0, sun50i_codec_out_mixer_pregain_scale),
0201 
0202     /* Microphone Amp boost gain */
0203     SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,
0204                SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,
0205                sun50i_codec_mic_gain_scale),
0206 
0207     /* Mixer pre-gain */
0208     SOC_SINGLE_TLV("Mic2 Playback Volume",
0209                SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,
0210                0x7, 0, sun50i_codec_out_mixer_pregain_scale),
0211 
0212     /* Microphone Amp boost gain */
0213     SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,
0214                SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,
0215                sun50i_codec_mic_gain_scale),
0216 
0217     /* ADC */
0218     SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,
0219                SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,
0220                sun50i_codec_out_mixer_pregain_scale),
0221 
0222     /* Mixer pre-gain */
0223     SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,
0224                SUN50I_ADDA_LINEIN_CTRL_LINEING,
0225                0x7, 0, sun50i_codec_out_mixer_pregain_scale),
0226 
0227     SOC_SINGLE_TLV("Line Out Playback Volume",
0228                SUN50I_ADDA_LINEOUT_CTRL1,
0229                SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
0230                sun50i_codec_lineout_vol_scale),
0231 
0232     SOC_SINGLE_TLV("Earpiece Playback Volume",
0233                SUN50I_ADDA_EARPIECE_CTRL1,
0234                SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,
0235                sun50i_codec_earpiece_vol_scale),
0236 };
0237 
0238 static const char * const sun50i_codec_hp_src_enum_text[] = {
0239     "DAC", "Mixer",
0240 };
0241 
0242 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,
0243                 SUN50I_ADDA_MIX_DAC_CTRL,
0244                 SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,
0245                 SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,
0246                 sun50i_codec_hp_src_enum_text);
0247 
0248 static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
0249     SOC_DAPM_ENUM("Headphone Source Playback Route",
0250               sun50i_codec_hp_src_enum),
0251 };
0252 
0253 static const struct snd_kcontrol_new sun50i_codec_hp_switch =
0254     SOC_DAPM_DOUBLE("Headphone Playback Switch",
0255             SUN50I_ADDA_MIX_DAC_CTRL,
0256             SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
0257             SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0);
0258 
0259 static const char * const sun50i_codec_lineout_src_enum_text[] = {
0260     "Stereo", "Mono Differential",
0261 };
0262 
0263 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
0264                 SUN50I_ADDA_LINEOUT_CTRL0,
0265                 SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
0266                 SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
0267                 sun50i_codec_lineout_src_enum_text);
0268 
0269 static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
0270     SOC_DAPM_ENUM("Line Out Source Playback Route",
0271               sun50i_codec_lineout_src_enum),
0272 };
0273 
0274 static const struct snd_kcontrol_new sun50i_codec_lineout_switch =
0275     SOC_DAPM_DOUBLE("Line Out Playback Switch",
0276             SUN50I_ADDA_LINEOUT_CTRL0,
0277             SUN50I_ADDA_LINEOUT_CTRL0_LEN,
0278             SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0);
0279 
0280 static const char * const sun50i_codec_earpiece_src_enum_text[] = {
0281     "DACR", "DACL", "Right Mixer", "Left Mixer",
0282 };
0283 
0284 static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum,
0285                 SUN50I_ADDA_EARPIECE_CTRL0,
0286                 SUN50I_ADDA_EARPIECE_CTRL0_ESPSR,
0287                 sun50i_codec_earpiece_src_enum_text);
0288 
0289 static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {
0290     SOC_DAPM_ENUM("Earpiece Source Playback Route",
0291               sun50i_codec_earpiece_src_enum),
0292 };
0293 
0294 static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {
0295     SOC_DAPM_SINGLE("Earpiece Playback Switch",
0296             SUN50I_ADDA_EARPIECE_CTRL1,
0297             SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
0298 };
0299 
0300 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
0301     /* DAC */
0302     SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
0303              SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),
0304     SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
0305              SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),
0306     /* ADC */
0307     SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,
0308              SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),
0309     SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,
0310              SUN50I_ADDA_ADC_CTRL_ADCREN, 0),
0311     /*
0312      * Due to this component and the codec belonging to separate DAPM
0313      * contexts, we need to manually link the above widgets to their
0314      * stream widgets at the card level.
0315      */
0316 
0317     SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),
0318     SND_SOC_DAPM_MUX("Left Headphone Source",
0319              SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
0320     SND_SOC_DAPM_MUX("Right Headphone Source",
0321              SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
0322     SND_SOC_DAPM_SWITCH("Left Headphone Switch",
0323                 SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
0324     SND_SOC_DAPM_SWITCH("Right Headphone Switch",
0325                 SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
0326     SND_SOC_DAPM_OUT_DRV("Left Headphone Amp",
0327                  SND_SOC_NOPM, 0, 0, NULL, 0),
0328     SND_SOC_DAPM_OUT_DRV("Right Headphone Amp",
0329                  SND_SOC_NOPM, 0, 0, NULL, 0),
0330     SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL,
0331                  SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
0332     SND_SOC_DAPM_OUTPUT("HP"),
0333 
0334     SND_SOC_DAPM_MUX("Left Line Out Source",
0335              SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
0336     SND_SOC_DAPM_MUX("Right Line Out Source",
0337              SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
0338     SND_SOC_DAPM_SWITCH("Left Line Out Switch",
0339                 SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
0340     SND_SOC_DAPM_SWITCH("Right Line Out Switch",
0341                 SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
0342     SND_SOC_DAPM_OUTPUT("LINEOUT"),
0343 
0344     SND_SOC_DAPM_MUX("Earpiece Source Playback Route",
0345              SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),
0346     SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch",
0347                   SND_SOC_NOPM, 0, 0,
0348                   sun50i_codec_earpiece_switch),
0349     SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,
0350                  SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),
0351     SND_SOC_DAPM_OUTPUT("EARPIECE"),
0352 
0353     /* Microphone inputs */
0354     SND_SOC_DAPM_INPUT("MIC1"),
0355 
0356     /* Microphone Bias */
0357     SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,
0358                 SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,
0359                 0, NULL, 0),
0360 
0361     /* Mic input path */
0362     SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,
0363              SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),
0364 
0365     /* Microphone input */
0366     SND_SOC_DAPM_INPUT("MIC2"),
0367 
0368     /* Microphone Bias */
0369     SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
0370                 SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
0371                 0, NULL, 0),
0372 
0373     /* Mic input path */
0374     SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
0375              SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),
0376 
0377     /* Line input */
0378     SND_SOC_DAPM_INPUT("LINEIN"),
0379 
0380     /* Mixers */
0381     SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
0382                SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,
0383                sun50i_a64_codec_mixer_controls,
0384                ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
0385     SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
0386                SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
0387                sun50i_a64_codec_mixer_controls,
0388                ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
0389     SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
0390                sun50i_codec_adc_mixer_controls,
0391                ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
0392     SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
0393                sun50i_codec_adc_mixer_controls,
0394                ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
0395 };
0396 
0397 static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
0398     /* Left Mixer Routes */
0399     { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
0400     { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
0401     { "Left Mixer", "Line In Playback Switch", "LINEIN" },
0402     { "Left Mixer", "DAC Playback Switch", "Left DAC" },
0403     { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
0404 
0405     /* Right Mixer Routes */
0406     { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
0407     { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
0408     { "Right Mixer", "Line In Playback Switch", "LINEIN" },
0409     { "Right Mixer", "DAC Playback Switch", "Right DAC" },
0410     { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
0411 
0412     /* Left ADC Mixer Routes */
0413     { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
0414     { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
0415     { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
0416     { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
0417     { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
0418 
0419     /* Right ADC Mixer Routes */
0420     { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
0421     { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
0422     { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
0423     { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
0424     { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
0425 
0426     /* ADC Routes */
0427     { "Left ADC", NULL, "Left ADC Mixer" },
0428     { "Right ADC", NULL, "Right ADC Mixer" },
0429 
0430     /* Headphone Routes */
0431     { "Left Headphone Source", "DAC", "Left DAC" },
0432     { "Left Headphone Source", "Mixer", "Left Mixer" },
0433     { "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" },
0434     { "Left Headphone Amp", NULL, "Left Headphone Switch" },
0435     { "Left Headphone Amp", NULL, "Headphone Amp" },
0436     { "HP", NULL, "Left Headphone Amp" },
0437 
0438     { "Right Headphone Source", "DAC", "Right DAC" },
0439     { "Right Headphone Source", "Mixer", "Right Mixer" },
0440     { "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" },
0441     { "Right Headphone Amp", NULL, "Right Headphone Switch" },
0442     { "Right Headphone Amp", NULL, "Headphone Amp" },
0443     { "HP", NULL, "Right Headphone Amp" },
0444 
0445     { "Headphone Amp", NULL, "cpvdd" },
0446 
0447     /* Microphone Routes */
0448     { "Mic1 Amplifier", NULL, "MIC1"},
0449 
0450     /* Microphone Routes */
0451     { "Mic2 Amplifier", NULL, "MIC2"},
0452 
0453     /* Line-out Routes */
0454     { "Left Line Out Source", "Stereo", "Left Mixer" },
0455     { "Left Line Out Source", "Mono Differential", "Left Mixer" },
0456     { "Left Line Out Source", "Mono Differential", "Right Mixer" },
0457     { "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" },
0458     { "LINEOUT", NULL, "Left Line Out Switch" },
0459 
0460     { "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" },
0461     { "Right Line Out Source", "Stereo", "Right Line Out Switch" },
0462     { "Right Line Out Source", "Mono Differential", "Left Line Out Switch" },
0463     { "LINEOUT", NULL, "Right Line Out Source" },
0464 
0465     /* Earpiece Routes */
0466     { "Earpiece Source Playback Route", "DACL", "Left DAC" },
0467     { "Earpiece Source Playback Route", "DACR", "Right DAC" },
0468     { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },
0469     { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },
0470     { "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" },
0471     { "Earpiece Amp", NULL, "Earpiece Switch" },
0472     { "EARPIECE", NULL, "Earpiece Amp" },
0473 };
0474 
0475 static int sun50i_a64_codec_suspend(struct snd_soc_component *component)
0476 {
0477     return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
0478                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE),
0479                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
0480 }
0481 
0482 static int sun50i_a64_codec_resume(struct snd_soc_component *component)
0483 {
0484     return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
0485                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0);
0486 }
0487 
0488 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
0489     .controls       = sun50i_a64_codec_controls,
0490     .num_controls       = ARRAY_SIZE(sun50i_a64_codec_controls),
0491     .dapm_widgets       = sun50i_a64_codec_widgets,
0492     .num_dapm_widgets   = ARRAY_SIZE(sun50i_a64_codec_widgets),
0493     .dapm_routes        = sun50i_a64_codec_routes,
0494     .num_dapm_routes    = ARRAY_SIZE(sun50i_a64_codec_routes),
0495     .suspend        = sun50i_a64_codec_suspend,
0496     .resume         = sun50i_a64_codec_resume,
0497 };
0498 
0499 static const struct of_device_id sun50i_codec_analog_of_match[] = {
0500     {
0501         .compatible = "allwinner,sun50i-a64-codec-analog",
0502     },
0503     {}
0504 };
0505 MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);
0506 
0507 static int sun50i_codec_analog_probe(struct platform_device *pdev)
0508 {
0509     struct regmap *regmap;
0510     void __iomem *base;
0511     bool enable;
0512 
0513     base = devm_platform_ioremap_resource(pdev, 0);
0514     if (IS_ERR(base)) {
0515         dev_err(&pdev->dev, "Failed to map the registers\n");
0516         return PTR_ERR(base);
0517     }
0518 
0519     regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
0520     if (IS_ERR(regmap)) {
0521         dev_err(&pdev->dev, "Failed to create regmap\n");
0522         return PTR_ERR(regmap);
0523     }
0524 
0525     enable = device_property_read_bool(&pdev->dev,
0526                        "allwinner,internal-bias-resistor");
0527     regmap_update_bits(regmap, SUN50I_ADDA_JACK_MIC_CTRL,
0528                BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN),
0529                enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN);
0530 
0531     return devm_snd_soc_register_component(&pdev->dev,
0532                            &sun50i_codec_analog_cmpnt_drv,
0533                            NULL, 0);
0534 }
0535 
0536 static struct platform_driver sun50i_codec_analog_driver = {
0537     .driver = {
0538         .name = "sun50i-codec-analog",
0539         .of_match_table = sun50i_codec_analog_of_match,
0540     },
0541     .probe = sun50i_codec_analog_probe,
0542 };
0543 module_platform_driver(sun50i_codec_analog_driver);
0544 
0545 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");
0546 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
0547 MODULE_LICENSE("GPL");
0548 MODULE_ALIAS("platform:sun50i-codec-analog");