Merge tag 'extcon-next-for-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2014 04:14:19 +0000 (20:14 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2014 04:14:19 +0000 (20:14 -0800)
Chanwoo writes:

Update extcon for v3.14

This patchset add new driver of extcon-max14577.c which detect various external
connector and fix minor issue of extcon provider driver(extcon-arizona/palams/
gpio.c). Also, update documentation of previous 'switch' porting guide and
extcon git repository url.

Detailed description for patchset:
- New driver of extcon-max14577.c
: Add extcon-max14577.c drvier to support Maxim MUIC(Micro USB Interface
Controller) which detect USB/TA/JIG/AUDIO-DOCK and additional accessory
according to each resistance when connected external connector.

- extcon-arizoan.c driver
: Code clean to use define macro instead of hex value
: Fix minor issue to reset back to our staring state
: Fix race with microphone detection and removal

- extcon-palmas.c driver
: Fix minor issue and renaming compatible string of Devicetree

- extcon-gpio.c driver
: Fix bug about ordering initialization of gpio pin on probe()
: Send uevent after wakeup from suspend state because some SoC
  haven't wakeup interrupt on suspend state.

- Documentation (Documentation/extcon/porting-android-switch-class)
: Fix switch class porting guide

- Update extcon git repository url

Documentation/devicetree/bindings/extcon/extcon-palmas.txt
Documentation/extcon/porting-android-switch-class
MAINTAINERS
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-gpio.c
drivers/extcon/extcon-max14577.c [new file with mode: 0644]
drivers/extcon/extcon-palmas.c
include/linux/extcon/extcon-gpio.h
include/linux/mfd/arizona/registers.h

index 7dab6a8..45414bb 100644 (file)
@@ -2,7 +2,11 @@ EXTCON FOR PALMAS/TWL CHIPS
 
 PALMAS USB COMPARATOR
 Required Properties:
- - compatible : Should be "ti,palmas-usb" or "ti,twl6035-usb"
+ - compatible: should contain one of:
+   * "ti,palmas-usb-vid".
+   * "ti,twl6035-usb-vid".
+   * "ti,palmas-usb" (DEPRECATED - use "ti,palmas-usb-vid").
+   * "ti,twl6035-usb" (DEPRECATED - use "ti,twl6035-usb-vid").
 
 Optional Properties:
  - ti,wakeup : To enable the wakeup comparator in probe
index 5377f63..49c81ca 100644 (file)
@@ -50,7 +50,7 @@ so that they are still compatible with legacy userspace processes.
        Extcon's extended features for switch device drivers with
        complex features usually required magic numbers in state
        value of switch_dev. With extcon, such magic numbers that
-       support multiple cables (
+       support multiple cables are no more required or supported.
 
   1. Define cable names at edev->supported_cable.
   2. (Recommended) remove print_state callback.
@@ -114,11 +114,8 @@ exclusive, the two cables cannot be in ATTACHED state simulteneously.
 
 ****** ABI Location
 
-  If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is
-disabled, /sys/class/switch/* are created as symbolic links to
-/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates
-/sys/class/switch directory, we disable symboling linking if
-CONFIG_ANDROID_SWITCH is enabled.
+  If "CONFIG_ANDROID" is enabled, /sys/class/switch/* are created
+as symbolic links to /sys/class/extcon/*.
 
   The two files of switch class, name and state, are provided with
 extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
index 0a1475b..cba11d2 100644 (file)
@@ -3330,6 +3330,7 @@ EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
 M:     MyungJoo Ham <myungjoo.ham@samsung.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 L:     linux-kernel@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
 S:     Maintained
 F:     drivers/extcon/
 F:     Documentation/extcon/
index f1d54a3..bdb5a00 100644 (file)
@@ -31,6 +31,16 @@ config EXTCON_ADC_JACK
        help
          Say Y here to enable extcon device driver based on ADC values.
 
+config EXTCON_MAX14577
+       tristate "MAX14577 EXTCON Support"
+       depends on MFD_MAX14577
+       select IRQ_DOMAIN
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the MUIC device of
+         Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
+         detector and switch.
+
 config EXTCON_MAX77693
        tristate "MAX77693 EXTCON Support"
        depends on MFD_MAX77693 && INPUT
index 759fdae..43eccc0 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF_EXTCON)         += of_extcon.o
 obj-$(CONFIG_EXTCON)           += extcon-class.o
 obj-$(CONFIG_EXTCON_GPIO)      += extcon-gpio.o
 obj-$(CONFIG_EXTCON_ADC_JACK)  += extcon-adc-jack.o
+obj-$(CONFIG_EXTCON_MAX14577)  += extcon-max14577.o
 obj-$(CONFIG_EXTCON_MAX77693)  += extcon-max77693.o
 obj-$(CONFIG_EXTCON_MAX8997)   += extcon-max8997.o
 obj-$(CONFIG_EXTCON_ARIZONA)   += extcon-arizona.o
index a287cec..c20602f 100644 (file)
 #define HPDET_DEBOUNCE 500
 #define DEFAULT_MICD_TIMEOUT 2000
 
+#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
+                        ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
+                        ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
+                        ARIZONA_MICD_LVL_7)
+
+#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
+
+#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
+
 struct arizona_extcon_info {
        struct device *dev;
        struct arizona *arizona;
@@ -426,26 +435,15 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
                }
 
                val &= ARIZONA_HP_LVL_B_MASK;
+               /* Convert to ohms, the value is in 0.5 ohm increments */
+               val /= 2;
 
                regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
                            &range);
                range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
                           >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
 
