Merge tag 'extcon-next-for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Aug 2015 16:12:15 +0000 (09:12 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Aug 2015 16:12:15 +0000 (09:12 -0700)
Chanwoo writes:

Update extcon for v4.3

This patchset include the function update of extcon drivers without critical
update and fix minor issue of extcon drivers.

Detailed description for patchset:
1. Update the extcon drivers:
- Update the logic of microphone detection for extcon-arizona driver
- Support GPIO based USB ID detection of extcon-palmas driver

2. Fix minor issues:
- Clean code and remove the opitonal print_state() function pointer from extcon
  core driver
- Clear interrupt bit state before requesting irq on extcon-max778433 driver
- Fix signedness bugs of extcon core driver

Documentation/devicetree/bindings/extcon/extcon-palmas.txt
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-gpio.c
drivers/extcon/extcon-max77843.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon-rt8973a.c
drivers/extcon/extcon-sm5502.c
drivers/extcon/extcon-usb-gpio.c
drivers/extcon/extcon.c
include/linux/extcon.h
include/linux/mfd/palmas.h

index 45414bbcd9455b13620e9923f0dec048995c82cb..f61d5af44a27f20d21479c9920081906440674a3 100644 (file)
@@ -10,8 +10,11 @@ Required Properties:
 
 Optional Properties:
  - ti,wakeup : To enable the wakeup comparator in probe
- - ti,enable-id-detection: Perform ID detection.
+ - ti,enable-id-detection: Perform ID detection. If id-gpio is specified
+               it performs id-detection using GPIO else using OTG core.
  - ti,enable-vbus-detection: Perform VBUS detection.
+ - id-gpio: gpio for GPIO ID detection. See gpio binding.
+ - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds.
 
 palmas-usb {
        compatible = "ti,twl6035-usb", "ti,palmas-usb";
index ad87f263056f1f4995dba394af244e829afa2f84..4b9f09cc38d879899b18314509d20a7292f81fa6 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
 #include <linux/gpio.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/regulator/consumer.h>
 #include <linux/extcon.h>
 
@@ -46,6 +48,9 @@
 #define HPDET_DEBOUNCE 500
 #define DEFAULT_MICD_TIMEOUT 2000
 
+#define MICD_DBTIME_TWO_READINGS 2
+#define MICD_DBTIME_FOUR_READINGS 4
+
 #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 | \
@@ -94,6 +99,8 @@ struct arizona_extcon_info {
        int hpdet_ip_version;
 
        struct extcon_dev *edev;
+
+       struct gpio_desc *micd_pol_gpio;
 };
 
 static const struct arizona_micd_config micd_default_modes[] = {
@@ -204,6 +211,10 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
        if (arizona->pdata.micd_pol_gpio > 0)
                gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
                                        info->micd_modes[mode].gpio);
+       else
+               gpiod_set_value_cansleep(info->micd_pol_gpio,
+                                        info->micd_modes[mode].gpio);
+
        regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
                           ARIZONA_MICD_BIAS_SRC_MASK,
                           info->micd_modes[mode].bias <<
@@ -757,10 +768,11 @@ static void arizona_micd_timeout_work(struct work_struct *work)
        mutex_lock(&info->lock);
 
        dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
-       arizona_identify_headphone(info);
 
        info->detecting = false;
 
+       arizona_identify_headphone(info);
+
        arizona_stop_mic(info);
 
        mutex_unlock(&info->lock);
@@ -820,12 +832,18 @@ static void arizona_micd_detect(struct work_struct *work)
        /* Due to jack detect this should never happen */
        if (!(val & ARIZONA_MICD_STS)) {
                dev_warn(arizona->dev, "Detected open circuit\n");
+               info->mic = false;
+               arizona_stop_mic(info);
                info->detecting = false;
+               arizona_identify_headphone(info);
                goto handled;
        }
 
        /* If we got a high impedence we should have a headset, report it. */
        if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
+               info->mic = true;
+               info->detecting = false;
+
                arizona_identify_headphone(info);
 
                ret = extcon_set_cable_state_(info->edev,
@@ -841,8 +859,6 @@ static void arizona_micd_detect(struct work_struct *work)
                                ret);
                }
 
-               info->mic = true;
-               info->detecting = false;
                goto handled;
        }
 
@@ -855,10 +871,11 @@ static void arizona_micd_detect(struct work_struct *work)
        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);
 
                        info->detecting = false;
 
