2013-04-02 11:32:02

by Mark Brown

[permalink] [raw]
Subject: [PATCH 0/16] extcon: arizona: Updates for v3.10

The following changes since commit df8c3dbee9e6f19ddb0ae8e05cdf76eb2d3b7f00:

extcon: arizona: Fix interaction between headphone outputs and identification (2013-03-26 15:45:26 +0000)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git tags/extcon-arizona-v3.10

for you to fetch changes up to 7abd4e2a8f1c3e534da44c35e2d3d6353573e51f:

extcon: arizona: Make mic detection timeout configurable (2013-04-02 11:54:07 +0100)

----------------------------------------------------------------
extcon: arizona: Updates for v3.10

There's a bunch of different things in this series, I can split them out
if need be:

- Support for configuring the button detection circuit to reflect the
accessories supplied with the system.
- Improvements in the HPDET based detection scheme.
- Additional robustness against more pathological use cases.
- A few small standalone fixes.

----------------------------------------------------------------
Charles Keepax (1):
extcon: arizona: Check we report a valid impedance

Mark Brown (15):
mfd: wm5102: Add registers for microphone detection level configuration
extcon: arizona: Attempt more microphone measurements
extcon: arizona: Allow configuration of button detection
extcon: arizona: Don't pulse MICBIAS for HPDET identification
extcon: arizona: Allow pull to be disabled on GPIO5 when used for JACKET
extcon: arizona: Raise minimum microphone impedance for HPDET method
extcon: arizona: Suppress duplicate JACKDET reports
extcon: arizona: Tune up HPDET debounce
extcon: arizona: Retry HPDET identification for high impedance
extcon: arizona: Don't ground flip when using HPDET identification
extcon: arizona: Simplify HPDET based identification
extcon: arizona: Time out if MICDET fails to report
extcon: arizona: Clear existing button reports before reporting new one
extcon: arizona: Allow additional debounce during microphone detection
extcon: arizona: Make mic detection timeout configurable

drivers/extcon/extcon-arizona.c | 391 ++++++++++++++++++++++++---------
drivers/mfd/wm5102-tables.c | 8 +
include/linux/mfd/arizona/pdata.h | 21 ++
include/linux/mfd/arizona/registers.h | 4 +
4 files changed, 320 insertions(+), 104 deletions(-)


Attachments:
(No filename) (2.32 kB)
signature.asc (836.00 B)
Digital signature
Download all attachments

2013-04-02 11:33:07

by Mark Brown

[permalink] [raw]
Subject: [PATCH 12/16] extcon: arizona: Simplify HPDET based identification

Rather than measuring both HP channels we can simply directly measure the
microphone impedance and then rely on MICDET for final confirmation of the
presence of a suitable microphone. This improves the overall performance
of the identification process.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 46 ++++++++++++++++++++-----------------
include/linux/mfd/arizona/pdata.h | 3 +++
2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 7c4ce81..a83ca27a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -459,7 +459,8 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
return val;
}

-static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
+static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
+ bool *mic)
{
struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio;
@@ -470,11 +471,9 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
*/
if (arizona->pdata.hpdet_acc_id) {
info->hpdet_res[info->num_hpdet_res++] = *reading;
- info->hpdet_res[info->num_hpdet_res++] = *reading;

/* Only check the mic directly if we didn't already ID it */
- if (id_gpio && info->num_hpdet_res == 2 &&
- !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
+ if (id_gpio && info->num_hpdet_res == 1) {
dev_dbg(arizona->dev, "Measuring mic\n");

regmap_update_bits(arizona->regmap,
@@ -493,10 +492,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
}

/* OK, got both. Now, compare... */
- dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
- info->hpdet_res[0], info->hpdet_res[1],
- info->hpdet_res[2]);
-
+ dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+ info->hpdet_res[0], info->hpdet_res[1]);

/* Take the headphone impedance for the main report */
*reading = info->hpdet_res[0];
@@ -512,13 +509,11 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
}

/*
- * Either the two grounds measure differently or we
- * measure the mic as high impedance.
+ * If we measure the mic as
*/
- if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
- (id_gpio && info->hpdet_res[2] > 1257)) {
+ if (!id_gpio || info->hpdet_res[1] > 50) {
dev_dbg(arizona->dev, "Detected mic\n");
- info->mic = true;
+ *mic = true;
info->detecting = true;
} else {
dev_dbg(arizona->dev, "Detected headphone\n");
@@ -541,6 +536,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
int id_gpio = arizona->pdata.hpdet_id_gpio;
int report = ARIZONA_CABLE_HEADPHONE;
int ret, reading;
+ bool mic = false;

mutex_lock(&info->lock);

@@ -576,7 +572,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
0);

- ret = arizona_hpdet_do_id(info, &reading);
+ ret = arizona_hpdet_do_id(info, &reading, &mic);
if (ret == -EAGAIN) {
goto out;
} else if (ret < 0) {
@@ -606,7 +602,7 @@ done:
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);

/* If we have a mic then reenable MICDET */
- if (info->mic)
+ if (mic || info->mic)
arizona_start_mic(info);

if (info->hpdet_active) {
@@ -681,6 +677,8 @@ err:
static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
+ int hp_reading = 32;
+ bool mic;
int ret;

dev_dbg(arizona->dev, "Starting identification via HPDET\n");
@@ -702,12 +700,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
goto err;
}

- ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
- ARIZONA_HP_POLL, ARIZONA_HP_POLL);
- if (ret != 0) {
- dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
- ret);
- goto err;
+ if (arizona->pdata.hpdet_acc_id_line) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Can't start HPDETL measurement: %d\n",
+ ret);
+ goto err;
+ }
+ } else {
+ arizona_hpdet_do_id(info, &hp_reading, &mic);
}