-               /* Skip up or down a range? */
-               if (range && (val < arizona_hpdet_c_ranges[range].min)) {
-                       range--;
-                       dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
-                               arizona_hpdet_c_ranges[range].min,
-                               arizona_hpdet_c_ranges[range].max);
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_HEADPHONE_DETECT_1,
-                                          ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-                                          range <<
-                                          ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-                       return -EAGAIN;
-               }
-
+               /* Skip up a range, or report? */
                if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
                    (val >= arizona_hpdet_c_ranges[range].max)) {
                        range++;
@@ -459,6 +457,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
                                           ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
                        return -EAGAIN;
                }
+
+               if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+                       dev_dbg(arizona->dev, "Reporting range boundary %d\n",
+                               arizona_hpdet_c_ranges[range].min);
+                       val = arizona_hpdet_c_ranges[range].min;
+               }
        }
 
        dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
@@ -594,9 +598,15 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
                dev_err(arizona->dev, "Failed to report HP/line: %d\n",
                        ret);
 
+done:
+       /* Reset back to starting range */
+       regmap_update_bits(arizona->regmap,
+                          ARIZONA_HEADPHONE_DETECT_1,
+                          ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+                          0);
+
        arizona_extcon_do_magic(info, 0);
 
-done:
        if (id_gpio)
                gpio_set_value_cansleep(id_gpio, 0);
 
@@ -765,7 +775,20 @@ static void arizona_micd_detect(struct work_struct *work)
 
        mutex_lock(&info->lock);
 
-       for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+       /* If the cable was removed while measuring ignore the result */
+       ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to check cable state: %d\n",
+                               ret);
+               mutex_unlock(&info->lock);
+               return;
+       } else if (!ret) {
+               dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
+               mutex_unlock(&info->lock);
+               return;
+       }
+
+       for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
                ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
                if (ret != 0) {
                        dev_err(arizona->dev,
@@ -784,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work)
                }
        }
 
-       if (i == 10 && !(val & 0x7fc)) {
+       if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
                dev_err(arizona->dev, "Failed to get valid MICDET value\n");
                mutex_unlock(&info->lock);
                return;
@@ -798,7 +821,7 @@ static void arizona_micd_detect(struct work_struct *work)
        }
 
        /* If we got a high impedence we should have a headset, report it. */
