Merge "power: smb1351-charger: Add support for OTG IRQ"

This commit is contained in:
qctecmdr 2021-01-14 15:49:40 -08:00 • committed by Gerrit - the friendly Code Review server
commit 75d39d367e

View file

@ -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,15 +8,18 @@
#include <linux/i2c.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/extcon.h>
#include <linux/extcon-provider.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/pinctrl/consumer.h>
@ -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 {
@ -1135,8 +1140,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 +1227,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 +1325,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 +1392,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 +1401,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 +1418,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 +1448,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 +1501,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 +1531,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 +1573,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 +1584,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 +1707,8 @@ static int smb1351_apsd_complete_handler(struct smb1351_charger *chip,
smb1351_request_dpdm(chip, false);
}
smb1351_update_desc_type(chip);
return 0;
}
@ -2058,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)
{
@ -2396,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:
@ -2457,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)
{
@ -2502,6 +2578,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;
@ -2576,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);
@ -2596,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);