From ee53d51499cf3b94b3d78513f3160eca68634386 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 16 Mar 2016 11:38:40 -0700 Subject: [PATCH] power: qpnp-smbcharger: Add extcon notifiers for USB Allow charger to expose an extcon device which can emit notification for USB and USB-HOST cable connection states. The driver can correspondingly register interest in being notified of these cable connection statuses. This is intended to replace the power_supply_set_present() and power_supply_set_usb_otg() mechanisms currently used. Change-Id: I6c7cf971f59ac3f3075f5c8f13786306729f25a8 Signed-off-by: Jack Pham --- drivers/power/Kconfig | 1 + drivers/power/qpnp-smbcharger.c | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index b194a89a103a..61c19907d0cf 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -523,6 +523,7 @@ config AXP20X_POWER config QPNP_SMBCHARGER tristate "QPNP SMB Charger driver" depends on SPMI + depends on EXTCON help Say Y here to enable the dual path switch mode battery charger which supports USB detection and battery charging up to 3A. diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index 12375aeb2818..ca6bba0582e5 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "pmic-voter.h" /* Mask/Bit helpers */ @@ -280,6 +281,9 @@ struct smbchg_chip { struct votable *hw_aicl_rerun_disable_votable; struct votable *hw_aicl_rerun_enable_indirect_votable; struct votable *aicl_deglitch_short_votable; + + /* extcon for VBUS / ID notification to USB */ + struct extcon_dev *extcon; }; enum qpnp_schg { @@ -419,6 +423,13 @@ enum aicl_short_deglitch_voters { HVDCP_SHORT_DEGLITCH_VOTER, NUM_HW_SHORT_DEGLITCH_VOTERS, }; + +static const unsigned int smbchg_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + static int smbchg_debug_mask; module_param_named( debug_mask, smbchg_debug_mask, int, S_IRUSR | S_IWUSR @@ -4524,6 +4535,7 @@ static void handle_usb_removal(struct smbchg_chip *chip) power_supply_set_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &pval); } + extcon_set_cable_state_(chip->extcon, EXTCON_USB, chip->usb_present); set_usb_psy_dp_dm(chip, POWER_SUPPLY_DP_DM_DPR_DMR); schedule_work(&chip->usb_set_online_work); @@ -4615,6 +4627,12 @@ static void handle_usb_insertion(struct smbchg_chip *chip) POWER_SUPPLY_PROP_PRESENT, &pval); } + /* Only notify USB if it's not a charger */ + if (usb_supply_type == POWER_SUPPLY_TYPE_USB || + usb_supply_type == POWER_SUPPLY_TYPE_USB_CDP) + extcon_set_cable_state_(chip->extcon, EXTCON_USB, + chip->usb_present); + /* Notify the USB psy if OV condition is not present */ if (!chip->usb_ov_det) { /* @@ -5524,6 +5542,8 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode, pval.intval = 1; power_supply_set_property(chip->usb_psy, POWER_SUPPLY_PROP_USB_OTG, &pval); + extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, + chip->typec_dfp); /* update FG */ set_property_on_fg(chip, POWER_SUPPLY_PROP_STATUS, get_prop_batt_status(chip)); @@ -5532,6 +5552,8 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode, pval.intval = 0; power_supply_set_property(chip->usb_psy, POWER_SUPPLY_PROP_USB_OTG, &pval); + extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, + chip->typec_dfp); /* update FG */ set_property_on_fg(chip, POWER_SUPPLY_PROP_STATUS, get_prop_batt_status(chip)); @@ -6418,6 +6440,9 @@ static irqreturn_t usbid_change_handler(int irq, void *_chip) power_supply_set_property(chip->usb_psy, POWER_SUPPLY_PROP_USB_OTG, &pval); } + + extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, otg_present); + if (otg_present) pr_smb(PR_STATUS, "OTG detected\n"); @@ -8018,6 +8043,18 @@ static int smbchg_probe(struct platform_device *pdev) return rc; } + chip->extcon = devm_extcon_dev_allocate(chip->dev, smbchg_extcon_cable); + if (IS_ERR(chip->extcon)) { + dev_err(chip->dev, "failed to allocate extcon device\n"); + return PTR_ERR(chip->extcon); + } + + rc = devm_extcon_dev_register(chip->dev, chip->extcon); + if (rc) { + dev_err(chip->dev, "failed to register extcon device\n"); + return rc; + } + rc = smbchg_hw_init(chip); if (rc < 0) { dev_err(&pdev->dev,