Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 354961
b: refs/heads/master
c: dd235ee
h: refs/heads/master
i:
  354959: a3ed94f
v: v3
  • Loading branch information
Mark Brown authored and Chanwoo Choi committed Jan 15, 2013
1 parent 0eb512f commit f78746b
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9b1270c71fb5f4783c72cae7e458b2cf8c657f84
refs/heads/master: dd235eea4ed75b1599dd9a53bb618fe5befeb731
159 changes: 147 additions & 12 deletions trunk/drivers/extcon/extcon-arizona.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ struct arizona_extcon_info {

bool hpdet_active;

int num_hpdet_res;
unsigned int hpdet_res[2];

bool mic;
bool detecting;
int jack_flips;
Expand All @@ -65,8 +68,8 @@ struct arizona_extcon_info {
};

static const struct arizona_micd_config micd_default_modes[] = {
{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
{ 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
};

static struct {
Expand Down Expand Up @@ -118,10 +121,6 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
bool change;
int ret;

info->detecting = true;
info->mic = false;
info->jack_flips = 0;

/* Microphone detection can't use idle mode */
pm_runtime_get(info->dev);

Expand Down Expand Up @@ -311,12 +310,80 @@ 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)
{
struct arizona *arizona = info->arizona;
int ret;

/*
* If we're using HPDET for accessory identification we need
* to take multiple measurements, step through them in sequence.
*/
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, 0);
regmap_update_bits(arizona->regmap,
ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_POLL, ARIZONA_HP_POLL);
return -EAGAIN;
}

/* OK, got both. Now, compare... */
dev_dbg(arizona->dev, "HPDET measured %d %d\n",
info->hpdet_res[0], info->hpdet_res[1]);

if (info->hpdet_res[0] > info->hpdet_res[1] * 2) {
dev_dbg(arizona->dev, "Detected mic\n");
info->mic = true;
ret = extcon_set_cable_state_(&info->edev,
ARIZONA_CABLE_MICROPHONE,
true);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to report mic: %d\n", ret);
}

/* Take the headphone impedance for the main report */
*reading = info->hpdet_res[1];
} else {
dev_dbg(arizona->dev, "Detected headphone\n");
}

/* 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);
}

return 0;
}

static irqreturn_t arizona_hpdet_irq(int irq, void *data)
{
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
int report = ARIZONA_CABLE_HEADPHONE;
int ret;
int ret, reading;

mutex_lock(&info->lock);

Expand Down Expand Up @@ -344,14 +411,23 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
} else if (ret < 0) {
goto done;
}
reading = ret;

/* Reset back to starting range */
regmap_update_bits(arizona->regmap,
ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_IMPEDANCE_RANGE_MASK, 0);
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
0);

ret = arizona_hpdet_do_id(info, &reading);
if (ret == -EAGAIN) {
goto out;
} else if (ret < 0) {
goto done;
}

/* Report high impedence cables as line outputs */
if (ret >= 5000)
if (reading >= 5000)
report = ARIZONA_CABLE_LINEOUT;
else
report = ARIZONA_CABLE_HEADPHONE;
Expand All @@ -370,8 +446,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
dev_warn(arizona->dev, "Failed to undo magic: %d\n", ret);

done:
regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_POLL, 0);

/* Revert back to MICDET mode */
regmap_update_bits(arizona->regmap,
Expand Down Expand Up @@ -451,8 +525,58 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)

info->hpdet_active = false;
}

static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
int ret;

dev_dbg(arizona->dev, "Starting identification via HPDET\n");

/* Make sure we keep the device enabled during the measurement */
pm_runtime_get(info->dev);

info->hpdet_active = true;

ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
if (ret != 0)
dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);

ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
if (ret != 0)
dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);

ret = regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
info->micd_modes[0].src |
ARIZONA_ACCDET_MODE_HPL);
if (ret != 0) {
dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
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;
}

return;

err:
regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);

/* Just report headphone */
ret = extcon_update_state(&info->edev,
1 << ARIZONA_CABLE_HEADPHONE,
1 << ARIZONA_CABLE_HEADPHONE);
if (ret != 0)
dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);

info->hpdet_active = false;
}

Expand Down Expand Up @@ -612,12 +736,24 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
dev_err(arizona->dev, "Mechanical report failed: %d\n",
ret);

arizona_start_mic(info);
if (!arizona->pdata.hpdet_acc_id) {
info->detecting = true;
info->mic = false;
info->jack_flips = 0;

arizona_start_mic(info);
} else {
arizona_start_hpdet_acc_id(info);
}
} else {
dev_dbg(arizona->dev, "Detected jack removal\n");

arizona_stop_mic(info);

info->num_hpdet_res = 0;
for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
info->hpdet_res[i] = 0;
info->mic = false;

for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
input_report_key(info->input,
Expand Down Expand Up @@ -665,7 +801,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
mutex_init(&info->lock);
info->arizona = arizona;
info->dev = &pdev->dev;
info->detecting = true;
platform_set_drvdata(pdev, info);

switch (arizona->type) {
Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/mfd/arizona/pdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ struct arizona_pdata {
/** GPIO5 is used for jack detection */
bool jd_gpio5;

/** Use the headphone detect circuit to identify the accessory */
bool hpdet_acc_id;

/** GPIO for mic detection polarity */
int micd_pol_gpio;

Expand Down

0 comments on commit f78746b

Please sign in to comment.