linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] mfd: max77693: Add defines for charger current control
@ 2019-09-10 20:02 Denis 'GNUtoo' Carikli
  2019-09-10 20:02 ` [PATCH 2/2] power_supply: max77693: Listen for cable events and enable charging Denis 'GNUtoo' Carikli
  0 siblings, 1 reply; 2+ messages in thread
From: Denis 'GNUtoo' Carikli @ 2019-09-10 20:02 UTC (permalink / raw)
  To: Chanwoo, Choi
  Cc: linux-kernel, Paul Kocialkowski, Wolfgang Wiedmeyer,
	Denis 'GNUtoo' Carikli

From: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>

This prepares for an updated regulator and charger driver. The defines
are needed to set the maximum input current and the fast charge
current.

Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
GNUtoo@cyberdimension.org: small fix
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
---
 include/linux/mfd/max77693-private.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index e798c81aec31..1853f8602f65 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -217,6 +217,9 @@ enum max77693_charger_battery_state {
 #define CHG_CNFG_01_CHGRSTRT_MASK	(0x3 << CHG_CNFG_01_CHGRSTRT_SHIFT)
 #define CHG_CNFG_01_PQEN_MAKS		BIT(CHG_CNFG_01_PQEN_SHIFT)
 
+/* MAX77693_CHG_REG_CHG_CNFG_02 register */
+#define CHG_CNFG_02_CC_MASK		0x3F
+
 /* MAX77693_CHG_REG_CHG_CNFG_03 register */
 #define CHG_CNFG_03_TOITH_SHIFT		0
 #define CHG_CNFG_03_TOTIME_SHIFT	3
@@ -245,6 +248,10 @@ enum max77693_charger_battery_state {
 
 /* MAX77693 CHG_CNFG_09 Register */
 #define CHG_CNFG_09_CHGIN_ILIM_MASK	0x7F
+#define CHG_CNFG_09_CHGIN_ILIM_500_MAX	500000
+#define CHG_CNFG_09_CHGIN_ILIM_500_MIN	470000
+#define CHG_CNFG_09_CHGIN_ILIM_0_MAX	60000
+#define CHG_CNFG_09_CHGIN_ILIM_0_MIN	0
 
 /* MAX77693 CHG_CTRL Register */
 #define SAFEOUT_CTRL_SAFEOUT1_MASK	0x3
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] power_supply: max77693: Listen for cable events and enable charging
  2019-09-10 20:02 [PATCH 1/2] mfd: max77693: Add defines for charger current control Denis 'GNUtoo' Carikli
@ 2019-09-10 20:02 ` Denis 'GNUtoo' Carikli
  0 siblings, 0 replies; 2+ messages in thread
From: Denis 'GNUtoo' Carikli @ 2019-09-10 20:02 UTC (permalink / raw)
  To: Chanwoo, Choi
  Cc: linux-kernel, Paul Kocialkowski, Wolfgang Wiedmeyer,
	Denis 'GNUtoo' Carikli

From: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>

This patch adds a listener for extcon cable events and enables
charging if an USB cable is connected. It recognizes SDP and DCP cable
types and treats them the same (same input current and fast charge
current). The maximum input current is set before the charger is
enabled and before the charger gets disabled, the maximum input
current is set to zero. The listener is inspired by the listener
implementation that was used for the AXP288 Charger driver.

The patch also adds support for the CURRENT_NOW property. It reads the
fast charge current that gets set before the charger is enabled or
disabled.

Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
GNUtoo@cyberdimension.org: small fixes
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
---
 drivers/power/supply/Kconfig            |   2 +-
 drivers/power/supply/max77693_charger.c | 176 ++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 5d91b5160b41..5cd06b1b145e 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -534,7 +534,7 @@ config CHARGER_MAX77650
 
 config CHARGER_MAX77693
 	tristate "Maxim MAX77693 battery charger driver"
-	depends on MFD_MAX77693
+	depends on MFD_MAX77693 && REGULATOR_MAX77693
 	help
 	  Say Y to enable support for the Maxim MAX77693 battery charger.
 
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index a2c5c9858639..b19490cb4a8f 100644
--- a/drivers/power/supply/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -12,8 +12,11 @@
 #include <linux/mfd/max77693.h>
 #include <linux/mfd/max77693-common.h>
 #include <linux/mfd/max77693-private.h>
