1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * This driver supports the analog controls for the internal codec 4 * found in Allwinner's A64 SoC. 5 * 6 * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org> 7 * Copyright (C) 2017 Marcus Cooper <codekipper@gmail.com> 8 * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com> 9 * 10 * Based on sun8i-codec-analog.c 11 * 12 */ 13 14 #include <linux/io.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/of_device.h> 19 #include <linux/platform_device.h> 20 #include <linux/regmap.h> 21 22 #include <sound/soc.h> 23 #include <sound/soc-dapm.h> 24 #include <sound/tlv.h> 25 26 #include "sun8i-adda-pr-regmap.h" 27 28 /* Codec analog control register offsets and bit fields */ 29 #define SUN50I_ADDA_HP_CTRL 0x00 30 #define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE 7 31 #define SUN50I_ADDA_HP_CTRL_HPPA_EN 6 32 #define SUN50I_ADDA_HP_CTRL_HPVOL 0 33 34 #define SUN50I_ADDA_OL_MIX_CTRL 0x01 35 #define SUN50I_ADDA_OL_MIX_CTRL_MIC1 6 36 #define SUN50I_ADDA_OL_MIX_CTRL_MIC2 5 37 #define SUN50I_ADDA_OL_MIX_CTRL_PHONE 4 38 #define SUN50I_ADDA_OL_MIX_CTRL_PHONEN 3 39 #define SUN50I_ADDA_OL_MIX_CTRL_LINEINL 2 40 #define SUN50I_ADDA_OL_MIX_CTRL_DACL 1 41 #define SUN50I_ADDA_OL_MIX_CTRL_DACR 0 42 43 #define SUN50I_ADDA_OR_MIX_CTRL 0x02 44 #define SUN50I_ADDA_OR_MIX_CTRL_MIC1 6 45 #define SUN50I_ADDA_OR_MIX_CTRL_MIC2 5 46 #define SUN50I_ADDA_OR_MIX_CTRL_PHONE 4 47 #define SUN50I_ADDA_OR_MIX_CTRL_PHONEP 3 48 #define SUN50I_ADDA_OR_MIX_CTRL_LINEINR 2 49 #define SUN50I_ADDA_OR_MIX_CTRL_DACR 1 50 #define SUN50I_ADDA_OR_MIX_CTRL_DACL 0 51 52 #define SUN50I_ADDA_EARPIECE_CTRL0 0x03 53 #define SUN50I_ADDA_EARPIECE_CTRL0_EAR_RAMP_TIME 4 54 #define SUN50I_ADDA_EARPIECE_CTRL0_ESPSR 0 55 56 #define SUN50I_ADDA_EARPIECE_CTRL1 0x04 57 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN 7 58 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE 6 59 #define SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL 0 60 61 #define SUN50I_ADDA_LINEOUT_CTRL0 0x05 62 #define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7 63 #define SUN50I_ADDA_LINEOUT_CTRL0_REN 6 64 #define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5 65 #define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4 66 67 #define SUN50I_ADDA_LINEOUT_CTRL1 0x06 68 #define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0 69 70 #define SUN50I_ADDA_MIC1_CTRL 0x07 71 #define SUN50I_ADDA_MIC1_CTRL_MIC1G 4 72 #define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN 3 73 #define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST 0 74 75 #define SUN50I_ADDA_MIC2_CTRL 0x08 76 #define SUN50I_ADDA_MIC2_CTRL_MIC2G 4 77 #define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN 3 78 #define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST 0 79 80 #define SUN50I_ADDA_LINEIN_CTRL 0x09 81 #define SUN50I_ADDA_LINEIN_CTRL_LINEING 0 82 83 #define SUN50I_ADDA_MIX_DAC_CTRL 0x0a 84 #define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN 7 85 #define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN 6 86 #define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN 5 87 #define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN 4 88 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE 3 89 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE 2 90 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS 1 91 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS 0 92 93 #define SUN50I_ADDA_L_ADCMIX_SRC 0x0b 94 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC1 6 95 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC2 5 96 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONE 4 97 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN 3 98 #define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL 2 99 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL 1 100 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR 0 101 102 #define SUN50I_ADDA_R_ADCMIX_SRC 0x0c 103 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC1 6 104 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC2 5 105 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONE 4 106 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP 3 107 #define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR 2 108 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR 1 109 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL 0 110 111 #define SUN50I_ADDA_ADC_CTRL 0x0d 112 #define SUN50I_ADDA_ADC_CTRL_ADCREN 7 113 #define SUN50I_ADDA_ADC_CTRL_ADCLEN 6 114 #define SUN50I_ADDA_ADC_CTRL_ADCG 0 115 116 #define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e 117 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7 118 119 #define SUN50I_ADDA_JACK_MIC_CTRL 0x1d 120 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5 121 122 /* mixer controls */ 123 static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { 124 SOC_DAPM_DOUBLE_R("DAC Playback Switch", 125 SUN50I_ADDA_OL_MIX_CTRL, 126 SUN50I_ADDA_OR_MIX_CTRL, 127 SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0), 128 SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", 129 SUN50I_ADDA_OL_MIX_CTRL, 130 SUN50I_ADDA_OR_MIX_CTRL, 131 SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0), 132 SOC_DAPM_DOUBLE_R("Line In Playback Switch", 133 SUN50I_ADDA_OL_MIX_CTRL, 134 SUN50I_ADDA_OR_MIX_CTRL, 135 SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0), 136 SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", 137 SUN50I_ADDA_OL_MIX_CTRL, 138 SUN50I_ADDA_OR_MIX_CTRL, 139 SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0), 140 SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", 141 SUN50I_ADDA_OL_MIX_CTRL, 142 SUN50I_ADDA_OR_MIX_CTRL, 143 SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0), 144 }; 145 146 /* ADC mixer controls */ 147 static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = { 148 SOC_DAPM_DOUBLE_R("Mixer Capture Switch", 149 SUN50I_ADDA_L_ADCMIX_SRC, 150 SUN50I_ADDA_R_ADCMIX_SRC, 151 SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0), 152 SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", 153 SUN50I_ADDA_L_ADCMIX_SRC, 154 SUN50I_ADDA_R_ADCMIX_SRC, 155 SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0), 156 SOC_DAPM_DOUBLE_R("Line In Capture Switch", 157 SUN50I_ADDA_L_ADCMIX_SRC, 158 SUN50I_ADDA_R_ADCMIX_SRC, 159 SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0), 160 SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", 161 SUN50I_ADDA_L_ADCMIX_SRC, 162 SUN50I_ADDA_R_ADCMIX_SRC, 163 SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0), 164 SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", 165 SUN50I_ADDA_L_ADCMIX_SRC, 166 SUN50I_ADDA_R_ADCMIX_SRC, 167 SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0), 168 }; 169 170 static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale, 171 -450, 150, 0); 172 static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale, 173 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 174 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), 175 ); 176 177 static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1); 178 179 static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale, 180 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 181 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), 182 ); 183 184 static const DECLARE_TLV_DB_RANGE(sun50i_codec_earpiece_vol_scale, 185 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 186 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), 187 ); 188 189 /* volume / mute controls */ 190 static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = { 191 SOC_SINGLE_TLV("Headphone Playback Volume", 192 SUN50I_ADDA_HP_CTRL, 193 SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0, 194 sun50i_codec_hp_vol_scale), 195 196 SOC_DOUBLE("Headphone Playback Switch", 197 SUN50I_ADDA_MIX_DAC_CTRL, 198 SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE, 199 SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0), 200 201 /* Mixer pre-gain */ 202 SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL, 203 SUN50I_ADDA_MIC1_CTRL_MIC1G, 204 0x7, 0, sun50i_codec_out_mixer_pregain_scale), 205 206 /* Microphone Amp boost gain */ 207 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL, 208 SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0, 209 sun50i_codec_mic_gain_scale), 210 211 /* Mixer pre-gain */ 212 SOC_SINGLE_TLV("Mic2 Playback Volume", 213 SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G, 214 0x7, 0, sun50i_codec_out_mixer_pregain_scale), 215 216 /* Microphone Amp boost gain */ 217 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL, 218 SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0, 219 sun50i_codec_mic_gain_scale), 220 221 /* ADC */ 222 SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL, 223 SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0, 224 sun50i_codec_out_mixer_pregain_scale), 225 226 /* Mixer pre-gain */ 227 SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL, 228 SUN50I_ADDA_LINEIN_CTRL_LINEING, 229 0x7, 0, sun50i_codec_out_mixer_pregain_scale), 230 231 SOC_SINGLE_TLV("Line Out Playback Volume", 232 SUN50I_ADDA_LINEOUT_CTRL1, 233 SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, 234 sun50i_codec_lineout_vol_scale), 235 236 SOC_DOUBLE("Line Out Playback Switch", 237 SUN50I_ADDA_LINEOUT_CTRL0, 238 SUN50I_ADDA_LINEOUT_CTRL0_LEN, 239 SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), 240 241 SOC_SINGLE_TLV("Earpiece Playback Volume", 242 SUN50I_ADDA_EARPIECE_CTRL1, 243 SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0, 244 sun50i_codec_earpiece_vol_scale), 245 246 SOC_SINGLE("Earpiece Playback Switch", 247 SUN50I_ADDA_EARPIECE_CTRL1, 248 SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0), 249 250 }; 251 252 static const char * const sun50i_codec_hp_src_enum_text[] = { 253 "DAC", "Mixer", 254 }; 255 256 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum, 257 SUN50I_ADDA_MIX_DAC_CTRL, 258 SUN50I_ADDA_MIX_DAC_CTRL_LHPIS, 259 SUN50I_ADDA_MIX_DAC_CTRL_RHPIS, 260 sun50i_codec_hp_src_enum_text); 261 262 static const struct snd_kcontrol_new sun50i_codec_hp_src[] = { 263 SOC_DAPM_ENUM("Headphone Source Playback Route", 264 sun50i_codec_hp_src_enum), 265 }; 266 267 static const char * const sun50i_codec_lineout_src_enum_text[] = { 268 "Stereo", "Mono Differential", 269 }; 270 271 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum, 272 SUN50I_ADDA_LINEOUT_CTRL0, 273 SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL, 274 SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL, 275 sun50i_codec_lineout_src_enum_text); 276 277 static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { 278 SOC_DAPM_ENUM("Line Out Source Playback Route", 279 sun50i_codec_lineout_src_enum), 280 }; 281 282 static const char * const sun50i_codec_earpiece_src_enum_text[] = { 283 "DACR", "DACL", "Right Mixer", "Left Mixer", 284 }; 285 286 static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum, 287 SUN50I_ADDA_EARPIECE_CTRL0, 288 SUN50I_ADDA_EARPIECE_CTRL0_ESPSR, 289 sun50i_codec_earpiece_src_enum_text); 290 291 static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = { 292 SOC_DAPM_ENUM("Earpiece Source Playback Route", 293 sun50i_codec_earpiece_src_enum), 294 }; 295 296 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { 297 /* DAC */ 298 SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, 299 SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0), 300 SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, 301 SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0), 302 /* ADC */ 303 SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL, 304 SUN50I_ADDA_ADC_CTRL_ADCLEN, 0), 305 SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL, 306 SUN50I_ADDA_ADC_CTRL_ADCREN, 0), 307 /* 308 * Due to this component and the codec belonging to separate DAPM 309 * contexts, we need to manually link the above widgets to their 310 * stream widgets at the card level. 311 */ 312 313 SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0), 314 SND_SOC_DAPM_MUX("Headphone Source Playback Route", 315 SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), 316 SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, 317 SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0), 318 SND_SOC_DAPM_OUTPUT("HP"), 319 320 SND_SOC_DAPM_MUX("Line Out Source Playback Route", 321 SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), 322 SND_SOC_DAPM_OUTPUT("LINEOUT"), 323 324 SND_SOC_DAPM_MUX("Earpiece Source Playback Route", 325 SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src), 326 SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1, 327 SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0), 328 SND_SOC_DAPM_OUTPUT("EARPIECE"), 329 330 /* Microphone inputs */ 331 SND_SOC_DAPM_INPUT("MIC1"), 332 333 /* Microphone Bias */ 334 SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL, 335 SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN, 336 0, NULL, 0), 337 338 /* Mic input path */ 339 SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL, 340 SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0), 341 342 /* Microphone input */ 343 SND_SOC_DAPM_INPUT("MIC2"), 344 345 /* Microphone Bias */ 346 SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL, 347 SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN, 348 0, NULL, 0), 349 350 /* Mic input path */ 351 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL, 352 SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0), 353 354 /* Line input */ 355 SND_SOC_DAPM_INPUT("LINEIN"), 356 357 /* Mixers */ 358 SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL, 359 SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0, 360 sun50i_a64_codec_mixer_controls, 361 ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), 362 SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL, 363 SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0, 364 sun50i_a64_codec_mixer_controls, 365 ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), 366 SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL, 367 SUN50I_ADDA_ADC_CTRL_ADCLEN, 0, 368 sun50i_codec_adc_mixer_controls, 369 ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), 370 SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL, 371 SUN50I_ADDA_ADC_CTRL_ADCREN, 0, 372 sun50i_codec_adc_mixer_controls, 373 ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), 374 }; 375 376 static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { 377 /* Left Mixer Routes */ 378 { "Left Mixer", "DAC Playback Switch", "Left DAC" }, 379 { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, 380 { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 381 382 /* Right Mixer Routes */ 383 { "Right Mixer", "DAC Playback Switch", "Right DAC" }, 384 { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, 385 { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 386 387 /* Left ADC Mixer Routes */ 388 { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, 389 { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, 390 { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 391 392 /* Right ADC Mixer Routes */ 393 { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, 394 { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, 395 { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 396 397 /* ADC Routes */ 398 { "Left ADC", NULL, "Left ADC Mixer" }, 399 { "Right ADC", NULL, "Right ADC Mixer" }, 400 401 /* Headphone Routes */ 402 { "Headphone Source Playback Route", "DAC", "Left DAC" }, 403 { "Headphone Source Playback Route", "DAC", "Right DAC" }, 404 { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, 405 { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, 406 { "Headphone Amp", NULL, "Headphone Source Playback Route" }, 407 { "Headphone Amp", NULL, "cpvdd" }, 408 { "HP", NULL, "Headphone Amp" }, 409 410 /* Microphone Routes */ 411 { "Mic1 Amplifier", NULL, "MIC1"}, 412 413 /* Microphone Routes */ 414 { "Mic2 Amplifier", NULL, "MIC2"}, 415 { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 416 { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 417 { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 418 { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 419 420 /* Line-in Routes */ 421 { "Left Mixer", "Line In Playback Switch", "LINEIN" }, 422 { "Right Mixer", "Line In Playback Switch", "LINEIN" }, 423 { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, 424 { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, 425 426 /* Line-out Routes */ 427 { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, 428 { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, 429 { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, 430 { "Line Out Source Playback Route", "Mono Differential", 431 "Right Mixer" }, 432 { "LINEOUT", NULL, "Line Out Source Playback Route" }, 433 434 /* Earpiece Routes */ 435 { "Earpiece Source Playback Route", "DACL", "Left DAC" }, 436 { "Earpiece Source Playback Route", "DACR", "Right DAC" }, 437 { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" }, 438 { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" }, 439 { "Earpiece Amp", NULL, "Earpiece Source Playback Route" }, 440 { "EARPIECE", NULL, "Earpiece Amp" }, 441 }; 442 443 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { 444 .controls = sun50i_a64_codec_controls, 445 .num_controls = ARRAY_SIZE(sun50i_a64_codec_controls), 446 .dapm_widgets = sun50i_a64_codec_widgets, 447 .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), 448 .dapm_routes = sun50i_a64_codec_routes, 449 .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), 450 }; 451 452 static const struct of_device_id sun50i_codec_analog_of_match[] = { 453 { 454 .compatible = "allwinner,sun50i-a64-codec-analog", 455 }, 456 {} 457 }; 458 MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match); 459 460 static int sun50i_codec_analog_probe(struct platform_device *pdev) 461 { 462 struct regmap *regmap; 463 void __iomem *base; 464 465 base = devm_platform_ioremap_resource(pdev, 0); 466 if (IS_ERR(base)) { 467 dev_err(&pdev->dev, "Failed to map the registers\n"); 468 return PTR_ERR(base); 469 } 470 471 regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); 472 if (IS_ERR(regmap)) { 473 dev_err(&pdev->dev, "Failed to create regmap\n"); 474 return PTR_ERR(regmap); 475 } 476 477 return devm_snd_soc_register_component(&pdev->dev, 478 &sun50i_codec_analog_cmpnt_drv, 479 NULL, 0); 480 } 481 482 static struct platform_driver sun50i_codec_analog_driver = { 483 .driver = { 484 .name = "sun50i-codec-analog", 485 .of_match_table = sun50i_codec_analog_of_match, 486 }, 487 .probe = sun50i_codec_analog_probe, 488 }; 489 module_platform_driver(sun50i_codec_analog_driver); 490 491 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64"); 492 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); 493 MODULE_LICENSE("GPL"); 494 MODULE_ALIAS("platform:sun50i-codec-analog"); 495