aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon-arizona.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-10 18:55:54 -0500
committerChanwoo Choi <cw00.choi@samsung.com>2013-01-15 01:42:18 -0500
commit1eda6aa7ce101b59dfd91abef2c8b0e51e96e199 (patch)
tree9dd5a408d0e5d2df0b8ff1c397cbc92cc86a2539 /drivers/extcon/extcon-arizona.c
parentdd235eea4ed75b1599dd9a53bb618fe5befeb731 (diff)
extcon: arizona: Support direct microphone measurement via HPDET
With some GPIO control it is possible to detect microphones in a wider range of configurations by directly measuring the microphone impedance when the HPDET method cannot distinguish between the behaviour of the two grounds. Allow a GPIO to be provided in platform data and use it to implement this behaviour. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r--drivers/extcon/extcon-arizona.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index ba9525ee4706..de141f72c8e5 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -56,7 +56,7 @@ struct arizona_extcon_info {
56 bool hpdet_active; 56 bool hpdet_active;
57 57
58 int num_hpdet_res; 58 int num_hpdet_res;
59 unsigned int hpdet_res[2]; 59 unsigned int hpdet_res[3];
60 60
61 bool mic; 61 bool mic;
62 bool detecting; 62 bool detecting;
@@ -313,6 +313,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
313static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) 313static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
314{ 314{
315 struct arizona *arizona = info->arizona; 315 struct arizona *arizona = info->arizona;
316 int id_gpio = arizona->pdata.hpdet_id_gpio;
316 int ret; 317 int ret;
317 318
318 /* 319 /*
@@ -338,9 +339,27 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
338 ARIZONA_ACCESSORY_DETECT_MODE_1, 339 ARIZONA_ACCESSORY_DETECT_MODE_1,
339 ARIZONA_ACCDET_SRC, 340 ARIZONA_ACCDET_SRC,
340 ~info->micd_modes[0].src); 341 ~info->micd_modes[0].src);
342
341 regmap_update_bits(arizona->regmap, 343 regmap_update_bits(arizona->regmap,
342 ARIZONA_HEADPHONE_DETECT_1, 344 ARIZONA_HEADPHONE_DETECT_1,
343 ARIZONA_HP_POLL, 0); 345 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
346 return -EAGAIN;
347 }
348
349 /* Only check the mic directly if we didn't already ID it */
350 if (id_gpio && info->num_hpdet_res == 2 &&
351 !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
352 dev_dbg(arizona->dev, "Measuring mic\n");
353
354 regmap_update_bits(arizona->regmap,
355 ARIZONA_ACCESSORY_DETECT_MODE_1,
356 ARIZONA_ACCDET_MODE_MASK |
357 ARIZONA_ACCDET_SRC,
358 ARIZONA_ACCDET_MODE_HPR |
359 info->micd_modes[0].src);
360
361 gpio_set_value_cansleep(id_gpio, 1);
362
344 regmap_update_bits(arizona->regmap, 363 regmap_update_bits(arizona->regmap,
345 ARIZONA_HEADPHONE_DETECT_1, 364 ARIZONA_HEADPHONE_DETECT_1,
346 ARIZONA_HP_POLL, ARIZONA_HP_POLL); 365 ARIZONA_HP_POLL, ARIZONA_HP_POLL);
@@ -348,10 +367,16 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
348 } 367 }
349 368
350 /* OK, got both. Now, compare... */ 369 /* OK, got both. Now, compare... */
351 dev_dbg(arizona->dev, "HPDET measured %d %d\n", 370 dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
352 info->hpdet_res[0], info->hpdet_res[1]); 371 info->hpdet_res[0], info->hpdet_res[1],
372 info->hpdet_res[2]);
353 373
354 if (info->hpdet_res[0] > info->hpdet_res[1] * 2) { 374 /*
375 * Either the two grounds measure differently or we
376 * measure the mic as high impedance.
377 */
378 if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
379 (id_gpio && info->hpdet_res[2] > 10)) {
355 dev_dbg(arizona->dev, "Detected mic\n"); 380 dev_dbg(arizona->dev, "Detected mic\n");
356 info->mic = true; 381 info->mic = true;
357 ret = extcon_set_cable_state_(&info->edev, 382 ret = extcon_set_cable_state_(&info->edev,
@@ -382,6 +407,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
382{ 407{
383 struct arizona_extcon_info *info = data; 408 struct arizona_extcon_info *info = data;
384 struct arizona *arizona = info->arizona; 409 struct arizona *arizona = info->arizona;
410 int id_gpio = arizona->pdata.hpdet_id_gpio;
385 int report = ARIZONA_CABLE_HEADPHONE; 411 int report = ARIZONA_CABLE_HEADPHONE;
386 int ret, reading; 412 int ret, reading;
387 413
@@ -446,6 +472,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
446 dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret); 472 dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);
447 473
448done: 474done:
475 if (id_gpio)
476 gpio_set_value_cansleep(id_gpio, 0);
449 477
450 /* Revert back to MICDET mode */ 478 /* Revert back to MICDET mode */
451 regmap_update_bits(arizona->regmap, 479 regmap_update_bits(arizona->regmap,
@@ -854,6 +882,18 @@ static int arizona_extcon_probe(struct platform_device *pdev)
854 } 882 }
855 } 883 }
856 884
885 if (arizona->pdata.hpdet_id_gpio > 0) {
886 ret = devm_gpio_request_one(&pdev->dev,
887 arizona->pdata.hpdet_id_gpio,
888 GPIOF_OUT_INIT_LOW,
889 "HPDET");
890 if (ret != 0) {
891 dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
892 arizona->pdata.hpdet_id_gpio, ret);
893 goto err_register;
894 }
895 }
896
857 if (arizona->pdata.micd_bias_start_time) 897 if (arizona->pdata.micd_bias_start_time)
858 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, 898 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
859 ARIZONA_MICD_BIAS_STARTTIME_MASK, 899 ARIZONA_MICD_BIAS_STARTTIME_MASK,