+#include <linux/extcon.h>
+#include <linux/regulator/consumer.h>
 
 #define MAX77693_CHARGER_NAME				"max77693-charger"
+#define MAX77693_EXTCON_DEV_NAME			"max77693-muic"
 static const char *max77693_charger_model		= "MAX77693";
 static const char *max77693_charger_manufacturer	= "Maxim Integrated";
 
@@ -21,12 +24,21 @@ struct max77693_charger {
 	struct device		*dev;
 	struct max77693_dev	*max77693;
 	struct power_supply	*charger;
+	struct regulator	*regu;
 
 	u32 constant_volt;
 	u32 min_system_volt;
 	u32 thermal_regulation_temp;
 	u32 batttery_overcurrent;
 	u32 charge_input_threshold_volt;
+
+	/* SDP/DCP USB charging cable notifications */
+	struct {
+		struct extcon_dev *edev;
+		bool connected;
+		struct notifier_block nb;
+		struct work_struct work;
+	} cable;
 };
 
 static int max77693_get_charger_state(struct regmap *regmap, int *val)
@@ -197,12 +209,28 @@ static int max77693_get_online(struct regmap *regmap, int *val)
 	return 0;
 }
 
+int max77693_get_charge_current(struct regmap *regmap, int *val)
+{
+	unsigned int data;
+	int ret;
+
+	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_CNFG_02, &data);
+	if (ret < 0)
+		return ret;
+
+	data &= CHG_CNFG_02_CC_MASK;
+	*val = data * 333 / 10; /* 3 steps/0.1A */
+
+	return 0;
+}
+
 static enum power_supply_property max77693_charger_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CHARGE_TYPE,
 	POWER_SUPPLY_PROP_HEALTH,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
@@ -231,6 +259,9 @@ static int max77693_charger_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_ONLINE:
 		ret = max77693_get_online(regmap, &val->intval);
 		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		ret = max77693_get_charge_current(regmap, &val->intval);
+		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = max77693_charger_model;
 		break;
@@ -285,6 +316,7 @@ static ssize_t fast_charge_timer_show(struct device *dev,
 
 	data &= CHG_CNFG_01_FCHGTIME_MASK;
 	data >>= CHG_CNFG_01_FCHGTIME_SHIFT;
+
 	switch (data) {
 	case 0x1 ... 0x7:
 		/* Starting from 4 hours, step by 2 hours */
@@ -573,6 +605,102 @@ static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg
 			CHG_CNFG_12_VCHGINREG_MASK, data);
 }
 
+static int max77693_enable_charger(struct max77693_charger *chg, bool enable)
+{
+	int ret;
+
+	if (enable) {
+		ret = regulator_set_current_limit(
+			chg->regu,
+			CHG_CNFG_09_CHGIN_ILIM_500_MIN,
+			CHG_CNFG_09_CHGIN_ILIM_500_MAX);
+
+		if (ret < 0)
+			return ret;
+
+		ret = regulator_enable(chg->regu);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* sets fast charge current to zero */
+		ret = regulator_set_current_limit(chg->regu,
+						  CHG_CNFG_09_CHGIN_ILIM_0_MIN,
+						  CHG_CNFG_09_CHGIN_ILIM_0_MAX);
+		if (ret < 0)
+			return ret;
+
+		ret = regulator_disable(chg->regu);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static void max77693_extcon_evt_worker(struct work_struct *work)
+{
+	struct max77693_charger *chg = container_of(work,
+						    struct max77693_charger,
+						    cable.work);
+	bool changed = false;
+	struct extcon_dev *edev = chg->cable.edev;
+	bool old_connected = chg->cable.connected;
+	bool is_charger_enabled;
+	int ret;
+
+	/* Determine cable/charger type */
+	if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) ||
+	    extcon_get_state(edev, EXTCON_CHG_USB_DCP)) {
+		dev_dbg(chg->dev, "USB charger is connected");
+		chg->cable.connected = true;
+	} else {
+		if (old_connected)
+			dev_dbg(chg->dev, "USB charger disconnected");
+		chg->cable.connected = false;
+	}
+
+	/* Cable status changed */
+	if (old_connected != chg->cable.connected)
+		changed = true;
+
+	if (!changed)
+		return;
+
+	if (regulator_is_enabled(chg->regu))
+		is_charger_enabled = true;
+	else
+		is_charger_enabled = false;
+
+	if (is_charger_enabled && !chg->cable.connected) {
+		ret = max77693_enable_charger(chg, false);
+		if (ret < 0) {
+			dev_err(chg->dev,
+				"failed to disable charger (%d)", ret);
+		}
+	} else if (!is_charger_enabled && chg->cable.connected) {
+		ret = max77693_enable_charger(chg, true);
+		if (ret < 0) {
+			dev_err(chg->dev,
+				"cannot enable charger (%d)", ret);
+		}
+	}
+
+	if (changed)
+		power_supply_changed(chg->charger);
+}
+
+static int max77693_handle_cable_evt(struct notifier_block *nb,
+				unsigned long event, void *param)
+{
+	struct max77693_charger *chg = container_of(nb,
+						    struct max77693_charger,
+						    cable.nb);
+
+	schedule_work(&chg->cable.work);
+
+	return NOTIFY_OK;
+}
+
 /*
  * Sets charger registers to proper and safe default values.
  */
@@ -684,6 +812,45 @@ static int max77693_charger_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	chg->regu = devm_regulator_get(chg->dev, "CHARGER");
+	if (IS_ERR(chg->regu)) {
+		ret = PTR_ERR(chg->regu);
+		dev_err(&pdev->dev,
+			"failed to get charger regulator %d\n", ret);
+		return ret;
+	}
+
+	chg->cable.edev = extcon_get_extcon_dev(MAX77693_EXTCON_DEV_NAME);
+	if (chg->cable.edev == NULL) {
+		dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n",
+			MAX77693_EXTCON_DEV_NAME);
+		return -EPROBE_DEFER;
+	}
+
+	/* set initial value */
+	chg->cable.connected = false;
+
+	/* Register for extcon notification */
+	INIT_WORK(&chg->cable.work, max77693_extcon_evt_worker);
+	chg->cable.nb.notifier_call = max77693_handle_cable_evt;
+	ret = extcon_register_notifier(chg->cable.edev, EXTCON_CHG_USB_SDP,
+				       &chg->cable.nb);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to register extcon notifier for SDP %d\n", ret);
+		return ret;
+	}
+
+	ret = extcon_register_notifier(chg->cable.edev, EXTCON_CHG_USB_DCP,
+				       &chg->cable.nb);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to register extcon notifier for DCP %d\n", ret);
+		extcon_unregister_notifier(chg->cable.edev,
+					   EXTCON_CHG_USB_SDP, &chg->cable.nb);
+		return ret;
+	}
+
 	ret = max77693_reg_init(chg);
 	if (ret)
 		return ret;
@@ -724,6 +891,10 @@ static int max77693_charger_probe(struct platform_device *pdev)
 	device_remove_file(&pdev->dev, &dev_attr_top_off_timer);
 	device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
 	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
+	extcon_unregister_notifier(chg->cable.edev, EXTCON_CHG_USB_SDP,
+				   &chg->cable.nb);
+	extcon_unregister_notifier(chg->cable.edev, EXTCON_CHG_USB_DCP,
+				   &chg->cable.nb);
 
 	return ret;
 }
@@ -736,6 +907,11 @@ static int max77693_charger_remove(struct platform_device *pdev)
 	device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
 	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
 
+	extcon_unregister_notifier(chg->cable.edev, EXTCON_CHG_USB_SDP,
+				   &chg->cable.nb);
+	extcon_unregister_notifier(chg->cable.edev, EXTCON_CHG_USB_DCP,
+				   &chg->cable.nb);
+
 	power_supply_unregister(chg->charger);
 
 	return 0;
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-09-10 20:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-10 20:02 [PATCH 1/2] mfd: max77693: Add defines for charger current control Denis 'GNUtoo' Carikli
2019-09-10 20:02 ` [PATCH 2/2] power_supply: max77693: Listen for cable events and enable charging Denis 'GNUtoo' Carikli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).