linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels
@ 2013-11-13 18:04 Charles Keepax
  2013-11-13 18:04 ` [PATCH 2/7] extcon: arizona: Fix reset of HPDET after race with removal Charles Keepax
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

Improve readability by creating a define for each microphone detection
level.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c       |   19 ++++++++++++++-----
 include/linux/mfd/arizona/registers.h |    9 +++++++++
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 3c55ec8..8810da1 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -44,6 +44,15 @@
 #define HPDET_DEBOUNCE 500
 #define DEFAULT_MICD_TIMEOUT 2000
 
+#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
+			 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
+			 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
+			 ARIZONA_MICD_LVL_7)
+
+#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
+
+#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
+
 struct arizona_extcon_info {
 	struct device *dev;
 	struct arizona *arizona;
@@ -765,7 +774,7 @@ static void arizona_micd_detect(struct work_struct *work)
 
 	mutex_lock(&info->lock);
 
-	for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+	for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
 		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
 		if (ret != 0) {
 			dev_err(arizona->dev,
@@ -784,7 +793,7 @@ static void arizona_micd_detect(struct work_struct *work)
 		}
 	}
 
-	if (i == 10 && !(val & 0x7fc)) {
+	if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
 		dev_err(arizona->dev, "Failed to get valid MICDET value\n");
 		mutex_unlock(&info->lock);
 		return;
@@ -798,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work)
 	}
 
 	/* If we got a high impedence we should have a headset, report it. */
-	if (info->detecting && (val & 0x400)) {
+	if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
 		arizona_identify_headphone(info);
 
 		ret = extcon_update_state(&info->edev,
@@ -827,7 +836,7 @@ static void arizona_micd_detect(struct work_struct *work)
 	 * plain headphones.  If both polarities report a low
 	 * impedence then give up and report headphones.
 	 */
-	if (info->detecting && (val & 0x3f8)) {
+	if (info->detecting && (val & MICD_LVL_1_TO_7)) {
 		if (info->jack_flips >= info->micd_num_modes * 10) {
 			dev_dbg(arizona->dev, "Detected HP/line\n");
 			arizona_identify_headphone(info);
@@ -851,7 +860,7 @@ static void arizona_micd_detect(struct work_struct *work)
 	 * If we're still detecting and we detect a short then we've
 	 * got a headphone.  Otherwise it's a button press.
 	 */
-	if (val & 0x3fc) {
+	if (val & MICD_LVL_0_TO_7) {
 		if (info->mic) {
 			dev_dbg(arizona->dev, "Mic button detected\n");
 
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index 4706d3d..10d9e70 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -2196,6 +2196,15 @@
 /*
  * R677 (0x2A5) - Mic Detect 3
  */
+#define ARIZONA_MICD_LVL_0                       0x0004  /* MICD_LVL - [2] */
+#define ARIZONA_MICD_LVL_1                       0x0008  /* MICD_LVL - [3] */
+#define ARIZONA_MICD_LVL_2                       0x0010  /* MICD_LVL - [4] */
+#define ARIZONA_MICD_LVL_3                       0x0020  /* MICD_LVL - [5] */
+#define ARIZONA_MICD_LVL_4                       0x0040  /* MICD_LVL - [6] */
+#define ARIZONA_MICD_LVL_5                       0x0080  /* MICD_LVL - [7] */
+#define ARIZONA_MICD_LVL_6                       0x0100  /* MICD_LVL - [8] */
+#define ARIZONA_MICD_LVL_7                       0x0200  /* MICD_LVL - [9] */
+#define ARIZONA_MICD_LVL_8                       0x0400  /* MICD_LVL - [10] */
 #define ARIZONA_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
 #define ARIZONA_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
 #define ARIZONA_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/7] extcon: arizona: Fix reset of HPDET after race with removal
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-13 18:04 ` [PATCH 3/7] extcon: arizona: Fix race with microphone detection and removal Charles Keepax
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

We need to make sure we reset back to our starting state, especially
making sure that we have disabled poll in the register cache.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 8810da1..8e2e33e 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -603,9 +603,15 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
 		dev_err(arizona->dev, "Failed to report HP/line: %d\n",
 			ret);
 
