diff options
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 50 |
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) | |||
313 | static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | 313 | static 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 | ||
448 | done: | 474 | done: |
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, |