return;
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 008b8c4..45c8477 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -128,6 +128,9 @@ struct arizona_pdata {
/** Use the headphone detect circuit to identify the accessory */
bool hpdet_acc_id;

+ /** Check for line output with HPDET method */
+ bool hpdet_acc_id_line;
+
/** GPIO used for mic isolation with HPDET */
int hpdet_id_gpio;

--
1.7.10.4

2013-04-02 11:33:05

by Mark Brown

[permalink] [raw]
Subject: [PATCH 13/16] extcon: arizona: Time out if MICDET fails to report

In pathological cases the microphone detection may fail to report, for
example due to a failure to get a stable measurement. Provide a timeout
to cover such cases.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index a83ca27a..e2d881a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -42,6 +42,7 @@
#define ARIZONA_HPDET_MAX 10000

#define HPDET_DEBOUNCE 500
+#define MICD_TIMEOUT 2000

struct arizona_extcon_info {
struct device *dev;
@@ -63,6 +64,7 @@ struct arizona_extcon_info {
bool micd_clamp;

struct delayed_work hpdet_work;
+ struct delayed_work micd_timeout_work;

bool hpdet_active;
bool hpdet_done;
@@ -730,6 +732,24 @@ err:
info->hpdet_active = false;
}

+static void arizona_micd_timeout_work(struct work_struct *work)
+{
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ micd_timeout_work.work);
+
+ mutex_lock(&info->lock);
+
+ dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
+ arizona_identify_headphone(info);
+
+ info->detecting = false;
+
+ arizona_stop_mic(info);
+
+ mutex_unlock(&info->lock);
+}
+
static irqreturn_t arizona_micdet(int irq, void *data)
{
struct arizona_extcon_info *info = data;
@@ -737,6 +757,8 @@ static irqreturn_t arizona_micdet(int irq, void *data)
unsigned int val = 0, lvl;
int ret, i, key;

+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
mutex_lock(&info->lock);

for (i = 0; i < 10 && !(val & 0x7fc); i++) {
@@ -858,6 +880,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
}

handled:
+ if (info->detecting)
+ schedule_delayed_work(&info->micd_timeout_work,
+ msecs_to_jiffies(MICD_TIMEOUT));
+
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);

@@ -880,10 +906,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val, present, mask;
- bool cancelled;
+ bool cancelled_hp, cancelled_mic;
int ret, i;

- cancelled = cancel_delayed_work_sync(&info->hpdet_work);
+ cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
+ cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);

pm_runtime_get_sync(info->dev);

@@ -909,10 +936,14 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
val &= mask;
if (val == info->last_jackdet) {
dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
- if (cancelled)
+ if (cancelled_hp)
schedule_delayed_work(&info->hpdet_work,
msecs_to_jiffies(HPDET_DEBOUNCE));

+ if (cancelled_mic)
+ schedule_delayed_work(&info->micd_timeout_work,
+ msecs_to_jiffies(MICD_TIMEOUT));
+
goto out;
}
info->last_jackdet = val;
@@ -1037,6 +1068,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+ INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
platform_set_drvdata(pdev, info);