+done:
+	/* Reset back to starting range */
+	regmap_update_bits(arizona->regmap,
+			   ARIZONA_HEADPHONE_DETECT_1,
+			   ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+			   0);
+
 	arizona_extcon_do_magic(info, 0);
 
-done:
 	if (id_gpio)
 		gpio_set_value_cansleep(id_gpio, 0);
 
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/7] extcon: arizona: Fix race with microphone detection and removal
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
  2013-11-13 18:04 ` [PATCH 2/7] extcon: arizona: Fix reset of HPDET after race with removal Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-13 18:04 ` [PATCH 4/7] extcon: arizona: No need to switch back down HPDET ranges Charles Keepax
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

The microphone detection code is run as delayed work to provide
additional debounce, it is possible that the jack could have been
removed by the time we process the microphone detection. Turn this
case into a no op.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 8e2e33e..1bae23e 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -780,6 +780,19 @@ static void arizona_micd_detect(struct work_struct *work)
 
 	mutex_lock(&info->lock);
 
+	/* If the cable was removed while measuring ignore the result */
+	ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
+	if (ret < 0) {
+		dev_err(arizona->dev, "Failed to check cable state: %d\n",
+				ret);
+		mutex_unlock(&info->lock);
+		return;
+	} else if (!ret) {
+		dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
+		mutex_unlock(&info->lock);
+		return;
+	}
+
 	for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
 		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
 		if (ret != 0) {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/7] extcon: arizona: No need to switch back down HPDET ranges
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
  2013-11-13 18:04 ` [PATCH 2/7] extcon: arizona: Fix reset of HPDET after race with removal Charles Keepax
  2013-11-13 18:04 ` [PATCH 3/7] extcon: arizona: Fix race with microphone detection and removal Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-13 18:04 ` [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D Charles Keepax
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

No point in revisiting ranges the detection will be no more accurate
the second time simply report that the resistance is right on the
range boundry.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |   21 +++++++--------------
 1 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 1bae23e..e311c52 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -441,20 +441,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
 		range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
 			   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
 
-		/* Skip up or down a range? */
-		if (range && (val < arizona_hpdet_c_ranges[range].min)) {
-			range--;
-			dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
-				arizona_hpdet_c_ranges[range].min,
-				arizona_hpdet_c_ranges[range].max);
-			regmap_update_bits(arizona->regmap,
-					   ARIZONA_HEADPHONE_DETECT_1,
-					   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-					   range <<
-					   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-			return -EAGAIN;
-		}
-
+		/* Skip up a range, or report? */
 		if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
 		    (val >= arizona_hpdet_c_ranges[range].max)) {
 			range++;
@@ -468,6 +455,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
 					   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
 			return -EAGAIN;
 		}
+
+		if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+			dev_dbg(arizona->dev, "Reporting range boundary %d\n",
+				arizona_hpdet_c_ranges[range].min);
+			val = arizona_hpdet_c_ranges[range].min;
+		}
 	}
 
 	dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
                   ` (2 preceding siblings ...)
  2013-11-13 18:04 ` [PATCH 4/7] extcon: arizona: No need to switch back down HPDET ranges Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-14 12:29   ` Chanwoo Choi
  2013-11-13 18:04 ` [PATCH 6/7] extcon: arizona: Factor out different headphone detection IPs Charles Keepax
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

wm5110 rev D is the first chip to use headphone detection IP 2, specify
such and make a small correction as the impedance value is actually read
in 0.5 ohm increments now.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e311c52..d08e342 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -435,6 +435,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
 		}
 
 		val &= ARIZONA_HP_LVL_B_MASK;
+		val /= 2;
 
 		regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
 			    &range);
@@ -1149,6 +1150,16 @@ static int arizona_extcon_probe(struct platform_device *pdev)
 			break;
 		}
 		break;
+	case WM5110:
+		switch (arizona->rev) {
+		case 0 ... 2:
+			break;
+		default:
+			info->micd_clamp = true;
+			info->hpdet_ip = 2;
+			break;
+		}
+		break;
 	default:
 		break;
 	}
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/7] extcon: arizona: Factor out different headphone detection IPs
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
                   ` (3 preceding siblings ...)
  2013-11-13 18:04 ` [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-13 18:04 ` [PATCH 7/7] extcon: arizona: Improve headphone detection error handling Charles Keepax
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

