power: supply: bq24190_charger: add extcon support for USB OTG
authorBrian Masney <masneyb@onstation.org>
Thu, 1 Nov 2018 00:11:46 +0000 (20:11 -0400)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Wed, 5 Dec 2018 21:53:32 +0000 (22:53 +0100)
Add extcon support so that we can notify USB drivers of cable state
changes. Based on work from Jonathan Marek. USB OTG was tested on a LG
Nexus 5 (hammerhead) phone.

Signed-off-by: Brian Masney <masneyb@onstation.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/bq24190_charger.c

index 9e7f3e33458ae41517a909786a197834389dcd09..4e64e6ac95c559b3668895a5cd9abff3db15fb39 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/extcon-provider.h>
 
 #define        BQ24190_MANUFACTURER    "Texas Instruments"
 
 struct bq24190_dev_info {
        struct i2c_client               *client;
        struct device                   *dev;
+       struct extcon_dev               *edev;
        struct power_supply             *charger;
        struct power_supply             *battery;
        struct delayed_work             input_current_limit_work;
@@ -174,6 +176,11 @@ struct bq24190_dev_info {
        u8                              watchdog;
 };
 
+static const unsigned int bq24190_usb_extcon_cable[] = {
+       EXTCON_USB,
+       EXTCON_NONE,
+};
+
 /*
  * The tables below provide a 2-way mapping for the value that goes in
  * the register field and the real-world value that it represents.
@@ -1528,6 +1535,20 @@ static const struct power_supply_desc bq24190_battery_desc = {
        .property_is_writeable  = bq24190_battery_property_is_writeable,
 };
 
+static int bq24190_configure_usb_otg(struct bq24190_dev_info *bdi, u8 ss_reg)
+{
+       bool otg_enabled;
+       int ret;
+
+       otg_enabled = !!(ss_reg & BQ24190_REG_SS_VBUS_STAT_MASK);
+       ret = extcon_set_state_sync(bdi->edev, EXTCON_USB, otg_enabled);
+       if (ret < 0)
+               dev_err(bdi->dev, "Can't set extcon state to %d: %d\n",
+                       otg_enabled, ret);
+
+       return ret;
+}
+
 static void bq24190_check_status(struct bq24190_dev_info *bdi)
 {
        const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
@@ -1597,8 +1618,10 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi)
                bdi->ss_reg = ss_reg;
        }
 
-       if (alert_charger || alert_battery)
+       if (alert_charger || alert_battery) {
                power_supply_changed(bdi->charger);
+               bq24190_configure_usb_otg(bdi, ss_reg);
+       }
        if (alert_battery && bdi->battery)
                power_supply_changed(bdi->battery);
 
@@ -1732,6 +1755,14 @@ static int bq24190_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
+       bdi->edev = devm_extcon_dev_allocate(dev, bq24190_usb_extcon_cable);
+       if (IS_ERR(bdi->edev))
+               return PTR_ERR(bdi->edev);
+
+       ret = devm_extcon_dev_register(dev, bdi->edev);
+       if (ret < 0)
+               return ret;
+
        pm_runtime_enable(dev);
        pm_runtime_use_autosuspend(dev);
        pm_runtime_set_autosuspend_delay(dev, 600);
@@ -1778,6 +1809,10 @@ static int bq24190_probe(struct i2c_client *client,
                goto out_charger;
        }
 
+       ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg);
+       if (ret < 0)
+               goto out_charger;
+
        ret = bq24190_sysfs_create_group(bdi);
        if (ret < 0) {
                dev_err(dev, "Can't create sysfs entries\n");