+                       arizona_identify_headphone(info);
+
                        arizona_stop_mic(info);
                } else {
                        info->micd_mode++;
@@ -1110,12 +1127,12 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
        regmap_update_bits(arizona->regmap, reg, mask, level);
 }
 
-static int arizona_extcon_of_get_pdata(struct arizona *arizona)
+static int arizona_extcon_device_get_pdata(struct arizona *arizona)
 {
        struct arizona_pdata *pdata = &arizona->pdata;
        unsigned int val = ARIZONA_ACCDET_MODE_HPL;
 
-       of_property_read_u32(arizona->dev->of_node, "wlf,hpdet-channel", &val);
+       device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
        switch (val) {
        case ARIZONA_ACCDET_MODE_HPL:
        case ARIZONA_ACCDET_MODE_HPR:
@@ -1127,6 +1144,24 @@ static int arizona_extcon_of_get_pdata(struct arizona *arizona)
                pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
        }
 
+       device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
+                                &pdata->micd_detect_debounce);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
+                                &pdata->micd_bias_start_time);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-rate",
+                                &pdata->micd_rate);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
+                                &pdata->micd_dbtime);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-timeout",
+                                &pdata->micd_timeout);
+
+       pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
+                                               "wlf,micd-force-micbias");
+
        return 0;
 }
 
@@ -1147,10 +1182,8 @@ static int arizona_extcon_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
-       if (IS_ENABLED(CONFIG_OF)) {
-               if (!dev_get_platdata(arizona->dev))
-                       arizona_extcon_of_get_pdata(arizona);
-       }
+       if (!dev_get_platdata(arizona->dev))
+               arizona_extcon_device_get_pdata(arizona);
 
        info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
        if (IS_ERR(info->micvdd)) {
@@ -1241,6 +1274,27 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                                arizona->pdata.micd_pol_gpio, ret);
                        goto err_register;
                }
+       } else {
+               if (info->micd_modes[0].gpio)
+                       mode = GPIOD_OUT_HIGH;
+               else
+                       mode = GPIOD_OUT_LOW;
+
+               /* We can't use devm here because we need to do the get
+                * against the MFD device, as that is where the of_node
+                * will reside, but if we devm against that the GPIO
+                * will not be freed if the extcon driver is unloaded.
+                */
+               info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
+                                                        "wlf,micd-pol",
+                                                        GPIOD_OUT_LOW);
+               if (IS_ERR(info->micd_pol_gpio)) {
+                       ret = PTR_ERR(info->micd_pol_gpio);
+                       dev_err(arizona->dev,
+                               "Failed to get microphone polarity GPIO: %d\n",
+                               ret);
+                       goto err_register;
+               }
        }
 
        if (arizona->pdata.hpdet_id_gpio > 0) {
@@ -1251,7 +1305,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
                                arizona->pdata.hpdet_id_gpio, ret);
-                       goto err_register;
+                       goto err_gpio;
                }
        }
 
@@ -1267,11 +1321,19 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                                   arizona->pdata.micd_rate
                                   << ARIZONA_MICD_RATE_SHIFT);
 
-       if (arizona->pdata.micd_dbtime)
+       switch (arizona->pdata.micd_dbtime) {
+       case MICD_DBTIME_FOUR_READINGS:
                regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
                                   ARIZONA_MICD_DBTIME_MASK,
-                                  arizona->pdata.micd_dbtime
-                                  << ARIZONA_MICD_DBTIME_SHIFT);
+                                  ARIZONA_MICD_DBTIME);
+               break;
+       case MICD_DBTIME_TWO_READINGS:
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                  ARIZONA_MICD_DBTIME_MASK, 0);
+               break;
+       default:
+               break;
+       }
 
        BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
 
@@ -1295,7 +1357,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                                dev_err(arizona->dev,
                                        "MICD ranges must be sorted\n");
                                ret = -EINVAL;
-                               goto err_input;
+                               goto err_gpio;
                        }
                }
        }
@@ -1314,7 +1376,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                        dev_err(arizona->dev, "Unsupported MICD level %d\n",
                                info->micd_ranges[i].max);
                        ret = -EINVAL;
-                       goto err_input;
+                       goto err_gpio;
                }
 
                dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
@@ -1387,7 +1449,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
                        ret);
-               goto err_input;
+               goto err_gpio;
        }
 
        ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
@@ -1458,7 +1520,8 @@ err_rise_wake:
        arizona_set_irq_wake(arizona, jack_irq_rise, 0);
 err_rise:
        arizona_free_irq(arizona, jack_irq_rise, info);
