extcon: arizona: Check we report a valid impedance
[pandora-kernel.git] / drivers / extcon / extcon-arizona.c
index 95748d3..4022fe2 100644 (file)
@@ -39,6 +39,8 @@
 #define ARIZONA_ACCDET_MODE_HPL 1
 #define ARIZONA_ACCDET_MODE_HPR 2
 
+#define HPDET_DEBOUNCE 250
+
 struct arizona_extcon_info {
        struct device *dev;
        struct arizona *arizona;
@@ -46,6 +48,8 @@ struct arizona_extcon_info {
        struct regulator *micvdd;
        struct input_dev *input;
 
+       u16 last_jackdet;
+
        int micd_mode;
        const struct arizona_micd_config *micd_modes;
        int micd_num_modes;
@@ -519,7 +523,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
                 * measure the mic as high impedance.
                 */
                if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
-                   (id_gpio && info->hpdet_res[2] > 10)) {
+                   (id_gpio && info->hpdet_res[2] > 1257)) {
                        dev_dbg(arizona->dev, "Detected mic\n");
                        info->mic = true;
                        info->detecting = true;
@@ -733,22 +737,30 @@ static irqreturn_t arizona_micdet(int irq, void *data)
 {
        struct arizona_extcon_info *info = data;
        struct arizona *arizona = info->arizona;
-       unsigned int val, lvl;
+       unsigned int val = 0, lvl;
        int ret, i, key;
 
        mutex_lock(&info->lock);
 
-       ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
-               mutex_unlock(&info->lock);
-               return IRQ_NONE;
-       }
+       for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+               ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+                       mutex_unlock(&info->lock);
+                       return IRQ_NONE;
+               }
+
+               dev_dbg(arizona->dev, "MICDET: %x\n", val);
 
-       dev_dbg(arizona->dev, "MICDET: %x\n", val);
+               if (!(val & ARIZONA_MICD_VALID)) {
+                       dev_warn(arizona->dev, "Microphone detection state invalid\n");
+                       mutex_unlock(&info->lock);
+                       return IRQ_NONE;
+               }
+       }
 
-       if (!(val & ARIZONA_MICD_VALID)) {
-               dev_warn(arizona->dev, "Microphone detection state invalid\n");
+       if (i == 10 && !(val & 0x7fc)) {
+               dev_err(arizona->dev, "Failed to get valid MICDET value\n");
                mutex_unlock(&info->lock);
                return IRQ_NONE;
        }
@@ -871,11 +883,12 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
        struct arizona_extcon_info *info = data;
        struct arizona *arizona = info->arizona;
        unsigned int val, present, mask;
+       bool cancelled;
        int ret, i;
 
-       pm_runtime_get_sync(info->dev);
+       cancelled = cancel_delayed_work_sync(&info->hpdet_work);
 
-       cancel_delayed_work_sync(&info->hpdet_work);
+       pm_runtime_get_sync(info->dev);
 
        mutex_lock(&info->lock);
 
@@ -896,7 +909,18 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                return IRQ_NONE;
        }
 
-       if ((val & mask) == present) {
+       val &= mask;
+       if (val == info->last_jackdet) {
+               dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+               if (cancelled)
+                       schedule_delayed_work(&info->hpdet_work,
+                                             msecs_to_jiffies(HPDET_DEBOUNCE));
+
+               goto out;
+       }
+       info->last_jackdet = val;
+
+       if (info->last_jackdet == present) {
                dev_dbg(arizona->dev, "Detected jack\n");
                ret = extcon_set_cable_state_(&info->edev,
                                              ARIZONA_CABLE_MECHANICAL, true);
@@ -913,7 +937,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                        arizona_start_mic(info);
                } else {
                        schedule_delayed_work(&info->hpdet_work,
-                                             msecs_to_jiffies(250));
+                                             msecs_to_jiffies(HPDET_DEBOUNCE));
                }
 
                regmap_update_bits(arizona->regmap,
@@ -953,6 +977,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                     ARIZONA_JD1_FALL_TRIG_STS |
                     ARIZONA_JD1_RISE_TRIG_STS);
 
+out:
        mutex_unlock(&info->lock);
 
        pm_runtime_mark_last_busy(info->dev);
@@ -986,6 +1011,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
        struct arizona_pdata *pdata;
        struct arizona_extcon_info *info;
+       unsigned int val;
        int jack_irq_fall, jack_irq_rise;
        int ret, mode, i, j;
 
@@ -1011,6 +1037,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
        mutex_init(&info->lock);
        info->arizona = arizona;
        info->dev = &pdev->dev;
+       info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
        INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
        platform_set_drvdata(pdev, info);
 
@@ -1172,9 +1199,13 @@ static int arizona_extcon_probe(struct platform_device *pdev)
         */
        if (info->micd_clamp) {
                if (arizona->pdata.jd_gpio5) {
-                       /* Put the GPIO into input mode */
+                       /* Put the GPIO into input mode with optional pull */
+                       val = 0xc101;
+                       if (arizona->pdata.jd_gpio5_nopull)
+                               val &= ~ARIZONA_GPN_PU;
+
                        regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
-                                    0xc101);
+                                    val);
 
                        regmap_update_bits(arizona->regmap,
                                           ARIZONA_MICD_CLAMP_CONTROL,