switch (arizona->type) {
--
1.7.10.4

2013-04-02 11:33:04

by Mark Brown

[permalink] [raw]
Subject: [PATCH 09/16] extcon: arizona: Tune up HPDET debounce

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 4022fe2..5344f43 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -39,7 +39,7 @@
#define ARIZONA_ACCDET_MODE_HPL 1
#define ARIZONA_ACCDET_MODE_HPR 2

-#define HPDET_DEBOUNCE 250
+#define HPDET_DEBOUNCE 500

struct arizona_extcon_info {
struct device *dev;
--
1.7.10.4

2013-04-02 11:33:47

by Mark Brown

[permalink] [raw]
Subject: [PATCH 16/16] extcon: arizona: Make mic detection timeout configurable

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 13 ++++++++++---
include/linux/mfd/arizona/pdata.h | 3 +++
2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index c7f8eb4..7a1b4a7 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -42,7 +42,7 @@
#define ARIZONA_HPDET_MAX 10000

#define HPDET_DEBOUNCE 500
-#define MICD_TIMEOUT 2000
+#define DEFAULT_MICD_TIMEOUT 2000

struct arizona_extcon_info {
struct device *dev;
@@ -60,6 +60,8 @@ struct arizona_extcon_info {
const struct arizona_micd_range *micd_ranges;
int num_micd_ranges;

+ int micd_timeout;
+
bool micd_reva;
bool micd_clamp;

@@ -889,7 +891,7 @@ static void arizona_micd_detect(struct work_struct *work)
handled:
if (info->detecting)
schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(MICD_TIMEOUT));
+ msecs_to_jiffies(info->micd_timeout));

pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
@@ -970,7 +972,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)

if (cancelled_mic)
schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(MICD_TIMEOUT));
+ msecs_to_jiffies(info->micd_timeout));

goto out;
}
@@ -1027,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
}

+ if (arizona->pdata.micd_timeout)
+ info->micd_timeout = arizona->pdata.micd_timeout;
+ else
+ info->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
/* 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 |
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 3ef300b..a0f9409 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -149,6 +149,9 @@ struct arizona_pdata {
/** Mic detect debounce level */
int micd_dbtime;

+ /** Mic detect timeout (ms) */
+ int micd_timeout;
+
/** Force MICBIAS on for mic detect */
bool micd_force_micbias;

--
1.7.10.4

2013-04-02 11:33:48

by Mark Brown

[permalink] [raw]
Subject: [PATCH 11/16] extcon: arizona: Don't ground flip when using HPDET identification

This extra check makes the procedure take longer and is of marginal use
in identification so do not execute it.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 24 +-----------------------
1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index c18cf14..7c4ce81 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -470,29 +470,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
*/
if (arizona->pdata.hpdet_acc_id) {
info->hpdet_res[info->num_hpdet_res++] = *reading;
-
- /*
- * If the impedence is too high don't measure the
- * second ground.
- */
- if (info->num_hpdet_res == 1 && *reading >= 45) {
- dev_dbg(arizona->dev, "Skipping ground flip\n");
- info->hpdet_res[info->num_hpdet_res++] = *reading;
- }
-
- if (info->num_hpdet_res == 1) {
- dev_dbg(arizona->dev, "Flipping ground\n");
-
- regmap_update_bits(arizona->regmap,
- ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_SRC,
- ~info->micd_modes[0].src);
-
- regmap_update_bits(arizona->regmap,
- ARIZONA_HEADPHONE_DETECT_1,
- ARIZONA_HP_POLL, ARIZONA_HP_POLL);
- return -EAGAIN;
- }
+ info->hpdet_res[info->num_hpdet_res++] = *reading;

/* Only check the mic directly if we didn't already ID it */
if (id_gpio && info->num_hpdet_res == 2 &&
--
1.7.10.4

2013-04-02 11:33:46

by Mark Brown

[permalink] [raw]
Subject: [PATCH 14/16] extcon: arizona: Clear existing button reports before reporting new one

If the user moves directly from one button to another then we won't get a
no buttons pressed event and will therefore end up reporting that two
buttons are simultaneously pressed which isn't supported by the hardware.
Make sure we clear any existing button reports before reporting any new
ones.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e2d881a..26f9a1a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -852,6 +852,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
lvl = val & ARIZONA_MICD_LVL_MASK;
lvl >>= ARIZONA_MICD_LVL_SHIFT;

+ for (i = 0; i < info->num_micd_ranges; i++)
+ input_report_key(info->input,
+ info->micd_ranges[i].key, 0);
+
WARN_ON(!lvl);
WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
--
1.7.10.4

2013-04-02 11:34:33

by Mark Brown

[permalink] [raw]
Subject: [PATCH 15/16] extcon: arizona: Allow additional debounce during microphone detection

Help mitigate against mechanical bounce during the initial detection by
allowing the configuration of an additional debounce on top of that the
hardware does during the initial phase of microphone detection operation.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 35 ++++++++++++++++++++++++++++++-----
include/linux/mfd/arizona/pdata.h | 3 +++
2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 26f9a1a..c7f8eb4 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -64,6 +64,7 @@ struct arizona_extcon_info {
bool micd_clamp;

struct delayed_work hpdet_work;
+ struct delayed_work micd_detect_work;
struct delayed_work micd_timeout_work;

bool hpdet_active;
@@ -750,9 +751,11 @@ static void arizona_micd_timeout_work(struct work_struct *work)
mutex_unlock(&info->lock);
}

-static irqreturn_t arizona_micdet(int irq, void *data)
+static void arizona_micd_detect(struct work_struct *work)
{
- struct arizona_extcon_info *info = data;
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ micd_detect_work.work);
struct arizona *arizona = info->arizona;
unsigned int val = 0, lvl;
int ret, i, key;
@@ -766,7 +769,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
if (ret != 0) {
dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
mutex_unlock(&info->lock);
- return IRQ_NONE;
+ return;
}

dev_dbg(arizona->dev, "MICDET: %x\n", val);
@@ -774,14 +777,14 @@ static irqreturn_t arizona_micdet(int irq, void *data)
if (!(val & ARIZONA_MICD_VALID)) {
dev_warn(arizona->dev, "Microphone detection state invalid\n");
mutex_unlock(&info->lock);
- return IRQ_NONE;
+ return;
}
}

if (i == 10 && !(val & 0x7fc)) {
dev_err(arizona->dev, "Failed to get valid MICDET value\n");
mutex_unlock(&info->lock);
- return IRQ_NONE;
+ return;
}

/* Due to jack detect this should never happen */
@@ -890,6 +893,27 @@ handled:

pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+ struct arizona_extcon_info *info = data;
+ struct arizona *arizona = info->arizona;
+ int debounce = arizona->pdata.micd_detect_debounce;
+
+ cancel_delayed_work_sync(&info->micd_detect_work);
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ mutex_lock(&info->lock);
+ if (!info->detecting)
+ debounce = 0;
+ mutex_unlock(&info->lock);
+
+ if (debounce)
+ schedule_delayed_work(&info->micd_detect_work,
+ msecs_to_jiffies(debounce));
+ else
+ arizona_micd_detect(&info->micd_detect_work.work);

return IRQ_HANDLED;
}
@@ -1072,6 +1096,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+ INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
platform_set_drvdata(pdev, info);

diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 45c8477..3ef300b 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -134,6 +134,9 @@ struct arizona_pdata {
/** GPIO used for mic isolation with HPDET */
int hpdet_id_gpio;

+ /** Extra debounce timeout used during initial mic detection (ms) */
+ int micd_detect_debounce;
+
/** GPIO for mic detection polarity */
int micd_pol_gpio;

--
1.7.10.4

2013-04-02 11:34:48

by Mark Brown

[permalink] [raw]
Subject: [PATCH 10/16] extcon: arizona: Retry HPDET identification for high impedance

Sometimes we can trigger measurements early if contacts are shorted during
a slow insertion. As well as debouncing add further robustness by retrying
if we get a high impedance measurement for headphones as this can indicate
that the headphones were not yet connected.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 5344f43..c18cf14 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -39,6 +39,8 @@
#define ARIZONA_ACCDET_MODE_HPL 1
#define ARIZONA_ACCDET_MODE_HPR 2

+#define ARIZONA_HPDET_MAX 10000
+
#define HPDET_DEBOUNCE 500

struct arizona_extcon_info {
@@ -64,6 +66,7 @@ struct arizona_extcon_info {

bool hpdet_active;
bool hpdet_done;
+ bool hpdet_retried;

int num_hpdet_res;
unsigned int hpdet_res[3];
@@ -112,6 +115,8 @@ static const char *arizona_cable[] = {
NULL,
};

+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
+
static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
unsigned int magic)
{
@@ -393,7 +398,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
/* If we go out of range report top of range */
if (val < 100 || val > 0x3fb) {
dev_dbg(arizona->dev, "Measurement out of range\n");
- return 10000;
+ return ARIZONA_HPDET_MAX;
}

dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
@@ -518,6 +523,16 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
/* Take the headphone impedance for the main report */
*reading = info->hpdet_res[0];

+ /* Sometimes we get false readings due to slow insert */
+ if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+ dev_dbg(arizona->dev, "Retrying high impedance\n");
+ info->num_hpdet_res = 0;
+ info->hpdet_retried = true;
+ arizona_start_hpdet_acc_id(info);
+ pm_runtime_put(info->dev);
+ return -EAGAIN;
+ }
+
/*
* Either the two grounds measure differently or we
* measure the mic as high impedance.
@@ -953,6 +968,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
info->hpdet_res[i] = 0;
info->mic = false;
info->hpdet_done = false;
+ info->hpdet_retried = false;

for (i = 0; i < info->num_micd_ranges; i++)
input_report_key(info->input,
--
1.7.10.4

2013-04-02 11:33:02

by Mark Brown

[permalink] [raw]
Subject: [PATCH 02/16] extcon: arizona: Attempt more microphone measurements

In some pathological use cases users may insert an accessory very slowly
causing multiple indeterminate measurements. Handle this by retrying many
measurements before we give up and declare a headphone.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index b289279..4bb0e9a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -153,6 +153,8 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
{
struct arizona *arizona = info->arizona;

+ mode %= info->num_micd_modes;
+
if (arizona->pdata.micd_pol_gpio > 0)
gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
info->micd_modes[mode].gpio);
@@ -783,7 +785,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
* impedence then give up and report headphones.
*/
if (info->detecting && (val & 0x3f8)) {
- if (info->jack_flips >= info->micd_num_modes) {
+ if (info->jack_flips >= info->micd_num_modes * 10) {
dev_dbg(arizona->dev, "Detected HP/line\n");
arizona_identify_headphone(info);

--
1.7.10.4

2013-04-02 11:35:08

by Mark Brown

[permalink] [raw]
Subject: [PATCH 07/16] extcon: arizona: Suppress duplicate JACKDET reports

In cases where we see a brief (dis)connection of the jack detection signals
we may see a noop jack insertion or removal where the jack has returned to
the original state by the time the interrupt is serviced. Suppress these
events in order to save work and avoid confusing the rest of the code.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 2f0bd49..9e4bffe 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -39,6 +39,8 @@
#define ARIZONA_ACCDET_MODE_HPL 1
#define ARIZONA_ACCDET_MODE_HPR 2

+#define HPDET_DEBOUNCE 250
+
struct arizona_extcon_info {
struct device *dev;
struct arizona *arizona;
@@ -46,6 +48,8 @@ struct arizona_extcon_info {
struct regulator *micvdd;
struct input_dev *input;

+ u16 last_jackdet;
+
int micd_mode;
const struct arizona_micd_config *micd_modes;
int micd_num_modes;
@@ -871,11 +875,12 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val, present, mask;
+ bool cancelled;
int ret, i;

- pm_runtime_get_sync(info->dev);
+ cancelled = cancel_delayed_work_sync(&info->hpdet_work);

- cancel_delayed_work_sync(&info->hpdet_work);
+ pm_runtime_get_sync(info->dev);

mutex_lock(&info->lock);

@@ -896,7 +901,18 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
return IRQ_NONE;
}

- if ((val & mask) == present) {
+ val &= mask;
+ if (val == info->last_jackdet) {
+ dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+ if (cancelled)
+ schedule_delayed_work(&info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+
+ goto out;
+ }
+ info->last_jackdet = val;
+
+ if (info->last_jackdet == present) {
dev_dbg(arizona->dev, "Detected jack\n");
ret = extcon_set_cable_state_(&info->edev,
ARIZONA_CABLE_MECHANICAL, true);
@@ -913,7 +929,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
arizona_start_mic(info);
} else {
schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(250));
+ msecs_to_jiffies(HPDET_DEBOUNCE));
}

regmap_update_bits(arizona->regmap,
@@ -953,6 +969,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ARIZONA_JD1_FALL_TRIG_STS |
ARIZONA_JD1_RISE_TRIG_STS);

+out:
mutex_unlock(&info->lock);

pm_runtime_mark_last_busy(info->dev);
@@ -1012,6 +1029,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
mutex_init(&info->lock);
info->arizona = arizona;
info->dev = &pdev->dev;
+ info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
platform_set_drvdata(pdev, info);

--
1.7.10.4

2013-04-02 11:35:06

by Mark Brown

[permalink] [raw]
Subject: [PATCH 08/16] extcon: arizona: Check we report a valid impedance

From: Charles Keepax <[email protected]>

Occasionally we can trigger an interrupt before we have completed
impedance measurement, although the valid bit will still be set. This
patch spins reading the impedance value until a valid value is seen.

Signed-off-by: Charles Keepax <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 9e4bffe..4022fe2 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -737,22 +737,30 @@ static irqreturn_t arizona_micdet(int irq, void *data)
{
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
- unsigned int val, lvl;
+ unsigned int val = 0, lvl;
int ret, i, key;

mutex_lock(&info->lock);

- ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
- mutex_unlock(&info->lock);
- return IRQ_NONE;
- }
+ for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+ mutex_unlock(&info->lock);
+ return IRQ_NONE;
+ }
+
+ dev_dbg(arizona->dev, "MICDET: %x\n", val);

- dev_dbg(arizona->dev, "MICDET: %x\n", val);
+ if (!(val & ARIZONA_MICD_VALID)) {
+ dev_warn(arizona->dev, "Microphone detection state invalid\n");
+ mutex_unlock(&info->lock);
+ return IRQ_NONE;
+ }
+ }

- if (!(val & ARIZONA_MICD_VALID)) {
- dev_warn(arizona->dev, "Microphone detection state invalid\n");
+ if (i == 10 && !(val & 0x7fc)) {
+ dev_err(arizona->dev, "Failed to get valid MICDET value\n");
mutex_unlock(&info->lock);
return IRQ_NONE;
}
--
1.7.10.4

2013-04-02 11:36:13

by Mark Brown

[permalink] [raw]
Subject: [PATCH 03/16] extcon: arizona: Allow configuration of button detection

The Arizona button detection circuit is configurable, allowing the system
integrator to program a range of thresholds for the buttons supported on
the accessory but currently the driver uses the default button ranges and
does not provide any flexibility in how this is exposed to the application
layer.

Provide platform data allowing the user to control this and to map
the buttons to keys in the input subsystem.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 164 ++++++++++++++++++++++++++++---------
include/linux/mfd/arizona/pdata.h | 9 ++
2 files changed, 134 insertions(+), 39 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 4bb0e9a..e233962 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -33,7 +33,7 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>

-#define ARIZONA_NUM_BUTTONS 6
+#define ARIZONA_MAX_MICD_RANGE 8

#define ARIZONA_ACCDET_MODE_MIC 0
#define ARIZONA_ACCDET_MODE_HPL 1
@@ -50,6 +50,9 @@ struct arizona_extcon_info {
const struct arizona_micd_config *micd_modes;
int micd_num_modes;

+ const struct arizona_micd_range *micd_ranges;
+ int num_micd_ranges;
+
bool micd_reva;
bool micd_clamp;

@@ -71,20 +74,25 @@ struct arizona_extcon_info {
};

static const struct arizona_micd_config micd_default_modes[] = {
- { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
+ { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
};

-static struct {
- u16 status;
- int report;
-} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
- { 0x1, BTN_0 },
- { 0x2, BTN_1 },
- { 0x4, BTN_2 },
- { 0x8, BTN_3 },
- { 0x10, BTN_4 },
- { 0x20, BTN_5 },
+static const struct arizona_micd_range micd_default_ranges[] = {
+ { .max = 11, .key = BTN_0 },
+ { .max = 28, .key = BTN_1 },
+ { .max = 54, .key = BTN_2 },
+ { .max = 100, .key = BTN_3 },
+ { .max = 186, .key = BTN_4 },
+ { .max = 430, .key = BTN_5 },
+};
+
+static const int arizona_micd_levels[] = {
+ 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
+ 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
+ 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
+ 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
+ 1257,
};

#define ARIZONA_CABLE_MECHANICAL 0
@@ -153,7 +161,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
{
struct arizona *arizona = info->arizona;

- mode %= info->num_micd_modes;
+ mode %= info->micd_num_modes;

if (arizona->pdata.micd_pol_gpio > 0)
gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
@@ -728,7 +736,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val, lvl;
- int ret, i;
+ int ret, i, key;

mutex_lock(&info->lock);

@@ -815,12 +823,13 @@ static irqreturn_t arizona_micdet(int irq, void *data)
lvl = val & ARIZONA_MICD_LVL_MASK;
lvl >>= ARIZONA_MICD_LVL_SHIFT;

- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
- if (lvl & arizona_lvl_to_key[i].status)
- input_report_key(info->input,
- arizona_lvl_to_key[i].report,
- 1);
- input_sync(info->input);
+ WARN_ON(!lvl);
+ WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
+ if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
+ key = info->micd_ranges[ffs(lvl) - 1].key;
+ input_report_key(info->input, key, 1);
+ input_sync(info->input);
+ }

} else if (info->detecting) {
dev_dbg(arizona->dev, "Headphone detected\n");
@@ -834,9 +843,9 @@ static irqreturn_t arizona_micdet(int irq, void *data)
}
} else {
dev_dbg(arizona->dev, "Mic button released\n");
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+ for (i = 0; i < info->num_micd_ranges; i++)
input_report_key(info->input,
- arizona_lvl_to_key[i].report, 0);
+ info->micd_ranges[i].key, 0);
input_sync(info->input);
arizona_extcon_pulse_micbias(info);
}
@@ -923,9 +932,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
info->mic = false;
info->hpdet_done = false;

- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+ for (i = 0; i < info->num_micd_ranges; i++)
input_report_key(info->input,
- arizona_lvl_to_key[i].report, 0);
+ info->micd_ranges[i].key, 0);
input_sync(info->input);

ret = extcon_update_state(&info->edev, 0xffffffff, 0);
@@ -954,13 +963,33 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
return IRQ_HANDLED;
}

+/* Map a level onto a slot in the register bank */
+static void arizona_micd_set_level(struct arizona *arizona, int index,
+ unsigned int level)
+{
+ int reg;
+ unsigned int mask;
+
+ reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
+
+ if (!(index % 2)) {
+ mask = 0x3f00;
+ level <<= 8;
+ } else {
+ mask = 0x3f;
+ }
+
+ /* Program the level itself */
+ regmap_update_bits(arizona->regmap, reg, mask, level);
+}
+
static int arizona_extcon_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata;
struct arizona_extcon_info *info;
int jack_irq_fall, jack_irq_rise;
- int ret, mode, i;
+ int ret, mode, i, j;

if (!arizona->dapm || !arizona->dapm->card)
return -EPROBE_DEFER;
@@ -1013,6 +1042,17 @@ static int arizona_extcon_probe(struct platform_device *pdev)
goto err;
}

+ info->input = devm_input_allocate_device(&pdev->dev);
+ if (!info->input) {
+ dev_err(arizona->dev, "Can't allocate input dev\n");
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ info->input->name = "Headset";
+ info->input->phys = "arizona/extcon";
+ info->input->dev.parent = &pdev->dev;
+
if (pdata->num_micd_configs) {
info->micd_modes = pdata->micd_configs;
info->micd_num_modes = pdata->num_micd_configs;
@@ -1068,6 +1108,66 @@ static int arizona_extcon_probe(struct platform_device *pdev)
arizona->pdata.micd_dbtime
<< ARIZONA_MICD_DBTIME_SHIFT);

+ BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
+
+ if (arizona->pdata.num_micd_ranges) {
+ info->micd_ranges = pdata->micd_ranges;
+ info->num_micd_ranges = pdata->num_micd_ranges;
+ } else {
+ info->micd_ranges = micd_default_ranges;
+ info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
+ }
+
+ if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
+ dev_err(arizona->dev, "Too many MICD ranges: %d\n",
+ arizona->pdata.num_micd_ranges);
+ }
+
+ if (info->num_micd_ranges > 1) {
+ for (i = 1; i < info->num_micd_ranges; i++) {
+ if (info->micd_ranges[i - 1].max >
+ info->micd_ranges[i].max) {
+ dev_err(arizona->dev,
+ "MICD ranges must be sorted\n");
+ ret = -EINVAL;
+ goto err_input;
+ }
+ }
+ }
+
+ /* Disable all buttons by default */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ ARIZONA_MICD_LVL_SEL_MASK, 0x81);
+
+ /* Set up all the buttons the user specified */
+ for (i = 0; i < info->num_micd_ranges; i++) {
+ for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
+ if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
+ break;
+
+ if (j == ARRAY_SIZE(arizona_micd_levels)) {
+ dev_err(arizona->dev, "Unsupported MICD level %d\n",
+ info->micd_ranges[i].max);
+ ret = -EINVAL;
+ goto err_input;
+ }
+
+ dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
+ arizona_micd_levels[j], i);
+
+ arizona_micd_set_level(arizona, i, j);
+ input_set_capability(info->input, EV_KEY,
+ info->micd_ranges[i].key);
+
+ /* Enable reporting of that range */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ 1 << i, 1 << i);
+ }
+
+ /* Set all the remaining keys to a maximum */
+ for (; i < ARIZONA_MAX_MICD_RANGE; i++)
+ arizona_micd_set_level(arizona, i, 0x3f);
+
/*
* If we have a clamp use it, activating in conjunction with
* GPIO5 if that is connected for jack detect operation.
@@ -1095,20 +1195,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)

arizona_extcon_set_mode(info, 0);

- info->input = devm_input_allocate_device(&pdev->dev);
- if (!info->input) {
- dev_err(arizona->dev, "Can't allocate input dev\n");
- ret = -ENOMEM;
- goto err_register;
- }
-
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
- input_set_capability(info->input, EV_KEY,
- arizona_lvl_to_key[i].report);
- info->input->name = "Headset";
- info->input->phys = "arizona/extcon";
- info->input->dev.parent = &pdev->dev;
-
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 455c51d..eb11a8a 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -86,6 +86,11 @@ struct arizona_micd_config {
bool gpio;
};

+struct arizona_micd_range {
+ int max; /** Ohms */
+ int key; /** Key to report to input layer */
+};
+
struct arizona_pdata {
int reset; /** GPIO controlling /RESET, if any */
int ldoena; /** GPIO controlling LODENA, if any */
@@ -138,6 +143,10 @@ struct arizona_pdata {
/** Force MICBIAS on for mic detect */
bool micd_force_micbias;

+ /** Mic detect level parameters */
+ const struct arizona_micd_range *micd_ranges;
+ int num_micd_ranges;
+
/** Headset polarity configurations */
struct arizona_micd_config *micd_configs;
int num_micd_configs;
--
1.7.10.4

2013-04-02 11:36:12

by Mark Brown

[permalink] [raw]
Subject: [PATCH 04/16] extcon: arizona: Don't pulse MICBIAS for HPDET identification

There is no need to do this as HPDET identification will cause MICBIAS to
be powered down again.

Signed-off-by: Mark Brown <[email protected]>
---
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 e233962..95748d3 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -693,8 +693,6 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)

info->hpdet_active = true;

- arizona_extcon_pulse_micbias(info);
-
arizona_extcon_do_magic(info, 0x4000);

ret = regmap_update_bits(arizona->regmap,
--
1.7.10.4

2013-04-02 11:36:11

by Mark Brown

[permalink] [raw]
Subject: [PATCH 06/16] extcon: arizona: Raise minimum microphone impedance for HPDET method

Ensure greater reliability by increasing the minimum threashold for
identifying a microphone.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 132bc99..2f0bd49 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -519,7 +519,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
* measure the mic as high impedance.
*/
if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
- (id_gpio && info->hpdet_res[2] > 10)) {
+ (id_gpio && info->hpdet_res[2] > 1257)) {
dev_dbg(arizona->dev, "Detected mic\n");
info->mic = true;
info->detecting = true;
--
1.7.10.4

2013-04-02 11:36:57

by Mark Brown

[permalink] [raw]
Subject: [PATCH 05/16] extcon: arizona: Allow pull to be disabled on GPIO5 when used for JACKET

In some designs an external pull won't be needed.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/extcon/extcon-arizona.c | 9 +++++++--
include/linux/mfd/arizona/pdata.h | 3 +++
2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 95748d3..132bc99 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -986,6 +986,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata;
struct arizona_extcon_info *info;
+ unsigned int val;
int jack_irq_fall, jack_irq_rise;
int ret, mode, i, j;

@@ -1172,9 +1173,13 @@ static int arizona_extcon_probe(struct platform_device *pdev)
*/
if (info->micd_clamp) {
if (arizona->pdata.jd_gpio5) {
- /* Put the GPIO into input mode */
+ /* Put the GPIO into input mode with optional pull */
+ val = 0xc101;
+ if (arizona->pdata.jd_gpio5_nopull)
+ val &= ~ARIZONA_GPN_PU;
+
regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
- 0xc101);
+ val);

regmap_update_bits(arizona->regmap,
ARIZONA_MICD_CLAMP_CONTROL,
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index eb11a8a..008b8c4 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -122,6 +122,9 @@ struct arizona_pdata {
/** GPIO5 is used for jack detection */
bool jd_gpio5;

+ /** Internal pull on GPIO5 is disabled when used for jack detection */
+ bool jd_gpio5_nopull;
+
/** Use the headphone detect circuit to identify the accessory */
bool hpdet_acc_id;

--
1.7.10.4

2013-04-02 11:33:00

by Mark Brown

[permalink] [raw]
Subject: [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration

Signed-off-by: Mark Brown <[email protected]>
---
drivers/mfd/wm5102-tables.c | 8 ++++++++
include/linux/mfd/arizona/registers.h | 4 ++++
2 files changed, 12 insertions(+)

diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index a433f58..ca2aed6 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -331,6 +331,10 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
{ 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
{ 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
+ { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */
+ { 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */
+ { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */
+ { 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */
{ 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
{ 0x000002CB, 0x0000 }, /* R715 - Isolation control */
{ 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
@@ -1090,6 +1094,10 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_DETECT_1:
case ARIZONA_MIC_DETECT_2:
case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_MIC_DETECT_LEVEL_1:
+ case ARIZONA_MIC_DETECT_LEVEL_2:
+ case ARIZONA_MIC_DETECT_LEVEL_3:
+ case ARIZONA_MIC_DETECT_LEVEL_4:
case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
case ARIZONA_ISOLATION_CONTROL:
case ARIZONA_JACK_DETECT_ANALOGUE:
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index 3403551..f43aa7c 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -124,6 +124,10 @@
#define ARIZONA_MIC_DETECT_1 0x2A3
#define ARIZONA_MIC_DETECT_2 0x2A4
#define ARIZONA_MIC_DETECT_3 0x2A5
+#define ARIZONA_MIC_DETECT_LEVEL_1 0x2A6
+#define ARIZONA_MIC_DETECT_LEVEL_2 0x2A7
+#define ARIZONA_MIC_DETECT_LEVEL_3 0x2A8
+#define ARIZONA_MIC_DETECT_LEVEL_4 0x2A9
#define ARIZONA_MIC_NOISE_MIX_CONTROL_1 0x2C3
#define ARIZONA_ISOLATION_CONTROL 0x2CB
#define ARIZONA_JACK_DETECT_ANALOGUE 0x2D3
--
1.7.10.4

2013-04-03 18:33:28

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 0/16] extcon: arizona: Updates for v3.10

On Tue, Apr 02, 2013 at 12:31:57PM +0100, Mark Brown wrote:
> The following changes since commit df8c3dbee9e6f19ddb0ae8e05cdf76eb2d3b7f00:
>
> extcon: arizona: Fix interaction between headphone outputs and identification (2013-03-26 15:45:26 +0000)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git tags/extcon-arizona-v3.10

Looks good to me, pulled and pushed out, thanks.

greg k-h