From 4e6168779508f62c27e43a4f7ded786bfdb0a394 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 15 Jan 2013 22:09:20 +0900 Subject: [PATCH 01/11] extcon: arizona: Disable debouce for accessory removal detection Ensure we clamp as quickly as possible after removal by disabling the debounce while there is an accessory present. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index de141f72c8e5..ce95f8625e8d 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -773,6 +773,10 @@ static irqreturn_t arizona_jackdet(int irq, void *data) } else { arizona_start_hpdet_acc_id(info); } + + regmap_update_bits(arizona->regmap, + ARIZONA_JACK_DETECT_DEBOUNCE, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0); } else { dev_dbg(arizona->dev, "Detected jack removal\n"); @@ -792,6 +796,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data) if (ret != 0) dev_err(arizona->dev, "Removal report failed: %d\n", ret); + + regmap_update_bits(arizona->regmap, + ARIZONA_JACK_DETECT_DEBOUNCE, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); } mutex_unlock(&info->lock); From e6dd8cf223d1a41b3c3168e97e2c33df0ef05e9d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Jan 2013 17:30:02 +0900 Subject: [PATCH 02/11] extcon: arizona: Retry failed HP measurements We now have mechanisms in place to allow retries so let's use them rather than guessing. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index ce95f8625e8d..528303440c2e 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -31,8 +31,6 @@ #include #include -#define ARIZONA_DEFAULT_HP 32 - #define ARIZONA_NUM_BUTTONS 6 #define ARIZONA_ACCDET_MODE_MIC 0 @@ -208,7 +206,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) if (!(val & ARIZONA_HP_DONE)) { dev_err(arizona->dev, "HPDET did not complete: %x\n", val); - val = ARIZONA_DEFAULT_HP; + return -EAGAIN; } val &= ARIZONA_HP_LVL_MASK; @@ -218,14 +216,14 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) if (!(val & ARIZONA_HP_DONE_B)) { dev_err(arizona->dev, "HPDET did not complete: %x\n", val); - return ARIZONA_DEFAULT_HP; + return -EAGAIN; } ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val); if (ret != 0) { dev_err(arizona->dev, "Failed to read HP value: %d\n", ret); - return ARIZONA_DEFAULT_HP; + return -EAGAIN; } regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, @@ -267,7 +265,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) if (!(val & ARIZONA_HP_DONE_B)) { dev_err(arizona->dev, "HPDET did not complete: %x\n", val); - return ARIZONA_DEFAULT_HP; + return -EAGAIN; } val &= ARIZONA_HP_LVL_B_MASK; From f9365d07dd5cb3c76b454b4c7827b2f6339cace2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Jan 2013 17:35:44 +0900 Subject: [PATCH 03/11] extcon: arizona: Remove duplicate rate configuration Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 528303440c2e..ab8b9c7359fb 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1003,10 +1003,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) goto err_micdet; } - regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, - ARIZONA_MICD_RATE_MASK, - 8 << ARIZONA_MICD_RATE_SHIFT); - arizona_clk32k_enable(arizona); regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, ARIZONA_JD1_DB, ARIZONA_JD1_DB); From 2e033db5ddf299de2ae568919d78b0258a5a6423 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Jan 2013 17:36:33 +0900 Subject: [PATCH 04/11] extcon: arizona: Support additional configuration of microphone detection Allow systems to tune detection rate and debounce suitably for their mechanical parameters. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 12 ++++++++++++ include/linux/mfd/arizona/pdata.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index ab8b9c7359fb..d7e1047ad68e 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -907,6 +907,18 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona->pdata.micd_bias_start_time << ARIZONA_MICD_BIAS_STARTTIME_SHIFT); + if (arizona->pdata.micd_rate) + regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, + ARIZONA_MICD_RATE_MASK, + arizona->pdata.micd_rate + << ARIZONA_MICD_RATE_SHIFT); + + if (arizona->pdata.micd_dbtime) + regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, + ARIZONA_MICD_DBTIME_MASK, + arizona->pdata.micd_dbtime + << ARIZONA_MICD_DBTIME_SHIFT); + /* * If we have a clamp use it, activating in conjunction with * GPIO5 if that is connected for jack detect operation. diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index bcbe4fda87cb..2f5f08e10b79 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -111,6 +111,12 @@ struct arizona_pdata { /** Mic detect ramp rate */ int micd_bias_start_time; + /** Mic detect sample rate */ + int micd_rate; + + /** Mic detect debounce level */ + int micd_dbtime; + /** Headset polarity configurations */ struct arizona_micd_config *micd_configs; int num_micd_configs; From bbbd46e3d7fcdf1c8362bf1c83bcc08a93676cc9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Jan 2013 19:38:43 +0000 Subject: [PATCH 05/11] extcon: arizona: Use regulated mode for microphone supply when detecting When starting microphone detection some headsets should be exposed to the fully regulated microphone bias in order to ensure that they behave in an optimal fashion. Signed-off-by: Mark Brown --- drivers/extcon/Kconfig | 2 +- drivers/extcon/extcon-arizona.c | 93 +++++++++++++++++++++++++++++++ include/linux/mfd/arizona/pdata.h | 3 + 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 07122a9ef36e..9377050e5335 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -47,7 +47,7 @@ config EXTCON_MAX8997 config EXTCON_ARIZONA tristate "Wolfson Arizona EXTCON support" - depends on MFD_ARIZONA && INPUT + depends on MFD_ARIZONA && INPUT && SND_SOC help Say Y here to enable support for external accessory detection with Wolfson Arizona devices. These are audio CODECs with diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index d7e1047ad68e..aa724314677a 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -113,6 +115,52 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); } +static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) +{ + switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) { + case 1: + return "MICBIAS1"; + case 2: + return "MICBIAS2"; + case 3: + return "MICBIAS3"; + default: + return "MICVDD"; + } +} + +static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) +{ + struct arizona *arizona = info->arizona; + const char *widget = arizona_extcon_get_micbias(info); + struct snd_soc_dapm_context *dapm = arizona->dapm; + int ret; + + mutex_lock(&dapm->card->dapm_mutex); + + ret = snd_soc_dapm_force_enable_pin(dapm, widget); + if (ret != 0) + dev_warn(arizona->dev, "Failed to enable %s: %d\n", + widget, ret); + + mutex_unlock(&dapm->card->dapm_mutex); + + snd_soc_dapm_sync(dapm); + + if (!arizona->pdata.micd_force_micbias) { + mutex_lock(&dapm->card->dapm_mutex); + + ret = snd_soc_dapm_disable_pin(arizona->dapm, widget); + if (ret != 0) + dev_warn(arizona->dev, "Failed to disable %s: %d\n", + widget, ret); + + mutex_unlock(&dapm->card->dapm_mutex); + + snd_soc_dapm_sync(dapm); + } +} + static void arizona_start_mic(struct arizona_extcon_info *info) { struct arizona *arizona = info->arizona; @@ -122,6 +170,15 @@ static void arizona_start_mic(struct arizona_extcon_info *info) /* Microphone detection can't use idle mode */ pm_runtime_get(info->dev); + if (info->detecting) { + ret = regulator_allow_bypass(info->micvdd, false); + if (ret != 0) { + dev_err(arizona->dev, + "Failed to regulate MICVDD: %d\n", + ret); + } + } + ret = regulator_enable(info->micvdd); if (ret != 0) { dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", @@ -138,6 +195,8 @@ static void arizona_start_mic(struct arizona_extcon_info *info) ARIZONA_ACCESSORY_DETECT_MODE_1, ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); + arizona_extcon_pulse_micbias(info); + regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, &change); @@ -150,18 +209,39 @@ static void arizona_start_mic(struct arizona_extcon_info *info) static void arizona_stop_mic(struct arizona_extcon_info *info) { struct arizona *arizona = info->arizona; + const char *widget = arizona_extcon_get_micbias(info); + struct snd_soc_dapm_context *dapm = arizona->dapm; bool change; + int ret; regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_ENA, 0, &change); + mutex_lock(&dapm->card->dapm_mutex); + + ret = snd_soc_dapm_disable_pin(dapm, widget); + if (ret != 0) + dev_warn(arizona->dev, + "Failed to disable %s: %d\n", + widget, ret); + + mutex_unlock(&dapm->card->dapm_mutex); + + snd_soc_dapm_sync(dapm); + if (info->micd_reva) { regmap_write(arizona->regmap, 0x80, 0x3); regmap_write(arizona->regmap, 0x294, 2); regmap_write(arizona->regmap, 0x80, 0x0); } + ret = regulator_allow_bypass(info->micvdd, true); + if (ret != 0) { + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", + ret); + } + if (change) { regulator_disable(info->micvdd); pm_runtime_mark_last_busy(info->dev); @@ -564,6 +644,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) info->hpdet_active = true; + arizona_extcon_pulse_micbias(info); + ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); if (ret != 0) dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); @@ -649,6 +731,13 @@ static irqreturn_t arizona_micdet(int irq, void *data) dev_err(arizona->dev, "Headset report failed: %d\n", ret); + /* Don't need to regulate for button detection */ + ret = regulator_allow_bypass(info->micvdd, false); + if (ret != 0) { + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", + ret); + } + info->mic = true; info->detecting = false; goto handled; @@ -716,6 +805,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) input_report_key(info->input, arizona_lvl_to_key[i].report, 0); input_sync(info->input); + arizona_extcon_pulse_micbias(info); } handled: @@ -817,6 +907,9 @@ static int arizona_extcon_probe(struct platform_device *pdev) int jack_irq_fall, jack_irq_rise; int ret, mode, i; + if (!arizona->dapm || !arizona->dapm->card) + return -EPROBE_DEFER; + pdata = dev_get_platdata(arizona->dev); info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 2f5f08e10b79..f8241753415c 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -117,6 +117,9 @@ struct arizona_pdata { /** Mic detect debounce level */ int micd_dbtime; + /** Force MICBIAS on for mic detect */ + bool micd_force_micbias; + /** Headset polarity configurations */ struct arizona_micd_config *micd_configs; int num_micd_configs; From e339af1c4567b1e63209329e2665781e598709f2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 4 Feb 2013 19:29:41 +0000 Subject: [PATCH 06/11] extcon: arizona: Remove extra jack flip increment Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index aa724314677a..c17a41ff60ea 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -750,8 +750,6 @@ static irqreturn_t arizona_micdet(int irq, void *data) * impedence then give up and report headphones. */ if (info->detecting && (val & 0x3f8)) { - info->jack_flips++; - if (info->jack_flips >= info->micd_num_modes) { dev_dbg(arizona->dev, "Detected HP/line\n"); arizona_identify_headphone(info); From 0e27bd3137778ac9e856fec99b1752bf054a987c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Feb 2013 21:00:15 +0000 Subject: [PATCH 07/11] extcon: arizona: Add some debounce time before starting HPDET identification The HPDET identification method does not have the same natural debounce built into it that the standard MICDET method does so add some extra on top of what the jack detection does in hardware to make sure we get a robust result. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index c17a41ff60ea..2ad0e4a35a23 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -53,6 +53,8 @@ struct arizona_extcon_info { bool micd_reva; bool micd_clamp; + struct delayed_work hpdet_work; + bool hpdet_active; int num_hpdet_res; @@ -640,7 +642,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) dev_dbg(arizona->dev, "Starting identification via HPDET\n"); /* Make sure we keep the device enabled during the measurement */ - pm_runtime_get(info->dev); + pm_runtime_get_sync(info->dev); info->hpdet_active = true; @@ -813,6 +815,17 @@ handled: return IRQ_HANDLED; } +static void arizona_hpdet_work(struct work_struct *work) +{ + struct arizona_extcon_info *info = container_of(work, + struct arizona_extcon_info, + hpdet_work.work); + + mutex_lock(&info->lock); + arizona_start_hpdet_acc_id(info); + mutex_unlock(&info->lock); +} + static irqreturn_t arizona_jackdet(int irq, void *data) { struct arizona_extcon_info *info = data; @@ -822,6 +835,8 @@ static irqreturn_t arizona_jackdet(int irq, void *data) pm_runtime_get_sync(info->dev); + cancel_delayed_work_sync(&info->hpdet_work); + mutex_lock(&info->lock); if (arizona->pdata.jd_gpio5) { @@ -857,7 +872,8 @@ static irqreturn_t arizona_jackdet(int irq, void *data) arizona_start_mic(info); } else { - arizona_start_hpdet_acc_id(info); + schedule_delayed_work(&info->hpdet_work, + msecs_to_jiffies(250)); } regmap_update_bits(arizona->regmap, @@ -927,6 +943,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) mutex_init(&info->lock); info->arizona = arizona; info->dev = &pdev->dev; + INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); platform_set_drvdata(pdev, info); switch (arizona->type) { @@ -1173,6 +1190,7 @@ static int arizona_extcon_remove(struct platform_device *pdev) arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); arizona_free_irq(arizona, jack_irq_rise, info); arizona_free_irq(arizona, jack_irq_fall, info); + cancel_delayed_work_sync(&info->hpdet_work); regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, ARIZONA_JD1_ENA, 0); arizona_clk32k_disable(arizona); From 903aa56fdf930fd17fc4f35610bb1c818b5a9327 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 7 Feb 2013 15:47:40 +0000 Subject: [PATCH 08/11] extcon: arizona: Don't HPDET magic when headphones are enabled The magic is already done as part of enabling the headphone output so does not need to be done when the headphone outputs are enabled. We hold the DAPM lock so the headphone status can't be changed underneath us. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 58 ++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 2ad0e4a35a23..cfd206c4797c 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -489,6 +489,7 @@ 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); @@ -543,13 +544,28 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) dev_err(arizona->dev, "Failed to report HP/line: %d\n", ret); - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret); + mutex_lock(&arizona->dapm->card->dapm_mutex); - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret); + 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); done: if (id_gpio) @@ -637,6 +653,7 @@ 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"); @@ -648,13 +665,30 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) arizona_extcon_pulse_micbias(info); - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); + mutex_lock(&arizona->dapm->card->dapm_mutex); - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); + 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); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, From 5d9ab708200fefc3ec6e4454c65584d14ce716b0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2013 10:13:38 +0000 Subject: [PATCH 09/11] extcon: arizona: Clear _trig_sts bits after jack detection It is important to clear the wake trigger status bits otherwise DCVDD will be held high independent of the state of the LDOENA line. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 7 +++++++ include/linux/mfd/arizona/registers.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index cfd206c4797c..aeaf217a05ee 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -939,6 +939,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); } + /* Clear trig_sts to make sure DCVDD is not forced up */ + regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, + ARIZONA_MICD_CLAMP_FALL_TRIG_STS | + ARIZONA_MICD_CLAMP_RISE_TRIG_STS | + ARIZONA_JD1_FALL_TRIG_STS | + ARIZONA_JD1_RISE_TRIG_STS); + mutex_unlock(&info->lock); pm_runtime_mark_last_busy(info->dev); diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 79e9dd4073d8..188d89abd963 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -5267,6 +5267,14 @@ /* * R3408 (0xD50) - AOD wkup and trig */ +#define ARIZONA_MICD_CLAMP_FALL_TRIG_STS 0x0080 /* MICD_CLAMP_FALL_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_FALL_TRIG_STS_MASK 0x0080 /* MICD_CLAMP_FALL_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_FALL_TRIG_STS_SHIFT 7 /* MICD_CLAMP_FALL_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_FALL_TRIG_STS_WIDTH 1 /* MICD_CLAMP_FALL_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_RISE_TRIG_STS 0x0040 /* MICD_CLAMP_RISE_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_RISE_TRIG_STS_MASK 0x0040 /* MICD_CLAMP_RISE_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_RISE_TRIG_STS_SHIFT 6 /* MICD_CLAMP_RISE_TRIG_STS */ +#define ARIZONA_MICD_CLAMP_RISE_TRIG_STS_WIDTH 1 /* MICD_CLAMP_RISE_TRIG_STS */ #define ARIZONA_GP5_FALL_TRIG_STS 0x0020 /* GP5_FALL_TRIG_STS */ #define ARIZONA_GP5_FALL_TRIG_STS_MASK 0x0020 /* GP5_FALL_TRIG_STS */ #define ARIZONA_GP5_FALL_TRIG_STS_SHIFT 5 /* GP5_FALL_TRIG_STS */ From c37b387f077c54c5a01fa240dc8448b60bd731c1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Feb 2013 17:48:49 +0000 Subject: [PATCH 10/11] extcon: arizona: Always take the first HPDET reading as the final one This should always be the most accurate reading for supported accessory configurations. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index aeaf217a05ee..d9918421e80b 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -451,6 +451,10 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) info->hpdet_res[0], info->hpdet_res[1], info->hpdet_res[2]); + + /* Take the headphone impedance for the main report */ + *reading = info->hpdet_res[0]; + /* * Either the two grounds measure differently or we * measure the mic as high impedance. @@ -466,9 +470,6 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) dev_err(arizona->dev, "Failed to report mic: %d\n", ret); } - - /* Take the headphone impedance for the main report */ - *reading = info->hpdet_res[1]; } else { dev_dbg(arizona->dev, "Detected headphone\n"); } From bf14ee5a460276a99ed35f9034bae9e74b01600f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Feb 2013 20:20:17 +0000 Subject: [PATCH 11/11] extcon: arizona: Use MICDET for final microphone identification When using HPDET to identify the accessory still run MICDET before we report a microphone in order to ensure that the accessory identified is compatible with the MICDET detection ranges after having confirmed that the device is not using a headphone. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index d9918421e80b..dc357a4051f6 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -56,6 +56,7 @@ struct arizona_extcon_info { struct delayed_work hpdet_work; bool hpdet_active; + bool hpdet_done; int num_hpdet_res; unsigned int hpdet_res[3]; @@ -394,7 +395,6 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) { struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; - int ret; /* * If we're using HPDET for accessory identification we need @@ -463,13 +463,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) (id_gpio && info->hpdet_res[2] > 10)) { dev_dbg(arizona->dev, "Detected mic\n"); info->mic = true; - ret = extcon_set_cable_state_(&info->edev, - ARIZONA_CABLE_MICROPHONE, - true); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to report mic: %d\n", ret); - } + info->detecting = true; } else { dev_dbg(arizona->dev, "Detected headphone\n"); } @@ -586,6 +580,8 @@ done: info->hpdet_active = false; } + info->hpdet_done = true; + out: mutex_unlock(&info->lock); @@ -597,6 +593,9 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) struct arizona *arizona = info->arizona; int ret; + if (info->hpdet_done) + return; + dev_dbg(arizona->dev, "Starting HPDET\n"); /* Make sure we keep the device enabled during the measurement */ @@ -923,6 +922,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) info->hpdet_res[i] = 0; info->mic = false; + info->hpdet_done = false; for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) input_report_key(info->input,