* [PATCH 02/16] extcon: arizona: Attempt more microphone measurements
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 03/16] extcon: arizona: Allow configuration of button detection Mark Brown
` (13 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 03/16] extcon: arizona: Allow configuration of button detection
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
2013-04-02 11:32 ` [PATCH 02/16] extcon: arizona: Attempt more microphone measurements Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 04/16] extcon: arizona: Don't pulse MICBIAS for HPDET identification Mark Brown
` (12 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 04/16] extcon: arizona: Don't pulse MICBIAS for HPDET identification
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
2013-04-02 11:32 ` [PATCH 02/16] extcon: arizona: Attempt more microphone measurements Mark Brown
2013-04-02 11:32 ` [PATCH 03/16] extcon: arizona: Allow configuration of button detection Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 05/16] extcon: arizona: Allow pull to be disabled on GPIO5 when used for JACKET Mark Brown
` (11 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
There is no need to do this as HPDET identification will cause MICBIAS to
be powered down again.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 05/16] extcon: arizona: Allow pull to be disabled on GPIO5 when used for JACKET
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (2 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 04/16] extcon: arizona: Don't pulse MICBIAS for HPDET identification Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 06/16] extcon: arizona: Raise minimum microphone impedance for HPDET method Mark Brown
` (10 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
In some designs an external pull won't be needed.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 06/16] extcon: arizona: Raise minimum microphone impedance for HPDET method
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (3 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 05/16] extcon: arizona: Allow pull to be disabled on GPIO5 when used for JACKET Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 07/16] extcon: arizona: Suppress duplicate JACKDET reports Mark Brown
` (9 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
Ensure greater reliability by increasing the minimum threashold for
identifying a microphone.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 07/16] extcon: arizona: Suppress duplicate JACKDET reports
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (4 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 06/16] extcon: arizona: Raise minimum microphone impedance for HPDET method Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 08/16] extcon: arizona: Check we report a valid impedance Mark Brown
` (8 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 08/16] extcon: arizona: Check we report a valid impedance
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (5 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 07/16] extcon: arizona: Suppress duplicate JACKDET reports Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 09/16] extcon: arizona: Tune up HPDET debounce Mark Brown
` (7 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Charles Keepax, Mark Brown
From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
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 <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 09/16] extcon: arizona: Tune up HPDET debounce
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (6 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 08/16] extcon: arizona: Check we report a valid impedance Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 10/16] extcon: arizona: Retry HPDET identification for high impedance Mark Brown
` (6 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 10/16] extcon: arizona: Retry HPDET identification for high impedance
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (7 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 09/16] extcon: arizona: Tune up HPDET debounce Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 11/16] extcon: arizona: Don't ground flip when using HPDET identification Mark Brown
` (5 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 11/16] extcon: arizona: Don't ground flip when using HPDET identification
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (8 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 10/16] extcon: arizona: Retry HPDET identification for high impedance Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 12/16] extcon: arizona: Simplify HPDET based identification Mark Brown
` (4 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 12/16] extcon: arizona: Simplify HPDET based identification
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (9 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 11/16] extcon: arizona: Don't ground flip when using HPDET identification Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 13/16] extcon: arizona: Time out if MICDET fails to report Mark Brown
` (3 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 13/16] extcon: arizona: Time out if MICDET fails to report
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (10 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 12/16] extcon: arizona: Simplify HPDET based identification Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 14/16] extcon: arizona: Clear existing button reports before reporting new one Mark Brown
` (2 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 14/16] extcon: arizona: Clear existing button reports before reporting new one
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (11 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 13/16] extcon: arizona: Time out if MICDET fails to report Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 15/16] extcon: arizona: Allow additional debounce during microphone detection Mark Brown
2013-04-02 11:32 ` [PATCH 16/16] extcon: arizona: Make mic detection timeout configurable Mark Brown
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 15/16] extcon: arizona: Allow additional debounce during microphone detection
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (12 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 14/16] extcon: arizona: Clear existing button reports before reporting new one Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
2013-04-02 11:32 ` [PATCH 16/16] extcon: arizona: Make mic detection timeout configurable Mark Brown
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 16/16] extcon: arizona: Make mic detection timeout configurable
2013-04-02 11:32 ` [PATCH 01/16] mfd: wm5102: Add registers for microphone detection level configuration Mark Brown
` (13 preceding siblings ...)
2013-04-02 11:32 ` [PATCH 15/16] extcon: arizona: Allow additional debounce during microphone detection Mark Brown
@ 2013-04-02 11:32 ` Mark Brown
14 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2013-04-02 11:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, MyungJoo Ham, Chanwoo Choi
Cc: linux-kernel, patches, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread