Skip to content

Commit

Permalink
power: supply: max8997_charger: Set CHARGER current limit
Browse files Browse the repository at this point in the history
Register for extcon notification and set charging current depending on
the detected cable type. Current values are taken from vendor kernel,
where most charger types end up setting 650mA [0].

Also enable and disable the CHARGER regulator based on extcon events.

[0] https://github.com/krzk/linux-vendor-backup/blob/samsung/galaxy-s2-epic-4g-touch-sph-d710-exynos4210-dump/drivers/misc/max8997-muic.c#L1675-L1678

Signed-off-by: Timon Baetz <timon.baetz@protonmail.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
  • Loading branch information
Timon Baetz authored and Sebastian Reichel committed Jan 5, 2021
1 parent e62333e commit f384989
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/power/supply/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ config CHARGER_MAX77693
config CHARGER_MAX8997
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
depends on MFD_MAX8997 && REGULATOR_MAX8997
depends on EXTCON || !EXTCON
help
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8997/LP3974 PMICs.
Expand Down
96 changes: 96 additions & 0 deletions drivers/power/supply/max8997_charger.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
// MyungJoo Ham <myungjoo.ham@samsung.com>

#include <linux/err.h>
#include <linux/extcon.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
#include <linux/regulator/consumer.h>

/* MAX8997_REG_STATUS4 */
#define DCINOK_SHIFT 1
Expand All @@ -31,6 +33,10 @@ struct charger_data {
struct device *dev;
struct max8997_dev *iodev;
struct power_supply *battery;
struct regulator *reg;
struct extcon_dev *edev;
struct notifier_block extcon_nb;
struct work_struct extcon_work;
};

static enum power_supply_property max8997_battery_props[] = {
Expand Down Expand Up @@ -88,6 +94,67 @@ static int max8997_battery_get_property(struct power_supply *psy,
return 0;
}

static void max8997_battery_extcon_evt_stop_work(void *data)
{
struct charger_data *charger = data;

cancel_work_sync(&charger->extcon_work);
}

static void max8997_battery_extcon_evt_worker(struct work_struct *work)
{
struct charger_data *charger =
container_of(work, struct charger_data, extcon_work);
struct extcon_dev *edev = charger->edev;
int current_limit;

if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
dev_dbg(charger->dev, "USB SDP charger is connected\n");
current_limit = 450000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) {
dev_dbg(charger->dev, "USB DCP charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_FAST) > 0) {
dev_dbg(charger->dev, "USB FAST charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_SLOW) > 0) {
dev_dbg(charger->dev, "USB SLOW charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
dev_dbg(charger->dev, "USB CDP charger is connected\n");
current_limit = 650000;
} else {
dev_dbg(charger->dev, "USB charger is diconnected\n");
current_limit = -1;
}

if (current_limit > 0) {
int ret = regulator_set_current_limit(charger->reg, current_limit, current_limit);

if (ret) {
dev_err(charger->dev, "failed to set current limit: %d\n", ret);
return;
}
ret = regulator_enable(charger->reg);
if (ret)
dev_err(charger->dev, "failed to enable regulator: %d\n", ret);
} else {
int ret = regulator_disable(charger->reg);

if (ret)
dev_err(charger->dev, "failed to disable regulator: %d\n", ret);
}
}

static int max8997_battery_extcon_evt(struct notifier_block *nb,
unsigned long event, void *param)
{
struct charger_data *charger =
container_of(nb, struct charger_data, extcon_nb);
schedule_work(&charger->extcon_work);
return NOTIFY_OK;
}

static const struct power_supply_desc max8997_battery_desc = {
.name = "max8997_pmic",
.type = POWER_SUPPLY_TYPE_BATTERY,
Expand Down Expand Up @@ -170,6 +237,35 @@ static int max8997_battery_probe(struct platform_device *pdev)
return PTR_ERR(charger->battery);
}

charger->reg = devm_regulator_get_optional(&pdev->dev, "charger");
if (IS_ERR(charger->reg)) {
if (PTR_ERR(charger->reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(&pdev->dev, "couldn't get charger regulator\n");
}
charger->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(charger->edev)) {
if (PTR_ERR(charger->edev) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(charger->dev, "couldn't get extcon device\n");
}

if (!IS_ERR(charger->reg) && !IS_ERR(charger->edev)) {
INIT_WORK(&charger->extcon_work, max8997_battery_extcon_evt_worker);
ret = devm_add_action(&pdev->dev, max8997_battery_extcon_evt_stop_work, charger);
if (ret) {
dev_err(&pdev->dev, "failed to add extcon evt stop action: %d\n", ret);
return ret;
}
charger->extcon_nb.notifier_call = max8997_battery_extcon_evt;
ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev,
&charger->extcon_nb);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon notifier\n");
return ret;
};
}

return 0;
}

Expand Down

0 comments on commit f384989

Please sign in to comment.