-err_input:
+err_gpio:
+       gpiod_put(info->micd_pol_gpio);
 err_register:
        pm_runtime_disable(&pdev->dev);
        return ret;
@@ -1470,6 +1533,8 @@ static int arizona_extcon_remove(struct platform_device *pdev)
        struct arizona *arizona = info->arizona;
        int jack_irq_rise, jack_irq_fall;
 
+       gpiod_put(info->micd_pol_gpio);
+
        pm_runtime_disable(&pdev->dev);
 
        regmap_update_bits(arizona->regmap,
index 355459a54e8b4fabe8c496fedeae7cef7d66add6..57c24fa52edb8ebf818489851f0425615bdda5f0 100644 (file)
@@ -65,22 +65,6 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
-{
-       struct device *dev = edev->dev.parent;
-       struct gpio_extcon_data *extcon_data = dev_get_drvdata(dev);
-       const char *state;
-
-       if (extcon_get_state(edev))
-               state = extcon_data->state_on;
-       else
-               state = extcon_data->state_off;
-
-       if (state)
-               return sprintf(buf, "%s\n", state);
-       return -EINVAL;
-}
-
 static int gpio_extcon_probe(struct platform_device *pdev)
 {
        struct gpio_extcon_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -110,8 +94,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
        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);
index fac2f1417a79ca47752839b79ae7a07522cb1ebb..cc5e7bca38c8579df8ad07233d8b4a8b09164a19 100644 (file)
@@ -781,6 +781,15 @@ static int max77843_muic_probe(struct platform_device *pdev)
        /* Support virtual irq domain for max77843 MUIC device */
        INIT_WORK(&info->irq_work, max77843_muic_irq_work);
 
+       /* Clear IRQ bits before request IRQs */
+       ret = regmap_bulk_read(max77843->regmap_muic,
+                       MAX77843_MUIC_REG_INT1, info->status,
+                       MAX77843_MUIC_IRQ_NUM);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to Clear IRQ bits\n");
+               goto err_muic_irq;
+       }
+
        for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
                struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
                unsigned int virq = 0;
index eebdf2a33bfe4b84e1fc1886e7222641f4a56122..93c30a885740e9bebb08c8f80162118c7e3f2359 100644 (file)
 #include <linux/mfd/palmas.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/workqueue.h>
+
+#define USB_GPIO_DEBOUNCE_MS   20      /* ms */
 
 static const unsigned int palmas_extcon_cable[] = {
        EXTCON_USB,
@@ -35,8 +40,6 @@ static const unsigned int palmas_extcon_cable[] = {
        EXTCON_NONE,
 };
 
-static const int mutually_exclusive[] = {0x3, 0x0};
-
 static void palmas_usb_wakeup(struct palmas *palmas, int enable)
 {
        if (enable)
@@ -120,19 +123,54 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
        return IRQ_HANDLED;
 }
 
+static void palmas_gpio_id_detect(struct work_struct *work)
+{
+       int id;
+       struct palmas_usb *palmas_usb = container_of(to_delayed_work(work),
+                                                    struct palmas_usb,
+                                                    wq_detectid);
+       struct extcon_dev *edev = palmas_usb->edev;
+
+       if (!palmas_usb->id_gpiod)
+               return;
+
+       id = gpiod_get_value_cansleep(palmas_usb->id_gpiod);
+
+       if (id) {
+               extcon_set_cable_state_(edev, EXTCON_USB_HOST, false);
+               dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+       } else {
+               extcon_set_cable_state_(edev, EXTCON_USB_HOST, true);
+               dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
+       }
+}
+
+static irqreturn_t palmas_gpio_id_irq_handler(int irq, void *_palmas_usb)
+{
+       struct palmas_usb *palmas_usb = _palmas_usb;
+
+       queue_delayed_work(system_power_efficient_wq, &palmas_usb->wq_detectid,
+                          palmas_usb->sw_debounce_jiffies);
+
+       return IRQ_HANDLED;
+}
+
 static void palmas_enable_irq(struct palmas_usb *palmas_usb)
 {
        palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
                PALMAS_USB_VBUS_CTRL_SET,
                PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP);
 
-       palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-               PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
+       if (palmas_usb->enable_id_detection) {
+               palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
+                            PALMAS_USB_ID_CTRL_SET,
+                            PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
 
-       palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-               PALMAS_USB_ID_INT_EN_HI_SET,
-               PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
-               PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
+               palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
+                            PALMAS_USB_ID_INT_EN_HI_SET,
+                            PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
+                            PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
+       }
 
        if (palmas_usb->enable_vbus_detection)
                palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
@@ -171,20 +209,37 @@ static int palmas_usb_probe(struct platform_device *pdev)
                        palmas_usb->wakeup = pdata->wakeup;
        }
 