This patch factors out each headphone detection IP in a seperate
function this makes the code a little more readable and prevents us
getting to excessive levels of indentation.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |  213 +++++++++++++++++++++++---------------
 1 files changed, 129 insertions(+), 84 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index d08e342..4441be4 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -354,7 +354,31 @@ static struct {
 	{ 1000, 10000 },
 };
 
-static int arizona_hpdet_read(struct arizona_extcon_info *info)
+static int arizona_hpdet_read_ip0(struct arizona_extcon_info *info)
+{
+	struct arizona *arizona = info->arizona;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
+			ret);
+		return ret;
+	}
+
+
+	if (!(val & ARIZONA_HP_DONE)) {
+		dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+		return -EAGAIN;
+	}
+
+	val &= ARIZONA_HP_LVL_MASK;
+
+	return val;
+}
+
+static int arizona_hpdet_read_ip1(struct arizona_extcon_info *info)
 {
 	struct arizona *arizona = info->arizona;
 	unsigned int val, range;
@@ -367,105 +391,126 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
 		return ret;
 	}
 
-	switch (info->hpdet_ip) {
-	case 0:
-		if (!(val & ARIZONA_HP_DONE)) {
-			dev_err(arizona->dev, "HPDET did not complete: %x\n",
-				val);
-			return -EAGAIN;
-		}
+	if (!(val & ARIZONA_HP_DONE_B)) {
+		dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+		return -EAGAIN;
+	}
 
-		val &= ARIZONA_HP_LVL_MASK;
-		break;
+	ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read HP value: %d\n", ret);
+		return -EAGAIN;
+	}
 
-	case 1:
-		if (!(val & ARIZONA_HP_DONE_B)) {
-			dev_err(arizona->dev, "HPDET did not complete: %x\n",
-				val);
-			return -EAGAIN;
-		}
+	regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
+	range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+		   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
 
-		ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
-		if (ret != 0) {
-			dev_err(arizona->dev, "Failed to read HP value: %d\n",
-				ret);
-			return -EAGAIN;
-		}
+	if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
+	    (val < 100 || val >= 0x3fb)) {
+		range++;
+		dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range);
+		regmap_update_bits(arizona->regmap,
+				   ARIZONA_HEADPHONE_DETECT_1,
+				   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+				   range <<
+				   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+		return -EAGAIN;
+	}
 
