diff options
Diffstat (limited to 'drivers/power/supply/qcom/qpnp-smbcharger.c')
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-smbcharger.c | 137 |
1 files changed, 134 insertions, 3 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 819c002ae0fc..e61a9c96d681 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -43,6 +43,13 @@ #include <linux/ktime.h> #include <linux/extcon.h> #include <linux/pmic-voter.h> +#include <linux/cclogic-core.h> + +#define SUPPORT_CCLOGIC_EVENT_TYPE + +#ifdef CONFIG_MACH_ZUK_Z2_PLUS +#define SUPPORT_ONLY_5V_CHARGER +#endif /* Mask/Bit helpers */ #define _SMB_MASK(BITS, POS) \ @@ -293,6 +300,12 @@ struct smbchg_chip { struct votable *hvdcp_enable_votable; /* extcon for VBUS / ID notification to USB */ struct extcon_dev *extcon; + +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + struct notifier_block cclogic_notif; + int cclogic_attached; + wait_queue_head_t cclogic_wait_queue; +#endif }; enum qpnp_schg { @@ -300,6 +313,14 @@ enum qpnp_schg { QPNP_SCHG_LITE, }; +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE +enum cclogic_event { + USB_DETACHED, + USB_ATTACHED, + USB_REMOVE, +}; +#endif + static char *version_str[] = { [QPNP_SCHG] = "SCHG", [QPNP_SCHG_LITE] = "SCHG_LITE", @@ -680,6 +701,14 @@ static enum pwr_path_type smbchg_get_pwr_path(struct smbchg_chip *chip) #define USBIN_SRC_DET_BIT BIT(2) #define FMB_STS_MASK SMB_MASK(3, 0) #define USBID_GND_THRESHOLD 0x495 + +static int id_state = 0; +int get_usb_id_state(void) +{ + return id_state; +} +EXPORT_SYMBOL(get_usb_id_state); + static bool is_otg_present_schg(struct smbchg_chip *chip) { int rc; @@ -761,7 +790,7 @@ static bool is_otg_present(struct smbchg_chip *chip) if (chip->schg_version == QPNP_SCHG_LITE) return is_otg_present_schg_lite(chip); - return is_otg_present_schg(chip); + return is_otg_present_schg(chip) || cclogic_get_otg_state(); } #define USBIN_9V BIT(5) @@ -3859,6 +3888,7 @@ struct regulator_ops smbchg_otg_reg_ops = { #define USBIN_ADAPTER_9V 0x3 #define USBIN_ADAPTER_5V_9V_CONT 0x2 #define USBIN_ADAPTER_5V_UNREGULATED_9V 0x5 +#define USBIN_ADAPTER_5V 0x0 static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) { int rc = 0; @@ -3888,9 +3918,15 @@ static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) return rc; } +#ifdef SUPPORT_ONLY_5V_CHARGER + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + USBIN_CHGR_CFG, + 0xFF, USBIN_ADAPTER_5V); +#else rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USBIN_CHGR_CFG, 0xFF, USBIN_ADAPTER_9V); +#endif if (rc < 0) { dev_err(chip->dev, "Couldn't write usb allowance rc=%d\n", rc); return rc; @@ -4653,10 +4689,19 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) if (rc < 0) pr_err("Couldn't configure HVDCP 9V rc=%d\n", rc); +#ifdef SUPPORT_ONLY_5V_CHARGER + /* disable HVDCP */ + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + CHGPTH_CFG, + HVDCP_EN_BIT, 0); + if (rc < 0) + pr_err("Couldn't disable HVDCP rc=%d\n", rc); +#else /* enable HVDCP */ rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); if (rc < 0) pr_err("Couldn't enable HVDCP rc=%d\n", rc); +#endif /* enable APSD */ rc = smbchg_sec_masked_write(chip, @@ -4666,9 +4711,15 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) pr_err("Couldn't enable APSD rc=%d\n", rc); /* Reset back to 5V unregulated */ +#ifdef SUPPORT_ONLY_5V_CHARGER + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + USBIN_CHGR_CFG, + ADAPTER_ALLOWANCE_MASK, USBIN_ADAPTER_5V); +#else rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USBIN_CHGR_CFG, ADAPTER_ALLOWANCE_MASK, USBIN_ADAPTER_5V_UNREGULATED_9V); +#endif if (rc < 0) pr_err("Couldn't write usb allowance rc=%d\n", rc); @@ -4736,7 +4787,7 @@ static void handle_usb_removal(struct smbchg_chip *chip) /* cancel/wait for hvdcp pending work if any */ cancel_delayed_work_sync(&chip->hvdcp_det_work); smbchg_relax(chip, PM_DETECT_HVDCP); - smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN); + smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_USB); extcon_set_cable_state_(chip->extcon, EXTCON_USB, chip->usb_present); smbchg_request_dpdm(chip, false); schedule_work(&chip->usb_set_online_work); @@ -4933,7 +4984,7 @@ close_time: } #define AICL_IRQ_LIMIT_SECONDS 60 -#define AICL_IRQ_LIMIT_COUNT 25 +#define AICL_IRQ_LIMIT_COUNT 35 static void increment_aicl_count(struct smbchg_chip *chip) { bool bad_charger = false; @@ -5119,11 +5170,18 @@ static int fake_insertion_removal(struct smbchg_chip *chip, bool insertion) pr_smb(PR_MISC, "Allow only %s charger\n", insertion ? "5-9V" : "9V only"); +#ifdef SUPPORT_ONLY_5V_CHARGER + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + USBIN_CHGR_CFG, + ADAPTER_ALLOWANCE_MASK, + USBIN_ADAPTER_5V); +#else rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USBIN_CHGR_CFG, ADAPTER_ALLOWANCE_MASK, insertion ? USBIN_ADAPTER_5V_9V_CONT : USBIN_ADAPTER_9V); +#endif if (rc < 0) { pr_err("Couldn't write usb allowance rc=%d\n", rc); return rc; @@ -5305,6 +5363,17 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) return rc; } +#ifdef SUPPORT_ONLY_5V_CHARGER + /* disable HVDCP */ + pr_smb(PR_MISC, "Disable HVDCP\n"); + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + CHGPTH_CFG, + HVDCP_EN_BIT, 0); + if (rc < 0) { + pr_err("Couldn't disable HVDCP rc=%d\n", rc); + return rc; + } +#else /* enable HVDCP */ pr_smb(PR_MISC, "Enable HVDCP\n"); rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); @@ -5312,6 +5381,7 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) pr_err("Couldn't enable HVDCP rc=%d\n", rc); return rc; } +#endif /* enable APSD */ pr_smb(PR_MISC, "Enabling APSD\n"); @@ -5967,6 +6037,7 @@ static int smbchg_battery_set_property(struct power_supply *psy, rc = vote(chip->dc_suspend_votable, USER_EN_VOTER, !val->intval, 0); chip->chg_enabled = val->intval; + power_supply_changed(chip->usb_psy); schedule_work(&chip->usb_set_online_work); break; case POWER_SUPPLY_PROP_CAPACITY: @@ -6632,6 +6703,14 @@ static irqreturn_t usbin_uv_handler(int irq, void *_chip) schedule_work(&chip->usb_set_online_work); } +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + /* usb pull out, wakeup wq if wq waiting cclogic attached event */ + if (reg & USBIN_UV_BIT) { + chip->cclogic_attached = USB_REMOVE; + wake_up_interruptible(&chip->cclogic_wait_queue); + } +#endif + smbchg_wipower_check(chip); out: return IRQ_HANDLED; @@ -6651,6 +6730,9 @@ static irqreturn_t src_detect_handler(int irq, void *_chip) bool usb_present = is_usb_present(chip); bool src_detect = is_src_detect_high(chip); int rc; +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + int ret; +#endif pr_smb(PR_STATUS, "%s chip->usb_present = %d usb_present = %d src_detect = %d hvdcp_3_det_ignore_uv=%d\n", @@ -6691,6 +6773,15 @@ static irqreturn_t src_detect_handler(int irq, void *_chip) if (src_detect) { update_usb_status(chip, usb_present, 0); +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + ret = wait_event_interruptible_timeout(chip->cclogic_wait_queue, + (chip->cclogic_attached == USB_ATTACHED) || + (chip->cclogic_attached == USB_REMOVE), + msecs_to_jiffies(2500)); + pr_info("Waiting cclogic state ret = %d\n", ret); + if (ret == 0) + pr_err("Waiting cclogic state timeout\n"); +#endif } else { update_usb_status(chip, 0, false); chip->aicl_irq_count = 0; @@ -8230,6 +8321,25 @@ static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip) } } +/* + * cclogic callback, notify cclogic event status: detached or attached + */ +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE +static int cclogic_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + struct smbchg_chip *chip = container_of(self, struct smbchg_chip, cclogic_notif); + if (event == 1) { /* usb detached */ + chip->cclogic_attached = USB_DETACHED; + } else if (event == 2) { /* usb attached */ + chip->cclogic_attached = USB_ATTACHED; + wake_up_interruptible(&chip->cclogic_wait_queue); + } + pr_smb(PR_MISC, "setting cclogic_attached = %d\n", + chip->cclogic_attached); + return 0; +} +#endif + static int smbchg_probe(struct platform_device *pdev) { int rc; @@ -8446,6 +8556,10 @@ static int smbchg_probe(struct platform_device *pdev) goto votables_cleanup; } +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + init_waitqueue_head(&chip->cclogic_wait_queue); +#endif + 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"); @@ -8543,6 +8657,15 @@ static int smbchg_probe(struct platform_device *pdev) } chip->allow_hvdcp3_detection = true; +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE + chip->cclogic_notif.notifier_call = cclogic_notifier_callback; + rc = cclogic_register_client(&chip->cclogic_notif); + if (rc) { + pr_err("Unable to register cclogic_notifier : %d\n", rc); + goto unregister_dc_psy1; + } +#endif + if (chip->cfg_chg_led_support && chip->schg_version == QPNP_SCHG_LITE) { rc = smbchg_register_chg_led(chip); @@ -8585,6 +8708,10 @@ static int smbchg_probe(struct platform_device *pdev) unregister_led_class: if (chip->cfg_chg_led_support && chip->schg_version == QPNP_SCHG_LITE) led_classdev_unregister(&chip->led_cdev); +#ifdef SUPPORT_CCLOGIC_EVENT_TYPE +unregister_dc_psy1: + cclogic_unregister_client(&chip->cclogic_notif); +#endif out: handle_usb_removal(chip); votables_cleanup: @@ -8617,6 +8744,10 @@ static int smbchg_remove(struct platform_device *pdev) debugfs_remove_recursive(chip->debug_root); +#ifdef SUPPORT_SCREEN_ON_FCC_OP + fb_unregister_client(&chip->fb_notif); +#endif + destroy_votable(chip->aicl_deglitch_short_votable); destroy_votable(chip->hw_aicl_rerun_enable_indirect_votable); destroy_votable(chip->hw_aicl_rerun_disable_votable); |