+       palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id",
+                                                       GPIOD_IN);
+       if (IS_ERR(palmas_usb->id_gpiod)) {
+               dev_err(&pdev->dev, "failed to get id gpio\n");
+               return PTR_ERR(palmas_usb->id_gpiod);
+       }
+
+       if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) {
+               palmas_usb->enable_id_detection = false;
+               palmas_usb->enable_gpio_id_detection = true;
+       }
+
+       if (palmas_usb->enable_gpio_id_detection) {
+               u32 debounce;
+
+               if (of_property_read_u32(node, "debounce-delay-ms", &debounce))
+                       debounce = USB_GPIO_DEBOUNCE_MS;
+
+               status = gpiod_set_debounce(palmas_usb->id_gpiod,
+                                           debounce * 1000);
+               if (status < 0)
+                       palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce);
+       }
+
+       INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect);
+
        palmas->usb = palmas_usb;
        palmas_usb->palmas = palmas;
 
        palmas_usb->dev  = &pdev->dev;
 
-       palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
-                                               PALMAS_ID_OTG_IRQ);
-       palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
-                                               PALMAS_ID_IRQ);
-       palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
-                                               PALMAS_VBUS_OTG_IRQ);
-       palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
-                                               PALMAS_VBUS_IRQ);
-
        palmas_usb_wakeup(palmas, palmas_usb->wakeup);
 
        platform_set_drvdata(pdev, palmas_usb);
@@ -195,7 +250,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to allocate extcon device\n");
                return -ENOMEM;
        }
-       palmas_usb->edev->mutually_exclusive = mutually_exclusive;
 
        status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
        if (status) {
@@ -204,6 +258,10 @@ static int palmas_usb_probe(struct platform_device *pdev)
        }
 
        if (palmas_usb->enable_id_detection) {
+               palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
+                                                            PALMAS_ID_OTG_IRQ);
+               palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
+                                                        PALMAS_ID_IRQ);
                status = devm_request_threaded_irq(palmas_usb->dev,
                                palmas_usb->id_irq,
                                NULL, palmas_id_irq_handler,
@@ -215,9 +273,33 @@ static int palmas_usb_probe(struct platform_device *pdev)
                                        palmas_usb->id_irq, status);
                        return status;
                }
+       } else if (palmas_usb->enable_gpio_id_detection) {
+               palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod);
+               if (palmas_usb->gpio_id_irq < 0) {
+                       dev_err(&pdev->dev, "failed to get id irq\n");
+                       return palmas_usb->gpio_id_irq;
+               }
+               status = devm_request_threaded_irq(&pdev->dev,
+                                                  palmas_usb->gpio_id_irq,
+                                                  NULL,
+                                                  palmas_gpio_id_irq_handler,
+                                                  IRQF_TRIGGER_RISING |
+                                                  IRQF_TRIGGER_FALLING |
+                                                  IRQF_ONESHOT,
+                                                  "palmas_usb_id",
+                                                  palmas_usb);
+               if (status < 0) {
+                       dev_err(&pdev->dev,
+                               "failed to request handler for id irq\n");
+                       return status;
+               }
        }
 
        if (palmas_usb->enable_vbus_detection) {
+               palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
+                                                      PALMAS_VBUS_OTG_IRQ);
+               palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
+                                                          PALMAS_VBUS_IRQ);
                status = devm_request_threaded_irq(palmas_usb->dev,
                                palmas_usb->vbus_irq, NULL,
                                palmas_vbus_irq_handler,
@@ -232,10 +314,21 @@ static int palmas_usb_probe(struct platform_device *pdev)
        }
 
        palmas_enable_irq(palmas_usb);
+       /* perform initial detection */
+       palmas_gpio_id_detect(&palmas_usb->wq_detectid.work);
        device_set_wakeup_capable(&pdev->dev, true);
        return 0;
 }
 
+static int palmas_usb_remove(struct platform_device *pdev)
+{
+       struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
+
+       cancel_delayed_work_sync(&palmas_usb->wq_detectid);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int palmas_usb_suspend(struct device *dev)
 {
@@ -246,6 +339,8 @@ static int palmas_usb_suspend(struct device *dev)
                        enable_irq_wake(palmas_usb->vbus_irq);
                if (palmas_usb->enable_id_detection)
                        enable_irq_wake(palmas_usb->id_irq);
+               if (palmas_usb->enable_gpio_id_detection)
+                       enable_irq_wake(palmas_usb->gpio_id_irq);
        }
        return 0;
 }
