/* * sound\soc\codec\ac100_dapm.c * (C) Copyright 2010-2017 * Reuuimlla Technology Co., Ltd. * huangxin * * some simple description for this code * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ac100.h" /* key define */ #define KEY_HEADSETHOOK (226) #define HEADSET_CHECKCOUNT (10) #define HEADSET_CHECKCOUNT_SUM (2) struct spk_gpio spkgpio; struct spk_gpio hsgpio; static int speaker_double_used; static int double_speaker_val; static int single_speaker_val; static int headset_val; static int earpiece_val; static int mainmic_val; static int headsetmic_val; static int dmic_used; static int adc_digital_val; static int agc_used; static int drc_used; static int aif2_lrck_div; static int aif2_bclk_div; static volatile int reset_flag; struct val_str { int *val; char *str; }; enum dectect_jack { PLUG_OUT = 0x0, PLUG_IN = 0x1, }; static struct val_str properties[] = { {&speaker_double_used, "speaker_double_used"}, {&double_speaker_val, "double_speaker_val"}, {&single_speaker_val, "single_speaker_val"}, {&headset_val, "headset_val"}, {&earpiece_val, "earpiece_val"}, {&mainmic_val, "mainmic_val"}, {&headsetmic_val, "headsetmic_val"}, {&dmic_used, "dmic_used"}, {&adc_digital_val, "adc_digital_val"}, {&agc_used, "agc_used"}, {&drc_used, "drc_used"} }; #define ac100_RATES (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_KNOT) #define ac100_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S18_3LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) struct voltage_supply { struct regulator *avcc; struct regulator *io1; struct regulator *io2; struct regulator *ldoin; struct regulator *cpvdd; }; /*struct for ac100*/ struct ac100_priv { struct ac100 *ac100; struct snd_soc_codec *codec; struct mutex dac_mutex; struct mutex adc_mutex; struct mutex mute_mutex; u8 dac_enable; u8 adc_enable; struct mutex aifclk_mutex; u8 aif1_clken; u8 aif2_clken; u8 aif3_clken; u8 aif2_mute; u8 aif1_mute; /*voltage supply*/ struct voltage_supply vol_supply; /*headset*/ int state; int check_count; int check_count_sum; struct work_struct codec_resume; struct delayed_work hs_detect_work; struct delayed_work hs_irq_work; struct mutex jack_mutex; struct snd_soc_jack jack; u32 detect_state; u32 jack_irq; /*switch irq*/ u32 HEADSET_DATA; /*threshod for switch insert*/ u32 switch_status; u32 key_volup; u32 key_voldown; u32 key_hook; u32 jack_gpio; bool hmic_used; }; #if 0 static void snd_sunxi_unregister_jack(struct ac100_priv *ac100) { /* *Set process button events to false so that the *delayed work will not be scheduled. */ cancel_delayed_work_sync(&ac100->hs_detect_work); cancel_delayed_work_sync(&ac100->hs_irq_work); } #endif static void get_configuration(struct platform_device *pdev) { struct device_node *node = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-ac100-codec"); unsigned int val; int i; int ret; for (i = 0; i < ARRAY_SIZE(properties); i++) { ret = of_property_read_u32(node, properties[i].str, &val); if (ret < 0) { dev_warn(&pdev->dev, "%s config missing or invalid\n", properties[i].str); *(properties[i].val) = 0; } else { *(properties[i].val) = val; pr_debug("%s=%d\n", properties[i].str, *(properties[i].val)); } } } #if 0 static void agc_config(struct snd_soc_codec *codec) { int reg_val; reg_val = snd_soc_read(codec, 0xb4); reg_val |= (0x3<<6); snd_soc_write(codec, 0xb4, reg_val); reg_val = snd_soc_read(codec, 0x84); reg_val &= ~(0x3f<<8); reg_val |= (0x31<<8); snd_soc_write(codec, 0x84, reg_val); reg_val = snd_soc_read(codec, 0x84); reg_val &= ~(0xff<<0); reg_val |= (0x28<<0); snd_soc_write(codec, 0x84, reg_val); reg_val = snd_soc_read(codec, 0x85); reg_val &= ~(0x3f<<8); reg_val |= (0x31<<8); snd_soc_write(codec, 0x85, reg_val); reg_val = snd_soc_read(codec, 0x85); reg_val &= ~(0xff<<0); reg_val |= (0x28<<0); snd_soc_write(codec, 0x85, reg_val); reg_val = snd_soc_read(codec, 0x8a); reg_val &= ~(0x7fff<<0); reg_val |= (0x24<<0); snd_soc_write(codec, 0x8a, reg_val); reg_val = snd_soc_read(codec, 0x8b); reg_val &= ~(0x7fff<<0); reg_val |= (0x2<<0); snd_soc_write(codec, 0x8b, reg_val); reg_val = snd_soc_read(codec, 0x8c); reg_val &= ~(0x7fff<<0); reg_val |= (0x24<<0); snd_soc_write(codec, 0x8c, reg_val); reg_val = snd_soc_read(codec, 0x8d); reg_val &= ~(0x7fff<<0); reg_val |= (0x2<<0); snd_soc_write(codec, 0x8d, reg_val); reg_val = snd_soc_read(codec, 0x8e); reg_val &= ~(0x1f<<8); reg_val |= (0xf<<8); reg_val &= ~(0x1f<<0); reg_val |= (0xf<<0); snd_soc_write(codec, 0x8e, reg_val); reg_val = snd_soc_read(codec, 0x93); reg_val &= ~(0x7ff<<0); reg_val |= (0xfc<<0); snd_soc_write(codec, 0x93, reg_val); snd_soc_write(codec, 0x94, 0xabb3); } #endif static void drc_config(struct snd_soc_codec *codec) { int reg_val; reg_val = snd_soc_read(codec, 0xa3); reg_val &= ~(0x7ff<<0); reg_val |= 1<<0; snd_soc_write(codec, 0xa3, reg_val); snd_soc_write(codec, 0xa4, 0x2baf); reg_val = snd_soc_read(codec, 0xa5); reg_val &= ~(0x7ff<<0); reg_val |= 1<<0; snd_soc_write(codec, 0xa5, reg_val); snd_soc_write(codec, 0xa6, 0x2baf); reg_val = snd_soc_read(codec, 0xa7); reg_val &= ~(0x7ff<<0); snd_soc_write(codec, 0xa7, reg_val); snd_soc_write(codec, 0xa8, 0x44a); reg_val = snd_soc_read(codec, 0xa9); reg_val &= ~(0x7ff<<0); snd_soc_write(codec, 0xa9, reg_val); snd_soc_write(codec, 0xaa, 0x1e06); reg_val = snd_soc_read(codec, 0xab); reg_val &= ~(0x7ff<<0); reg_val |= (0x352<<0); snd_soc_write(codec, 0xab, reg_val); snd_soc_write(codec, 0xac, 0x6910); reg_val = snd_soc_read(codec, 0xad); reg_val &= ~(0x7ff<<0); reg_val |= (0x77a<<0); snd_soc_write(codec, 0xad, reg_val); snd_soc_write(codec, 0xae, 0xaaaa); reg_val = snd_soc_read(codec, 0xaf); reg_val &= ~(0x7ff<<0); reg_val |= (0x2de<<0); snd_soc_write(codec, 0xaf, reg_val); snd_soc_write(codec, 0xb0, 0xc982); snd_soc_write(codec, 0x16, 0x9f9f); } static void agc_enable(struct snd_soc_codec *codec, bool on) { int reg_val; if (on) { reg_val = snd_soc_read(codec, MOD_CLK_ENA); reg_val |= (0x1<dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->dac_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: AC100_DBG("%s,line:%d\n", __func__, __LINE__); if (ac100->dac_enable == 0) { /*enable dac module clk*/ snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<dac_enable++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->dac_enable > 0) { ac100->dac_enable--; if (ac100->dac_enable == 0) { snd_soc_update_bits(codec, DAC_DIG_CTRL, (0x1<dac_mutex); return 0; } static int late_enable_adc(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->adc_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (ac100->adc_enable == 0) { /*enable adc module clk*/ snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<adc_enable++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->adc_enable > 0) { ac100->adc_enable--; if (ac100->adc_enable == 0) { snd_soc_update_bits(codec, ADC_DIG_CTRL, (0x1<adc_mutex); return 0; } static int ac100_speaker_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: AC100_DBG("[speaker open ]%s,line:%d\n", __func__, __LINE__); if (drc_used) drc_enable(codec, 1); msleep(30); if (spkgpio.used) gpio_set_value(spkgpio.gpio, 1); break; case SND_SOC_DAPM_PRE_PMD: AC100_DBG("[speaker close ]%s,line:%d\n", __func__, __LINE__); if (spkgpio.used) gpio_set_value(spkgpio.gpio, 0); if (drc_used) drc_enable(codec, 0); break; default: break; } return 0; } static int ac100_earpiece_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: AC100_DBG("[earpiece open ]%s,line:%d\n", __func__, __LINE__); snd_soc_update_bits(codec, ESPKOUT_CTRL, (0x1<dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: /*open*/ AC100_DBG("post:open:%s,line:%d\n", __func__, __LINE__); snd_soc_update_bits(codec, OMIXER_DACA_CTRL, (0xf<dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->aifclk_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (ac100->aif1_clken == 0) { /*enable AIF1CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->aif1_clken > 0) { ac100->aif1_clken--; if (ac100->aif1_clken == 0) { /*disable AIF1CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aifclk_mutex); return 0; } int ac100_aif2clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->aifclk_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (ac100->aif2_clken == 0) { /*enable AIF2CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->aif2_clken > 0) { ac100->aif2_clken--; if (ac100->aif2_clken == 0) { /*disable AIF2CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aifclk_mutex); return 0; } int ac100_aif3clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->aifclk_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (ac100->aif2_clken == 0) { /*enable AIF2CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken++; if (ac100->aif3_clken == 0) { /*enable AIF3CLK*/ snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<aif3_clken++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->aif2_clken > 0) { ac100->aif2_clken--; if (ac100->aif2_clken == 0) { /*disable AIF2CLK*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken == 0 && ac100->aif3_clken == 0) snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif3_clken > 0) { ac100->aif3_clken--; if (ac100->aif3_clken == 0) { /*enable AIF3CLK*/ snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<aifclk_mutex); return 0; } static int aif2inl_vir_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: snd_soc_update_bits(codec, AIF3_SGP_CTRL, (0x3<dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: snd_soc_update_bits(codec, AIF3_SGP_CTRL, (0x3<dapm); struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: snd_soc_update_bits(codec, ADC_DIG_CTRL, (0x1<adc_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (ac100->adc_enable == 0) { /*enable adc module clk*/ snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<adc_enable++; break; case SND_SOC_DAPM_POST_PMD: if (ac100->adc_enable > 0) { ac100->adc_enable--; if (ac100->adc_enable == 0) { snd_soc_update_bits(codec, ADC_DIG_CTRL, (0x1<adc_mutex); return 0; } static const DECLARE_TLV_DB_SCALE(headphone_vol_tlv, -6300, 100, 0); static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -450, 150, 0); static const DECLARE_TLV_DB_SCALE(speaker_vol_tlv, -4800, 150, 0); static const DECLARE_TLV_DB_SCALE(earpiece_vol_tlv, -4350, 150, 0); static const DECLARE_TLV_DB_SCALE(aif1_ad_slot0_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif1_ad_slot1_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif1_da_slot0_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif1_da_slot1_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif1_ad_slot0_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(aif1_ad_slot1_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(aif2_ad_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif2_da_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(aif2_ad_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(dig_vol_tlv, -7308, 116, 0); static const DECLARE_TLV_DB_SCALE(dac_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(adc_input_vol_tlv, -450, 150, 0); /*mic1/mic2: 0db when 000, and from 30db to 48db when 001 to 111*/ static const DECLARE_TLV_DB_SCALE(mic1_boost_vol_tlv, 0, 200, 0); static const DECLARE_TLV_DB_SCALE(mic2_boost_vol_tlv, 0, 200, 0); static const DECLARE_TLV_DB_SCALE(linein_amp_vol_tlv, -1200, 300, 0); static const DECLARE_TLV_DB_SCALE(axui_amp_vol_tlv, -1200, 300, 0); static const DECLARE_TLV_DB_SCALE(axin_to_l_r_mix_vol_tlv, -450, 150, 0); static const DECLARE_TLV_DB_SCALE(mic1_to_l_r_mix_vol_tlv, -450, 150, 0); static const DECLARE_TLV_DB_SCALE(mic2_to_l_r_mix_vol_tlv, -450, 150, 0); static const DECLARE_TLV_DB_SCALE(linein_to_l_r_mix_vol_tlv, -450, 150, 0); static const struct snd_kcontrol_new ac100_controls[] = { /*AIF1*/ SOC_DOUBLE_TLV("AIF1 ADC timeslot 0 volume", AIF1_VOL_CTRL1, AIF1_AD0L_VOL, AIF1_AD0R_VOL, 0xff, 0, aif1_ad_slot0_vol_tlv), SOC_DOUBLE_TLV("AIF1 ADC timeslot 1 volume", AIF1_VOL_CTRL2, AIF1_AD1L_VOL, AIF1_AD1R_VOL, 0xff, 0, aif1_ad_slot1_vol_tlv), SOC_DOUBLE_TLV("AIF1 DAC timeslot 0 volume", AIF1_VOL_CTRL3, AIF1_DA0L_VOL, AIF1_DA0R_VOL, 0xff, 0, aif1_da_slot0_vol_tlv), SOC_DOUBLE_TLV("AIF1 DAC timeslot 1 volume", AIF1_VOL_CTRL4, AIF1_DA1L_VOL, AIF1_DA1R_VOL, 0xff, 0, aif1_da_slot1_vol_tlv), SOC_DOUBLE_TLV("AIF1 ADC timeslot 0 mixer gain", AIF1_MXR_GAIN, AIF1_AD0L_MXR_GAIN, AIF1_AD0R_MXR_GAIN, 0xf, 0, aif1_ad_slot0_mix_vol_tlv), SOC_DOUBLE_TLV("AIF1 ADC timeslot 1 mixer gain", AIF1_MXR_GAIN, AIF1_AD1L_MXR_GAIN, AIF1_AD1R_MXR_GAIN, 0x3, 0, aif1_ad_slot1_mix_vol_tlv), /*AIF2*/ SOC_DOUBLE_TLV("AIF2 ADC volume", AIF2_VOL_CTRL1, AIF2_ADCL_VOL, AIF2_ADCR_VOL, 0xff, 0, aif2_ad_vol_tlv), SOC_DOUBLE_TLV("AIF2 DAC volume", AIF2_VOL_CTRL2, AIF2_DACL_VOL, AIF2_DACR_VOL, 0xff, 0, aif2_da_vol_tlv), SOC_DOUBLE_TLV("AIF2 ADC mixer gain", AIF2_MXR_GAIN, AIF2_ADCL_MXR_GAIN, AIF2_ADCR_MXR_GAIN, 0xf, 0, aif2_ad_mix_vol_tlv), /*ADC*/ SOC_DOUBLE_TLV("ADC volume", ADC_VOL_CTRL, ADC_VOL_L, ADC_VOL_R, 0xff, 0, adc_vol_tlv), /*DAC*/ SOC_DOUBLE_TLV("DAC volume", DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R, 0xff, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC mixer gain", DAC_MXR_GAIN, DACL_MXR_GAIN, DACR_MXR_GAIN, 0xf, 0, dac_mix_vol_tlv), SOC_SINGLE_TLV("digital volume", DAC_DBG_CTRL, DVC, 0x3f, 0, dig_vol_tlv), /*ADC*/ SOC_SINGLE_TLV("LADC input gain", ADC_APC_CTRL, ADCLG, 0x7, 0, adc_input_vol_tlv), SOC_SINGLE_TLV("RADC input gain", ADC_APC_CTRL, ADCRG, 0x7, 0, adc_input_vol_tlv), SOC_SINGLE_TLV("MIC1 boost amplifier gain", ADC_SRCBST_CTRL, ADC_MIC1G, 0x7, 0, mic1_boost_vol_tlv), SOC_SINGLE_TLV("MIC2 boost amplifier gain", ADC_SRCBST_CTRL, ADC_MIC2G, 0x7, 0, mic2_boost_vol_tlv), SOC_SINGLE_TLV("LINEINL-LINEINR pre-amplifier gain", ADC_SRCBST_CTRL, LINEIN_PREG, 0x7, 0, linein_amp_vol_tlv), SOC_SINGLE_TLV("AUXI pre-amplifier gain", ADC_SRCBST_CTRL, AUXI_PREG, 0x7, 0, axui_amp_vol_tlv), SOC_SINGLE_TLV("AXin to L_R output mixer gain", OMIXER_BST1_CTRL, AXG, 0x7, 0, axin_to_l_r_mix_vol_tlv), SOC_SINGLE_TLV("MIC1 BST stage to L_R outp mixer gain", OMIXER_BST1_CTRL, OMIXER_MIC1G, 0x7, 0, mic1_to_l_r_mix_vol_tlv), SOC_SINGLE_TLV("MIC2 BST stage to L_R outp mixer gain", OMIXER_BST1_CTRL, OMIXER_MIC2G, 0x7, 0, mic2_to_l_r_mix_vol_tlv), SOC_SINGLE_TLV("LINEINL/R to L_R output mixer gain", OMIXER_BST1_CTRL, LINEING, 0x7, 0, linein_to_l_r_mix_vol_tlv), SOC_SINGLE_TLV("earpiece volume", ESPKOUT_CTRL, ESP_VOL, 0x1f, 0, earpiece_vol_tlv), SOC_SINGLE_TLV("speaker volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv), SOC_SINGLE_TLV("line out volume", LOUT_CTRL, LINEOUTG, 0x7, 0, lineout_vol_tlv), SOC_SINGLE_TLV("headphone volume", HPOUT_CTRL, HP_VOL, 0x3f, 0, headphone_vol_tlv), }; /*AIF1 AD0 OUT */ static const char * const aif1out0l_text[] = { "AIF1_AD0L", "AIF1_AD0R", "SUM_AIF1AD0L_AIF1AD0R", "AVE_AIF1AD0L_AIF1AD0R" }; static const char * const aif1out0r_text[] = { "AIF1_AD0R", "AIF1_AD0L", "SUM_AIF1AD0L_AIF1AD0R", "AVE_AIF1AD0L_AIF1AD0R" }; static const struct soc_enum aif1out0l_enum = SOC_ENUM_SINGLE(AIF1_ADCDAT_CTRL, AIF1_AD0L_SRC, ARRAY_SIZE(aif1out0l_text), aif1out0l_text); static const struct snd_kcontrol_new aif1out0l_mux = SOC_DAPM_ENUM("AIF1OUT0L Mux", aif1out0l_enum); static const struct soc_enum aif1out0r_enum = SOC_ENUM_SINGLE(AIF1_ADCDAT_CTRL, AIF1_AD0R_SRC, ARRAY_SIZE(aif1out0r_text), aif1out0r_text); static const struct snd_kcontrol_new aif1out0r_mux = SOC_DAPM_ENUM("AIF1OUT0R Mux", aif1out0r_enum); /*AIF1 AD1 OUT */ static const char * const aif1out1l_text[] = { "AIF1_AD1L", "AIF1_AD1R", "SUM_AIF1ADC1L_AIF1ADC1R", "AVE_AIF1ADC1L_AIF1ADC1R" }; static const char * const aif1out1r_text[] = { "AIF1_AD1R", "AIF1_AD1L", "SUM_AIF1ADC1L_AIF1ADC1R", "AVE_AIF1ADC1L_AIF1ADC1R" }; static const struct soc_enum aif1out1l_enum = SOC_ENUM_SINGLE(AIF1_ADCDAT_CTRL, AIF1_AD1L_SRC, ARRAY_SIZE(aif1out1l_text), aif1out1l_text); static const struct snd_kcontrol_new aif1out1l_mux = SOC_DAPM_ENUM("AIF1OUT1L Mux", aif1out1l_enum); static const struct soc_enum aif1out1r_enum = SOC_ENUM_SINGLE(AIF1_ADCDAT_CTRL, AIF1_AD1R_SRC, ARRAY_SIZE(aif1out1r_text), aif1out1r_text); static const struct snd_kcontrol_new aif1out1r_mux = SOC_DAPM_ENUM("AIF1OUT1R Mux", aif1out1r_enum); /*AIF1 DA0 IN*/ static const char * const aif1in0l_text[] = { "AIF1_DA0L", "AIF1_DA0R", "SUM_AIF1DA0L_AIF1DA0R", "AVE_AIF1DA0L_AIF1DA0R" }; static const char * const aif1in0r_text[] = { "AIF1_DA0R", "AIF1_DA0L", "SUM_AIF1DA0L_AIF1DA0R", "AVE_AIF1DA0L_AIF1DA0R" }; static const struct soc_enum aif1in0l_enum = SOC_ENUM_SINGLE(AIF1_DACDAT_CTRL, AIF1_DA0L_SRC, ARRAY_SIZE(aif1in0l_text), aif1in0l_text); static const struct snd_kcontrol_new aif1in0l_mux = SOC_DAPM_ENUM("AIF1IN0L Mux", aif1in0l_enum); static const struct soc_enum aif1in0r_enum = SOC_ENUM_SINGLE(AIF1_DACDAT_CTRL, AIF1_DA0R_SRC, ARRAY_SIZE(aif1in0r_text), aif1in0r_text); static const struct snd_kcontrol_new aif1in0r_mux = SOC_DAPM_ENUM("AIF1IN0R Mux", aif1in0r_enum); /*AIF1 DA1 IN*/ static const char * const aif1in1l_text[] = { "AIF1_DA1L", "AIF1_DA1R", "SUM_AIF1DA1L_AIF1DA1R", "AVE_AIF1DA1L_AIF1DA1R" }; static const char * const aif1in1r_text[] = { "AIF1_DA1R", "AIF1_DA1L", "SUM_AIF1DA1L_AIF1DA1R", "AVE_AIF1DA1L_AIF1DA1R" }; static const struct soc_enum aif1in1l_enum = SOC_ENUM_SINGLE(AIF1_DACDAT_CTRL, AIF1_DA1L_SRC, ARRAY_SIZE(aif1in1l_text), aif1in1l_text); static const struct snd_kcontrol_new aif1in1l_mux = SOC_DAPM_ENUM("AIF1IN1L Mux", aif1in1l_enum); static const struct soc_enum aif1in1r_enum = SOC_ENUM_SINGLE(AIF1_DACDAT_CTRL, AIF1_DA1R_SRC, ARRAY_SIZE(aif1in1r_text), aif1in1r_text); static const struct snd_kcontrol_new aif1in1r_mux = SOC_DAPM_ENUM("AIF1IN1R Mux", aif1in1r_enum); /*0x13register*/ /*AIF1 ADC0 MIXER SOURCE*/ static const struct snd_kcontrol_new aif1_ad0l_mxr_src_ctl[] = { SOC_DAPM_SINGLE("AIF1 DA0L Switch", AIF1_MXR_SRC, AIF1_AD0L_AIF1_DA0L_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACL Switch", AIF1_MXR_SRC, AIF1_AD0L_AIF2_DACL_MXR, 1, 0), SOC_DAPM_SINGLE("ADCL Switch", AIF1_MXR_SRC, AIF1_AD0L_ADCL_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACR Switch", AIF1_MXR_SRC, AIF1_AD0L_AIF2_DACR_MXR, 1, 0), }; static const struct snd_kcontrol_new aif1_ad0r_mxr_src_ctl[] = { SOC_DAPM_SINGLE("AIF1 DA0R Switch", AIF1_MXR_SRC, AIF1_AD0R_AIF1_DA0R_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACR Switch", AIF1_MXR_SRC, AIF1_AD0R_AIF2_DACR_MXR, 1, 0), SOC_DAPM_SINGLE("ADCR Switch", AIF1_MXR_SRC, AIF1_AD0R_ADCR_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACL Switch", AIF1_MXR_SRC, AIF1_AD0R_AIF2_DACL_MXR, 1, 0), }; /*AIF1 ADC1 MIXER SOURCE*/ static const struct snd_kcontrol_new aif1_ad1l_mxr_src_ctl[] = { SOC_DAPM_SINGLE("AIF2 DACL Switch", AIF1_MXR_SRC, AIF1_AD1L_AIF2_DACL_MXR, 1, 0), SOC_DAPM_SINGLE("ADCL Switch", AIF1_MXR_SRC, AIF1_AD1L_ADCL_MXR, 1, 0), }; static const struct snd_kcontrol_new aif1_ad1r_mxr_src_ctl[] = { SOC_DAPM_SINGLE("AIF2 DACR Switch", AIF1_MXR_SRC, AIF1_AD1R_AIF2_DACR_MXR, 1, 0), SOC_DAPM_SINGLE("ADCR Switch", AIF1_MXR_SRC, AIF1_AD1R_ADCR_MXR, 1, 0), }; /*4C register*/ static const struct snd_kcontrol_new dacl_mxr_src_controls[] = { SOC_DAPM_SINGLE("ADCL Switch", DAC_MXR_SRC, DACL_MXR_ADCL, 1, 0), SOC_DAPM_SINGLE("AIF2DACL Switch", DAC_MXR_SRC, DACL_MXR_AIF2_DACL, 1, 0), SOC_DAPM_SINGLE("AIF1DA1L Switch", DAC_MXR_SRC, DACL_MXR_AIF1_DA1L, 1, 0), SOC_DAPM_SINGLE("AIF1DA0L Switch", DAC_MXR_SRC, DACL_MXR_AIF1_DA0L, 1, 0), }; static const struct snd_kcontrol_new dacr_mxr_src_controls[] = { SOC_DAPM_SINGLE("ADCR Switch", DAC_MXR_SRC, DACR_MXR_ADCR, 1, 0), SOC_DAPM_SINGLE("AIF2DACR Switch", DAC_MXR_SRC, DACR_MXR_AIF2_DACR, 1, 0), SOC_DAPM_SINGLE("AIF1DA1R Switch", DAC_MXR_SRC, DACR_MXR_AIF1_DA1R, 1, 0), SOC_DAPM_SINGLE("AIF1DA0R Switch", DAC_MXR_SRC, DACR_MXR_AIF1_DA0R, 1, 0), }; /*output mixer source select*/ /*defined left output mixer*/ static const struct snd_kcontrol_new ac100_loutmix_controls[] = { SOC_DAPM_SINGLE("DACR Switch", OMIXER_SR, LMIXMUTEDACR, 1, 0), SOC_DAPM_SINGLE("DACL Switch", OMIXER_SR, LMIXMUTEDACL, 1, 0), SOC_DAPM_SINGLE("AUXINL Switch", OMIXER_SR, LMIXMUTEAUXINL, 1, 0), SOC_DAPM_SINGLE("LINEINL Switch", OMIXER_SR, LMIXMUTELINEINL, 1, 0), SOC_DAPM_SINGLE("LINEINL-LINEINR Switch", OMIXER_SR, LMIXMUTELINEINLR, 1, 0), SOC_DAPM_SINGLE("MIC2Booststage Switch", OMIXER_SR, LMIXMUTEMIC2BOOST, 1, 0), SOC_DAPM_SINGLE("MIC1Booststage Switch", OMIXER_SR, LMIXMUTEMIC1BOOST, 1, 0), }; /*defined right output mixer*/ static const struct snd_kcontrol_new ac100_routmix_controls[] = { SOC_DAPM_SINGLE("DACL Switch", OMIXER_SR, RMIXMUTEDACL, 1, 0), SOC_DAPM_SINGLE("DACR Switch", OMIXER_SR, RMIXMUTEDACR, 1, 0), SOC_DAPM_SINGLE("AUXINR Switch", OMIXER_SR, RMIXMUTEAUXINR, 1, 0), SOC_DAPM_SINGLE("LINEINR Switch", OMIXER_SR, RMIXMUTELINEINR, 1, 0), SOC_DAPM_SINGLE("LINEINL-LINEINR Switch", OMIXER_SR, RMIXMUTELINEINLR, 1, 0), SOC_DAPM_SINGLE("MIC2Booststage Switch", OMIXER_SR, RMIXMUTEMIC2BOOST, 1, 0), SOC_DAPM_SINGLE("MIC1Booststage Switch", OMIXER_SR, RMIXMUTEMIC1BOOST, 1, 0), }; /*hp source select*/ /*headphone input source*/ static const char * const ac100_hp_r_func_sel[] = { "DACR HPR Switch", "Right Analog Mixer HPR Switch"}; static const struct soc_enum ac100_hp_r_func_enum = SOC_ENUM_SINGLE(HPOUT_CTRL, RHPS, 2, ac100_hp_r_func_sel); static const struct snd_kcontrol_new ac100_hp_r_func_controls = SOC_DAPM_ENUM("HP_R Mux", ac100_hp_r_func_enum); static const char * const ac100_hp_l_func_sel[] = { "DACL HPL Switch", "Left Analog Mixer HPL Switch"}; static const struct soc_enum ac100_hp_l_func_enum = SOC_ENUM_SINGLE(HPOUT_CTRL, LHPS, 2, ac100_hp_l_func_sel); static const struct snd_kcontrol_new ac100_hp_l_func_controls = SOC_DAPM_ENUM("HP_L Mux", ac100_hp_l_func_enum); /*spk source select*/ static const char * const ac100_rspks_func_sel[] = { "MIXER Switch", "MIXR MIXL Switch"}; static const struct soc_enum ac100_rspks_func_enum = SOC_ENUM_SINGLE(SPKOUT_CTRL, RSPKS, 2, ac100_rspks_func_sel); static const struct snd_kcontrol_new ac100_rspks_func_controls = SOC_DAPM_ENUM("SPK_R Mux", ac100_rspks_func_enum); static const char * const ac100_lspks_l_func_sel[] = { "MIXEL Switch", "MIXL MIXR Switch"}; static const struct soc_enum ac100_lspks_func_enum = SOC_ENUM_SINGLE(SPKOUT_CTRL, LSPKS, 2, ac100_lspks_l_func_sel); static const struct snd_kcontrol_new ac100_lspks_func_controls = SOC_DAPM_ENUM("SPK_L Mux", ac100_lspks_func_enum); /*earpiece source select*/ static const char * const ac100_earpiece_func_sel[] = { "DACR", "DACL", "Right Analog Mixer", "Left Analog Mixer"}; static const struct soc_enum ac100_earpiece_func_enum = SOC_ENUM_SINGLE(ESPKOUT_CTRL, ESPSR, 4, ac100_earpiece_func_sel); static const struct snd_kcontrol_new ac100_earpiece_func_controls = SOC_DAPM_ENUM("EAR Mux", ac100_earpiece_func_enum); /*AIF2 out */ static const char * const aif2outl_text[] = { "AIF2_ADCL", "AIF2_ADCR", "SUM_AIF2_ADCL_AIF2_ADCR", "AVE_AIF2_ADCL_AIF2_ADCR" }; static const char * const aif2outr_text[] = { "AIF2_ADCR", "AIF2_ADCL", "SUM_AIF2_ADCL_AIF2_ADCR", "AVE_AIF2_ADCL_AIF2_ADCR" }; static const struct soc_enum aif2outl_enum = SOC_ENUM_SINGLE(AIF2_ADCDAT_CTRL, AIF2_ADCL_SRC, ARRAY_SIZE(aif2outl_text), aif2outl_text); static const struct snd_kcontrol_new aif2outl_mux = SOC_DAPM_ENUM("AIF2OUTL Mux", aif2outl_enum); static const struct soc_enum aif2outr_enum = SOC_ENUM_SINGLE(AIF2_ADCDAT_CTRL, AIF2_ADCR_SRC, ARRAY_SIZE(aif2outr_text), aif2outr_text); static const struct snd_kcontrol_new aif2outr_mux = SOC_DAPM_ENUM("AIF2OUTR Mux", aif2outr_enum); /*AIF2 IN*/ static const char * const aif2inl_text[] = { "AIF2_DACL", "AIF2_DACR", "SUM_AIF2DACL_AIF2DACR", "AVE_AIF2DACL_AIF2DACR" }; static const char * const aif2inr_text[] = { "AIF2_DACR", "AIF2_DACL", "SUM_AIF2DACL_AIF2DACR", "AVE_AIF2DACL_AIF2DACR" }; static const struct soc_enum aif2inl_enum = SOC_ENUM_SINGLE(AIF2_DACDAT_CTRL, AIF2_DACL_SRC, ARRAY_SIZE(aif2inl_text), aif2inl_text); static const struct snd_kcontrol_new aif2inl_mux = SOC_DAPM_ENUM("AIF2INL Mux", aif2inl_enum); static const struct soc_enum aif2inr_enum = SOC_ENUM_SINGLE(AIF2_DACDAT_CTRL, AIF2_DACR_SRC, ARRAY_SIZE(aif2inr_text), aif2inr_text); static const struct snd_kcontrol_new aif2inr_mux = SOC_DAPM_ENUM("AIF2INR Mux", aif2inr_enum); /*23 REGIDTER*/ /*AIF2 source select*/ static const struct snd_kcontrol_new aif2_adcl_mxr_src_controls[] = { SOC_DAPM_SINGLE("AIF1 DA0L Switch", AIF2_MXR_SRC, AIF2_ADCL_AIF1DA0L_MXR, 1, 0), SOC_DAPM_SINGLE("AIF1 DA1L Switch", AIF2_MXR_SRC, AIF2_ADCL_AIF1DA1L_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACR Switch", AIF2_MXR_SRC, AIF2_ADCL_AIF2DACR_MXR, 1, 0), SOC_DAPM_SINGLE("ADCL Switch", AIF2_MXR_SRC, AIF2_ADCL_ADCL_MXR, 1, 0), }; static const struct snd_kcontrol_new aif2_adcr_mxr_src_controls[] = { SOC_DAPM_SINGLE("AIF1 DA0R Switch", AIF2_MXR_SRC, AIF2_ADCR_AIF1DA0R_MXR, 1, 0), SOC_DAPM_SINGLE("AIF1 DA1R Switch", AIF2_MXR_SRC, AIF2_ADCR_AIF1DA1R_MXR, 1, 0), SOC_DAPM_SINGLE("AIF2 DACL Switch", AIF2_MXR_SRC, AIF2_ADCR_AIF2DACL_MXR, 1, 0), SOC_DAPM_SINGLE("ADCR Switch", AIF2_MXR_SRC, AIF2_ADCR_ADCR_MXR, 1, 0), }; /*aif3 out 33 REGISTER*/ static const char * const aif3out_text[] = { "AIF2 ADC left channel", "AIF2 ADC right channel" }; static const unsigned int aif3out_values[] = {1, 2}; static const struct soc_enum aif3out_enum = SOC_VALUE_ENUM_SINGLE(AIF3_SGP_CTRL, AIF3_ADC_SRC, 3, ARRAY_SIZE(aif3out_text), aif3out_text, aif3out_values); static const struct snd_kcontrol_new aif3out_mux = SOC_DAPM_ENUM("AIF3OUT Mux", aif3out_enum); /*aif2 DAC INPUT SOURCE SELECT 33 REGISTER*/ static const char * const aif2dacin_text[] = { "Left_s right_s AIF2", "Left_s AIF3 Right_s AIF2", "Left_s AIF2 Right_s AIF3" }; static const struct soc_enum aif2dacin_enum = SOC_ENUM_SINGLE(AIF3_SGP_CTRL, AIF2_DAC_SRC, 3, aif2dacin_text); static const struct snd_kcontrol_new aif2dacin_mux = SOC_DAPM_ENUM("AIF2 DAC SRC Mux", aif2dacin_enum); /*ADC SOURCE SELECT*/ /*defined left input adc mixer*/ static const struct snd_kcontrol_new ac100_ladcmix_controls[] = { SOC_DAPM_SINGLE("MIC1 boost Switch", ADC_SRC, LADCMIXMUTEMIC1BOOST, 1, 0), SOC_DAPM_SINGLE("MIC2 boost Switch", ADC_SRC, LADCMIXMUTEMIC2BOOST, 1, 0), SOC_DAPM_SINGLE("LININL-R Switch", ADC_SRC, LADCMIXMUTELINEINLR, 1, 0), SOC_DAPM_SINGLE("LINEINL Switch", ADC_SRC, LADCMIXMUTELINEINL, 1, 0), SOC_DAPM_SINGLE("AUXINL Switch", ADC_SRC, LADCMIXMUTEAUXINL, 1, 0), SOC_DAPM_SINGLE("Lout_Mixer_Switch", ADC_SRC, LADCMIXMUTELOUTPUT, 1, 0), SOC_DAPM_SINGLE("Rout_Mixer_Switch", ADC_SRC, LADCMIXMUTEROUTPUT, 1, 0), }; /*defined right input adc mixer*/ static const struct snd_kcontrol_new ac100_radcmix_controls[] = { SOC_DAPM_SINGLE("MIC1 boost Switch", ADC_SRC, RADCMIXMUTEMIC1BOOST, 1, 0), SOC_DAPM_SINGLE("MIC2 boost Switch", ADC_SRC, RADCMIXMUTEMIC2BOOST, 1, 0), SOC_DAPM_SINGLE("LINEINL-R Switch", ADC_SRC, RADCMIXMUTELINEINLR, 1, 0), SOC_DAPM_SINGLE("LINEINR Switch", ADC_SRC, RADCMIXMUTELINEINR, 1, 0), SOC_DAPM_SINGLE("AUXINR Switch", ADC_SRC, RADCMIXMUTEAUXINR, 1, 0), SOC_DAPM_SINGLE("Rout_Mixer_Switch", ADC_SRC, RADCMIXMUTEROUTPUT, 1, 0), SOC_DAPM_SINGLE("Lout_Mixer_Switch", ADC_SRC, RADCMIXMUTELOUTPUT, 1, 0), }; /*mic2 source select*/ static const char * const mic2src_text[] = { "MIC2", "MIC3"}; static const struct soc_enum mic2src_enum = SOC_ENUM_SINGLE(ADC_SRCBST_CTRL, MIC2SLT, ARRAY_SIZE(mic2src_text), mic2src_text); static const struct snd_kcontrol_new mic2src_mux = SOC_DAPM_ENUM("MIC2 SRC", mic2src_enum); /*59 register*/ /*defined lineout mixer*/ static const struct snd_kcontrol_new lineout_mix_controls[] = { SOC_DAPM_SINGLE("MIC1 boost Switch", LOUT_CTRL, LINEOUTS0, 1, 0), SOC_DAPM_SINGLE("MIC2 boost Switch", LOUT_CTRL, LINEOUTS1, 1, 0), SOC_DAPM_SINGLE("Rout_Mixer_Switch", LOUT_CTRL, LINEOUTS2, 1, 0), SOC_DAPM_SINGLE("Lout_Mixer_Switch", LOUT_CTRL, LINEOUTS3, 1, 0), }; /*DMIC*/ static const char * const adc_mux_text[] = {"ADC", "DMIC"}; static const struct soc_enum adc_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(adc_mux_text), adc_mux_text); static const struct snd_kcontrol_new adcl_mux = SOC_DAPM_ENUM("ADCL Mux", adc_enum); static const struct snd_kcontrol_new adcr_mux = SOC_DAPM_ENUM("ADCR Mux", adc_enum); /*In next four kcontrols, the register is no sense*/ static const struct snd_kcontrol_new aif2inl_aif2switch = SOC_DAPM_SINGLE("aif2inl aif2Switch", AIF1_RXD_CTRL, 8, 1, 0); static const struct snd_kcontrol_new aif2inr_aif2switch = SOC_DAPM_SINGLE("aif2inr aif2Switch", AIF1_RXD_CTRL, 9, 1, 0); static const struct snd_kcontrol_new aif2inl_aif3switch = SOC_DAPM_SINGLE("aif2inl aif3Switch", AIF1_RXD_CTRL, 10, 1, 0); static const struct snd_kcontrol_new aif2inr_aif3switch = SOC_DAPM_SINGLE("aif2inr aif3Switch", AIF1_RXD_CTRL, 11, 1, 0); /*built widget*/ static const struct snd_soc_dapm_widget ac100_dapm_widgets[] = { /*aif2 switch*/ SND_SOC_DAPM_SWITCH("AIF2INL Mux switch", SND_SOC_NOPM, 0, 1, &aif2inl_aif2switch), SND_SOC_DAPM_SWITCH("AIF2INR Mux switch", SND_SOC_NOPM, 0, 1, &aif2inr_aif2switch), SND_SOC_DAPM_SWITCH("AIF2INL Mux VIR switch", SND_SOC_NOPM, 0, 1, &aif2inl_aif3switch), SND_SOC_DAPM_SWITCH("AIF2INR Mux VIR switch", SND_SOC_NOPM, 0, 1, &aif2inr_aif3switch), SND_SOC_DAPM_MUX("AIF1OUT0L Mux", AIF1_ADCDAT_CTRL, AIF1_AD0L_ENA, 0, &aif1out0l_mux), SND_SOC_DAPM_MUX("AIF1OUT0R Mux", AIF1_ADCDAT_CTRL, AIF1_AD0R_ENA, 0, &aif1out0r_mux), SND_SOC_DAPM_MUX("AIF1OUT1L Mux", AIF1_ADCDAT_CTRL, AIF1_AD1L_ENA, 0, &aif1out1l_mux), SND_SOC_DAPM_MUX("AIF1OUT1R Mux", AIF1_ADCDAT_CTRL, AIF1_AD1R_ENA, 0, &aif1out1r_mux), SND_SOC_DAPM_MUX("AIF1IN0L Mux", AIF1_DACDAT_CTRL, AIF1_DA0L_ENA, 0, &aif1in0l_mux), SND_SOC_DAPM_MUX("AIF1IN0R Mux", AIF1_DACDAT_CTRL, AIF1_DA0R_ENA, 0, &aif1in0r_mux), SND_SOC_DAPM_MUX("AIF1IN1L Mux", AIF1_DACDAT_CTRL, AIF1_DA1L_ENA, 0, &aif1in1l_mux), SND_SOC_DAPM_MUX("AIF1IN1R Mux", AIF1_DACDAT_CTRL, AIF1_DA1R_ENA, 0, &aif1in1r_mux), SND_SOC_DAPM_MIXER("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0, aif1_ad0l_mxr_src_ctl, ARRAY_SIZE(aif1_ad0l_mxr_src_ctl)), SND_SOC_DAPM_MIXER("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0, aif1_ad0r_mxr_src_ctl, ARRAY_SIZE(aif1_ad0r_mxr_src_ctl)), SND_SOC_DAPM_MIXER("AIF1 AD1L Mixer", SND_SOC_NOPM, 0, 0, aif1_ad1l_mxr_src_ctl, ARRAY_SIZE(aif1_ad1l_mxr_src_ctl)), SND_SOC_DAPM_MIXER("AIF1 AD1R Mixer", SND_SOC_NOPM, 0, 0, aif1_ad1r_mxr_src_ctl, ARRAY_SIZE(aif1_ad1r_mxr_src_ctl)), SND_SOC_DAPM_MIXER_E("DACL Mixer", OMIXER_DACA_CTRL, DACALEN, 0, dacl_mxr_src_controls, ARRAY_SIZE(dacl_mxr_src_controls), late_enable_dac, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("DACR Mixer", OMIXER_DACA_CTRL, DACAREN, 0, dacr_mxr_src_controls, ARRAY_SIZE(dacr_mxr_src_controls), late_enable_dac, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), /*dac digital enble*/ SND_SOC_DAPM_DAC("DAC En", NULL, DAC_DIG_CTRL, ENDA, 0), /*ADC digital enble*/ SND_SOC_DAPM_ADC("ADC En", NULL, ADC_DIG_CTRL, ENAD, 0), SND_SOC_DAPM_MIXER("Left Output Mixer", OMIXER_DACA_CTRL, LMIXEN, 0, ac100_loutmix_controls, ARRAY_SIZE(ac100_loutmix_controls)), SND_SOC_DAPM_MIXER("Right Output Mixer", OMIXER_DACA_CTRL, RMIXEN, 0, ac100_routmix_controls, ARRAY_SIZE(ac100_routmix_controls)), SND_SOC_DAPM_MUX("HP_R Mux", SND_SOC_NOPM, 0, 0, &ac100_hp_r_func_controls), SND_SOC_DAPM_MUX("HP_L Mux", SND_SOC_NOPM, 0, 0, &ac100_hp_l_func_controls), SND_SOC_DAPM_MUX("SPK_R Mux", SPKOUT_CTRL, RSPK_EN, 0, &ac100_rspks_func_controls), SND_SOC_DAPM_MUX("SPK_L Mux", SPKOUT_CTRL, LSPK_EN, 0, &ac100_lspks_func_controls), SND_SOC_DAPM_PGA("SPK_LR Adder", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("EAR Mux", ESPKOUT_CTRL, ESPPA_MUTE, 0, &ac100_earpiece_func_controls), /*output widget*/ SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), SND_SOC_DAPM_OUTPUT("EAROUTP"), SND_SOC_DAPM_OUTPUT("EAROUTN"), SND_SOC_DAPM_OUTPUT("SPK1P"), SND_SOC_DAPM_OUTPUT("SPK2P"), SND_SOC_DAPM_OUTPUT("SPK1N"), SND_SOC_DAPM_OUTPUT("SPK2N"), SND_SOC_DAPM_OUTPUT("LINEOUTP"), SND_SOC_DAPM_OUTPUT("LINEOUTN"), SND_SOC_DAPM_MUX("AIF2OUTL Mux", AIF2_ADCDAT_CTRL, AIF2_ADCL_EN, 0, &aif2outl_mux), SND_SOC_DAPM_MUX("AIF2OUTR Mux", AIF2_ADCDAT_CTRL, AIF2_ADCR_EN, 0, &aif2outr_mux), SND_SOC_DAPM_MUX("AIF2INL Mux", AIF2_DACDAT_CTRL, AIF2_DACL_ENA, 0, &aif2inl_mux), SND_SOC_DAPM_MUX("AIF2INR Mux", AIF2_DACDAT_CTRL, AIF2_DACR_ENA, 0, &aif2inr_mux), SND_SOC_DAPM_PGA("AIF2INL_VIR", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("AIF2INR_VIR", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("AIF2 ADL Mixer", SND_SOC_NOPM, 0, 0, aif2_adcl_mxr_src_controls, ARRAY_SIZE(aif2_adcl_mxr_src_controls)), SND_SOC_DAPM_MIXER("AIF2 ADR Mixer", SND_SOC_NOPM, 0, 0, aif2_adcr_mxr_src_controls, ARRAY_SIZE(aif2_adcr_mxr_src_controls)), SND_SOC_DAPM_MUX("AIF3OUT Mux", SND_SOC_NOPM, 0, 0, &aif3out_mux), /* SND_SOC_DAPM_MUX("AIF2 DAC SRC Mux",*/ /* SND_SOC_NOPM, 0, 0, &aif2dacin_mux),*/ /*virtual widget*/ SND_SOC_DAPM_PGA_E("AIF2INL Mux VIR", SND_SOC_NOPM, 0, 0, NULL, 0, aif2inl_vir_event, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("AIF2INR Mux VIR", SND_SOC_NOPM, 0, 0, NULL, 0, aif2inr_vir_event, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("LEFT ADC input Mixer", ADC_APC_CTRL, ADCLEN, 0, ac100_ladcmix_controls, ARRAY_SIZE(ac100_ladcmix_controls), late_enable_adc, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("RIGHT ADC input Mixer", ADC_APC_CTRL, ADCREN, 0, ac100_radcmix_controls, ARRAY_SIZE(ac100_radcmix_controls), late_enable_adc, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), /*mic reference*/ SND_SOC_DAPM_PGA("MIC1 PGA", ADC_SRCBST_CTRL, MIC1AMPEN, 0, NULL, 0), SND_SOC_DAPM_PGA("MIC2 PGA", ADC_SRCBST_CTRL, MIC2AMPEN, 0, NULL, 0), SND_SOC_DAPM_PGA("LINEIN PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("MIC2 SRC", SND_SOC_NOPM, 0, 0, &mic2src_mux), SND_SOC_DAPM_MIXER("Line Out Mixer", LOUT_CTRL, LINEOUTEN, 0, lineout_mix_controls, ARRAY_SIZE(lineout_mix_controls)), /*INPUT widget*/ SND_SOC_DAPM_INPUT("MIC1P"), SND_SOC_DAPM_INPUT("MIC1N"), SND_SOC_DAPM_MICBIAS("MainMic Bias", ADC_APC_CTRL, MBIASEN, 0), SND_SOC_DAPM_MICBIAS("HMic Bias", ADC_APC_CTRL, HBIASEN, 0), SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_INPUT("MIC3"), SND_SOC_DAPM_INPUT("LINEINP"), SND_SOC_DAPM_INPUT("LINEINN"), SND_SOC_DAPM_INPUT("AXIR"), SND_SOC_DAPM_INPUT("AXIL"), SND_SOC_DAPM_INPUT("D_MIC"), /*aif1 interface*/ SND_SOC_DAPM_AIF_IN_E("AIF1DACL", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0, ac100_aif1clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_IN_E("AIF1DACR", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0, ac100_aif1clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_OUT_E("AIF1ADCL", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0, ac100_aif1clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_OUT_E("AIF1ADCR", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0, ac100_aif1clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), /*aif2 interface*/ SND_SOC_DAPM_AIF_IN_E("AIF2DACL", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0, ac100_aif2clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_IN_E("AIF2DACR", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0, ac100_aif2clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_OUT_E("AIF2ADCL", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0, ac100_aif2clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_OUT_E("AIF2ADCR", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0, ac100_aif2clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), /*aif3 interface*/ SND_SOC_DAPM_AIF_OUT_E("AIF3OUT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0, ac100_aif3clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_IN_E("AIF3IN", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0, ac100_aif3clk, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), /*headphone*/ SND_SOC_DAPM_HP("Headphone", ac100_headphone_event), /*speaker*/ SND_SOC_DAPM_SPK("External Speaker", ac100_speaker_event), /*earpiece*/ SND_SOC_DAPM_SPK("Earpiece", ac100_earpiece_event), /*lineout*/ SND_SOC_DAPM_LINE("Lineout", NULL), /*DMIC*/ SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0, &adcl_mux), SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux), SND_SOC_DAPM_PGA_E("DMICL VIR", SND_SOC_NOPM, 0, 0, NULL, 0, dmic_mux_ev, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("DMICR VIR", SND_SOC_NOPM, 0, 0, NULL, 0, dmic_mux_ev, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route ac100_dapm_routes[] = { {"AIF1ADCL", NULL, "AIF1OUT0L Mux"}, {"AIF1ADCR", NULL, "AIF1OUT0R Mux"}, {"AIF1ADCL", NULL, "AIF1OUT1L Mux"}, {"AIF1ADCR", NULL, "AIF1OUT1R Mux"}, /* aif1out0 mux 11---13*/ {"AIF1OUT0L Mux", "AIF1_AD0L", "AIF1 AD0L Mixer"}, {"AIF1OUT0L Mux", "AIF1_AD0R", "AIF1 AD0R Mixer"}, {"AIF1OUT0R Mux", "AIF1_AD0R", "AIF1 AD0R Mixer"}, {"AIF1OUT0R Mux", "AIF1_AD0L", "AIF1 AD0L Mixer"}, /*AIF1OUT1 mux 11--13 */ {"AIF1OUT1L Mux", "AIF1_AD1L", "AIF1 AD1L Mixer"}, {"AIF1OUT1L Mux", "AIF1_AD1R", "AIF1 AD1R Mixer"}, {"AIF1OUT1R Mux", "AIF1_AD1R", "AIF1 AD1R Mixer"}, {"AIF1OUT1R Mux", "AIF1_AD1L", "AIF1 AD1L Mixer"}, /*AIF1 AD0L Mixer*/ {"AIF1 AD0L Mixer", "AIF1 DA0L Switch", "AIF1IN0L Mux"}, {"AIF1 AD0L Mixer", "AIF2 DACL Switch", "AIF2INL_VIR"}, {"AIF1 AD0L Mixer", "ADCL Switch", "ADCL Mux"}, {"AIF1 AD0L Mixer", "AIF2 DACR Switch", "AIF2INR_VIR"}, /*AIF1 AD0R Mixer*/ {"AIF1 AD0R Mixer", "AIF1 DA0R Switch", "AIF1IN0R Mux"}, {"AIF1 AD0R Mixer", "AIF2 DACR Switch", "AIF2INR_VIR"}, {"AIF1 AD0R Mixer", "ADCR Switch", "ADCR Mux"}, {"AIF1 AD0R Mixer", "AIF2 DACL Switch", "AIF2INL_VIR"}, /*AIF1 AD1L Mixer*/ {"AIF1 AD1L Mixer", "AIF2 DACL Switch", "AIF2INL_VIR"}, {"AIF1 AD1L Mixer", "ADCL Switch", "ADCL Mux"}, /*AIF1 AD1R Mixer*/ {"AIF1 AD1R Mixer", "AIF2 DACR Switch", "AIF2INR_VIR"}, {"AIF1 AD1R Mixer", "ADCR Switch", "ADCR Mux"}, /*AIF1 DA0 IN 12h*/ {"AIF1IN0L Mux", "AIF1_DA0L", "AIF1DACL"}, {"AIF1IN0L Mux", "AIF1_DA0R", "AIF1DACR"}, {"AIF1IN0R Mux", "AIF1_DA0R", "AIF1DACR"}, {"AIF1IN0R Mux", "AIF1_DA0L", "AIF1DACL"}, /*AIF1 DA1 IN 12h*/ {"AIF1IN1L Mux", "AIF1_DA1L", "AIF1DACL"}, {"AIF1IN1L Mux", "AIF1_DA1R", "AIF1DACR"}, {"AIF1IN1R Mux", "AIF1_DA1R", "AIF1DACR"}, {"AIF1IN1R Mux", "AIF1_DA1L", "AIF1DACL"}, /*aif2 virtual*/ {"AIF2INL Mux switch", "aif2inl aif2Switch", "AIF2INL Mux"}, {"AIF2INR Mux switch", "aif2inr aif2Switch", "AIF2INR Mux"}, {"AIF2INL_VIR", NULL, "AIF2INL Mux switch"}, {"AIF2INR_VIR", NULL, "AIF2INR Mux switch"}, {"AIF2INL_VIR", NULL, "AIF2INL Mux VIR"}, {"AIF2INR_VIR", NULL, "AIF2INR Mux VIR"}, /*4c*/ {"DACL Mixer", "AIF1DA0L Switch", "AIF1IN0L Mux"}, {"DACL Mixer", "AIF1DA1L Switch", "AIF1IN1L Mux"}, {"DACL Mixer", "ADCL Switch", "ADCL Mux"}, {"DACL Mixer", "AIF2DACL Switch", "AIF2INL_VIR"}, {"DACR Mixer", "AIF1DA0R Switch", "AIF1IN0R Mux"}, {"DACR Mixer", "AIF1DA1R Switch", "AIF1IN1R Mux"}, {"DACR Mixer", "ADCR Switch", "ADCR Mux"}, {"DACR Mixer", "AIF2DACR Switch", "AIF2INR_VIR"}, {"Right Output Mixer", "DACR Switch", "DACR Mixer"}, {"Right Output Mixer", "DACL Switch", "DACL Mixer"}, {"Right Output Mixer", "AUXINR Switch", "AXIR"}, {"Right Output Mixer", "LINEINR Switch", "LINEINN"}, {"Right Output Mixer", "LINEINL-LINEINR Switch", "LINEIN PGA"}, {"Right Output Mixer", "MIC2Booststage Switch", "MIC2 PGA"}, {"Right Output Mixer", "MIC1Booststage Switch", "MIC1 PGA"}, {"Left Output Mixer", "DACL Switch", "DACL Mixer"}, {"Left Output Mixer", "DACR Switch", "DACR Mixer"}, {"Left Output Mixer", "AUXINL Switch", "AXIL"}, {"Left Output Mixer", "LINEINL Switch", "LINEINP"}, {"Left Output Mixer", "LINEINL-LINEINR Switch", "LINEIN PGA"}, {"Left Output Mixer", "MIC2Booststage Switch", "MIC2 PGA"}, {"Left Output Mixer", "MIC1Booststage Switch", "MIC1 PGA"}, /*hp mux*/ {"HP_R Mux", "DACR HPR Switch", "DACR Mixer"}, {"HP_R Mux", "Right Analog Mixer HPR Switch", "Right Output Mixer"}, {"HP_L Mux", "DACL HPL Switch", "DACL Mixer"}, {"HP_L Mux", "Left Analog Mixer HPL Switch", "Left Output Mixer"}, /*hp endpoint*/ {"HPOUTR", NULL, "HP_R Mux"}, {"HPOUTL", NULL, "HP_L Mux"}, {"Headphone", NULL, "HPOUTR"}, {"Headphone", NULL, "HPOUTL"}, /*External Speaker*/ {"External Speaker", NULL, "SPK1P"}, {"External Speaker", NULL, "SPK1N"}, {"External Speaker", NULL, "SPK2P"}, {"External Speaker", NULL, "SPK2N"}, /*spk mux*/ {"SPK_LR Adder", NULL, "Right Output Mixer"}, {"SPK_LR Adder", NULL, "Left Output Mixer"}, {"SPK_L Mux", "MIXL MIXR Switch", "SPK_LR Adder"}, {"SPK_L Mux", "MIXEL Switch", "Left Output Mixer"}, {"SPK_R Mux", "MIXR MIXL Switch", "SPK_LR Adder"}, {"SPK_R Mux", "MIXER Switch", "Right Output Mixer"}, {"SPK1P", NULL, "SPK_R Mux"}, {"SPK1N", NULL, "SPK_R Mux"}, {"SPK2P", NULL, "SPK_L Mux"}, {"SPK2N", NULL, "SPK_L Mux"}, /*earpiece mux*/ {"EAR Mux", "DACR", "DACR Mixer"}, {"EAR Mux", "DACL", "DACL Mixer"}, {"EAR Mux", "Right Analog Mixer", "Right Output Mixer"}, {"EAR Mux", "Left Analog Mixer", "Left Output Mixer"}, {"EAROUTP", NULL, "EAR Mux"}, {"EAROUTN", NULL, "EAR Mux"}, {"Earpiece", NULL, "EAROUTP"}, {"Earpiece", NULL, "EAROUTN"}, /*LADC SOURCE mixer*/ {"LEFT ADC input Mixer", "MIC1 boost Switch", "MIC1 PGA"}, {"LEFT ADC input Mixer", "MIC2 boost Switch", "MIC2 PGA"}, {"LEFT ADC input Mixer", "LININL-R Switch", "LINEIN PGA"}, {"LEFT ADC input Mixer", "LINEINL Switch", "LINEINN"}, {"LEFT ADC input Mixer", "AUXINL Switch", "AXIL"}, {"LEFT ADC input Mixer", "Lout_Mixer_Switch", "Left Output Mixer"}, {"LEFT ADC input Mixer", "Rout_Mixer_Switch", "Right Output Mixer"}, /*RADC SOURCE mixer*/ {"RIGHT ADC input Mixer", "MIC1 boost Switch", "MIC1 PGA"}, {"RIGHT ADC input Mixer", "MIC2 boost Switch", "MIC2 PGA"}, {"RIGHT ADC input Mixer", "LINEINL-R Switch", "LINEIN PGA"}, {"RIGHT ADC input Mixer", "LINEINR Switch", "LINEINP"}, {"RIGHT ADC input Mixer", "AUXINR Switch", "AXIR"}, {"RIGHT ADC input Mixer", "Rout_Mixer_Switch", "Right Output Mixer"}, {"RIGHT ADC input Mixer", "Lout_Mixer_Switch", "Left Output Mixer"}, {"MIC1 PGA", NULL, "MIC1P"}, {"MIC1 PGA", NULL, "MIC1N"}, {"MIC2 PGA", NULL, "MIC2 SRC"}, {"MIC2 SRC", "MIC2", "MIC2"}, {"MIC2 SRC", "MIC3", "MIC3"}, {"LINEIN PGA", NULL, "LINEINP"}, {"LINEIN PGA", NULL, "LINEINN"}, {"LINEOUTP", NULL, "Line Out Mixer"}, {"LINEOUTN", NULL, "Line Out Mixer"}, {"Lineout", NULL, "LINEOUTP"}, {"Lineout", NULL, "LINEOUTN"}, /*lineout*/ {"Line Out Mixer", "MIC1 boost Switch", "MIC1 PGA"}, {"Line Out Mixer", "MIC2 boost Switch", "MIC2 PGA"}, {"Line Out Mixer", "Rout_Mixer_Switch", "Right Output Mixer"}, {"Line Out Mixer", "Lout_Mixer_Switch", "Left Output Mixer"}, /*AIF2 out */ {"AIF2ADCL", NULL, "AIF2OUTL Mux"}, {"AIF2ADCR", NULL, "AIF2OUTR Mux"}, {"AIF2OUTL Mux", "AIF2_ADCL", "AIF2 ADL Mixer"}, {"AIF2OUTL Mux", "AIF2_ADCR", "AIF2 ADR Mixer"}, {"AIF2OUTR Mux", "AIF2_ADCR", "AIF2 ADR Mixer"}, {"AIF2OUTR Mux", "AIF2_ADCL", "AIF2 ADL Mixer"}, /*23*/ {"AIF2 ADL Mixer", "AIF1 DA0L Switch", "AIF1IN0L Mux"}, {"AIF2 ADL Mixer", "AIF1 DA1L Switch", "AIF1IN1L Mux"}, {"AIF2 ADL Mixer", "AIF2 DACR Switch", "AIF2INR_VIR"}, {"AIF2 ADL Mixer", "ADCL Switch", "ADCL Mux"}, {"AIF2 ADR Mixer", "AIF1 DA0R Switch", "AIF1IN0R Mux"}, {"AIF2 ADR Mixer", "AIF1 DA1R Switch", "AIF1IN1R Mux"}, {"AIF2 ADR Mixer", "AIF2 DACL Switch", "AIF2INL_VIR"}, {"AIF2 ADR Mixer", "ADCR Switch", "ADCR Mux"}, /*aif2*/ {"AIF2INL Mux", "AIF2_DACL", "AIF2DACL"}, {"AIF2INL Mux", "AIF2_DACR", "AIF2DACR"}, {"AIF2INR Mux", "AIF2_DACR", "AIF2DACR"}, {"AIF2INR Mux", "AIF2_DACL", "AIF2DACL"}, /*aif3*/ {"AIF2INL Mux VIR switch", "aif2inl aif3Switch", "AIF3IN"}, {"AIF2INR Mux VIR switch", "aif2inr aif3Switch", "AIF3IN"}, {"AIF2INL Mux VIR", NULL, "AIF2INL Mux VIR switch"}, {"AIF2INR Mux VIR", NULL, "AIF2INR Mux VIR switch"}, {"AIF3OUT", NULL, "AIF3OUT Mux"}, {"AIF3OUT Mux", "AIF2 ADC left channel", "AIF2 ADL Mixer"}, {"AIF3OUT Mux", "AIF2 ADC right channel", "AIF2 ADR Mixer"}, /*ADC--ADCMUX*/ {"ADCR Mux", "ADC", "RIGHT ADC input Mixer"}, {"ADCL Mux", "ADC", "LEFT ADC input Mixer"}, /*DMIC*/ {"ADCR Mux", "DMIC", "DMICR VIR"}, {"ADCL Mux", "DMIC", "DMICL VIR"}, {"DMICL VIR", NULL, "D_MIC"}, {"DMICR VIR", NULL, "D_MIC"}, }; /* PLL divisors */ struct pll_div { unsigned int pll_in; unsigned int pll_out; int m; int n_i; int n_f; }; struct aif1_fs { unsigned int samplerate; int aif1_bclk_bit; int aif1_srbit; }; struct aif1_bclk { int aif1_bclk_div; int aif1_bclk_bit; }; struct aif1_lrck { int aif1_lrck_div; int aif1_lrck_bit; }; struct aif1_word_size { int aif1_wsize_val; int aif1_wsize_bit; }; /* * Note : pll code from original tdm/i2s driver. * freq_out = freq_in * N/(m*(2k+1)) , k=1,N=N_i+N_f,N_f=factor*0.2; */ static const struct pll_div codec_pll_div[] = { {128000, 22579200, 1, 529, 1}, {192000, 22579200, 1, 352, 4}, {256000, 22579200, 1, 264, 3}, {384000, 22579200, 1, 176, 2},/*((176+2*0.2)*6000000)/(38*(2*1+1))*/ {6000000, 22579200, 38, 429, 0},/*((429+0*0.2)*6000000)/(38*(2*1+1))*/ {13000000, 22579200, 19, 99, 0}, {19200000, 22579200, 25, 88, 1}, {24000000, 22579200, 38, 107, 1}, {128000, 24576000, 1, 576, 0}, {192000, 24576000, 1, 384, 0}, {256000, 24576000, 1, 288, 0}, {384000, 24576000, 1, 192, 0}, {2048000, 24576000, 1, 36, 0}, {1024000, 24576000, 1, 72, 0}, {3072000, 24576000, 1, 24, 0}, {6000000, 24576000, 25, 307, 1}, {13000000, 24576000, 42, 238, 1}, {19200000, 24576000, 25, 88, 1}, {24000000, 24576000, 25, 76, 4}, }; /*for all of the fs freq. lrck_div is 64*/ static const struct aif1_fs codec_aif1_fs[] = { {44100, 4, 7}, {48000, 4, 8}, {8000, 9, 0}, {11025, 8, 1}, {12000, 8, 2}, {16000, 7, 3}, {22050, 6, 4}, {24000, 6, 5}, {32000, 5, 6}, {96000, 2, 9}, {192000, 1, 10}, }; static const struct aif1_bclk codec_aif1_bclk[] = { {1, 0}, {2, 1}, {4, 2}, {6, 3}, {8, 4}, {12, 5}, {16, 6}, {24, 7}, {32, 8}, {48, 9}, {64, 10}, {96, 11}, {128, 12}, {192, 13}, }; static const struct aif1_lrck codec_aif1_lrck[] = { {16, 0}, {32, 1}, {64, 2}, {128, 3}, {256, 4}, }; static const struct aif1_word_size codec_aif1_wsize[] = { {8, 0}, {16, 1}, {20, 2}, {24, 3}, }; static int ac100_aif_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->mute_mutex); if (mute) { if (ac100->aif2_mute == 0) snd_soc_write(codec, DAC_VOL_CTRL, 0); } else { snd_soc_write(codec, DAC_VOL_CTRL, 0xa0a0); } mutex_unlock(&ac100->mute_mutex); return 0; } static int ac100_aif2_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); mutex_lock(&ac100->mute_mutex); if (mute == 0) { snd_soc_write(codec, DAC_VOL_CTRL, 0xa0a0); ac100->aif2_mute = 1; } else ac100->aif2_mute = 0; mutex_unlock(&ac100->mute_mutex); return 0; } static void ac100_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; int reg_val; AC100_DBG("%s,line:%d\n", __func__, __LINE__); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { if (agc_used) agc_enable(codec, 0); reg_val = (snd_soc_read(codec, AIF_SR_CTRL) >> 12); reg_val &= 0xf; if (codec_dai->playback_active && dmic_used && ((reg_val == 0x4) || (reg_val == 0x5))) { snd_soc_update_bits(codec, AIF_SR_CTRL, (0xf<codec; switch (codec_dai->id) { case 1: AIF_CLK_CTRL = AIF1_CLK_CTRL; aif1_lrck_div = 64; break; case 2: AIF_CLK_CTRL = AIF2_CLK_CTRL; aif1_lrck_div = 64; break; default: return -EINVAL; } for (i = 0; i < ARRAY_SIZE(codec_aif1_bclk); i++) { if (codec_aif1_bclk[i].aif1_bclk_div == aif1_bclk_div) { snd_soc_update_bits(codec, AIF_CLK_CTRL, (0xf<capture_active && dmic_used && codec_aif1_fs[i].samplerate == 44100) snd_soc_update_bits(codec, AIF_SR_CTRL, (0xf<capture_active && dmic_used && codec_aif1_fs[i].samplerate == 48000) snd_soc_update_bits(codec, AIF_SR_CTRL, (0xf<codec; switch (clk_id) { case AIF1_CLK: AC100_DBG("%s,line:%d,snd_soc_read(SYSCLK_CTRL):%x\n", __func__, __LINE__, snd_soc_read(codec, SYSCLK_CTRL)); /*system clk from aif1*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<codec; switch (codec_dai->id) { case 1: AC100_DBG("%s,line:%d\n", __func__, __LINE__); AIF_CLK_CTRL = AIF1_CLK_CTRL; break; case 2: AC100_DBG("%s,line:%d\n", __func__, __LINE__); AIF_CLK_CTRL = AIF2_CLK_CTRL; break; default: return -EINVAL; } AC100_DBG("%s,line:%d\n", __func__, __LINE__); /* * master or slave selection * 0 = Master mode * 1 = Slave mode */ reg_val = snd_soc_read(codec, AIF_CLK_CTRL); reg_val &= ~(0x1<codec; AC100_DBG("%s, line:%d, pll_id:%d\n", __func__, __LINE__, pll_id); if (!freq_out) return 0; if ((freq_in < 128000) || (freq_in > 24576000)) { return -EINVAL; } else if ((freq_in == 24576000) || (freq_in == 22579200)) { switch (pll_id) { case AC100_MCLK1: /*select aif1 clk source from mclk1*/ snd_soc_update_bits(codec, SYSCLK_CTRL, (0x3<codec; AC100_DBG("%s,line:%d\n", __func__, __LINE__); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && agc_used) agc_enable(codec, 1); return 0; } static int ac100_aif2_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *codec_dai) { int i = 0; int AIF_CLK_CTRL = 0; int aif1_word_size = 16; int aif1_bclk_div = aif2_bclk_div;/*aif2_bclk_div=8, 24.576M/8=3.072M*/ int aif1_lrck_div = aif2_lrck_div;/*aif2_lrck_div=64, 3.072M/64=48k*/ struct snd_soc_codec *codec = codec_dai->codec; switch (codec_dai->id) { case 1: AIF_CLK_CTRL = AIF1_CLK_CTRL; break; case 2: AIF_CLK_CTRL = AIF2_CLK_CTRL; break; default: return -EINVAL; } for (i = 0; i < ARRAY_SIZE(codec_aif1_bclk); i++) { if (codec_aif1_bclk[i].aif1_bclk_div == aif1_bclk_div) { snd_soc_update_bits(codec, AIF_CLK_CTRL, (0xf<codec; AC100_DBG("%s,line:%d\n", __func__, __LINE__); /* DAI signal inversions */ reg_val = snd_soc_read(codec, AIF3_CLK_CTRL); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + nor frame */ reg_val &= ~(0x1<codec; /*config aif3clk from aif2clk*/ snd_soc_update_bits(codec, AIF3_CLK_CTRL, (0x3<jack_mutex); reg_val = snd_soc_read(ac100->codec, HMIC_STS); hmic_data = (reg_val & 0x1f00) >> HMIC_DATA; if (((ac100->switch_status & SND_JACK_HEADSET) == SND_JACK_HEADSET) && (reg_val & HMKC_KEYDOWN_PEND)) { if ((hmic_data >= 0x19) && (reset_flag == 0)) { ac100->switch_status |= SND_JACK_BTN_0; snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->switch_status &= ~SND_JACK_BTN_0; snd_jack_report(ac100->jack.jack, ac100->switch_status); pr_warn("[%s] line=%d,hmic_data:0x%x,Hook\n", __func__, __LINE__, hmic_data); if (reset_flag) reset_flag--; } else if ((hmic_data < 0x19 && hmic_data >= 0x16) && (reset_flag == 0)) { ac100->switch_status |= SND_JACK_BTN_1; snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->switch_status &= ~SND_JACK_BTN_1; snd_jack_report(ac100->jack.jack, ac100->switch_status); pr_warn("[%s] line=%d,hmic_data:0x%x,VOL++\n", __func__, __LINE__, hmic_data); if (reset_flag) reset_flag--; } else if ((hmic_data < 0x16 && hmic_data >= 0x10) && (reset_flag == 0)) { ac100->switch_status |= SND_JACK_BTN_2; snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->switch_status &= ~SND_JACK_BTN_2; snd_jack_report(ac100->jack.jack, ac100->switch_status); pr_warn("[%s] line=%d,hmic_data:0x%x,VOL--\n", __func__, __LINE__, hmic_data); if (reset_flag) reset_flag--; } else { /*This could be other key data,try fix it*/ pr_debug("keydata:%x,Key data err\n", reg_val); } } else { /* for headphone*/ } /* Clear the key and hmic_data irq pending*/ reg_val = snd_soc_read(ac100->codec, HMIC_STS); if ((reg_val & 0x1f) != 0) { reg_val |= (0x1f << 0); snd_soc_write(ac100->codec, HMIC_STS, reg_val); } mutex_unlock(&ac100->jack_mutex); } /* * Identify the jack type as Headset/Headphone/None */ static int sunxi_check_jack_type(struct snd_soc_jack *jack) { u32 reg_val = 0; unsigned int temp_value[11]; u32 tempdata = 0; struct ac100_priv *ac100 = container_of(jack, struct ac100_priv, jack); mutex_lock(&ac100->jack_mutex); ac100->check_count = 0; ac100->check_count_sum = 0; for (;;) { msleep(30); /*read HMIC_DATA */ reg_val = snd_soc_read(ac100->codec, HMIC_STS); reg_val = (reg_val>>HMIC_DATA); reg_val &= 0x1f; if (ac100->check_count_sum <= HEADSET_CHECKCOUNT_SUM) { if (ac100->check_count <= HEADSET_CHECKCOUNT) { temp_value[ac100->check_count] = reg_val; ac100->check_count++; if (ac100->check_count >= 2) { if (!(temp_value[ ac100->check_count - 1] == temp_value[ (ac100->check_count) - 2])) { ac100->check_count = 0; ac100->check_count_sum = 0; } } } else { ac100->check_count_sum++; } } else { tempdata = temp_value[ac100->check_count-2]; break; } } if (tempdata >= ac100->HEADSET_DATA) { /* headphone:3 */ pr_err("[%s] line=%d, (SND_JACK_HEADPHONE)--\n-- ac100->HEADSET_DATA:0x%x, tempdata:0x%x\n", __func__, __LINE__, ac100->HEADSET_DATA, tempdata); ac100->switch_status = SND_JACK_HEADPHONE; snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->check_count = 0; ac100->check_count_sum = 0; reset_flag = 0; } else if ((tempdata < ac100->HEADSET_DATA) && (tempdata >= 0x1)) { /* headset:4 */ pr_warn("[%s] line=%d, (SND_JACK_HEADSET)--\n-- ac100->HEADSET_DATA:0x%x, tempdata:0x%x\n", __func__, __LINE__, ac100->HEADSET_DATA, tempdata); ac100->switch_status = SND_JACK_HEADSET; snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->check_count = 0; ac100->check_count_sum = 0; reset_flag = 0; } else { ac100->switch_status = 0; /*clear headset pulgout pending.*/ snd_jack_report(ac100->jack.jack, ac100->switch_status); pr_warn("[%s] line:%d,HEADPHONE_IDLE\n", __func__, __LINE__); ac100->check_count = 0; ac100->check_count_sum = 0; reset_flag = 0; } reg_val = snd_soc_read(ac100->codec, HMIC_STS); /* for clearing plug on after plugin*/ if (reg_val & HMIC_PULLOUT_PEND) { reg_val &= ~(0x1 << HMIC_PLUGIN_PEND); reg_val &= ~(0x1 << HMKC_KEYDOWN_PEND); reg_val &= ~(0x1 << HMIC_DATA_PEND); reg_val |= (0x1 << HMIC_PULLOUT_PEND); snd_soc_write(ac100->codec, HMIC_STS, reg_val); } mutex_unlock(&ac100->jack_mutex); return ac100->switch_status; } /* **sunxi_jack_work: clear audiocodec pending and Record the interrupt. */ static void sunxi_jack_work(struct work_struct *work) { int reg_val = 0; int jack_state = 0; struct ac100_priv *ac100 = container_of(work, struct ac100_priv, hs_irq_work.work); struct snd_soc_codec *codec = ac100->codec; ac100->check_count = 0; ac100->check_count_sum = 0; jack_state = snd_soc_read(ac100->codec, HMIC_STS); pr_warn("[%s] line:%d, jack_state:0x%x\n", __func__, __LINE__, jack_state); /*headphone insert*/ if (jack_state & (1 << HMIC_PLUGIN_PEND)) { reg_val = snd_soc_read(ac100->codec, HMIC_STS); reg_val |= 0x1 << HMIC_PLUGIN_PEND; reg_val &= ~(0x1 << HMKC_KEYDOWN_PEND); /* correct data */ reg_val &= ~(0x1 << HMIC_DATA_PEND); snd_soc_write(ac100->codec, HMIC_STS, reg_val); ac100->detect_state = PLUG_IN; sunxi_check_jack_type(&ac100->jack); } schedule_delayed_work(&ac100->hs_detect_work, msecs_to_jiffies(60)); mutex_lock(&ac100->jack_mutex); msleep(20); jack_state = snd_soc_read(codec, HMIC_STS); /*headphone insert*/ if (!(jack_state >> HMIC_DATA) || ((jack_state & (1 << HMIC_PULLOUT_PEND)) && !(jack_state >> HMIC_DATA))) { reg_val = snd_soc_read(codec, HMIC_STS); snd_soc_write(codec, HMIC_STS, reg_val); ac100->detect_state = PLUG_OUT; reset_flag++; pr_err("[%s]====Earhpone PLUG_OUT====\n", __func__); ac100->switch_status = 0; /*clear headset pulgout pending.*/ snd_jack_report(ac100->jack.jack, ac100->switch_status); ac100->check_count = 0; ac100->check_count_sum = 0; reset_flag = 0; } mutex_unlock(&ac100->jack_mutex); } /* **sunxi_jack_irq: the interrupt handlers */ static irqreturn_t sunxi_jack_irq(int irq, void *para) { struct ac100_priv *ac100 = (struct ac100_priv *)para; bool ret = false; if (ac100 == NULL) return -EINVAL; pr_warn("[%s] ======line:%d======\n", __func__, __LINE__); ret = schedule_delayed_work(&ac100->hs_irq_work, msecs_to_jiffies(60)); if (!ret) pr_err("[sunxi_jack_irq]add work struct failed!\n"); return 0; } #endif static void codec_resume_work(struct work_struct *work) { struct ac100_priv *ac100 = container_of(work, struct ac100_priv, codec_resume); struct snd_soc_codec *codec = ac100->codec; int ret = 0; #if 0 /* headset irq gpio */ ac100->jack_irq = gpio_to_irq(ac100->jack_gpio); if (IS_ERR_VALUE(ac100->jack_irq)) pr_warn("[AC100] map gpio to jack_irq failed, errno = %d\n", ac100->jack_irq); pr_err("[AC100] gpio [%d] map to jack_irq [%d] ok\n", ac100->jack_gpio, ac100->jack_irq); /* request jack_irq, set jack_irq type to high level trigger */ ret = devm_request_irq(codec->dev, ac100->jack_irq, sunxi_jack_irq, IRQF_TRIGGER_FALLING, "SWTICH_EINT", ac100); if (IS_ERR_VALUE(ret)) pr_warn("[AC100] request jack_irq %d failed, errno = %d\n", ac100->jack_irq, ret); gpio_set_debounce(ac100->jack_gpio, 1); #endif ret = regulator_enable(ac100->vol_supply.avcc); if (ret) pr_err("[AC100] %s(line:%d):fail to enable regulator!\n", __func__, __LINE__); ret = regulator_enable(ac100->vol_supply.io1); if (ret) pr_err("[AC100] %s(line:%d):fail to enable regulator!\n", __func__, __LINE__); ret = regulator_enable(ac100->vol_supply.io2); if (ret) pr_err("[AC100] %s(line:%d):fail to enable regulator!\n", __func__, __LINE__); ret = regulator_enable(ac100->vol_supply.ldoin); if (ret) pr_err("[AC100] %s(line:%d):fail to enable regulator!\n", __func__, __LINE__); ret = regulator_enable(ac100->vol_supply.cpvdd); if (ret) pr_err("[AC100] %s(line:%d):fail to enable regulator!\n", __func__, __LINE__); msleep(50); pr_err("%s : %d \n", __func__, __LINE__); set_configuration(codec); #if 0 if (agc_used) agc_config(codec); #endif if (drc_used) drc_config(codec); pr_err("%s : %d \n", __func__, __LINE__); /*enable this bit to prevent leakage from ldoin*/ snd_soc_update_bits(codec, ADDA_TUNE3, (0x1<> 24) & 0xF; if (flag) { /*write*/ reg = (val >> 16) & 0xFF; value_w = val & 0xFFFF; snd_soc_write(ac100->codec, reg, value_w); pr_info("write 0x%x to reg:0x%x\n", value_w, reg); } else { char *p = str; int len; u16 value; reg = (val>>8) & 0xFF; num = val&0xff; pr_info("\n"); pr_info("read:start add:0x%x,count:0x%x\n", reg, num); do { value = snd_soc_read(ac100->codec, reg); len = sprintf(p, "0x%x: 0x%04x ", reg, value); p += len; reg += 1; i++; if (i%4 == 0 || i == num) { pr_info("%s\n", str); p = str; } } while (i < num); } return count; } static ssize_t ac100_debug_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 i = 0; int count = 0; u16 value; u8 reg = 0x00; u8 num = 0xc0; struct ac100_priv *ac100 = dev_get_drvdata(dev); pr_info("--------------------help------------------------\n"); pr_info("echo flag|reg|val > ac100\n"); pr_info("eg read addr=0x06,count 0x10:echo 0610 >ac100\n"); pr_info("eg write val:0x13fe to 0x06 :echo 10613fe > ac100\n"); pr_info("------------------------------------------------\n"); count += sprintf(buf+count, "read:start add:0x%x,count:0x%x\n", reg, num); do { value = snd_soc_read(ac100->codec, reg); count += sprintf(buf + count, "0x%x: 0x%04x ", reg, value); reg += 1; i++; if (i%4 == 0 || i == num) count += sprintf(buf + count, "\n"); } while (i < num); return count; } static DEVICE_ATTR(ac100, 0644, ac100_debug_show, ac100_debug_store); static struct attribute *audio_debug_attrs[] = { &dev_attr_ac100.attr, NULL, }; static struct attribute_group audio_debug_attr_group = { .name = "ac100_debug", .attrs = audio_debug_attrs, }; /************************************************************/ static int ac100_codec_probe(struct snd_soc_codec *codec) { int ret = 0; unsigned int val; struct device_node *node = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-ac100-codec"); struct ac100_priv *ac100; struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); pr_err("%s : %d \n", __func__, __LINE__); ac100 = dev_get_drvdata(codec->dev); if (ac100 == NULL) return -ENOMEM; ac100->codec = codec; snd_soc_codec_set_drvdata(codec, ac100); #if 0 /*ac100 jack driver*/ ret = snd_soc_card_jack_new(codec->component.card, "sunxi Audio Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, &ac100->jack, NULL, 0); if (ret) { pr_err("jack creation failed\n"); return ret; } snd_jack_set_key(ac100->jack.jack, SND_JACK_BTN_0, KEY_MEDIA); snd_jack_set_key(ac100->jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); snd_jack_set_key(ac100->jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); ac100->check_count = 0; ac100->check_count_sum = 0; /* *initial the parameters for judge switch state */ ac100->detect_state = PLUG_OUT; ac100->HEADSET_DATA = 0x15; INIT_DELAYED_WORK(&ac100->hs_detect_work, sunxi_check_switch); INIT_DELAYED_WORK(&ac100->hs_irq_work, sunxi_jack_work); mutex_init(&ac100->jack_mutex); /* * map the jack_irq of gpio * headphone gpio irq pin is *** * item_eint.gpio.gpio = ****; */ ac100->jack_irq = gpio_to_irq(ac100->jack_gpio); if (IS_ERR_VALUE(ac100->jack_irq)) { pr_warn("[AC100] map gpio to jack_irq failed, errno = %d\n", ac100->jack_irq); return -EINVAL; } pr_err("[AC100] gpio [%d] map to jack_irq [%d] ok\n", ac100->jack_gpio, ac100->jack_irq); /* request jack_irq, set jack_irq type to high level trigger */ ret = devm_request_irq(codec->dev, ac100->jack_irq, sunxi_jack_irq, IRQF_TRIGGER_FALLING, "IRQ_AUDIO", ac100); if (IS_ERR_VALUE(ret)) { pr_err("[AC100] request jack_irq %d failed, errno = %d\n", ac100->jack_irq, ret); return -EINVAL; } ret = gpio_set_debounce(ac100->jack_gpio, 1); if (ret) { pr_err("[AC100]gpio_set_debouncefailed(ret:%d)\n", ret); return -EINVAL; } INIT_WORK(&ac100->codec_resume, codec_resume_work); #endif pr_err("%s : %d \n", __func__, __LINE__); ac100->dac_enable = 0; ac100->adc_enable = 0; ac100->aif1_clken = 0; ac100->aif2_clken = 0; ac100->aif3_clken = 0; mutex_init(&ac100->dac_mutex); mutex_init(&ac100->adc_mutex); mutex_init(&ac100->aifclk_mutex); mutex_init(&ac100->mute_mutex); /* * config gpio info of audio_pa_ctrl, * the default pa config is close(check pa sys_config1.fex) */ if (spkgpio.used) { gpio_direction_output(spkgpio.gpio, 1); gpio_set_value(spkgpio.gpio, 0); } ret = of_property_read_u32(node, "aif2_lrck_div", &val); if (ret < 0) { dev_warn(codec->dev, "aif2_lrck_div config missing or invalid\n"); aif2_lrck_div = 256; } else { aif2_lrck_div = val; pr_debug("aif2_lrck_div=%d\n", val); } ret = of_property_read_u32(node, "aif2_bclk_div", &val); if (ret < 0) { dev_warn(codec->dev, "aif2_bclk_div config missing or invalid\n"); aif2_bclk_div = 12; } else { aif2_bclk_div = val; pr_debug("aif2_bclk_div=%d\n", val); } pr_debug("%s,line:%d\n", __func__, __LINE__); /* get and enable vcc-avcc */ ac100->vol_supply.avcc = regulator_get(NULL, "vcc-avcc"); if (IS_ERR(ac100->vol_supply.avcc)) { pr_err("get audio vcc-avcc failed\n"); ret = -EFAULT; } else { ret = regulator_enable(ac100->vol_supply.avcc); if (ret) { pr_err("[%s]:vcc-avcc enable failed!\n", __func__); ret = EINVAL; } } /* get and enable vcc-io1 */ ac100->vol_supply.io1 = regulator_get(NULL, "vcc-io1"); if (IS_ERR(ac100->vol_supply.io1)) { pr_err("get audio vcc-io1 failed\n"); ret = -EFAULT; } else { ret = regulator_enable(ac100->vol_supply.io1); if (ret) { pr_err("[%s]:vcc-io1 enable failed!\n", __func__); ret = EINVAL; } } /* get and enable vcc-io2 */ ac100->vol_supply.io2 = regulator_get(NULL, "vcc-io2"); if (IS_ERR(ac100->vol_supply.io2)) { pr_err("get audio vcc-io2 failed\n"); ret = -EFAULT; } else { ret = regulator_enable(ac100->vol_supply.io2); if (ret) { pr_err("[%s]:vcc-io2 enable failed!\n", __func__); ret = EINVAL; } } /* get and enable vcc-ldoin */ ac100->vol_supply.ldoin = regulator_get(NULL, "vcc-ldoin"); if (IS_ERR(ac100->vol_supply.ldoin)) { pr_err("get audio vcc-ldoin failed\n"); ret = -EFAULT; } else { ret = regulator_enable(ac100->vol_supply.ldoin); if (ret) { pr_err("[%s]:vcc-ldoin enable failed!\n", __func__); ret = EINVAL; } } /* get and enable vcc-cppvdd */ ac100->vol_supply.cpvdd = regulator_get(NULL, "vcc-cpvdd"); if (IS_ERR(ac100->vol_supply.cpvdd)) { pr_err("get audio vcc-cpvdd failed\n"); ret = -EFAULT; } else { ret = regulator_enable(ac100->vol_supply.cpvdd); if (ret) { pr_err("[%s]:vcc-cpvdd enable failed!\n", __func__); ret = EINVAL; } } pr_err("%s : %d \n", __func__, __LINE__); set_configuration(ac100->codec); pr_err("%s : %d \n", __func__, __LINE__); /*enable this bit to prevent leakage from ldoin*/ snd_soc_update_bits(codec, ADDA_TUNE3, (0x1<dev, ac100->jack_irq, NULL); #endif ret = regulator_disable(ac100->vol_supply.avcc); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); regulator_put(ac100->vol_supply.avcc); ret = regulator_disable(ac100->vol_supply.io1); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); regulator_put(ac100->vol_supply.io1); ret = regulator_disable(ac100->vol_supply.io2); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); regulator_put(ac100->vol_supply.io2); ret = regulator_disable(ac100->vol_supply.ldoin); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); regulator_put(ac100->vol_supply.ldoin); ret = regulator_disable(ac100->vol_supply.cpvdd); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); regulator_put(ac100->vol_supply.cpvdd); kfree(ac100); return 0; } static int ac100_codec_suspend(struct snd_soc_codec *codec) { int ret = 0; char pin_name[SUNXI_PIN_NAME_MAX_LEN]; unsigned long config; struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); AC100_DBG("[codec]:suspend\n"); /* check if called in talking standby */ /* * if (check_scene_locked(SCENE_TALKING_STANDBY) == 0) { * pr_err("In talking standby, audio codec do not suspend!!\n"); * return 0; * } */ ac100_set_bias_level(codec, SND_SOC_BIAS_OFF); ret = regulator_disable(ac100->vol_supply.avcc); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); ret = regulator_disable(ac100->vol_supply.io1); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); ret = regulator_disable(ac100->vol_supply.io2); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); ret = regulator_disable(ac100->vol_supply.ldoin); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); ret = regulator_disable(ac100->vol_supply.cpvdd); if (ret) pr_err("[AC100] %s(line:%d):fail to disable regulator!\n", __func__, __LINE__); #if 0 devm_free_irq(codec->dev, ac100->jack_irq, ac100); sunxi_gpio_to_name(ac100->jack_gpio, pin_name); config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 7); pin_config_set(SUNXI_PINCTRL, pin_name, config); #endif if (spkgpio.used) { sunxi_gpio_to_name(spkgpio.gpio, pin_name); config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 7); pin_config_set(SUNXI_PINCTRL, pin_name, config); } return 0; } static int ac100_codec_resume(struct snd_soc_codec *codec) { struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); AC100_DBG("[codec]:resume"); ac100->switch_status = 0; ac100_set_bias_level(codec, SND_SOC_BIAS_STANDBY); // schedule_work(&ac100->codec_resume); return 0; } static unsigned int sndvir_audio_read(struct snd_soc_codec *codec, unsigned int reg) { unsigned int data; struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); struct ac100 *ac100_dev = ac100->ac100; /* Device I/O API */ data = ac100_reg_read(ac100_dev, reg); return data; } static int sndvir_audio_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { int ret = 0; struct ac100_priv *ac100 = snd_soc_codec_get_drvdata(codec); struct ac100 *ac100_dev = ac100->ac100; ret = ac100_reg_write(ac100_dev, reg, value); return 0; } static struct snd_soc_codec_driver soc_codec_dev_sndvir_audio = { .probe = ac100_codec_probe, .remove = ac100_codec_remove, .suspend = ac100_codec_suspend, .resume = ac100_codec_resume, .set_bias_level = ac100_set_bias_level, .read = sndvir_audio_read, .write = sndvir_audio_write, .ignore_pmdown_time = 1, }; static const struct of_device_id sunxi_codec_of_match[] = { { .compatible = "allwinner,sunxi-ac100-codec", }, {}, }; static int ac100_probe(struct platform_device *pdev) { int ret = 0; struct ac100_priv *ac100; struct gpio_config config; struct device_node *node = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-ac100-codec"); pr_err("%s,line:%d\n", __func__, __LINE__); if (!node) { dev_err(&pdev->dev, "can not get dt node for this device.\n"); return -EINVAL; } ac100 = devm_kzalloc(&pdev->dev, sizeof(struct ac100_priv), GFP_KERNEL); if (ac100 == NULL) return -ENOMEM; platform_set_drvdata(pdev, ac100); ac100->ac100 = dev_get_drvdata(pdev->dev.parent); get_configuration(pdev); /*initial speaker gpio */ spkgpio.gpio = of_get_named_gpio_flags(node, "gpio-spk", 0, (enum of_gpio_flags *)&config); if (!gpio_is_valid(spkgpio.gpio)) { pr_err("failed to get gpio-spk gpio from dts,spkgpio:%d\n", spkgpio.gpio); spkgpio.used = 0; } else { ret = devm_gpio_request(&pdev->dev, spkgpio.gpio, "SPK"); if (ret) { spkgpio.used = 0; pr_err("failed to request gpio-spk gpio\n"); } else { spkgpio.used = 1; gpio_direction_output(spkgpio.gpio, 1); gpio_set_value(spkgpio.gpio, 0); pr_debug("set spkgpio ok(spkgpio:%d)\n", spkgpio.gpio); } } /*initial headset irq gpio */ ac100->jack_gpio = of_get_named_gpio_flags(node, "gpio-hs", 0, (enum of_gpio_flags *)&config); if (!gpio_is_valid(ac100->jack_gpio)) { pr_err("failed to get gpio-hs gpio from dts,hsgpio:%d\n", ac100->jack_gpio); ac100->hmic_used = 0; } else { ret = devm_gpio_request(&pdev->dev, ac100->jack_gpio, "HEADSET"); if (ret) { ac100->hmic_used = 0; pr_err("failed to request gpio-hs gpio\n"); } else { ac100->hmic_used = 1; pr_err("set headset gpio:%d\n", ac100->jack_gpio); } } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sndvir_audio, ac100_dai, ARRAY_SIZE(ac100_dai)); if (ret < 0) dev_err(&pdev->dev, "Failed to register ac100: %d\n", ret); ret = sysfs_create_group(&pdev->dev.kobj, &audio_debug_attr_group); if (ret) pr_err("failed to create attr group\n"); return 0; } static void ac100_shutdown(struct platform_device *pdev) { int reg_val; struct ac100_priv *ac100 = platform_get_drvdata(pdev); struct snd_soc_codec *codec = ac100->codec; /*set headphone volume to 0*/ reg_val = snd_soc_read(codec, HPOUT_CTRL); reg_val &= ~(0x3f<dev.kobj, &audio_debug_attr_group); snd_soc_unregister_codec(&pdev->dev); return 0; } static struct platform_driver ac100_codec_driver = { .driver = { .name = "ac100-codec", .owner = THIS_MODULE, // .of_match_table = sunxi_codec_of_match, }, .probe = ac100_probe, .remove = ac100_remove, .shutdown = ac100_shutdown, }; //module_platform_driver(ac100_codec_driver); static int __init ac100_codec_driver_init(void) { return platform_driver_register(&ac100_codec_driver); } static void __exit ac100_codec_driver_exit(void) { platform_driver_unregister(&ac100_codec_driver); } late_initcall(ac100_codec_driver_init); module_exit(ac100_codec_driver_exit); MODULE_DESCRIPTION("ASoC AC100 driver"); MODULE_AUTHOR("huangxin"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ac100-codec");