brintos

brintos / linux-shallow public Read only

0
0
Text · 20.6 KiB · 2dcdf11 Raw
597 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * This driver supports the analog controls for the internal codec4 * 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.c11 *12 */13 14#include <linux/io.h>15#include <linux/kernel.h>16#include <linux/mod_devicetable.h>17#include <linux/module.h>18#include <linux/platform_device.h>19#include <linux/regmap.h>20 21#include <sound/soc.h>22#include <sound/soc-dapm.h>23#include <sound/tlv.h>24 25#include "sun8i-adda-pr-regmap.h"26 27/* Codec analog control register offsets and bit fields */28#define SUN50I_ADDA_HP_CTRL		0x0029#define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE		730#define SUN50I_ADDA_HP_CTRL_HPPA_EN		631#define SUN50I_ADDA_HP_CTRL_HPVOL		032 33#define SUN50I_ADDA_OL_MIX_CTRL		0x0134#define SUN50I_ADDA_OL_MIX_CTRL_MIC1		635#define SUN50I_ADDA_OL_MIX_CTRL_MIC2		536#define SUN50I_ADDA_OL_MIX_CTRL_PHONE		437#define SUN50I_ADDA_OL_MIX_CTRL_PHONEN		338#define SUN50I_ADDA_OL_MIX_CTRL_LINEINL		239#define SUN50I_ADDA_OL_MIX_CTRL_DACL		140#define SUN50I_ADDA_OL_MIX_CTRL_DACR		041 42#define SUN50I_ADDA_OR_MIX_CTRL		0x0243#define SUN50I_ADDA_OR_MIX_CTRL_MIC1		644#define SUN50I_ADDA_OR_MIX_CTRL_MIC2		545#define SUN50I_ADDA_OR_MIX_CTRL_PHONE		446#define SUN50I_ADDA_OR_MIX_CTRL_PHONEP		347#define SUN50I_ADDA_OR_MIX_CTRL_LINEINR		248#define SUN50I_ADDA_OR_MIX_CTRL_DACR		149#define SUN50I_ADDA_OR_MIX_CTRL_DACL		050 51#define SUN50I_ADDA_EARPIECE_CTRL0	0x0352#define SUN50I_ADDA_EARPIECE_CTRL0_EAR_RAMP_TIME	453#define SUN50I_ADDA_EARPIECE_CTRL0_ESPSR		054 55#define SUN50I_ADDA_EARPIECE_CTRL1	0x0456#define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN	757#define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE	658#define SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL	059 60#define SUN50I_ADDA_LINEOUT_CTRL0	0x0561#define SUN50I_ADDA_LINEOUT_CTRL0_LEN		762#define SUN50I_ADDA_LINEOUT_CTRL0_REN		663#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL	564#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL	465 66#define SUN50I_ADDA_LINEOUT_CTRL1	0x0667#define SUN50I_ADDA_LINEOUT_CTRL1_VOL		068 69#define SUN50I_ADDA_MIC1_CTRL		0x0770#define SUN50I_ADDA_MIC1_CTRL_MIC1G		471#define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN		372#define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST		073 74#define SUN50I_ADDA_MIC2_CTRL		0x0875#define SUN50I_ADDA_MIC2_CTRL_MIC2G		476#define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN		377#define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST		078 79#define SUN50I_ADDA_LINEIN_CTRL		0x0980#define SUN50I_ADDA_LINEIN_CTRL_LINEING		081 82#define SUN50I_ADDA_MIX_DAC_CTRL	0x0a83#define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN	784#define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN	685#define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN		586#define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN		487#define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE	388#define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE	289#define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS		190#define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS		091 92#define SUN50I_ADDA_L_ADCMIX_SRC	0x0b93#define SUN50I_ADDA_L_ADCMIX_SRC_MIC1		694#define SUN50I_ADDA_L_ADCMIX_SRC_MIC2		595#define SUN50I_ADDA_L_ADCMIX_SRC_PHONE		496#define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN		397#define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL	298#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL		199#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR		0100 101#define SUN50I_ADDA_R_ADCMIX_SRC	0x0c102#define SUN50I_ADDA_R_ADCMIX_SRC_MIC1		6103#define SUN50I_ADDA_R_ADCMIX_SRC_MIC2		5104#define SUN50I_ADDA_R_ADCMIX_SRC_PHONE		4105#define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP		3106#define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR	2107#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR		1108#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL		0109 110#define SUN50I_ADDA_ADC_CTRL		0x0d111#define SUN50I_ADDA_ADC_CTRL_ADCREN		7112#define SUN50I_ADDA_ADC_CTRL_ADCLEN		6113#define SUN50I_ADDA_ADC_CTRL_ADCG		0114 115#define SUN50I_ADDA_HS_MBIAS_CTRL	0x0e116#define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN	7117 118#define SUN50I_ADDA_MDET_CTRL		0x1c119#define SUN50I_ADDA_MDET_CTRL_SELDETADC_FS	4120#define SUN50I_ADDA_MDET_CTRL_SELDETADC_DB	2121#define SUN50I_ADDA_MDET_CTRL_SELDETADC_BF	0122 123#define SUN50I_ADDA_JACK_MIC_CTRL	0x1d124#define SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN	7125#define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN	6126#define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN	5127#define SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN	4128 129/* mixer controls */130static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {131	SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",132			  SUN50I_ADDA_OL_MIX_CTRL,133			  SUN50I_ADDA_OR_MIX_CTRL,134			  SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),135	SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",136			  SUN50I_ADDA_OL_MIX_CTRL,137			  SUN50I_ADDA_OR_MIX_CTRL,138			  SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),139	SOC_DAPM_DOUBLE_R("Line In Playback Switch",140			  SUN50I_ADDA_OL_MIX_CTRL,141			  SUN50I_ADDA_OR_MIX_CTRL,142			  SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),143	SOC_DAPM_DOUBLE_R("DAC Playback Switch",144			  SUN50I_ADDA_OL_MIX_CTRL,145			  SUN50I_ADDA_OR_MIX_CTRL,146			  SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),147	SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",148			  SUN50I_ADDA_OL_MIX_CTRL,149			  SUN50I_ADDA_OR_MIX_CTRL,150			  SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),151};152 153/* ADC mixer controls */154static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {155	SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",156			  SUN50I_ADDA_L_ADCMIX_SRC,157			  SUN50I_ADDA_R_ADCMIX_SRC,158			  SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),159	SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",160			  SUN50I_ADDA_L_ADCMIX_SRC,161			  SUN50I_ADDA_R_ADCMIX_SRC,162			  SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),163	SOC_DAPM_DOUBLE_R("Line In Capture Switch",164			  SUN50I_ADDA_L_ADCMIX_SRC,165			  SUN50I_ADDA_R_ADCMIX_SRC,166			  SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),167	SOC_DAPM_DOUBLE_R("Mixer Capture Switch",168			  SUN50I_ADDA_L_ADCMIX_SRC,169			  SUN50I_ADDA_R_ADCMIX_SRC,170			  SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),171	SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",172			  SUN50I_ADDA_L_ADCMIX_SRC,173			  SUN50I_ADDA_R_ADCMIX_SRC,174			  SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),175};176 177static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,178				  -450, 150, 0);179static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale,180	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),181	1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),182);183 184static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1);185 186static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale,187	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),188	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),189);190 191static const DECLARE_TLV_DB_RANGE(sun50i_codec_earpiece_vol_scale,192	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),193	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),194);195 196/* volume / mute controls */197static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {198	SOC_SINGLE_TLV("Headphone Playback Volume",199		       SUN50I_ADDA_HP_CTRL,200		       SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,201		       sun50i_codec_hp_vol_scale),202 203	/* Mixer pre-gain */204	SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,205		       SUN50I_ADDA_MIC1_CTRL_MIC1G,206		       0x7, 0, sun50i_codec_out_mixer_pregain_scale),207 208	/* Microphone Amp boost gain */209	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,210		       SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,211		       sun50i_codec_mic_gain_scale),212 213	/* Mixer pre-gain */214	SOC_SINGLE_TLV("Mic2 Playback Volume",215		       SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,216		       0x7, 0, sun50i_codec_out_mixer_pregain_scale),217 218	/* Microphone Amp boost gain */219	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,220		       SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,221		       sun50i_codec_mic_gain_scale),222 223	/* ADC */224	SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,225		       SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,226		       sun50i_codec_out_mixer_pregain_scale),227 228	/* Mixer pre-gain */229	SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,230		       SUN50I_ADDA_LINEIN_CTRL_LINEING,231		       0x7, 0, sun50i_codec_out_mixer_pregain_scale),232 233	SOC_SINGLE_TLV("Line Out Playback Volume",234		       SUN50I_ADDA_LINEOUT_CTRL1,235		       SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,236		       sun50i_codec_lineout_vol_scale),237 238	SOC_SINGLE_TLV("Earpiece Playback Volume",239		       SUN50I_ADDA_EARPIECE_CTRL1,240		       SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,241		       sun50i_codec_earpiece_vol_scale),242};243 244static const char * const sun50i_codec_hp_src_enum_text[] = {245	"DAC", "Mixer",246};247 248static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,249			    SUN50I_ADDA_MIX_DAC_CTRL,250			    SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,251			    SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,252			    sun50i_codec_hp_src_enum_text);253 254static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {255	SOC_DAPM_ENUM("Headphone Source Playback Route",256		      sun50i_codec_hp_src_enum),257};258 259static const struct snd_kcontrol_new sun50i_codec_hp_switch =260	SOC_DAPM_DOUBLE("Headphone Playback Switch",261			SUN50I_ADDA_MIX_DAC_CTRL,262			SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,263			SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0);264 265static const char * const sun50i_codec_lineout_src_enum_text[] = {266	"Stereo", "Mono Differential",267};268 269static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,270			    SUN50I_ADDA_LINEOUT_CTRL0,271			    SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,272			    SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,273			    sun50i_codec_lineout_src_enum_text);274 275static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {276	SOC_DAPM_ENUM("Line Out Source Playback Route",277		      sun50i_codec_lineout_src_enum),278};279 280static const struct snd_kcontrol_new sun50i_codec_lineout_switch =281	SOC_DAPM_DOUBLE("Line Out Playback Switch",282			SUN50I_ADDA_LINEOUT_CTRL0,283			SUN50I_ADDA_LINEOUT_CTRL0_LEN,284			SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0);285 286static const char * const sun50i_codec_earpiece_src_enum_text[] = {287	"DACR", "DACL", "Right Mixer", "Left Mixer",288};289 290static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum,291			    SUN50I_ADDA_EARPIECE_CTRL0,292			    SUN50I_ADDA_EARPIECE_CTRL0_ESPSR,293			    sun50i_codec_earpiece_src_enum_text);294 295static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {296	SOC_DAPM_ENUM("Earpiece Source Playback Route",297		      sun50i_codec_earpiece_src_enum),298};299 300static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {301	SOC_DAPM_SINGLE("Earpiece Playback Switch",302			SUN50I_ADDA_EARPIECE_CTRL1,303			SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),304};305 306static int sun50i_codec_hbias_event(struct snd_soc_dapm_widget *w,307				    struct snd_kcontrol *kcontrol, int event)308{309	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);310	u32 value = !!SND_SOC_DAPM_EVENT_ON(event);311 312	regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,313			   BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),314			   value << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);315 316	return 0;317}318 319static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {320	/* DAC */321	SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,322			 SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),323	SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,324			 SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),325	/* ADC */326	SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,327			 SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),328	SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,329			 SUN50I_ADDA_ADC_CTRL_ADCREN, 0),330	/*331	 * Due to this component and the codec belonging to separate DAPM332	 * contexts, we need to manually link the above widgets to their333	 * stream widgets at the card level.334	 */335 336	SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),337	SND_SOC_DAPM_MUX("Left Headphone Source",338			 SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),339	SND_SOC_DAPM_MUX("Right Headphone Source",340			 SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),341	SND_SOC_DAPM_SWITCH("Left Headphone Switch",342			    SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),343	SND_SOC_DAPM_SWITCH("Right Headphone Switch",344			    SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),345	SND_SOC_DAPM_OUT_DRV("Left Headphone Amp",346			     SND_SOC_NOPM, 0, 0, NULL, 0),347	SND_SOC_DAPM_OUT_DRV("Right Headphone Amp",348			     SND_SOC_NOPM, 0, 0, NULL, 0),349	SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL,350			     SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),351	SND_SOC_DAPM_OUTPUT("HP"),352 353	SND_SOC_DAPM_MUX("Left Line Out Source",354			 SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),355	SND_SOC_DAPM_MUX("Right Line Out Source",356			 SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),357	SND_SOC_DAPM_SWITCH("Left Line Out Switch",358			    SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),359	SND_SOC_DAPM_SWITCH("Right Line Out Switch",360			    SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),361	SND_SOC_DAPM_OUTPUT("LINEOUT"),362 363	SND_SOC_DAPM_MUX("Earpiece Source Playback Route",364			 SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),365	SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch",366				  SND_SOC_NOPM, 0, 0,367				  sun50i_codec_earpiece_switch),368	SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,369			     SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),370	SND_SOC_DAPM_OUTPUT("EARPIECE"),371 372	/* Microphone inputs */373	SND_SOC_DAPM_INPUT("MIC1"),374 375	/* Microphone Bias */376	SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,377			    SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,378			    0, NULL, 0),379 380	/* Mic input path */381	SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,382			 SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),383 384	/* Microphone input */385	SND_SOC_DAPM_INPUT("MIC2"),386 387	/* Microphone Bias */388	SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,389			    SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,390			    0, sun50i_codec_hbias_event,391			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),392 393	/* Mic input path */394	SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,395			 SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),396 397	/* Line input */398	SND_SOC_DAPM_INPUT("LINEIN"),399 400	/* Mixers */401	SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,402			   SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,403			   sun50i_a64_codec_mixer_controls,404			   ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),405	SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,406			   SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,407			   sun50i_a64_codec_mixer_controls,408			   ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),409	SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,410			   sun50i_codec_adc_mixer_controls,411			   ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),412	SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,413			   sun50i_codec_adc_mixer_controls,414			   ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),415};416 417static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {418	/* Left Mixer Routes */419	{ "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },420	{ "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },421	{ "Left Mixer", "Line In Playback Switch", "LINEIN" },422	{ "Left Mixer", "DAC Playback Switch", "Left DAC" },423	{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },424 425	/* Right Mixer Routes */426	{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },427	{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },428	{ "Right Mixer", "Line In Playback Switch", "LINEIN" },429	{ "Right Mixer", "DAC Playback Switch", "Right DAC" },430	{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },431 432	/* Left ADC Mixer Routes */433	{ "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },434	{ "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },435	{ "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },436	{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },437	{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },438 439	/* Right ADC Mixer Routes */440	{ "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },441	{ "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },442	{ "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },443	{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },444	{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },445 446	/* ADC Routes */447	{ "Left ADC", NULL, "Left ADC Mixer" },448	{ "Right ADC", NULL, "Right ADC Mixer" },449 450	/* Headphone Routes */451	{ "Left Headphone Source", "DAC", "Left DAC" },452	{ "Left Headphone Source", "Mixer", "Left Mixer" },453	{ "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" },454	{ "Left Headphone Amp", NULL, "Left Headphone Switch" },455	{ "Left Headphone Amp", NULL, "Headphone Amp" },456	{ "HP", NULL, "Left Headphone Amp" },457 458	{ "Right Headphone Source", "DAC", "Right DAC" },459	{ "Right Headphone Source", "Mixer", "Right Mixer" },460	{ "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" },461	{ "Right Headphone Amp", NULL, "Right Headphone Switch" },462	{ "Right Headphone Amp", NULL, "Headphone Amp" },463	{ "HP", NULL, "Right Headphone Amp" },464 465	{ "Headphone Amp", NULL, "cpvdd" },466 467	/* Microphone Routes */468	{ "Mic1 Amplifier", NULL, "MIC1"},469 470	/* Microphone Routes */471	{ "Mic2 Amplifier", NULL, "MIC2"},472 473	/* Line-out Routes */474	{ "Left Line Out Source", "Stereo", "Left Mixer" },475	{ "Left Line Out Source", "Mono Differential", "Left Mixer" },476	{ "Left Line Out Source", "Mono Differential", "Right Mixer" },477	{ "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" },478	{ "LINEOUT", NULL, "Left Line Out Switch" },479 480	{ "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" },481	{ "Right Line Out Source", "Stereo", "Right Line Out Switch" },482	{ "Right Line Out Source", "Mono Differential", "Left Line Out Switch" },483	{ "LINEOUT", NULL, "Right Line Out Source" },484 485	/* Earpiece Routes */486	{ "Earpiece Source Playback Route", "DACL", "Left DAC" },487	{ "Earpiece Source Playback Route", "DACR", "Right DAC" },488	{ "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },489	{ "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },490	{ "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" },491	{ "Earpiece Amp", NULL, "Earpiece Switch" },492	{ "EARPIECE", NULL, "Earpiece Amp" },493};494 495static int sun50i_a64_codec_set_bias_level(struct snd_soc_component *component,496					   enum snd_soc_bias_level level)497{498	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);499	int hbias;500 501	switch (level) {502	case SND_SOC_BIAS_OFF:503		regmap_clear_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,504				   BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |505				   BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN));506 507		regmap_set_bits(component->regmap, SUN50I_ADDA_HP_CTRL,508				BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));509		break;510	case SND_SOC_BIAS_STANDBY:511		regmap_clear_bits(component->regmap, SUN50I_ADDA_HP_CTRL,512				   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));513 514		hbias = snd_soc_dapm_get_pin_status(dapm, "HBIAS");515		regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,516				   BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |517				   BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),518				   BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |519				   hbias << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);520		break;521	default:522		break;523	}524 525	return 0;526}527 528static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {529	.controls		= sun50i_a64_codec_controls,530	.num_controls		= ARRAY_SIZE(sun50i_a64_codec_controls),531	.dapm_widgets		= sun50i_a64_codec_widgets,532	.num_dapm_widgets	= ARRAY_SIZE(sun50i_a64_codec_widgets),533	.dapm_routes		= sun50i_a64_codec_routes,534	.num_dapm_routes	= ARRAY_SIZE(sun50i_a64_codec_routes),535	.set_bias_level		= sun50i_a64_codec_set_bias_level,536	.idle_bias_on		= true,537	.suspend_bias_off	= true,538};539 540static const struct of_device_id sun50i_codec_analog_of_match[] = {541	{542		.compatible = "allwinner,sun50i-a64-codec-analog",543	},544	{}545};546MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);547 548static int sun50i_codec_analog_probe(struct platform_device *pdev)549{550	struct regmap *regmap;551	void __iomem *base;552	bool enable;553 554	base = devm_platform_ioremap_resource(pdev, 0);555	if (IS_ERR(base)) {556		dev_err(&pdev->dev, "Failed to map the registers\n");557		return PTR_ERR(base);558	}559 560	regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);561	if (IS_ERR(regmap)) {562		dev_err(&pdev->dev, "Failed to create regmap\n");563		return PTR_ERR(regmap);564	}565 566	enable = device_property_read_bool(&pdev->dev,567					   "allwinner,internal-bias-resistor");568	regmap_update_bits(regmap, SUN50I_ADDA_JACK_MIC_CTRL,569			   BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN),570			   enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN);571 572	/* Select sample interval of the ADC sample to 16ms */573	regmap_update_bits(regmap, SUN50I_ADDA_MDET_CTRL,574			   0x7 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |575			   0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF,576			   0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |577			   0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF);578 579	return devm_snd_soc_register_component(&pdev->dev,580					       &sun50i_codec_analog_cmpnt_drv,581					       NULL, 0);582}583 584static struct platform_driver sun50i_codec_analog_driver = {585	.driver = {586		.name = "sun50i-codec-analog",587		.of_match_table = sun50i_codec_analog_of_match,588	},589	.probe = sun50i_codec_analog_probe,590};591module_platform_driver(sun50i_codec_analog_driver);592 593MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");594MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");595MODULE_LICENSE("GPL");596MODULE_ALIAS("platform:sun50i-codec-analog");597