@@ -259,6 +354,8 @@ static int palmas_usb_resume(struct device *dev)
                        disable_irq_wake(palmas_usb->vbus_irq);
                if (palmas_usb->enable_id_detection)
                        disable_irq_wake(palmas_usb->id_irq);
+               if (palmas_usb->enable_gpio_id_detection)
+                       disable_irq_wake(palmas_usb->gpio_id_irq);
        }
        return 0;
 };
@@ -276,6 +373,7 @@ static const struct of_device_id of_palmas_match_tbl[] = {
 
 static struct platform_driver palmas_usb_driver = {
        .probe = palmas_usb_probe,
+       .remove = palmas_usb_remove,
        .driver = {
                .name = "palmas-usb",
                .of_match_table = of_palmas_match_tbl,
index 92c939221a41fa1177bc31395f827d8af2b9b5a7..11592e980bc18f2885d91b61720b2b24e943aa0e 100644 (file)
@@ -693,7 +693,6 @@ MODULE_DEVICE_TABLE(i2c, rt8973a_i2c_id);
 static struct i2c_driver rt8973a_muic_i2c_driver = {
        .driver         = {
                .name   = "rt8973a",
-               .owner  = THIS_MODULE,
                .pm     = &rt8973a_muic_pm_ops,
                .of_match_table = rt8973a_dt_match,
        },
index 817dece23b4c2c2048ca190e8b2645de57408dcf..0ffefefa2e260ac9f9a12794befc84b3d1a14d18 100644 (file)
@@ -685,7 +685,6 @@ MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
 static struct i2c_driver sm5502_muic_i2c_driver = {
        .driver         = {
                .name   = "sm5502",
-               .owner  = THIS_MODULE,
                .pm     = &sm5502_muic_pm_ops,
                .of_match_table = sm5502_dt_match,
        },
index a2a44536a608c2c1e300c8c02b40cd1e96bc5f0e..2b2fecffb1ad647ba1b0184da3872fef3a287c23 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/extcon.h>
+#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 43b57b02d050d197fe7994ea744231b7a580eb23..a07addde297be4576a9306d170feb5e9b910a6d8 100644 (file)
@@ -126,7 +126,7 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id
 
 static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
 {
-       unsigned int id = -EINVAL;
+       int id = -EINVAL;
        int i = 0;
 
        /* Find the id of extcon cable */
@@ -143,7 +143,7 @@ static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
 
 static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
 {
-       unsigned int id;
+       int id;
 
        if (edev->max_supported == 0)
                return -EINVAL;
@@ -172,14 +172,6 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
        int i, count = 0;
        struct extcon_dev *edev = dev_get_drvdata(dev);
 
-       if (edev->print_state) {
-               int ret = edev->print_state(edev, buf);
-
-               if (ret >= 0)
-                       return ret;
-               /* Use default if failed */
-       }
-
        if (edev->max_supported == 0)
                return sprintf(buf, "%u\n", edev->state);
 
@@ -272,6 +264,9 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
        unsigned long flags;
        bool attached;
 
+       if (!edev)
+               return -EINVAL;
+
        spin_lock_irqsave(&edev->lock, flags);
 
        if (edev->state != ((edev->state & ~mask) | (state & mask))) {
@@ -345,6 +340,9 @@ EXPORT_SYMBOL_GPL(extcon_update_state);
  */
 int extcon_set_state(struct extcon_dev *edev, u32 state)
 {
+       if (!edev)
+               return -EINVAL;
+
        return extcon_update_state(edev, 0xffffffff, state);
 }
 EXPORT_SYMBOL_GPL(extcon_set_state);
@@ -358,6 +356,9 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id)
 {
        int index;
 
+       if (!edev)
+               return -EINVAL;
+
        index = find_cable_index_by_id(edev, id);
        if (index < 0)
                return index;
@@ -378,7 +379,7 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
  */
 int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
 {
-       unsigned int id;
+       int id;
 
        id = find_cable_id_by_name(edev, cable_name);
        if (id < 0)
@@ -402,6 +403,9 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id,
        u32 state;
        int index;
 
+       if (!edev)
+               return -EINVAL;
+
        index = find_cable_index_by_id(edev, id);
        if (index < 0)
                return index;
@@ -426,7 +430,7 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
 int extcon_set_cable_state(struct extcon_dev *edev,
                        const char *cable_name, bool cable_state)
 {
-       unsigned int id;
+       int id;
 
        id = find_cable_id_by_name(edev, cable_name);
        if (id < 0)
@@ -444,6 +448,9 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
 {
        struct extcon_dev *sd;
 
+       if (!extcon_name)
+               return ERR_PTR(-EINVAL);
+
        mutex_lock(&extcon_dev_list_lock);
        list_for_each_entry(sd, &extcon_dev_list, entry) {
                if (!strcmp(sd->name, extcon_name))
@@ -572,6 +579,9 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
        unsigned long flags;
        int ret, idx;
 
+       if (!edev || !nb)
+               return -EINVAL;
+
        idx = find_cable_index_by_id(edev, id);
 
        spin_lock_irqsave(&edev->lock, flags);
@@ -594,6 +604,9 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
        unsigned long flags;
        int ret, idx;
 
+       if (!edev || !nb)
+               return -EINVAL;
+
        idx = find_cable_index_by_id(edev, id);
 
        spin_lock_irqsave(&edev->lock, flags);
@@ -654,6 +667,9 @@ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
 {
        struct extcon_dev *edev;
 
+       if (!supported_cable)
+               return ERR_PTR(-EINVAL);
+
        edev = kzalloc(sizeof(*edev), GFP_KERNEL);
        if (!edev)
                return ERR_PTR(-ENOMEM);
@@ -754,7 +770,7 @@ int extcon_dev_register(struct extcon_dev *edev)
                        return ret;
        }
 
-       if (!edev->supported_cable)
+       if (!edev || !edev->supported_cable)
                return -EINVAL;
 
        for (; edev->supported_cable[index] != EXTCON_NONE; index++);
@@ -960,6 +976,9 @@ void extcon_dev_unregister(struct extcon_dev *edev)
 {
        int index;
 
+       if (!edev)
+               return;
+
        mutex_lock(&extcon_dev_list_lock);
        list_del(&edev->entry);
        mutex_unlock(&extcon_dev_list_lock);
@@ -1066,6 +1085,9 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
        struct device_node *node;
        struct extcon_dev *edev;
 
+       if (!dev)
+               return ERR_PTR(-EINVAL);
+
        if (!dev->of_node) {
                dev_err(dev, "device does not have a device node entry\n");
                return ERR_PTR(-EINVAL);
index b16d929fa75f811c211d171abb9c2f96d64a930f..c0f8c4fc5d45ae01be88cc26e9a07c6d273c84ce 100644 (file)
@@ -27,8 +27,6 @@
 #define __LINUX_EXTCON_H__
 
 #include <linux/device.h>
-#include <linux/notifier.h>
-#include <linux/sysfs.h>
 
 /*
  * Define the unique id of supported external connectors
@@ -77,8 +75,6 @@ struct extcon_cable;
  *                     be attached simulataneously. {0x7, 0} is equivalent to
  *                     {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
  *                     can be no simultaneous connections.
- * @print_state:       An optional callback to override the method to print the
- *                     status of the extcon device.
  * @dev:               Device of this extcon.
  * @state:             Attach/detach state of this extcon. Do not provide at
  *                     register-time.
@@ -102,9 +98,6 @@ struct extcon_dev {
        const unsigned int *supported_cable;
        const u32 *mutually_exclusive;
 
-       /* Optional callbacks to override class functions */
-       ssize_t (*print_state)(struct extcon_dev *edev, char *buf);
-
        /* Internal data. Please do not set. */
        struct device dev;
        struct raw_notifier_head *nh;
index bb270bd03eedc3eb570555b9929b7ba652a38f6e..13e1d96935ed7248a645b9b207ef64577a4b2653 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/extcon.h>
+#include <linux/of_gpio.h>
 #include <linux/usb/phy_companion.h>
 
 #define PALMAS_NUM_CLIENTS             3
@@ -551,10 +552,16 @@ struct palmas_usb {
        int vbus_otg_irq;
        int vbus_irq;
 
+       int gpio_id_irq;
+       struct gpio_desc *id_gpiod;
+       unsigned long sw_debounce_jiffies;
+       struct delayed_work wq_detectid;
+
        enum palmas_usb_state linkstat;
        int wakeup;
        bool enable_vbus_detection;
        bool enable_id_detection;
+       bool enable_gpio_id_detection;
 };
 
 #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)