-       if (info->detecting && (val & 0x400)) {
+       if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
                arizona_identify_headphone(info);
 
                ret = extcon_update_state(&info->edev,
@@ -827,7 +850,7 @@ static void arizona_micd_detect(struct work_struct *work)
         * plain headphones.  If both polarities report a low
         * impedence then give up and report headphones.
         */
-       if (info->detecting && (val & 0x3f8)) {
+       if (info->detecting && (val & MICD_LVL_1_TO_7)) {
                if (info->jack_flips >= info->micd_num_modes * 10) {
                        dev_dbg(arizona->dev, "Detected HP/line\n");
                        arizona_identify_headphone(info);
@@ -851,7 +874,7 @@ static void arizona_micd_detect(struct work_struct *work)
         * If we're still detecting and we detect a short then we've
         * got a headphone.  Otherwise it's a button press.
         */
-       if (val & 0x3fc) {
+       if (val & MICD_LVL_0_TO_7) {
                if (info->mic) {
                        dev_dbg(arizona->dev, "Mic button detected\n");
 
@@ -1126,6 +1149,16 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                        break;
                }
                break;
+       case WM5110:
+               switch (arizona->rev) {
+               case 0 ... 2:
+                       break;
+               default:
+                       info->micd_clamp = true;
+                       info->hpdet_ip = 2;
+                       break;
+               }
+               break;
        default:
                break;
        }
index 7e0dff5..a63a6b2 100644 (file)
@@ -40,6 +40,7 @@ struct gpio_extcon_data {
        int irq;
        struct delayed_work work;
        unsigned long debounce_jiffies;
+       bool check_on_resume;
 };
 
 static void gpio_extcon_work(struct work_struct *work)
@@ -103,8 +104,15 @@ static int gpio_extcon_probe(struct platform_device *pdev)
        extcon_data->gpio_active_low = pdata->gpio_active_low;
        extcon_data->state_on = pdata->state_on;
        extcon_data->state_off = pdata->state_off;
+       extcon_data->check_on_resume = pdata->check_on_resume;
        if (pdata->state_on && pdata->state_off)
                extcon_data->edev.print_state = extcon_gpio_print_state;
+
+       ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
+                                   pdev->name);
+       if (ret < 0)
+               return ret;
+
        if (pdata->debounce) {
                ret = gpio_set_debounce(extcon_data->gpio,
                                        pdata->debounce * 1000);
@@ -117,11 +125,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
-                                   pdev->name);
-       if (ret < 0)
-               goto err;
-
        INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
 
        extcon_data->irq = gpio_to_irq(extcon_data->gpio);
@@ -159,12 +162,31 @@ static int gpio_extcon_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpio_extcon_resume(struct device *dev)
+{
+       struct gpio_extcon_data *extcon_data;
+
+       extcon_data = dev_get_drvdata(dev);
+       if (extcon_data->check_on_resume)
+               queue_delayed_work(system_power_efficient_wq,
+                       &extcon_data->work, extcon_data->debounce_jiffies);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops gpio_extcon_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
+};
+
 static struct platform_driver gpio_extcon_driver = {
        .probe          = gpio_extcon_probe,
        .remove         = gpio_extcon_remove,
        .driver         = {
                .name   = "extcon-gpio",
                .owner  = THIS_MODULE,
+               .pm     = &gpio_extcon_pm_ops,
        },
 };
 
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
new file mode 100644 (file)
index 0000000..3846941
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
+ *
+ * Copyright (C) 2013 Samsung Electrnoics
+ * Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max14577.h>
+#include <linux/mfd/max14577-private.h>
+#include <linux/extcon.h>
+
+#define        DEV_NAME                        "max14577-muic"
+#define        DELAY_MS_DEFAULT                17000           /* unit: millisecond */
+
+enum max14577_muic_adc_debounce_time {
+       ADC_DEBOUNCE_TIME_5MS = 0,
+       ADC_DEBOUNCE_TIME_10MS,
+       ADC_DEBOUNCE_TIME_25MS,
+       ADC_DEBOUNCE_TIME_38_62MS,
+};
+
+enum max14577_muic_status {
+       MAX14577_MUIC_STATUS1 = 0,
+       MAX14577_MUIC_STATUS2 = 1,
+       MAX14577_MUIC_STATUS_END,
+};
+
+struct max14577_muic_info {
+       struct device *dev;
+       struct max14577 *max14577;
+       struct extcon_dev *edev;
+       int prev_cable_type;
+       int prev_chg_type;
+       u8 status[MAX14577_MUIC_STATUS_END];
+
+       bool irq_adc;
+       bool irq_chg;
+       struct work_struct irq_work;
+       struct mutex mutex;
+
+       /*
+        * Use delayed workqueue to detect cable state and then
+        * notify cable state to notifiee/platform through uevent.
+        * After completing the booting of platform, the extcon provider
+        * driver should notify cable state to upper layer.
+        */
+       struct delayed_work wq_detcable;
+
+       /*
+        * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+        * h/w path of COMP2/COMN1 on CONTROL1 register.
+        */
+       int path_usb;
+       int path_uart;
+};
+
+enum max14577_muic_cable_group {
+       MAX14577_CABLE_GROUP_ADC = 0,
+       MAX14577_CABLE_GROUP_CHG,
+};
+
+/**
+ * struct max14577_muic_irq
+ * @irq: the index of irq list of MUIC device.
+ * @name: the name of irq.
+ * @virq: the virtual irq to use irq domain
+ */
+struct max14577_muic_irq {
+       unsigned int irq;
+       const char *name;
+       unsigned int virq;
+};
+
+static struct max14577_muic_irq muic_irqs[] = {
+       { MAX14577_IRQ_INT1_ADC,        "muic-ADC" },
+       { MAX14577_IRQ_INT1_ADCLOW,     "muic-ADCLOW" },
+       { MAX14577_IRQ_INT1_ADCERR,     "muic-ADCError" },
+       { MAX14577_IRQ_INT2_CHGTYP,     "muic-CHGTYP" },
+       { MAX14577_IRQ_INT2_CHGDETRUN,  "muic-CHGDETRUN" },
+       { MAX14577_IRQ_INT2_DCDTMR,     "muic-DCDTMR" },
+       { MAX14577_IRQ_INT2_DBCHG,      "muic-DBCHG" },
+       { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
+};
+
+/* Define supported accessory type */
+enum max14577_muic_acc_type {
+       MAX14577_MUIC_ADC_GROUND = 0x0,
+       MAX14577_MUIC_ADC_SEND_END_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S1_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S2_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S3_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S4_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S5_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S6_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S7_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S8_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S9_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S10_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S11_BUTTON,
+       MAX14577_MUIC_ADC_REMOTE_S12_BUTTON,
+       MAX14577_MUIC_ADC_RESERVED_ACC_1,
+       MAX14577_MUIC_ADC_RESERVED_ACC_2,
+       MAX14577_MUIC_ADC_RESERVED_ACC_3,
+       MAX14577_MUIC_ADC_RESERVED_ACC_4,
+       MAX14577_MUIC_ADC_RESERVED_ACC_5,
+       MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2,
+       MAX14577_MUIC_ADC_PHONE_POWERED_DEV,
+       MAX14577_MUIC_ADC_TTY_CONVERTER,
+       MAX14577_MUIC_ADC_UART_CABLE,
+       MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG,
+       MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF,
+       MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON,
+       MAX14577_MUIC_ADC_AV_CABLE_NOLOAD,
+       MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG,
+       MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF,
+       MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON,
+       MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1, /* with Remote and Simple Ctrl */
+       MAX14577_MUIC_ADC_OPEN,
+};
+
+/* max14577 MUIC device support below list of accessories(external connector) */
+enum {
+       EXTCON_CABLE_USB = 0,
+       EXTCON_CABLE_TA,
+       EXTCON_CABLE_FAST_CHARGER,
+       EXTCON_CABLE_SLOW_CHARGER,
+       EXTCON_CABLE_CHARGE_DOWNSTREAM,
+       EXTCON_CABLE_JIG_USB_ON,
+       EXTCON_CABLE_JIG_USB_OFF,
+       EXTCON_CABLE_JIG_UART_OFF,
+       EXTCON_CABLE_JIG_UART_ON,
+
+       _EXTCON_CABLE_NUM,
+};
+
+static const char *max14577_extcon_cable[] = {
+       [EXTCON_CABLE_USB]                      = "USB",
+       [EXTCON_CABLE_TA]                       = "TA",
+       [EXTCON_CABLE_FAST_CHARGER]             = "Fast-charger",
+       [EXTCON_CABLE_SLOW_CHARGER]             = "Slow-charger",
+       [EXTCON_CABLE_CHARGE_DOWNSTREAM]        = "Charge-downstream",
+       [EXTCON_CABLE_JIG_USB_ON]               = "JIG-USB-ON",
+       [EXTCON_CABLE_JIG_USB_OFF]              = "JIG-USB-OFF",
+       [EXTCON_CABLE_JIG_UART_OFF]             = "JIG-UART-OFF",
+       [EXTCON_CABLE_JIG_UART_ON]              = "JIG-UART-ON",
+
+       NULL,
+};
+
+/*
+ * max14577_muic_set_debounce_time - Set the debounce time of ADC
+ * @info: the instance including private data of max14577 MUIC
+ * @time: the debounce time of ADC
+ */
+static int max14577_muic_set_debounce_time(struct max14577_muic_info *info,
+               enum max14577_muic_adc_debounce_time time)
+{
+       u8 ret;
+
+       switch (time) {
+       case ADC_DEBOUNCE_TIME_5MS:
+       case ADC_DEBOUNCE_TIME_10MS:
+       case ADC_DEBOUNCE_TIME_25MS:
+       case ADC_DEBOUNCE_TIME_38_62MS:
+               ret = max14577_update_reg(info->max14577->regmap,
+                                         MAX14577_MUIC_REG_CONTROL3,
+                                         CTRL3_ADCDBSET_MASK,
+                                         time << CTRL3_ADCDBSET_SHIFT);
+               if (ret) {
+                       dev_err(info->dev, "failed to set ADC debounce time\n");
+                       return ret;
+               }
+               break;
+       default:
+               dev_err(info->dev, "invalid ADC debounce time\n");
+               return -EINVAL;
+       }
+
+       return 0;
+};
+
+/*
+ * max14577_muic_set_path - Set hardware line according to attached cable
+ * @info: the instance including private data of max14577 MUIC
+ * @value: the path according to attached cable
+ * @attached: the state of cable (true:attached, false:detached)
+ *
+ * The max14577 MUIC device share outside H/W line among a varity of cables
+ * so, this function set internal path of H/W line according to the type of
+ * attached cable.
+ */
+static int max14577_muic_set_path(struct max14577_muic_info *info,
+               u8 val, bool attached)
+{
+       int ret = 0;
+       u8 ctrl1, ctrl2 = 0;
+
+       /* Set open state to path before changing hw path */
+       ret = max14577_update_reg(info->max14577->regmap,
+                               MAX14577_MUIC_REG_CONTROL1,
+                               CLEAR_IDBEN_MICEN_MASK, CTRL1_SW_OPEN);
+       if (ret < 0) {
+               dev_err(info->dev, "failed to update MUIC register\n");
+               return ret;
+       }
+
+       if (attached)
+               ctrl1 = val;
+       else
+               ctrl1 = CTRL1_SW_OPEN;
+
+       ret = max14577_update_reg(info->max14577->regmap,
+                               MAX14577_MUIC_REG_CONTROL1,
+                               CLEAR_IDBEN_MICEN_MASK, ctrl1);
+       if (ret < 0) {
+               dev_err(info->dev, "failed to update MUIC register\n");
+               return ret;
+       }
+
+       if (attached)
+               ctrl2 |= CTRL2_CPEN_MASK;       /* LowPwr=0, CPEn=1 */
+       else
+               ctrl2 |= CTRL2_LOWPWR_MASK;     /* LowPwr=1, CPEn=0 */
+
+       ret = max14577_update_reg(info->max14577->regmap,
+                       MAX14577_REG_CONTROL2,
+                       CTRL2_LOWPWR_MASK | CTRL2_CPEN_MASK, ctrl2);
+       if (ret < 0) {
+               dev_err(info->dev, "failed to update MUIC register\n");
+               return ret;
+       }
+
+       dev_dbg(info->dev,
+               "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
+               ctrl1, ctrl2, attached ? "attached" : "detached");
+
+       return 0;
+}
+
+/*
+ * max14577_muic_get_cable_type - Return cable type and check cable state
+ * @info: the instance including private data of max14577 MUIC
+ * @group: the path according to attached cable
+ * @attached: store cable state and return
+ *
+ * This function check the cable state either attached or detached,
+ * and then divide precise type of cable according to cable group.
+ *     - max14577_CABLE_GROUP_ADC
+ *     - max14577_CABLE_GROUP_CHG
+ */
+static int max14577_muic_get_cable_type(struct max14577_muic_info *info,
+               enum max14577_muic_cable_group group, bool *attached)
+{
+       int cable_type = 0;
+       int adc;
+       int chg_type;
+
+       switch (group) {
+       case MAX14577_CABLE_GROUP_ADC:
+               /*
+                * Read ADC value to check cable type and decide cable state
+                * according to cable type
+                */
+               adc = info->status[MAX14577_MUIC_STATUS1] & STATUS1_ADC_MASK;
+               adc >>= STATUS1_ADC_SHIFT;
+
+               /*
+                * Check current cable state/cable type and store cable type
+                * (info->prev_cable_type) for handling cable when cable is
+                * detached.
+                */
+               if (adc == MAX14577_MUIC_ADC_OPEN) {
+                       *attached = false;
+
+                       cable_type = info->prev_cable_type;
+                       info->prev_cable_type = MAX14577_MUIC_ADC_OPEN;
+               } else {
+                       *attached = true;
+
+                       cable_type = info->prev_cable_type = adc;
+               }
+               break;
+       case MAX14577_CABLE_GROUP_CHG:
+               /*
+                * Read charger type to check cable type and decide cable state
+                * according to type of charger cable.
+                */
+               chg_type = info->status[MAX14577_MUIC_STATUS2] &
+                       STATUS2_CHGTYP_MASK;
+               chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+               if (chg_type == MAX14577_CHARGER_TYPE_NONE) {
+                       *attached = false;
+
+                       cable_type = info->prev_chg_type;
+                       info->prev_chg_type = MAX14577_CHARGER_TYPE_NONE;
+               } else {
+                       *attached = true;
+
+                       /*
+                        * Check current cable state/cable type and store cable
+                        * type(info->prev_chg_type) for handling cable when
+                        * charger cable is detached.
+                        */
+                       cable_type = info->prev_chg_type = chg_type;
+               }
+
+               break;
+       default:
+               dev_err(info->dev, "Unknown cable group (%d)\n", group);
+               cable_type = -EINVAL;
+               break;
+       }
+
+       return cable_type;
+}
+
+static int max14577_muic_jig_handler(struct max14577_muic_info *info,
+               int cable_type, bool attached)
+{
+       char cable_name[32];
+       int ret = 0;
+       u8 path = CTRL1_SW_OPEN;
+
+       dev_dbg(info->dev,
+               "external connector is %s (adc:0x%02x)\n",
+               attached ? "attached" : "detached", cable_type);
+
+       switch (cable_type) {
+       case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF:    /* ADC_JIG_USB_OFF */
+               /* PATH:AP_USB */
+               strcpy(cable_name, "JIG-USB-OFF");
+               path = CTRL1_SW_USB;
+               break;
+       case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON:     /* ADC_JIG_USB_ON */
+               /* PATH:AP_USB */
+               strcpy(cable_name, "JIG-USB-ON");
+               path = CTRL1_SW_USB;
+               break;
+       case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF:   /* ADC_JIG_UART_OFF */
+               /* PATH:AP_UART */
+               strcpy(cable_name, "JIG-UART-OFF");
+               path = CTRL1_SW_UART;
+               break;
+       default:
+               dev_err(info->dev, "failed to detect %s jig cable\n",
+                       attached ? "attached" : "detached");
+               return -EINVAL;
+       }
+
+       ret = max14577_muic_set_path(info, path, attached);
+       if (ret < 0)
+               return ret;
+
+       extcon_set_cable_state(info->edev, cable_name, attached);
+
+       return 0;
+}
+
+static int max14577_muic_adc_handler(struct max14577_muic_info *info)
+{
+       int cable_type;
+       bool attached;
+       int ret = 0;
+
+       /* Check accessory state which is either detached or attached */
+       cable_type = max14577_muic_get_cable_type(info,
+                               MAX14577_CABLE_GROUP_ADC, &attached);
+
+       dev_dbg(info->dev,
+               "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
+               attached ? "attached" : "detached", cable_type,
+               info->prev_cable_type);
+
+       switch (cable_type) {
+       case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF:
+       case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON:
+       case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF:
+               /* JIG */
+               ret = max14577_muic_jig_handler(info, cable_type, attached);
+               if (ret < 0)
+                       return ret;
+               break;
+       case MAX14577_MUIC_ADC_GROUND:
+       case MAX14577_MUIC_ADC_SEND_END_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S1_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S2_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S3_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S4_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S5_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S6_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S7_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S8_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S9_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S10_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S11_BUTTON:
+       case MAX14577_MUIC_ADC_REMOTE_S12_BUTTON:
+       case MAX14577_MUIC_ADC_RESERVED_ACC_1:
+       case MAX14577_MUIC_ADC_RESERVED_ACC_2:
+       case MAX14577_MUIC_ADC_RESERVED_ACC_3:
+       case MAX14577_MUIC_ADC_RESERVED_ACC_4:
+       case MAX14577_MUIC_ADC_RESERVED_ACC_5:
+       case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2:
+       case MAX14577_MUIC_ADC_PHONE_POWERED_DEV:
+       case MAX14577_MUIC_ADC_TTY_CONVERTER:
+       case MAX14577_MUIC_ADC_UART_CABLE:
+       case MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG:
+       case MAX14577_MUIC_ADC_AV_CABLE_NOLOAD:
+       case MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG:
+       case MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON:
+       case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1:
+               /*
+                * This accessory isn't used in general case if it is specially
+                * needed to detect additional accessory, should implement
+                * proper operation when this accessory is attached/detached.
+                */
+               dev_info(info->dev,
+                       "accessory is %s but it isn't used (adc:0x%x)\n",
+                       attached ? "attached" : "detached", cable_type);
+               return -EAGAIN;
+       default:
+               dev_err(info->dev,
+                       "failed to detect %s accessory (adc:0x%x)\n",
+                       attached ? "attached" : "detached", cable_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int max14577_muic_chg_handler(struct max14577_muic_info *info)
+{
+       int chg_type;
+       bool attached;
+       int ret = 0;
+
+       chg_type = max14577_muic_get_cable_type(info,
+                               MAX14577_CABLE_GROUP_CHG, &attached);
+
+       dev_dbg(info->dev,
+               "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
+                       attached ? "attached" : "detached",
+                       chg_type, info->prev_chg_type);
+
+       switch (chg_type) {
+       case MAX14577_CHARGER_TYPE_USB:
+               /* PATH:AP_USB */
+               ret = max14577_muic_set_path(info, info->path_usb, attached);
+               if (ret < 0)
+                       return ret;
+
+               extcon_set_cable_state(info->edev, "USB", attached);
+               break;
+       case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
+               extcon_set_cable_state(info->edev, "TA", attached);
+               break;
+       case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
+               extcon_set_cable_state(info->edev,
+                               "Charge-downstream", attached);
+               break;
+       case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
+               extcon_set_cable_state(info->edev, "Slow-charger", attached);
+               break;
+       case MAX14577_CHARGER_TYPE_SPECIAL_1A:
+               extcon_set_cable_state(info->edev, "Fast-charger", attached);
+               break;
+       case MAX14577_CHARGER_TYPE_NONE:
+       case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
+               break;
+       default:
+               dev_err(info->dev,
+                       "failed to detect %s accessory (chg_type:0x%x)\n",
+                       attached ? "attached" : "detached", chg_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void max14577_muic_irq_work(struct work_struct *work)
+{
+       struct max14577_muic_info *info = container_of(work,
+                       struct max14577_muic_info, irq_work);
+       int ret = 0;
+
+       if (!info->edev)
+               return;
+
+       mutex_lock(&info->mutex);
+
+       ret = max14577_bulk_read(info->max14577->regmap,
+                       MAX14577_MUIC_REG_STATUS1, info->status, 2);
+       if (ret) {
+               dev_err(info->dev, "failed to read MUIC register\n");
+               mutex_unlock(&info->mutex);
+               return;
+       }
+
+       if (info->irq_adc) {
+               ret = max14577_muic_adc_handler(info);
+               info->irq_adc = false;
+       }
+       if (info->irq_chg) {
+               ret = max14577_muic_chg_handler(info);
+               info->irq_chg = false;
+       }
+
+       if (ret < 0)
+               dev_err(info->dev, "failed to handle MUIC interrupt\n");
+
+       mutex_unlock(&info->mutex);
+
+       return;
+}
+
+static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+{
+       struct max14577_muic_info *info = data;
+       int i, irq_type = -1;
+
+       /*
+        * We may be called multiple times for different nested IRQ-s.
+        * Including changes in INT1_ADC and INT2_CGHTYP at once.
+        * However we only need to know whether it was ADC, charger
+        * or both interrupts so decode IRQ and turn on proper flags.
+        */
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
+               if (irq == muic_irqs[i].virq)
+                       irq_type = muic_irqs[i].irq;
+
+       switch (irq_type) {
+       case MAX14577_IRQ_INT1_ADC:
+       case MAX14577_IRQ_INT1_ADCLOW:
+       case MAX14577_IRQ_INT1_ADCERR:
+               /* Handle all of accessory except for
+                  type of charger accessory */
+               info->irq_adc = true;
+               break;
+       case MAX14577_IRQ_INT2_CHGTYP:
+       case MAX14577_IRQ_INT2_CHGDETRUN:
+       case MAX14577_IRQ_INT2_DCDTMR:
+       case MAX14577_IRQ_INT2_DBCHG:
+       case MAX14577_IRQ_INT2_VBVOLT:
+               /* Handle charger accessory */
+               info->irq_chg = true;
+               break;
+       default:
+               dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
+                               irq_type);
+               return IRQ_HANDLED;
+       }
+       schedule_work(&info->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static int max14577_muic_detect_accessory(struct max14577_muic_info *info)
+{
+       int ret = 0;
+       int adc;
+       int chg_type;
+       bool attached;
+
+       mutex_lock(&info->mutex);
+
+       /* Read STATUSx register to detect accessory */
+       ret = max14577_bulk_read(info->max14577->regmap,
+                       MAX14577_MUIC_REG_STATUS1, info->status, 2);
+       if (ret) {
+               dev_err(info->dev, "failed to read MUIC register\n");
+               mutex_unlock(&info->mutex);
+               return ret;
+       }
+
+       adc = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_ADC,
+                                       &attached);
+       if (attached && adc != MAX14577_MUIC_ADC_OPEN) {
+               ret = max14577_muic_adc_handler(info);
+               if (ret < 0) {
+                       dev_err(info->dev, "Cannot detect accessory\n");
+                       mutex_unlock(&info->mutex);
+                       return ret;
+               }
+       }
+
+       chg_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_CHG,
+                                       &attached);
+       if (attached && chg_type != MAX14577_CHARGER_TYPE_NONE) {
+               ret = max14577_muic_chg_handler(info);
+               if (ret < 0) {
+                       dev_err(info->dev, "Cannot detect charger accessory\n");
+                       mutex_unlock(&info->mutex);
+                       return ret;
+               }
+       }
+
+       mutex_unlock(&info->mutex);
+
+       return 0;
+}
+
+static void max14577_muic_detect_cable_wq(struct work_struct *work)
+{
+       struct max14577_muic_info *info = container_of(to_delayed_work(work),
+                               struct max14577_muic_info, wq_detcable);
+
+       max14577_muic_detect_accessory(info);
+}
+
+static int max14577_muic_probe(struct platform_device *pdev)
+{
+       struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
+       struct max14577_muic_info *info;
+       int delay_jiffies;
+       int ret;
+       int i;
+       u8 id;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+       info->dev = &pdev->dev;
+       info->max14577 = max14577;
+
+       platform_set_drvdata(pdev, info);
+       mutex_init(&info->mutex);
+
+       INIT_WORK(&info->irq_work, max14577_muic_irq_work);
+
+       /* Support irq domain for max14577 MUIC device */
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
+               struct max14577_muic_irq *muic_irq = &muic_irqs[i];
+               unsigned int virq = 0;
+
+               virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
+               if (!virq)
+                       return -EINVAL;
+               muic_irq->virq = virq;
+
+               ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+                               max14577_muic_irq_handler,
+                               IRQF_NO_SUSPEND,
+                               muic_irq->name, info);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed: irq request (IRQ: %d,"
+                               " error :%d)\n",
+                               muic_irq->irq, ret);
+                       return ret;
+               }
+       }
+
+       /* Initialize extcon device */
+       info->edev = devm_kzalloc(&pdev->dev, sizeof(*info->edev), GFP_KERNEL);
+       if (!info->edev) {
+               dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+               return -ENOMEM;
+       }
+       info->edev->name = DEV_NAME;
+       info->edev->supported_cable = max14577_extcon_cable;
+       ret = extcon_dev_register(info->edev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register extcon device\n");
+               return ret;
+       }
+
+       /* Default h/w line path */
+       info->path_usb = CTRL1_SW_USB;
+       info->path_uart = CTRL1_SW_UART;
+       delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+
+       /* Set initial path for UART */
+       max14577_muic_set_path(info, info->path_uart, true);
+
+       /* Check revision number of MUIC device*/
+       ret = max14577_read_reg(info->max14577->regmap,
+                       MAX14577_REG_DEVICEID, &id);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to read revision number\n");
+               goto err_extcon;
+       }
+       dev_info(info->dev, "device ID : 0x%x\n", id);
+
+       /* Set ADC debounce time */
+       max14577_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
+
+       /*
+        * Detect accessory after completing the initialization of platform
+        *
+        * - Use delayed workqueue to detect cable state and then
+        * notify cable state to notifiee/platform through uevent.
+        * After completing the booting of platform, the extcon provider
+        * driver should notify cable state to upper layer.
+        */
+       INIT_DELAYED_WORK(&info->wq_detcable, max14577_muic_detect_cable_wq);
+       ret = queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
+                       delay_jiffies);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "failed to schedule delayed work for cable detect\n");
+               goto err_extcon;
+       }
+
+       return ret;
+
+err_extcon:
+       extcon_dev_unregister(info->edev);
+       return ret;
+}
+
+static int max14577_muic_remove(struct platform_device *pdev)
+{
+       struct max14577_muic_info *info = platform_get_drvdata(pdev);
+
+       cancel_work_sync(&info->irq_work);
+       extcon_dev_unregister(info->edev);
+
+       return 0;
+}
+
+static struct platform_driver max14577_muic_driver = {
+       .driver         = {
+               .name   = DEV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max14577_muic_probe,
+       .remove         = max14577_muic_remove,
+};
+
+module_platform_driver(max14577_muic_driver);
+
+MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:extcon-max14577");
index 6c91976..2aea4bc 100644 (file)
@@ -78,20 +78,24 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
 
 static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
 {
-       unsigned int set;
+       unsigned int set, id_src;
        struct palmas_usb *palmas_usb = _palmas_usb;
 
        palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
                PALMAS_USB_ID_INT_LATCH_SET, &set);
+       palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
+               PALMAS_USB_ID_INT_SRC, &id_src);
 
-       if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
+       if ((set & PALMAS_USB_ID_INT_SRC_ID_GND) &&
+                               (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
                palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
                        PALMAS_USB_ID_INT_LATCH_CLR,
                        PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
                palmas_usb->linkstat = PALMAS_USB_STATE_ID;
                extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
                dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
-       } else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
+       } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
+                               (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
                palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
                        PALMAS_USB_ID_INT_LATCH_CLR,
                        PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
@@ -103,6 +107,11 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
                palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
                extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
                dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+       } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
+                               (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
+               palmas_usb->linkstat = PALMAS_USB_STATE_ID;
+               extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
+               dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
        }
 
        return IRQ_HANDLED;
@@ -269,7 +278,9 @@ static const struct dev_pm_ops palmas_pm_ops = {
 
 static struct of_device_id of_palmas_match_tbl[] = {
        { .compatible = "ti,palmas-usb", },
+       { .compatible = "ti,palmas-usb-vid", },
        { .compatible = "ti,twl6035-usb", },
+       { .compatible = "ti,twl6035-usb-vid", },
        { /* end */ }
 };
 
index 4195810..8900fdf 100644 (file)
@@ -51,6 +51,7 @@ struct gpio_extcon_platform_data {
        /* if NULL, "0" or "1" will be printed */
        const char *state_on;
        const char *state_off;
+       bool check_on_resume;
 };
 
 #endif /* __EXTCON_GPIO_H__ */
index cb49417..b319765 100644 (file)
 /*
  * R677 (0x2A5) - Mic Detect 3
  */
+#define ARIZONA_MICD_LVL_0                       0x0004  /* MICD_LVL - [2] */
+#define ARIZONA_MICD_LVL_1                       0x0008  /* MICD_LVL - [3] */
+#define ARIZONA_MICD_LVL_2                       0x0010  /* MICD_LVL - [4] */
+#define ARIZONA_MICD_LVL_3                       0x0020  /* MICD_LVL - [5] */
+#define ARIZONA_MICD_LVL_4                       0x0040  /* MICD_LVL - [6] */
+#define ARIZONA_MICD_LVL_5                       0x0080  /* MICD_LVL - [7] */
+#define ARIZONA_MICD_LVL_6                       0x0100  /* MICD_LVL - [8] */
+#define ARIZONA_MICD_LVL_7                       0x0200  /* MICD_LVL - [9] */
+#define ARIZONA_MICD_LVL_8                       0x0400  /* MICD_LVL - [10] */
 #define ARIZONA_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
 #define ARIZONA_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
 #define ARIZONA_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */