summaryrefslogtreecommitdiff
path: root/drivers/power/supply/qcom/qpnp-smbcharger.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/supply/qcom/qpnp-smbcharger.c')
-rw-r--r--drivers/power/supply/qcom/qpnp-smbcharger.c137
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);