diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/nau8540.c | 98 | ||||
-rw-r--r-- | sound/soc/codecs/nau8540.h | 20 | ||||
-rw-r--r-- | sound/soc/codecs/nau8824.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/nau8825.c | 101 | ||||
-rw-r--r-- | sound/soc/codecs/nau8825.h | 3 | ||||
-rw-r--r-- | sound/soc/mxs/mxs-sgtl5000.c | 25 |
6 files changed, 201 insertions, 64 deletions
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index f9c9933acffb..b08fb7e243c3 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -233,6 +233,41 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new digital_ch1_mux = SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum); +static int adc_power_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + msleep(300); + /* DO12 and DO34 pad output enable */ + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, 0); + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, 0); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI); + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI); + } + return 0; +} + +static int aiftx_power_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001); + regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0000); + } + return 0; +} + static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0), @@ -247,14 +282,18 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0), SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0), - SND_SOC_DAPM_ADC("ADC1", NULL, - NAU8540_REG_POWER_MANAGEMENT, 0, 0), - SND_SOC_DAPM_ADC("ADC2", NULL, - NAU8540_REG_POWER_MANAGEMENT, 1, 0), - SND_SOC_DAPM_ADC("ADC3", NULL, - NAU8540_REG_POWER_MANAGEMENT, 2, 0), - SND_SOC_DAPM_ADC("ADC4", NULL, - NAU8540_REG_POWER_MANAGEMENT, 3, 0), + SND_SOC_DAPM_ADC_E("ADC1", NULL, + NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, + NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, + NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, + NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0), @@ -270,7 +309,8 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_MUX("Digital CH1 Mux", SND_SOC_NOPM, 0, 0, &digital_ch1_mux), - SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0, + aiftx_power_control, SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route nau8540_dapm_routes[] = { @@ -575,7 +615,8 @@ static void nau8540_fll_apply(struct regmap *regmap, NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK, NAU8540_CLK_SRC_MCLK | fll_param->mclk_src); regmap_update_bits(regmap, NAU8540_REG_FLL1, - NAU8540_FLL_RATIO_MASK, fll_param->ratio); + NAU8540_FLL_RATIO_MASK | NAU8540_ICTRL_LATCH_MASK, + fll_param->ratio | (0x6 << NAU8540_ICTRL_LATCH_SFT)); /* FLL 16-bit fractional input */ regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac); /* FLL 10-bit integer input */ @@ -596,13 +637,14 @@ static void nau8540_fll_apply(struct regmap *regmap, NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | NAU8540_FLL_FTR_SW_FILTER); regmap_update_bits(regmap, NAU8540_REG_FLL6, - NAU8540_SDM_EN, NAU8540_SDM_EN); + NAU8540_SDM_EN | NAU8540_CUTOFF500, + NAU8540_SDM_EN | NAU8540_CUTOFF500); } else { regmap_update_bits(regmap, NAU8540_REG_FLL5, NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU); - regmap_update_bits(regmap, - NAU8540_REG_FLL6, NAU8540_SDM_EN, 0); + regmap_update_bits(regmap, NAU8540_REG_FLL6, + NAU8540_SDM_EN | NAU8540_CUTOFF500, 0); } } @@ -617,17 +659,22 @@ static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source, switch (pll_id) { case NAU8540_CLK_FLL_MCLK: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_MCLK | 0); break; case NAU8540_CLK_FLL_BLK: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_BLK | + (0xf << NAU8540_GAIN_ERR_SFT)); break; case NAU8540_CLK_FLL_FS: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_FS | + (0xf << NAU8540_GAIN_ERR_SFT)); break; default: @@ -710,9 +757,24 @@ static void nau8540_init_regs(struct nau8540 *nau8540) regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL, NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN, NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN); - /* ADC OSR selection, CLK_ADC = Fs * OSR */ + /* ADC OSR selection, CLK_ADC = Fs * OSR; + * Channel time alignment enable. + */ regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE, - NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64); + NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK, + NAU8540_CH_SYNC | NAU8540_ADC_OSR_64); + /* PGA input mode selection */ + regmap_update_bits(regmap, NAU8540_REG_FEPGA1, + NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT, + NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT); + regmap_update_bits(regmap, NAU8540_REG_FEPGA2, + NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT, + NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT); + /* DO12 and DO34 pad output disable */ + regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI); + regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI); } static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index 5db5b224944d..732b490edf81 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -100,9 +100,13 @@ #define NAU8540_CLK_MCLK_SRC_MASK 0xf /* FLL1 (0x04) */ +#define NAU8540_ICTRL_LATCH_SFT 10 +#define NAU8540_ICTRL_LATCH_MASK (0x7 << NAU8540_ICTRL_LATCH_SFT) #define NAU8540_FLL_RATIO_MASK 0x7f /* FLL3 (0x06) */ +#define NAU8540_GAIN_ERR_SFT 12 +#define NAU8540_GAIN_ERR_MASK (0xf << NAU8540_GAIN_ERR_SFT) #define NAU8540_FLL_CLK_SRC_SFT 10 #define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT) #define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT) @@ -127,6 +131,7 @@ /* FLL6 (0x9) */ #define NAU8540_DCO_EN (0x1 << 15) #define NAU8540_SDM_EN (0x1 << 14) +#define NAU8540_CUTOFF500 (0x1 << 13) /* PCM_CTRL0 (0x10) */ #define NAU8540_I2S_BP_SFT 7 @@ -146,6 +151,7 @@ #define NAU8540_I2S_DF_PCM_AB 0x3 /* PCM_CTRL1 (0x11) */ +#define NAU8540_I2S_DO12_TRI (0x1 << 15) #define NAU8540_I2S_LRC_DIV_SFT 12 #define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT) #define NAU8540_I2S_DO12_OE (0x1 << 4) @@ -156,6 +162,7 @@ #define NAU8540_I2S_BLK_DIV_MASK 0x7 /* PCM_CTRL1 (0x12) */ +#define NAU8540_I2S_DO34_TRI (0x1 << 15) #define NAU8540_I2S_DO34_OE (0x1 << 11) #define NAU8540_I2S_TSLOT_L_MASK 0x3ff @@ -165,6 +172,7 @@ #define NAU8540_TDM_TX_MASK 0xf /* ADC_SAMPLE_RATE (0x3A) */ +#define NAU8540_CH_SYNC (0x1 << 14) #define NAU8540_ADC_OSR_MASK 0x3 #define NAU8540_ADC_OSR_256 0x3 #define NAU8540_ADC_OSR_128 0x2 @@ -183,6 +191,18 @@ #define NAU8540_PRECHARGE_DIS (0x1 << 13) #define NAU8540_GLOBAL_BIAS_EN (0x1 << 12) +/* FEPGA1 (0x69) */ +#define NAU8540_FEPGA1_MODCH2_SHT_SFT 7 +#define NAU8540_FEPGA1_MODCH2_SHT (0x1 << NAU8540_FEPGA1_MODCH2_SHT_SFT) +#define NAU8540_FEPGA1_MODCH1_SHT_SFT 3 +#define NAU8540_FEPGA1_MODCH1_SHT (0x1 << NAU8540_FEPGA1_MODCH1_SHT_SFT) + +/* FEPGA2 (0x6A) */ +#define NAU8540_FEPGA2_MODCH4_SHT_SFT 7 +#define NAU8540_FEPGA2_MODCH4_SHT (0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT) +#define NAU8540_FEPGA2_MODCH3_SHT_SFT 3 +#define NAU8540_FEPGA2_MODCH3_SHT (0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT) + /* System Clock Source */ enum { diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 0240759f951c..088e0cef4cb8 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -43,7 +43,7 @@ static bool nau8824_is_jack_inserted(struct nau8824 *nau8824); /* the parameter threshold of FLL */ #define NAU_FREF_MAX 13500000 -#define NAU_FVCO_MAX 124000000 +#define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 /* scaling for mclk from sysclk_src output */ @@ -811,7 +811,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824) NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE); /* Close clock for jack type detection at manual mode */ - nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0); + if (dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0); } static void nau8824_jdet_work(struct work_struct *work) @@ -843,6 +844,11 @@ static void nau8824_jdet_work(struct work_struct *work) event_mask |= SND_JACK_HEADSET; snd_soc_jack_report(nau8824->jack, event, event_mask); + /* Enable short key press and release interruption. */ + regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING, + NAU8824_IRQ_KEY_RELEASE_DIS | + NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0); + nau8824_sema_release(nau8824); } @@ -850,15 +856,15 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824) { struct regmap *regmap = nau8824->regmap; - /* Enable jack ejection, short key press and release interruption. */ + /* Enable jack ejection interruption. */ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1, NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN, NAU8824_IRQ_EJECT_EN); regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING, - NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_KEY_RELEASE_DIS | - NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0); + NAU8824_IRQ_EJECT_DIS, 0); /* Enable internal VCO needed for interruptions */ - nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0); + if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0); regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL, NAU8824_JD_SLEEP_MODE, 0); } diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e853a6dfd33b..a1b697b6fb64 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -194,10 +194,10 @@ static const struct reg_default nau8825_reg_defaults[] = { /* register backup table when cross talk detection */ static struct reg_default nau8825_xtalk_baktab[] = { - { NAU8825_REG_ADC_DGAIN_CTRL, 0 }, + { NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf }, { NAU8825_REG_HSVOL_CTRL, 0 }, - { NAU8825_REG_DACL_CTRL, 0 }, - { NAU8825_REG_DACR_CTRL, 0 }, + { NAU8825_REG_DACL_CTRL, 0x00cf }, + { NAU8825_REG_DACR_CTRL, 0x02cf }, }; static const unsigned short logtable[256] = { @@ -245,13 +245,14 @@ static const unsigned short logtable[256] = { * tasks are allowed to acquire the semaphore, calling this function will * put the task to sleep. If the semaphore is not released within the * specified number of jiffies, this function returns. - * Acquires the semaphore without jiffies. If no more tasks are allowed - * to acquire the semaphore, calling this function will put the task to - * sleep until the semaphore is released. * If the semaphore is not released within the specified number of jiffies, - * this function returns -ETIME. - * If the sleep is interrupted by a signal, this function will return -EINTR. - * It returns 0 if the semaphore was acquired successfully. + * this function returns -ETIME. If the sleep is interrupted by a signal, + * this function will return -EINTR. It returns 0 if the semaphore was + * acquired successfully. + * + * Acquires the semaphore without jiffies. Try to acquire the semaphore + * atomically. Returns 0 if the semaphore has been acquired successfully + * or 1 if it it cannot be acquired. */ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) { @@ -262,8 +263,8 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) if (ret < 0) dev_warn(nau8825->dev, "Acquire semaphore timeout\n"); } else { - ret = down_interruptible(&nau8825->xtalk_sem); - if (ret < 0) + ret = down_trylock(&nau8825->xtalk_sem); + if (ret) dev_warn(nau8825->dev, "Acquire semaphore fail\n"); } @@ -454,22 +455,32 @@ static void nau8825_xtalk_backup(struct nau8825 *nau8825) { int i; + if (nau8825->xtalk_baktab_initialized) + return; + /* Backup some register values to backup table */ for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg, &nau8825_xtalk_baktab[i].def); + + nau8825->xtalk_baktab_initialized = true; } -static void nau8825_xtalk_restore(struct nau8825 *nau8825) +static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel) { int i, volume; + if (!nau8825->xtalk_baktab_initialized) + return; + /* Restore register values from backup table; When the driver restores - * the headphone volumem, it needs recover to original level gradually - * with 3dB per step for less pop noise. + * the headphone volume in XTALK_DONE state, it needs recover to + * original level gradually with 3dB per step for less pop noise. + * Otherwise, the restore should do ASAP. */ for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) { - if (nau8825_xtalk_baktab[i].reg == NAU8825_REG_HSVOL_CTRL) { + if (!cause_cancel && nau8825_xtalk_baktab[i].reg == + NAU8825_REG_HSVOL_CTRL) { /* Ramping up the volume change to reduce pop noise */ volume = nau8825_xtalk_baktab[i].def & NAU8825_HPR_VOL_MASK; @@ -479,6 +490,8 @@ static void nau8825_xtalk_restore(struct nau8825 *nau8825) regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg, nau8825_xtalk_baktab[i].def); } + + nau8825->xtalk_baktab_initialized = false; } static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825) @@ -644,7 +657,7 @@ static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825) NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0); } -static void nau8825_xtalk_clean(struct nau8825 *nau8825) +static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel) { /* Enable internal VCO needed for interruptions */ nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); @@ -660,7 +673,7 @@ static void nau8825_xtalk_clean(struct nau8825 *nau8825) NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE); /* Restore value of specific register for cross talk */ - nau8825_xtalk_restore(nau8825); + nau8825_xtalk_restore(nau8825, cause_cancel); } static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol) @@ -779,7 +792,7 @@ static void nau8825_xtalk_measure(struct nau8825 *nau8825) dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone); regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL, (sidetone << 8) | sidetone); - nau8825_xtalk_clean(nau8825); + nau8825_xtalk_clean(nau8825, false); nau8825->xtalk_state = NAU8825_XTALK_DONE; break; default: @@ -815,13 +828,14 @@ static void nau8825_xtalk_work(struct work_struct *work) static void nau8825_xtalk_cancel(struct nau8825 *nau8825) { - /* If the xtalk_protect is true, that means the process is still - * on going. The driver forces to cancel the cross talk task and + /* If the crosstalk is eanbled and the process is on going, + * the driver forces to cancel the crosstalk task and * restores the configuration to original status. */ - if (nau8825->xtalk_protect) { + if (nau8825->xtalk_enable && nau8825->xtalk_state != + NAU8825_XTALK_DONE) { cancel_work_sync(&nau8825->xtalk_work); - nau8825_xtalk_clean(nau8825); + nau8825_xtalk_clean(nau8825, true); } /* Reset parameters for cross talk suppression function */ nau8825_sema_reset(nau8825); @@ -1246,8 +1260,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); osr &= NAU8825_DAC_OVERSAMPLE_MASK; if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) + params_rate(params), osr)) { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_DAC_SRC_MASK, osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); @@ -1255,8 +1271,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); osr &= NAU8825_ADC_SYNC_DOWN_MASK; if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) + params_rate(params), osr)) { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_ADC_SRC_MASK, osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); @@ -1273,8 +1291,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, bclk_div = 1; else if (bclk_fs <= 128) bclk_div = 0; - else + else { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div); @@ -1294,6 +1314,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, val_len |= NAU8825_I2S_DL_32; break; default: + nau8825_sema_release(nau8825); return -EINVAL; } @@ -1312,8 +1333,6 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; - nau8825_sema_acquire(nau8825, 3 * HZ); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: ctrl2_val |= NAU8825_I2S_MS_MASTER; @@ -1355,6 +1374,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } + nau8825_sema_acquire(nau8825, 3 * HZ); + regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK | NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK, @@ -1687,7 +1708,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { if (nau8825_is_jack_inserted(regmap)) { event |= nau8825_jack_insert(nau8825); - if (!nau8825->xtalk_bypass && !nau8825->high_imped) { + if (nau8825->xtalk_enable && !nau8825->high_imped) { /* Apply the cross talk suppression in the * headset without high impedance. */ @@ -1701,12 +1722,15 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) int ret; nau8825->xtalk_protect = true; ret = nau8825_sema_acquire(nau8825, 0); - if (ret < 0) + if (ret) nau8825->xtalk_protect = false; } /* Startup cross talk detection process */ - nau8825->xtalk_state = NAU8825_XTALK_PREPARE; - schedule_work(&nau8825->xtalk_work); + if (nau8825->xtalk_protect) { + nau8825->xtalk_state = + NAU8825_XTALK_PREPARE; + schedule_work(&nau8825->xtalk_work); + } } else { /* The cross talk suppression shouldn't apply * in the headset with high impedance. Thus, @@ -1733,7 +1757,9 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) nau8825->xtalk_event_mask = event_mask; } } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) { - schedule_work(&nau8825->xtalk_work); + /* crosstalk detection enable and process on going */ + if (nau8825->xtalk_enable && nau8825->xtalk_protect) + schedule_work(&nau8825->xtalk_work); clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; } else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) == NAU8825_JACK_INSERTION_DETECTED) { @@ -2382,7 +2408,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) regcache_sync(nau8825->regmap); nau8825->xtalk_protect = true; ret = nau8825_sema_acquire(nau8825, 0); - if (ret < 0) + if (ret) nau8825->xtalk_protect = false; enable_irq(nau8825->irq); @@ -2441,8 +2467,8 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) nau8825->jack_insert_debounce); dev_dbg(dev, "jack-eject-debounce: %d\n", nau8825->jack_eject_debounce); - dev_dbg(dev, "crosstalk-bypass: %d\n", - nau8825->xtalk_bypass); + dev_dbg(dev, "crosstalk-enable: %d\n", + nau8825->xtalk_enable); } static int nau8825_read_device_properties(struct device *dev, @@ -2507,8 +2533,8 @@ static int nau8825_read_device_properties(struct device *dev, &nau8825->jack_eject_debounce); if (ret) nau8825->jack_eject_debounce = 0; - nau8825->xtalk_bypass = device_property_read_bool(dev, - "nuvoton,crosstalk-bypass"); + nau8825->xtalk_enable = device_property_read_bool(dev, + "nuvoton,crosstalk-enable"); nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { @@ -2569,6 +2595,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c, */ nau8825->xtalk_state = NAU8825_XTALK_DONE; nau8825->xtalk_protect = false; + nau8825->xtalk_baktab_initialized = false; sema_init(&nau8825->xtalk_sem, 1); INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 8aee5c8647ae..f7e732125882 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -476,7 +476,8 @@ struct nau8825 { int xtalk_event_mask; bool xtalk_protect; int imp_rms[NAU8825_XTALK_IMM]; - int xtalk_bypass; + int xtalk_enable; + bool xtalk_baktab_initialized; /* True if initialized. */ }; int nau8825_enable_jack_detect(struct snd_soc_codec *codec, diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2ed3240cc682..2b3f2408301a 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -93,6 +93,14 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { }, }; +static const struct snd_soc_dapm_widget mxs_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Line Out Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + static struct snd_soc_card mxs_sgtl5000 = { .name = "mxs_sgtl5000", .owner = THIS_MODULE, @@ -141,10 +149,23 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) card->dev = &pdev->dev; + if (of_find_property(np, "audio-routing", NULL)) { + card->dapm_widgets = mxs_sgtl5000_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(mxs_sgtl5000_dapm_widgets); + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); + return ret; + } + } + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); return ret; } |