diff options
| author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-10 18:55:54 -0500 |
|---|---|---|
| committer | Chanwoo Choi <cw00.choi@samsung.com> | 2013-01-15 01:42:18 -0500 |
| commit | 1eda6aa7ce101b59dfd91abef2c8b0e51e96e199 (patch) | |
| tree | 9dd5a408d0e5d2df0b8ff1c397cbc92cc86a2539 /drivers/extcon | |
| parent | dd235eea4ed75b1599dd9a53bb618fe5befeb731 (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')
| -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, |