-		regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-			    &range);
-		range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
-			   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+	/* 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 ARIZONA_HPDET_MAX;
+	}
 
-		if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
-		    (val < 100 || val >= 0x3fb)) {
-			range++;
-			dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
-				range);
-			regmap_update_bits(arizona->regmap,
-					   ARIZONA_HEADPHONE_DETECT_1,
-					   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-					   range <<
-					   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-			return -EAGAIN;
-		}
+	dev_dbg(arizona->dev, "HPDET read %d in range %d\n", val, range);
 
-		/* 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 ARIZONA_HPDET_MAX;
-		}
+	val = arizona_hpdet_b_ranges[range].factor_b
+		/ ((val * 100) - arizona_hpdet_b_ranges[range].factor_a);
+
+	return val;
+}
+
+static int arizona_hpdet_read_ip2(struct arizona_extcon_info *info)
+{
+	struct arizona *arizona = info->arizona;
+	unsigned int val, range;
+	int ret;
 
-		dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
-			val, range);
+	ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
+			ret);
+		return ret;
+	}
 
-		val = arizona_hpdet_b_ranges[range].factor_b
-			/ ((val * 100) -
-			   arizona_hpdet_b_ranges[range].factor_a);
+	if (!(val & ARIZONA_HP_DONE_B)) {
+		dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+		return -EAGAIN;
+	}
+
+	val &= ARIZONA_HP_LVL_B_MASK;
+	val /= 2;
+
+	regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
+	range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+		   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+	/* Skip up a range, or report? */
+	if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
+	    (val >= arizona_hpdet_c_ranges[range].max)) {
+		range++;
+		dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
+			arizona_hpdet_c_ranges[range].min,
+			arizona_hpdet_c_ranges[range].max);
+		regmap_update_bits(arizona->regmap,
+				   ARIZONA_HEADPHONE_DETECT_1,
+				   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+				   range <<
+				   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+		return -EAGAIN;
+	}
+
+	if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+		dev_dbg(arizona->dev, "Reporting range boundary %d\n",
+			arizona_hpdet_c_ranges[range].min);
+		val = arizona_hpdet_c_ranges[range].min;
+	}
+
+	return val;
+}
+
+static int arizona_hpdet_read(struct arizona_extcon_info *info)
+{
+	struct arizona *arizona = info->arizona;
+	int ret = 0;
+
+	switch (info->hpdet_ip) {
+	case 0:
+		ret = arizona_hpdet_read_ip0(info);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case 1:
+		ret = arizona_hpdet_read_ip1(info);
+		if (ret < 0)
+			return ret;
 		break;
 
 	default:
 		dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
 			 info->hpdet_ip);
 	case 2:
-		if (!(val & ARIZONA_HP_DONE_B)) {
-			dev_err(arizona->dev, "HPDET did not complete: %x\n",
-				val);
-			return -EAGAIN;
-		}
-
-		val &= ARIZONA_HP_LVL_B_MASK;
-		val /= 2;
-
-		regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-			    &range);
-		range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
-			   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
-
-		/* Skip up a range, or report? */
-		if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
-		    (val >= arizona_hpdet_c_ranges[range].max)) {
-			range++;
-			dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
-				arizona_hpdet_c_ranges[range].min,
-				arizona_hpdet_c_ranges[range].max);
-			regmap_update_bits(arizona->regmap,
-					   ARIZONA_HEADPHONE_DETECT_1,
-					   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-					   range <<
-					   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-			return -EAGAIN;
-		}
-
-		if (range && (val < arizona_hpdet_c_ranges[range].min)) {
-			dev_dbg(arizona->dev, "Reporting range boundary %d\n",
-				arizona_hpdet_c_ranges[range].min);
-			val = arizona_hpdet_c_ranges[range].min;
-		}
+		ret = arizona_hpdet_read_ip2(info);
+		if (ret < 0)
+			return ret;
+		break;
 	}
 
-	dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
-	return val;
+	dev_dbg(arizona->dev, "HP impedance %d ohms\n", ret);
+	return ret;
 }
 
 static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/7] extcon: arizona: Improve headphone detection error handling
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
                   ` (4 preceding siblings ...)
  2013-11-13 18:04 ` [PATCH 6/7] extcon: arizona: Factor out different headphone detection IPs Charles Keepax
