168 lines
4.8 KiB
Diff
168 lines
4.8 KiB
Diff
|
From 0f7667b7fbbea13855b4a34b4cf17595357463f0 Mon Sep 17 00:00:00 2001
|
||
|
From: Sergey Larin <cerg2010cerg2010@mail.ru>
|
||
|
Date: Thu, 20 Jun 2019 20:19:35 +0300
|
||
|
Subject: [PATCH] power: supply: Add regulator to max8903 charger for VBUS
|
||
|
control
|
||
|
|
||
|
When OTG cable is inserted, the host needs to enable VBUS in order to
|
||
|
supply power to the connected device. However, the charger detects that
|
||
|
and starts charging the battery, draining the supplied power.
|
||
|
|
||
|
Avoid this by using an optional regulator subnode which disables charging
|
||
|
when enabled.
|
||
|
|
||
|
Signed-off-by: Sergey Larin <cerg2010cerg2010@mail.ru>
|
||
|
---
|
||
|
drivers/power/supply/Kconfig | 1 +
|
||
|
drivers/power/supply/max8903_charger.c | 72 +++++++++++++++++++++++++-
|
||
|
2 files changed, 72 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
|
||
|
index dd7da41f230c..9d394ae8a3b8 100644
|
||
|
--- a/drivers/power/supply/Kconfig
|
||
|
+++ b/drivers/power/supply/Kconfig
|
||
|
@@ -440,6 +440,7 @@ config CHARGER_ISP1704
|
||
|
|
||
|
config CHARGER_MAX8903
|
||
|
tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
|
||
|
+ depends on REGULATOR
|
||
|
help
|
||
|
Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
|
||
|
The driver supports controlling charger-enable and current-limit
|
||
|
diff --git a/drivers/power/supply/max8903_charger.c b/drivers/power/supply/max8903_charger.c
|
||
|
index 0bd39b0cc257..465fdae7179b 100644
|
||
|
--- a/drivers/power/supply/max8903_charger.c
|
||
|
+++ b/drivers/power/supply/max8903_charger.c
|
||
|
@@ -16,15 +16,18 @@
|
||
|
#include <linux/power_supply.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/power/max8903_charger.h>
|
||
|
+#include <linux/regulator/driver.h>
|
||
|
|
||
|
struct max8903_data {
|
||
|
struct max8903_pdata *pdata;
|
||
|
struct device *dev;
|
||
|
struct power_supply *psy;
|
||
|
struct power_supply_desc psy_desc;
|
||
|
+ struct regulator_desc otg_rdesc;
|
||
|
bool fault;
|
||
|
bool usb_in;
|
||
|
bool ta_in;
|
||
|
+ bool otg_en;
|
||
|
};
|
||
|
|
||
|
static enum power_supply_property max8903_charger_props[] = {
|
||
|
@@ -43,7 +46,7 @@ static int max8903_get_property(struct power_supply *psy,
|
||
|
case POWER_SUPPLY_PROP_STATUS:
|
||
|
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||
|
if (gpio_is_valid(data->pdata->chg)) {
|
||
|
- if (gpio_get_value(data->pdata->chg) == 0)
|
||
|
+ if (gpio_get_value_cansleep(data->pdata->chg) == 0)
|
||
|
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||
|
else if (data->usb_in || data->ta_in)
|
||
|
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||
|
@@ -75,6 +78,8 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
|
||
|
bool ta_in;
|
||
|
enum power_supply_type old_type;
|
||
|
|
||
|
+ /* Do not touch OTG mode */
|
||
|
+
|
||
|
ta_in = gpio_get_value(pdata->dok) ? false : true;
|
||
|
|
||
|
if (ta_in == data->ta_in)
|
||
|
@@ -116,6 +121,10 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
|
||
|
bool usb_in;
|
||
|
enum power_supply_type old_type;
|
||
|
|
||
|
+ /* Don't do anything if OTG is active */
|
||
|
+ if (data->otg_en)
|
||
|
+ return IRQ_HANDLED;
|
||
|
+
|
||
|
usb_in = gpio_get_value(pdata->uok) ? false : true;
|
||
|
|
||
|
if (usb_in == data->usb_in)
|
||
|
@@ -330,12 +339,55 @@ static int max8903_setup_gpios(struct platform_device *pdev)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int max8903_otg_enable(struct regulator_dev *rdev)
|
||
|
+{
|
||
|
+ struct max8903_data *data = rdev_get_drvdata(rdev);
|
||
|
+ struct max8903_pdata *pdata = data->pdata;
|
||
|
+
|
||
|
+ /* Disable charging */
|
||
|
+ data->otg_en = true;
|
||
|
+ if (data->usb_in)
|
||
|
+ gpio_set_value(pdata->cen, 1);
|
||
|
+ data->usb_in = false;
|
||
|
+
|
||
|
+ if (data->psy_desc.type != POWER_SUPPLY_TYPE_BATTERY)
|
||
|
+ {
|
||
|
+ data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
|
||
|
+ power_supply_changed(data->psy);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int max8903_otg_disable(struct regulator_dev *rdev)
|
||
|
+{
|
||
|
+ struct max8903_data *data = rdev_get_drvdata(rdev);
|
||
|
+
|
||
|
+ /* Enable charging */
|
||
|
+ data->otg_en = false;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int max8903_otg_is_enabled(struct regulator_dev *rdev)
|
||
|
+{
|
||
|
+ struct max8903_data *data = rdev_get_drvdata(rdev);
|
||
|
+ return data->otg_en;
|
||
|
+}
|
||
|
+
|
||
|
+struct regulator_ops otg_ops = {
|
||
|
+ .enable = max8903_otg_enable,
|
||
|
+ .disable = max8903_otg_disable,
|
||
|
+ .is_enabled = max8903_otg_is_enabled,
|
||
|
+};
|
||
|
+
|
||
|
static int max8903_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
struct max8903_data *data;
|
||
|
struct device *dev = &pdev->dev;
|
||
|
struct max8903_pdata *pdata = pdev->dev.platform_data;
|
||
|
struct power_supply_config psy_cfg = {};
|
||
|
+ struct regulator_config config = {};
|
||
|
+ struct regulator_dev *otg_reg;
|
||
|
int ret = 0;
|
||
|
|
||
|
data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
|
||
|
@@ -420,6 +472,24 @@ static int max8903_probe(struct platform_device *pdev)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ data->otg_rdesc.id = -1;
|
||
|
+ data->otg_rdesc.name = "otg-vbus";
|
||
|
+ data->otg_rdesc.ops = &otg_ops;
|
||
|
+ data->otg_rdesc.owner = THIS_MODULE;
|
||
|
+ data->otg_rdesc.type = REGULATOR_VOLTAGE;
|
||
|
+ data->otg_rdesc.supply_name = "usb-otg-in";
|
||
|
+ data->otg_rdesc.of_match = of_match_ptr("otg-vbus");
|
||
|
+
|
||
|
+ config.dev = dev;
|
||
|
+ config.driver_data = data;
|
||
|
+
|
||
|
+ otg_reg = devm_regulator_register(dev, &data->otg_rdesc,
|
||
|
+ &config);
|
||
|
+ if (IS_ERR(otg_reg))
|
||
|
+ {
|
||
|
+ dev_info(dev, "regulator not registered");
|
||
|
+ }
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.22.0
|
||
|
|