extcon/ASoC: arizona: Fix interactions around HPDET
Subsystems (5)
This patch series fixes an interaction between the extcon and ASoC drivers for arizona. Since both drivers are under active development there are likely going to be cross tree issues - there's already some further patches on the ASoC side - so it'd be good to get this pulled into both trees.
I've taken the liberty of pulling into ASoC already, if there's a problem with that I can drop the changes easily enough.
The following changes since commit 8bb9660418e05bb1845ac1a2428444d78e322cc7:
Linux 3.9-rc4 (2013-03-23 16:52:44 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git tags/arizona-extcon-asoc
for you to fetch changes up to 63fea17128397d440753883d16e7d2d9aa95a66b:
extcon: arizona: Fix interaction between headphone outputs and identification (2013-03-26 14:26:05 +0000)
----------------------------------------------------------------
ASoC/extcon: arizona: Fix interaction between HPDET and headphone outputs
This patch series covers both ASoC and extcon subsystems and fixes an interaction between the HPDET function and the headphone outputs - we really shouldn't run HPDET while the headphone is active. The first patch is a refactoring to make the extcon side easier.
----------------------------------------------------------------
Mark Brown (3):
extcon: arizona: Factor out magic application
ASoC: arizona: Fix interaction between headphone outputs and identification
extcon: arizona: Fix interaction between headphone outputs and identification
drivers/extcon/extcon-arizona.c | 107 ++++++++++++++++++-------------------- include/linux/mfd/arizona/core.h | 3 ++ sound/soc/codecs/arizona.c | 33 ++++++++++++ sound/soc/codecs/arizona.h | 3 ++ sound/soc/codecs/wm5102.c | 8 +-- sound/soc/codecs/wm5110.c | 8 +-- 6 files changed, 99 insertions(+), 63 deletions(-)
PATCH 1/3 extcon: arizona: Factor out magic application
We have a very similar sequence doing magic writes in several places (one of which missed an update to interlock with the CODEC driver) so factor it out into a function.
--- drivers/extcon/extcon-arizona.c | 91 ++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 55 deletions(-)
drivers/extcon/extcon-arizona.c +36 -55
@@ -100,6 +100,39 @@ static const char *arizona_cable[] = { NULL, }; +static void arizona_extcon_do_magic (struct arizona_extcon_info *info, +unsigned int magic) +{ +struct arizona *arizona = info->arizona; +unsigned int val; +int ret; + +mutex_lock (&arizona->dapm->card->dapm_mutex); + + ret =regmap_read (arizona->regmap,ARIZONA_OUTPUT_ENABLES_1 , &val); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to read output enables: %d\n" , + ret); + val =0 ; + } + +if (!(val & (ARIZONA_OUT1L_ENA |ARIZONA_OUT1R_ENA ))) { + ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 , + magic); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , + ret); + + ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 , + magic); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , + ret); + } + +mutex_unlock (&arizona->dapm->card->dapm_mutex); +} +static void arizona_extcon_set_mode (struct arizona_extcon_info *info,int mode) {struct arizona *arizona = info->arizona;
@@ -484,7 +517,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)struct arizona *arizona = info->arizona;int id_gpio = arizona->pdata.hpdet_id_gpio;int report =ARIZONA_CABLE_HEADPHONE ; -unsigned int val;int ret, reading;mutex_lock (&info->lock);
@@ -539,28 +571,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)dev_err (arizona->dev,"Failed to report HP/line: %d\n" , ret); -mutex_lock (&arizona->dapm->card->dapm_mutex); - - ret =regmap_read (arizona->regmap,ARIZONA_OUTPUT_ENABLES_1 , &val); -if (ret !=0 ) { -dev_err (arizona->dev,"Failed to read output enables: %d\n" , - ret); - val =0 ; - } - -if (!(val & (ARIZONA_OUT1L_ENA |ARIZONA_OUT1R_ENA ))) { - ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 ,0 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to undo magic: %d\n" , - ret); - - ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 ,0 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to undo magic: %d\n" , - ret); - } - -mutex_unlock (&arizona->dapm->card->dapm_mutex); +arizona_extcon_do_magic (info,0 ); done:if (id_gpio)
@@ -606,13 +617,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)if (info->mic)arizona_stop_mic (info); - ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 ,0x4000 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); - - ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 ,0x4000 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); +arizona_extcon_do_magic (info,0x4000 ); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -653,7 +658,6 @@ err:static void arizona_start_hpdet_acc_id (struct arizona_extcon_info *info) {struct arizona *arizona = info->arizona; -unsigned int val;int ret;dev_dbg (arizona->dev,"Starting identification via HPDET\n" );
@@ -665,30 +669,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)arizona_extcon_pulse_micbias (info); -mutex_lock (&arizona->dapm->card->dapm_mutex); - - ret =regmap_read (arizona->regmap,ARIZONA_OUTPUT_ENABLES_1 , &val); -if (ret !=0 ) { -dev_err (arizona->dev,"Failed to read output enables: %d\n" , - ret); - val =0 ; - } - -if (!(val & (ARIZONA_OUT1L_ENA |ARIZONA_OUT1R_ENA ))) { - ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 , -0x4000 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , - ret); - - ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 , -0x4000 ); -if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , - ret); - } - -mutex_unlock (&arizona->dapm->card->dapm_mutex); +arizona_extcon_do_magic (info,0x4000 ); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
Signature · 1 line
1.7.10.4
PATCH 2/3 ASoC: arizona: Fix interaction between headphone outputs and identification
Running HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running.
Do the ASoC side of this by storing the enable state in the core driver structure and only writing to the device if a flag indicating that the accessory detection side is in a state where it can have the headphone output stage enabled.
--- include/linux/mfd/arizona/core.h | 3 +++ sound/soc/codecs/arizona.c | 33 +++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 3 +++ sound/soc/codecs/wm5102.c | 8 ++++---- sound/soc/codecs/wm5110.c | 8 ++++---- 5 files changed, 47 insertions(+), 8 deletions(-)
include/linux/mfd/arizona/core.h +3 -0
@@ -100,6 +100,9 @@ struct arizona {struct regmap_irq_chip_data *aod_irq_chip;struct regmap_irq_chip_data *irq_chip; +bool hpdet_magic; +unsigned int hp_ena; +struct mutex clk_lock;int clk32k_ref;
sound/soc/codecs/arizona.c +33 -0
@@ -364,6 +364,39 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, }EXPORT_SYMBOL_GPL (arizona_out_ev); +int arizona_hp_ev (struct snd_soc_dapm_widget *w, +struct snd_kcontrol *kcontrol, +int event) +{ +struct arizona_priv *priv =snd_soc_codec_get_drvdata (w->codec); +unsigned int mask =1 << w->shift; +unsigned int val; + +switch (event) { +case SND_SOC_DAPM_POST_PMU : + val = mask; +break ; +case SND_SOC_DAPM_PRE_PMD : + val =0 ; +break ; +default : +return -EINVAL ; + } + +/* Store the desired state for the HP outputs */ + priv->arizona->hp_ena &= ~mask; + priv->arizona->hp_ena |= val; + +/* Force off if HPDET magic is active */ +if (priv->arizona->hpdet_magic) + val =0 ; + +snd_soc_update_bits (w->codec,ARIZONA_OUTPUT_ENABLES_1 , mask, val); + +return 0 ; +} +EXPORT_SYMBOL_GPL (arizona_hp_ev); +static unsigned int arizona_sysclk_48k_rates[] = {6144000 ,12288000 ,
sound/soc/codecs/arizona.h +3 -0
@@ -184,6 +184,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,extern int arizona_out_ev (struct snd_soc_dapm_widget *w,struct snd_kcontrol *kcontrol,int event); +extern int arizona_hp_ev (struct snd_soc_dapm_widget *w, +struct snd_kcontrol *kcontrol, +int event);extern int arizona_set_sysclk (struct snd_soc_codec *codec,int clk_id,int source,unsigned int freq,int dir);
sound/soc/codecs/wm5102.c +4 -4
@@ -1131,11 +1131,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),SND_SOC_DAPM_VALUE_MUX ("AEC Loopback" ,ARIZONA_DAC_AEC_CONTROL_1 ,ARIZONA_AEC_LOOPBACK_ENA ,0 , &wm5102_aec_loopback_mux), -SND_SOC_DAPM_PGA_E ("OUT1L" ,ARIZONA_OUTPUT_ENABLES_1 , -ARIZONA_OUT1L_ENA_SHIFT ,0 ,NULL ,0 , arizona_out_ev, +SND_SOC_DAPM_PGA_E ("OUT1L" ,SND_SOC_NOPM , +ARIZONA_OUT1L_ENA_SHIFT ,0 ,NULL ,0 , arizona_hp_ev,SND_SOC_DAPM_PRE_PMD |SND_SOC_DAPM_POST_PMU ), -SND_SOC_DAPM_PGA_E ("OUT1R" ,ARIZONA_OUTPUT_ENABLES_1 , -ARIZONA_OUT1R_ENA_SHIFT ,0 ,NULL ,0 , arizona_out_ev, +SND_SOC_DAPM_PGA_E ("OUT1R" ,SND_SOC_NOPM , +ARIZONA_OUT1R_ENA_SHIFT ,0 ,NULL ,0 , arizona_hp_ev,SND_SOC_DAPM_PRE_PMD |SND_SOC_DAPM_POST_PMU ), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
sound/soc/codecs/wm5110.c +4 -4
@@ -551,11 +551,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,SND_SOC_DAPM_AIF_IN ("AIF3RX2" ,NULL ,0 ,ARIZONA_AIF3_RX_ENABLES ,ARIZONA_AIF3RX2_ENA_SHIFT ,0 ), -SND_SOC_DAPM_PGA_E ("OUT1L" ,ARIZONA_OUTPUT_ENABLES_1 , -ARIZONA_OUT1L_ENA_SHIFT ,0 ,NULL ,0 , arizona_out_ev, +SND_SOC_DAPM_PGA_E ("OUT1L" ,SND_SOC_NOPM , +ARIZONA_OUT1L_ENA_SHIFT ,0 ,NULL ,0 , arizona_hp_ev,SND_SOC_DAPM_PRE_PMD |SND_SOC_DAPM_POST_PMU ), -SND_SOC_DAPM_PGA_E ("OUT1R" ,ARIZONA_OUTPUT_ENABLES_1 , -ARIZONA_OUT1R_ENA_SHIFT ,0 ,NULL ,0 , arizona_out_ev, +SND_SOC_DAPM_PGA_E ("OUT1R" ,SND_SOC_NOPM , +ARIZONA_OUT1R_ENA_SHIFT ,0 ,NULL ,0 , arizona_hp_ev,SND_SOC_DAPM_PRE_PMD |SND_SOC_DAPM_POST_PMU ), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
Signature · 1 line
1.7.10.4
PATCH 3/3 extcon: arizona: Fix interaction between headphone outputs and identification
In reply to Mark BrownRunning HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running.
For extcon instead of checking if the headphone output is enabled when doing magic application unconditionally disable the output and restore the state which ASoC wants set when undoing the magic.
--- drivers/extcon/extcon-arizona.c | 44 ++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-)
drivers/extcon/extcon-arizona.c +30 -14
@@ -104,29 +104,45 @@ static void arizona_extcon_do_magic(struct arizona_extcon_info *info, unsigned int magic) {struct arizona *arizona = info->arizona; -unsigned int val;int ret;mutex_lock (&arizona->dapm->card->dapm_mutex); - ret =regmap_read (arizona->regmap,ARIZONA_OUTPUT_ENABLES_1 , &val); -if (ret !=0 ) { -dev_err (arizona->dev,"Failed to read output enables: %d\n" , - ret); - val =0 ; - } + arizona->hpdet_magic = magic; -if (!(val & (ARIZONA_OUT1L_ENA |ARIZONA_OUT1R_ENA ))) { - ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 , - magic); +/* Keep the HP output stages disabled while doing the magic */ +if (magic) { + ret =regmap_update_bits (arizona->regmap, +ARIZONA_OUTPUT_ENABLES_1 , +ARIZONA_OUT1L_ENA | +ARIZONA_OUT1R_ENA ,0 );if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , +dev_warn (arizona->dev, +"Failed to disable headphone outputs: %d\n" , + ret); + } + + ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 , + magic); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); - ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 , - magic); + ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 , + magic); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , + ret); + +/* Restore the desired state while not doing the magic */ +if (!magic) { + ret =regmap_update_bits (arizona->regmap, +ARIZONA_OUTPUT_ENABLES_1 , +ARIZONA_OUT1L_ENA | +ARIZONA_OUT1R_ENA , arizona->hp_ena);if (ret !=0 ) -dev_warn (arizona->dev,"Failed to do magic: %d\n" , +dev_warn (arizona->dev, +"Failed to restore headphone outputs: %d\n" , ret); }
Signature · 1 line
1.7.10.4
Quoted 2 lines · Mark Brown
I've taken the liberty of pulling into ASoC already, if there's a problem with that I can drop the changes easily enough.
While adding the ASoC stuff on top I realised that one of the overlapping changes should just be squashed down into the ASoC change here so I've gone ahead and done that and redone the tag, sorry about the noise.
From 04f2108cbde151329b7222d5399df71376a76358 Mon Sep 17 00:00:00 2001
From: Mark Brown <[email protected]>
Date: Mon, 25 Mar 2013 10:10:35 +0000
Subject: [PATCH] ASoC: arizona: Ensure generic output event is run for
headphones
--- sound/soc/codecs/arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/arizona.c +1 -1
@@ -631,7 +631,7 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,snd_soc_update_bits (w->codec,ARIZONA_OUTPUT_ENABLES_1 , mask, val); -return 0 ; +return arizona_out_ev (w, kcontrol, event); }EXPORT_SYMBOL_GPL (arizona_hp_ev);
Signature · 1 line
1.7.10.4
Quoted 9 lines · Mark Brown
Quoted 2 lines · Mark Brown
I've taken the liberty of pulling into ASoC already, if there's a problem with that I can drop the changes easily enough.
While adding the ASoC stuff on top I realised that one of the overlapping changes should just be squashed down into the ASoC change here so I've gone ahead and done that and redone the tag, sorry about the noise.
No problem. I've merged this to my char-misc.next branch so all should be good.
thanks,
greg k-h