@ 2013-11-13 18:04 ` Charles Keepax
  2013-11-14  9:32 ` [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Lee Jones
  2013-11-14 12:38 ` Chanwoo Choi
  7 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-13 18:04 UTC (permalink / raw)
  To: cw00.choi
  Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel, Charles Keepax

In several places the return value of regmap operations is not checked
whilst handling headphone detection. This patch adds checks for these
return values. Additionally, failing to read/write a register is a
serious enough error we should abort the headphone detection process so
correct a couple of cases where this was not the case.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/extcon/extcon-arizona.c |   82 ++++++++++++++++++++++++++++----------
 1 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 4441be4..ea3a22c 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -399,22 +399,32 @@ static int arizona_hpdet_read_ip1(struct arizona_extcon_info *info)
 	ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
 	if (ret != 0) {
 		dev_err(arizona->dev, "Failed to read HP value: %d\n", ret);
-		return -EAGAIN;
+		return ret;
 	}
 
-	regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
+	ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
 	range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
 		   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read HP range: %d\n", ret);
+		return ret;
+	}
 
 	if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
 	    (val < 100 || val >= 0x3fb)) {
 		range++;
 		dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range);
-		regmap_update_bits(arizona->regmap,
-				   ARIZONA_HEADPHONE_DETECT_1,
-				   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-				   range <<
-				   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+		ret = regmap_update_bits(arizona->regmap,
+					 ARIZONA_HEADPHONE_DETECT_1,
+					 ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+					 range <<
+					 ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+		if (ret != 0) {
+			dev_err(arizona->dev,
+				"Failed to move range (%d): %d\n",
+				range, ret);
+			return ret;
+		}
 		return -EAGAIN;
 	}
 
@@ -453,7 +463,11 @@ static int arizona_hpdet_read_ip2(struct arizona_extcon_info *info)
 	val &= ARIZONA_HP_LVL_B_MASK;
 	val /= 2;
 
-	regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
+	ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read HP range: %d\n", ret);
+		return ret;
+	}
 	range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
 		   >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
 
@@ -464,11 +478,17 @@ static int arizona_hpdet_read_ip2(struct arizona_extcon_info *info)
 		dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
 			arizona_hpdet_c_ranges[range].min,
 			arizona_hpdet_c_ranges[range].max);
-		regmap_update_bits(arizona->regmap,
+		ret = regmap_update_bits(arizona->regmap,
 				   ARIZONA_HEADPHONE_DETECT_1,
 				   ARIZONA_HP_IMPEDANCE_RANGE_MASK,
 				   range <<
 				   ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+		if (ret != 0) {
+			dev_err(arizona->dev,
+				"Failed to move range (%d): %d\n",
+				range, ret);
+			return ret;
+		}
 		return -EAGAIN;
 	}
 
@@ -518,6 +538,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
 {
 	struct arizona *arizona = info->arizona;
 	int id_gpio = arizona->pdata.hpdet_id_gpio;
+	int ret;
 
 	/*
 	 * If we're using HPDET for accessory identification we need
@@ -530,18 +551,30 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
 		if (id_gpio && info->num_hpdet_res == 1) {
 			dev_dbg(arizona->dev, "Measuring mic\n");
 
-			regmap_update_bits(arizona->regmap,
-					   ARIZONA_ACCESSORY_DETECT_MODE_1,
-					   ARIZONA_ACCDET_MODE_MASK |
-					   ARIZONA_ACCDET_SRC,
-					   ARIZONA_ACCDET_MODE_HPR |
-					   info->micd_modes[0].src);
+			ret = regmap_update_bits(arizona->regmap,
+					ARIZONA_ACCESSORY_DETECT_MODE_1,
+					ARIZONA_ACCDET_MODE_MASK |
+					ARIZONA_ACCDET_SRC,
+					ARIZONA_ACCDET_MODE_HPR |
+					info->micd_modes[0].src);
+			if (ret != 0) {
+				dev_err(arizona->dev,
+					"Failed to change HPDET source: %d\n",
+					ret);
+				return ret;
+			}
 
 			gpio_set_value_cansleep(id_gpio, 1);
 
-			regmap_update_bits(arizona->regmap,
-					   ARIZONA_HEADPHONE_DETECT_1,
-					   ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+			ret = regmap_update_bits(arizona->regmap,
+					ARIZONA_HEADPHONE_DETECT_1,
+					ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+			if (ret != 0) {
+				dev_err(arizona->dev,
+					"Failed to re-enable HPDET: %d\n",
+					ret);
+				return ret;
+			}
 			return -EAGAIN;
 		}
 
@@ -574,10 +607,15 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
 		}
 
 		/* Make sure everything is reset back to the real polarity */
-		regmap_update_bits(arizona->regmap,
-				   ARIZONA_ACCESSORY_DETECT_MODE_1,
-				   ARIZONA_ACCDET_SRC,
-				   info->micd_modes[0].src);
+		ret = regmap_update_bits(arizona->regmap,
+					 ARIZONA_ACCESSORY_DETECT_MODE_1,
+					 ARIZONA_ACCDET_SRC,
+					 info->micd_modes[0].src);
+		if (ret != 0) {
+			dev_err(arizona->dev, "Failed to reset polarity: %d\n",
+				ret);
+			return ret;
+		}
 	}
 
 	return 0;
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
                   ` (5 preceding siblings ...)
  2013-11-13 18:04 ` [PATCH 7/7] extcon: arizona: Improve headphone detection error handling Charles Keepax
@ 2013-11-14  9:32 ` Lee Jones
  2013-11-14 12:38 ` Chanwoo Choi
  7 siblings, 0 replies; 11+ messages in thread
From: Lee Jones @ 2013-11-14  9:32 UTC (permalink / raw)
  To: Charles Keepax; +Cc: cw00.choi, myungjoo.ham, sameo, patches, linux-kernel

On Wed, 13 Nov 2013, Charles Keepax wrote:

> Improve readability by creating a define for each microphone detection
> level.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  drivers/extcon/extcon-arizona.c       |   19 ++++++++++++++-----
>  include/linux/mfd/arizona/registers.h |    9 +++++++++
>  2 files changed, 23 insertions(+), 5 deletions(-)

For the MFD changes:
  Acked-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D
  2013-11-13 18:04 ` [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D Charles Keepax
@ 2013-11-14 12:29   ` Chanwoo Choi
  0 siblings, 0 replies; 11+ messages in thread
From: Chanwoo Choi @ 2013-11-14 12:29 UTC (permalink / raw)
  To: Charles Keepax; +Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel

Hi Charles,

On 11/14/2013 03:04 AM, Charles Keepax wrote:
> wm5110 rev D is the first chip to use headphone detection IP 2, specify
> such and make a small correction as the impedance value is actually read
> in 0.5 ohm increments now.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  drivers/extcon/extcon-arizona.c |   11 +++++++++++
>  1 files changed, 11 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
> index e311c52..d08e342 100644
> --- a/drivers/extcon/extcon-arizona.c
> +++ b/drivers/extcon/extcon-arizona.c
> @@ -435,6 +435,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
>  		}
>  
>  		val &= ARIZONA_HP_LVL_B_MASK;
> +		val /= 2;

What is meaning of 2?

>  
>  		regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
>  			    &range);
> @@ -1149,6 +1150,16 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>  			break;
>  		}
>  		break;
> +	case WM5110:
> +		switch (arizona->rev) {
> +		case 0 ... 2:
> +			break;
> +		default:
> +			info->micd_clamp = true;
> +			info->hpdet_ip = 2;
> +			break;
> +		}
> +		break;
>  	default:
>  		break;
>  	}
> 



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels
  2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
                   ` (6 preceding siblings ...)
  2013-11-14  9:32 ` [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Lee Jones
@ 2013-11-14 12:38 ` Chanwoo Choi
  2013-11-14 14:23   ` Charles Keepax
  7 siblings, 1 reply; 11+ messages in thread
From: Chanwoo Choi @ 2013-11-14 12:38 UTC (permalink / raw)
  To: Charles Keepax; +Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel

Hi Charles,

I tried to apply this patch[1-4]. But happen fail of 'git am'.
Did you develop this patchset based on extcon-next tree?

Also, you should add version information of patch subject as following:
- [PATCHv2 1/7] extcon: arizona: Add defines for microphone detection levels

Thanks,
Chanwoo Choi

On 11/14/2013 03:04 AM, Charles Keepax wrote:
> Improve readability by creating a define for each microphone detection
> level.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  drivers/extcon/extcon-arizona.c       |   19 ++++++++++++++-----
>  include/linux/mfd/arizona/registers.h |    9 +++++++++
>  2 files changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
> index 3c55ec8..8810da1 100644
> --- a/drivers/extcon/extcon-arizona.c
> +++ b/drivers/extcon/extcon-arizona.c
> @@ -44,6 +44,15 @@
>  #define HPDET_DEBOUNCE 500
>  #define DEFAULT_MICD_TIMEOUT 2000
>  
> +#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
> +			 ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
> +			 ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
> +			 ARIZONA_MICD_LVL_7)
> +
> +#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
> +
> +#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
> +
>  struct arizona_extcon_info {
>  	struct device *dev;
>  	struct arizona *arizona;
> @@ -765,7 +774,7 @@ static void arizona_micd_detect(struct work_struct *work)
>  
>  	mutex_lock(&info->lock);
>  
> -	for (i = 0; i < 10 && !(val & 0x7fc); i++) {
> +	for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
>  		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
>  		if (ret != 0) {
>  			dev_err(arizona->dev,
> @@ -784,7 +793,7 @@ static void arizona_micd_detect(struct work_struct *work)
>  		}
>  	}
>  
> -	if (i == 10 && !(val & 0x7fc)) {
> +	if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
>  		dev_err(arizona->dev, "Failed to get valid MICDET value\n");
>  		mutex_unlock(&info->lock);
>  		return;
> @@ -798,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work)
>  	}
>  
>  	/* If we got a high impedence we should have a headset, report it. */
> -	if (info->detecting && (val & 0x400)) {
> +	if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
>  		arizona_identify_headphone(info);
>  
>  		ret = extcon_update_state(&info->edev,
> @@ -827,7 +836,7 @@ static void arizona_micd_detect(struct work_struct *work)
>  	 * plain headphones.  If both polarities report a low
>  	 * impedence then give up and report headphones.
>  	 */
> -	if (info->detecting && (val & 0x3f8)) {
> +	if (info->detecting && (val & MICD_LVL_1_TO_7)) {
>  		if (info->jack_flips >= info->micd_num_modes * 10) {
>  			dev_dbg(arizona->dev, "Detected HP/line\n");
>  			arizona_identify_headphone(info);
> @@ -851,7 +860,7 @@ static void arizona_micd_detect(struct work_struct *work)
>  	 * If we're still detecting and we detect a short then we've
>  	 * got a headphone.  Otherwise it's a button press.
>  	 */
> -	if (val & 0x3fc) {
> +	if (val & MICD_LVL_0_TO_7) {
>  		if (info->mic) {
>  			dev_dbg(arizona->dev, "Mic button detected\n");
>  
> diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
> index 4706d3d..10d9e70 100644
> --- a/include/linux/mfd/arizona/registers.h
> +++ b/include/linux/mfd/arizona/registers.h
> @@ -2196,6 +2196,15 @@
>  /*
>   * R677 (0x2A5) - Mic Detect 3
>   */
> +#define ARIZONA_MICD_LVL_0                       0x0004  /* MICD_LVL - [2] */
> +#define ARIZONA_MICD_LVL_1                       0x0008  /* MICD_LVL - [3] */
> +#define ARIZONA_MICD_LVL_2                       0x0010  /* MICD_LVL - [4] */
> +#define ARIZONA_MICD_LVL_3                       0x0020  /* MICD_LVL - [5] */
> +#define ARIZONA_MICD_LVL_4                       0x0040  /* MICD_LVL - [6] */
> +#define ARIZONA_MICD_LVL_5                       0x0080  /* MICD_LVL - [7] */
> +#define ARIZONA_MICD_LVL_6                       0x0100  /* MICD_LVL - [8] */
> +#define ARIZONA_MICD_LVL_7                       0x0200  /* MICD_LVL - [9] */
> +#define ARIZONA_MICD_LVL_8                       0x0400  /* MICD_LVL - [10] */
>  #define ARIZONA_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
>  #define ARIZONA_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
>  #define ARIZONA_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels
  2013-11-14 12:38 ` Chanwoo Choi
@ 2013-11-14 14:23   ` Charles Keepax
  0 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2013-11-14 14:23 UTC (permalink / raw)
  To: Chanwoo Choi; +Cc: myungjoo.ham, sameo, lee.jones, patches, linux-kernel

On Thu, Nov 14, 2013 at 09:38:30PM +0900, Chanwoo Choi wrote:
> Hi Charles,
> 
> I tried to apply this patch[1-4]. But happen fail of 'git am'.
> Did you develop this patchset based on extcon-next tree?
> 
> Also, you should add version information of patch subject as following:
> - [PATCHv2 1/7] extcon: arizona: Add defines for microphone detection levels
> 
> Thanks,
> Chanwoo Choi

Sorry probably my fault I will resend, adding a comment for the
/2.

Thanks,
Charles

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-11-14 14:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-13 18:04 [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Charles Keepax
2013-11-13 18:04 ` [PATCH 2/7] extcon: arizona: Fix reset of HPDET after race with removal Charles Keepax
2013-11-13 18:04 ` [PATCH 3/7] extcon: arizona: Fix race with microphone detection and removal Charles Keepax
2013-11-13 18:04 ` [PATCH 4/7] extcon: arizona: No need to switch back down HPDET ranges Charles Keepax
2013-11-13 18:04 ` [PATCH 5/7] extcon: arizona: Add support for headphone detection on wm5110 rev D Charles Keepax
2013-11-14 12:29   ` Chanwoo Choi
2013-11-13 18:04 ` [PATCH 6/7] extcon: arizona: Factor out different headphone detection IPs Charles Keepax
2013-11-13 18:04 ` [PATCH 7/7] extcon: arizona: Improve headphone detection error handling Charles Keepax
2013-11-14  9:32 ` [PATCH 1/7] extcon: arizona: Add defines for microphone detection levels Lee Jones
2013-11-14 12:38 ` Chanwoo Choi
2013-11-14 14:23   ` Charles Keepax

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).