From ad4702457c1449a7294356fafe4ccaedb98df256 Mon Sep 17 00:00:00 2001 From: Kavya Nunna Date: Tue, 24 Nov 2020 14:34:35 +0530 Subject: [PATCH 1/2] power: supply: smb1351: Add support to make SMB1351 driver GKI complaint Replace existing non standard power supply properties with standard power supply properties to make the smb1351 driver GKI complaint. Change-Id: Iec18b6f267c30739928d85fd10ca676b17102a11 Signed-off-by: Kavya Nunna --- drivers/power/supply/qcom/smb1351-charger.c | 105 +++++++++++++------- 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c index 2c010d5575bb..d1f4a17bd1ff 100644 --- a/drivers/power/supply/qcom/smb1351-charger.c +++ b/drivers/power/supply/qcom/smb1351-charger.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -1135,8 +1135,7 @@ static int smb1351_hw_init(struct smb1351_charger *chip) static enum power_supply_property smb1351_battery_properties[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_CHARGING_ENABLED, - POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_HEALTH, @@ -1223,7 +1222,7 @@ static int smb1351_get_prop_charge_type(struct smb1351_charger *chip) if (reg == STATUS_FAST_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_FAST; else if (reg == STATUS_TAPER_CHARGING) - return POWER_SUPPLY_CHARGE_TYPE_TAPER; + return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE; else if (reg == STATUS_PRE_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; else @@ -1321,15 +1320,65 @@ static char *smb1351_usb_supplicants[] = { "bms", }; +static enum power_supply_usb_type smb1351_usb_psy_supported_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_DCP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_ACA, +}; + static enum power_supply_property smb1351_usb_properties[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CURRENT_MAX, - POWER_SUPPLY_PROP_TYPE, - POWER_SUPPLY_PROP_REAL_TYPE, - POWER_SUPPLY_PROP_SDP_CURRENT_MAX, + POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, }; +static void smb1351_update_desc_type(struct smb1351_charger *chip) +{ + switch (chip->charger_type) { + case POWER_SUPPLY_TYPE_USB_CDP: + case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB: + case POWER_SUPPLY_TYPE_USB_ACA: + chip->usb_psy_d.type = chip->charger_type; + break; + case POWER_SUPPLY_TYPE_USB_HVDCP: + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB_DCP; + break; + default: + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB; + break; + } +} + +static void smb1351_get_usb_type(struct smb1351_charger *chip, + union power_supply_propval *val) +{ + switch (chip->charger_type) { + case POWER_SUPPLY_TYPE_USB_CDP: + val->intval = POWER_SUPPLY_USB_TYPE_CDP; + break; + case POWER_SUPPLY_TYPE_USB_DCP: + val->intval = POWER_SUPPLY_USB_TYPE_DCP; + break; + case POWER_SUPPLY_TYPE_USB: + val->intval = POWER_SUPPLY_USB_TYPE_SDP; + break; + case POWER_SUPPLY_TYPE_USB_ACA: + val->intval = POWER_SUPPLY_USB_TYPE_ACA; + break; + case POWER_SUPPLY_TYPE_USB_HVDCP: + val->intval = POWER_SUPPLY_USB_TYPE_DCP; + break; + default: + val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN; + break; + } +} + static int smb1351_usb_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -1338,7 +1387,7 @@ static int smb1351_usb_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CURRENT_MAX: - case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: val->intval = chip->usb_psy_ma * 1000; break; case POWER_SUPPLY_PROP_PRESENT: @@ -1347,16 +1396,8 @@ static int smb1351_usb_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: val->intval = chip->chg_present && !chip->usb_suspended_status; break; - case POWER_SUPPLY_PROP_TYPE: - val->intval = chip->charger_type; - break; - case POWER_SUPPLY_PROP_REAL_TYPE: - if (chip->charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) - val->intval = POWER_SUPPLY_TYPE_USB_DCP; - else if (chip->charger_type == POWER_SUPPLY_TYPE_UNKNOWN) - val->intval = POWER_SUPPLY_TYPE_USB; - else - val->intval = chip->charger_type; + case POWER_SUPPLY_PROP_USB_TYPE: + smb1351_get_usb_type(chip, val); break; default: return -EINVAL; @@ -1372,7 +1413,7 @@ static int smb1351_usb_set_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CURRENT_MAX: - case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: chip->usb_psy_ma = val->intval / 1000; smb1351_enable_volatile_writes(chip); smb1351_set_usb_chg_current(chip, chip->usb_psy_ma); @@ -1402,8 +1443,7 @@ static int smb1351_batt_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { - case POWER_SUPPLY_PROP_CHARGING_ENABLED: - case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: case POWER_SUPPLY_PROP_CAPACITY: return 1; default: @@ -1456,12 +1496,9 @@ static int smb1351_battery_set_property(struct power_supply *psy, return -EINVAL; } break; - case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: smb1351_usb_suspend(chip, USER, !val->intval); break; - case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED: - smb1351_battchg_disable(chip, USER, !val->intval); - break; case POWER_SUPPLY_PROP_CAPACITY: chip->fake_battery_soc = val->intval; power_supply_changed(chip->batt_psy); @@ -1489,12 +1526,9 @@ static int smb1351_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = smb1351_get_prop_batt_capacity(chip); break; - case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: val->intval = !chip->usb_suspended_status; break; - case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED: - val->intval = !chip->battchg_disabled_status; - break; case POWER_SUPPLY_PROP_CHARGE_TYPE: val->intval = smb1351_get_prop_charge_type(chip); break; @@ -1534,7 +1568,6 @@ static void smb1351_hvdcp_det_work(struct work_struct *work) { int rc; u8 reg; - union power_supply_propval pval = {0, }; struct smb1351_charger *chip = container_of(work, struct smb1351_charger, hvdcp_det_work.work); @@ -1546,12 +1579,6 @@ static void smb1351_hvdcp_det_work(struct work_struct *work) } pr_debug("STATUS_7_REG = 0x%02X\n", reg); - if (reg) { - pr_debug("HVDCP detected; notifying USB PSY\n"); - pval.intval = POWER_SUPPLY_TYPE_USB_HVDCP; - power_supply_set_property(chip->usb_psy, - POWER_SUPPLY_PROP_TYPE, &pval); - } end: pm_relax(chip->dev); } @@ -1675,6 +1702,8 @@ static int smb1351_apsd_complete_handler(struct smb1351_charger *chip, smb1351_request_dpdm(chip, false); } + smb1351_update_desc_type(chip); + return 0; } @@ -2502,6 +2531,8 @@ static int smb1351_main_charger_probe(struct i2c_client *client, chip->usb_psy_d.get_property = smb1351_usb_get_property; chip->usb_psy_d.set_property = smb1351_usb_set_property; chip->usb_psy_d.properties = smb1351_usb_properties; + chip->usb_psy_d.usb_types = smb1351_usb_psy_supported_types, + chip->usb_psy_d.num_usb_types = ARRAY_SIZE(smb1351_usb_psy_supported_types); chip->usb_psy_d.num_properties = ARRAY_SIZE(smb1351_usb_properties); chip->usb_psy_d.property_is_writeable = smb1351_usb_is_writeable; From dfc409f9b1d5f911b4a4eebbce884c85e3ecb688 Mon Sep 17 00:00:00 2001 From: Kavya Nunna Date: Thu, 24 Dec 2020 17:44:47 +0530 Subject: [PATCH 2/2] power: smb1351-charger: Add support for OTG IRQ SMB1351 does not have a USB_ID detection logic. Add support for handling the ID detection over a dedicated GPIO. Change-Id: Iadaf9344ab00bec1b173516a5004187e98e89302 Signed-off-by: Kavya Nunna --- drivers/power/supply/qcom/smb1351-charger.c | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c index d1f4a17bd1ff..ff4aeec39d03 100644 --- a/drivers/power/supply/qcom/smb1351-charger.c +++ b/drivers/power/supply/qcom/smb1351-charger.c @@ -11,12 +11,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -493,6 +496,8 @@ struct smb1351_charger { struct regulator *dpdm_reg; enum power_supply_type charger_type; bool otg_enable; + int usb_id_gpio; + int usb_id_irq; }; struct smb_irq_info { @@ -2087,6 +2092,27 @@ static irqreturn_t smb1351_chg_stat_handler(int irq, void *dev_id) return IRQ_HANDLED; } +irqreturn_t smb1351_usb_id_irq_handler(int irq, void *data) +{ + struct smb1351_charger *chip = data; + bool id_state; + int rc = 0; + + id_state = gpio_get_value(chip->usb_id_gpio); + pr_debug("id_state=%d\n", id_state); + + rc = smb1351_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, + id_state ? 0 : CMD_OTG_EN_BIT); + if (rc < 0) + pr_err("Failed to %s OTG\n", id_state ? "disable" : "enable"); + else + pr_debug("SMB1351 OTG %s\n", id_state ? "disabled" : "enabled"); + + extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, !id_state); + + return IRQ_HANDLED; +} + #define LAST_CNFG_REG 0x16 static int show_cnfg_regs(struct seq_file *m, void *data) { @@ -2425,6 +2451,9 @@ static int smb1351_determine_initial_state(struct smb1351_charger *chip) smb1351_apsd_complete_handler(chip, 1); } + if (chip->usb_id_gpio > 0) + smb1351_usb_id_irq_handler(0, chip); + return 0; fail_init_status: @@ -2486,6 +2515,24 @@ static int create_debugfs_entries(struct smb1351_charger *chip) return 0; } +static int smb1351_init_otg(struct smb1351_charger *chip) +{ + chip->usb_id_gpio = chip->usb_id_irq = -EINVAL; + + if (of_find_property(chip->dev->of_node, "qcom,usb-id-gpio", NULL)) + chip->usb_id_gpio = of_get_named_gpio(chip->dev->of_node, + "qcom,usb-id-gpio", 0); + + chip->usb_id_irq = of_irq_get_byname(chip->dev->of_node, + "smb1351_usb_id_irq"); + + if (chip->usb_id_irq < 0 || chip->usb_id_gpio < 0) + pr_err("OTG irq (%d) / gpio (%d) not defined\n", + chip->usb_id_irq, chip->usb_id_gpio); + + return 0; +} + static int smb1351_main_charger_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2607,6 +2654,12 @@ static int smb1351_main_charger_probe(struct i2c_client *client, goto fail_smb1351_hw_init; } + rc = smb1351_init_otg(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't init otg rc=%d\n", rc); + return rc; + } + rc = smb1351_determine_initial_state(chip); if (rc) { pr_err("Couldn't determine initial state rc=%d\n", rc); @@ -2627,6 +2680,22 @@ static int smb1351_main_charger_probe(struct i2c_client *client, enable_irq_wake(client->irq); } + if (chip->usb_id_irq > 0 && chip->usb_id_gpio > 0) { + rc = devm_request_threaded_irq(chip->dev, + chip->usb_id_irq, NULL, + smb1351_usb_id_irq_handler, + IRQF_ONESHOT + | IRQF_TRIGGER_FALLING + | IRQF_TRIGGER_RISING, + "smb1351_usb_id_irq", chip); + + if (rc < 0) { + pr_err("Failed to register id-irq rc=%d\n", rc); + return rc; + } + enable_irq_wake(chip->usb_id_irq); + } + create_debugfs_entries(chip); dump_regs(chip);