lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 26 May 2017 13:04:13 +0200
From:   Enric Balletbo i Serra <enric.balletbo@...labora.com>
To:     sre@...nel.org, robh@...nel.org
Cc:     mark.rutland@....com, linux-pm@...r.kernel.org,
        devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
        kernel@...workimprov.net
Subject: [PATCH v3 4/4] power: tps65217_charger: add support for NTC type, voltage and current charge

Allow the possibility to configure the charge and the current voltage of
the charger and also the NTC type for battery temperature measurement.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@...labora.com>
---
Changes since v2:
 - Requested by Sebastian Reichel
   - Use the simple-battery framework
   - Use device_property_read_u32 instead of of_property_read_u32
Changes since v1:
 - None

 drivers/power/supply/tps65217_charger.c | 194 ++++++++++++++++++++++++++++++--
 include/linux/mfd/tps65217.h            |   2 +
 2 files changed, 188 insertions(+), 8 deletions(-)

diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c
index 1f52340..5939e77 100644
--- a/drivers/power/supply/tps65217_charger.c
+++ b/drivers/power/supply/tps65217_charger.c
@@ -39,6 +39,12 @@
 #define NUM_CHARGER_IRQS	2
 #define POLL_INTERVAL		(HZ * 2)
 
+struct tps65217_charger_platform_data {
+	int	charge_voltage_uv;
+	int	charge_current_ua;
+	int	ntc_type;
+};
+
 struct tps65217_charger {
 	struct tps65217 *tps;
 	struct device *dev;
@@ -48,16 +54,84 @@ struct tps65217_charger {
 	int	prev_online;
 
 	struct task_struct	*poll_task;
+	struct tps65217_charger_platform_data *pdata;
 };
 
 static enum power_supply_property tps65217_charger_props[] = {
 	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 };
 
-static int tps65217_config_charger(struct tps65217_charger *charger)
+static int tps65217_set_charge_current(struct tps65217_charger *charger,
+				       unsigned int uamp)
+{
+	int ret, val;
+
+	dev_dbg(charger->dev, "setting charge current to %d uA\n", uamp);
+
+	if (uamp == 300000)
+		val = 0x00;
+	else if (uamp == 400000)
+		val = 0x01;
+	else if (uamp == 500000)
+		val = 0x02;
+	else if (uamp == 700000)
+		val = 0x03;
+	else
+		return -EINVAL;
+
+	ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG3,
+				TPS65217_CHGCONFIG3_ICHRG_MASK,
+				val << TPS65217_CHGCONFIG3_ICHRG_SHIFT,
+				TPS65217_PROTECT_NONE);
+	if (ret) {
+		dev_err(charger->dev,
+			"failed to set ICHRG setting to 0x%02x (err: %d)\n",
+			val, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tps65217_set_charge_voltage(struct tps65217_charger *charger,
+				       unsigned int uvolt)
+{
+	int ret, val;
+
+	dev_dbg(charger->dev, "setting charge voltage to %d uV\n", uvolt);
+
+	if (uvolt != 4100000 && uvolt != 4150000 &&
+	    uvolt != 4200000 && uvolt != 4250000)
+		return -EINVAL;
+
+	val = (uvolt - 4100000) / 50000;
+
+	ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG2,
+				TPS65217_CHGCONFIG2_VOREG_MASK,
+				val << TPS65217_CHGCONFIG2_VOREG_SHIFT,
+				TPS65217_PROTECT_NONE);
+	if (ret) {
+		dev_err(charger->dev,
+			"failed to set VOCHG setting to 0x%02x (err: %d)\n",
+			val, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tps65217_set_ntc_type(struct tps65217_charger *charger,
+				 unsigned int ntc)
 {
 	int ret;
 
+	dev_dbg(charger->dev, "setting NTC type to %d\n", ntc);
+
+	if (ntc != 0 && ntc != 1)
+		return -EINVAL;
+
 	/*
 	 * tps65217 rev. G, p. 31 (see p. 32 for NTC schematic)
 	 *
@@ -74,14 +148,57 @@ static int tps65217_config_charger(struct tps65217_charger *charger)
 	 * NTC TYPE (for battery temperature measurement)
 	 *   0 – 100k (curve 1, B = 3960)
 	 *   1 – 10k  (curve 2, B = 3480) (default on reset)
-	 *
 	 */
-	ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
-				  TPS65217_CHGCONFIG1_NTC_TYPE,
-				  TPS65217_PROTECT_NONE);
+	if (ntc) {
+		ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
+					TPS65217_CHGCONFIG1_NTC_TYPE,
+					TPS65217_CHGCONFIG1_NTC_TYPE,
+					TPS65217_PROTECT_NONE);
+		if (ret) {
+			dev_err(charger->dev,
+				"failed to set NTC type to 10K: %d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
+					  TPS65217_CHGCONFIG1_NTC_TYPE,
+					  TPS65217_PROTECT_NONE);
+		if (ret) {
+			dev_err(charger->dev,
+				"failed to set NTC type to 100K: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int tps65217_config_charger(struct tps65217_charger *charger)
+{
+	int ret;
+	struct tps65217_charger_platform_data *pdata = charger->pdata;
+
+	if (!charger->pdata)
+		return -EINVAL;
+
+	ret = tps65217_set_charge_voltage(charger, pdata->charge_voltage_uv);
+	if (ret) {
+		dev_err(charger->dev,
+			"failed to set charge voltage setting: %d\n", ret);
+		return ret;
+	}
+
+	ret = tps65217_set_charge_current(charger, pdata->charge_current_ua);
+	if (ret) {
+		dev_err(charger->dev,
+			"failed to set charge current setting: %d\n", ret);
+		return ret;
+	}
+
+	ret = tps65217_set_ntc_type(charger, pdata->ntc_type);
 	if (ret) {
 		dev_err(charger->dev,
-			"failed to set 100k NTC setting: %d\n", ret);
+			"failed to set NTC type setting: %d\n", ret);
 		return ret;
 	}
 
@@ -118,11 +235,23 @@ static int tps65217_charger_get_property(struct power_supply *psy,
 					 union power_supply_propval *val)
 {
 	struct tps65217_charger *charger = power_supply_get_drvdata(psy);
+	struct tps65217_charger_platform_data *pdata = charger->pdata;
 
 	if (psp == POWER_SUPPLY_PROP_ONLINE) {
 		val->intval = charger->online;
 		return 0;
 	}
+
+	if (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE) {
+		val->intval = pdata->charge_voltage_uv;
+		return 0;
+	}
+
+	if (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) {
+		val->intval = pdata->charge_current_ua;
+		return 0;
+	}
+
 	return -EINVAL;
 }
 
@@ -185,6 +314,49 @@ static int tps65217_charger_poll_task(void *data)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct tps65217_charger_platform_data *tps65217_charger_pdata_init(
+		struct tps65217_charger *charger)
+{
+	struct tps65217_charger_platform_data *pdata;
+	struct power_supply_battery_info info = {};
+	int ret;
+
+	pdata = devm_kzalloc(charger->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * If battery info is not supplied just ignore and program default
+	 * values.
+	 */
+	power_supply_get_battery_info(charger->psy, &info);
+
+	if (info.charge_voltage_uv > 0)
+		pdata->charge_voltage_uv = info.charge_voltage_uv;
+	else
+		pdata->charge_voltage_uv = 4100000;
+
+	if (info.charge_current_ua > 0)
+		pdata->charge_current_ua = info.charge_current_ua;
+	else
+		pdata->charge_current_ua = 500000;
+
+	ret = device_property_read_u32(charger->dev, "ti,ntc-type",
+				       &pdata->ntc_type);
+	if (ret)
+		pdata->ntc_type = 1;	/* 10k  (curve 2, B = 3480) */
+
+	return pdata;
+}
+#else /* CONFIG_OF */
+static struct tps65217_charger_platform_data *tps65217_charger_pdata_init(
+		struct tps65217_charger *charger)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF */
+
 static const struct power_supply_desc tps65217_charger_desc = {
 	.name			= "tps65217-charger",
 	.type			= POWER_SUPPLY_TYPE_MAINS,
@@ -222,8 +394,11 @@ static int tps65217_charger_probe(struct platform_device *pdev)
 		return PTR_ERR(charger->psy);
 	}
 
-	irq[0] = platform_get_irq_byname(pdev, "USB");
-	irq[1] = platform_get_irq_byname(pdev, "AC");
+	charger->pdata = tps65217_charger_pdata_init(charger);
+	if (IS_ERR(charger->pdata)) {
+		dev_err(charger->dev, "failed: getting platform data\n");
+		return PTR_ERR(charger->pdata);
+	}
 
 	ret = tps65217_config_charger(charger);
 	if (ret < 0) {
@@ -231,6 +406,9 @@ static int tps65217_charger_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	irq[0] = platform_get_irq_byname(pdev, "USB");
+	irq[1] = platform_get_irq_byname(pdev, "AC");
+
 	/* Create a polling thread if an interrupt is invalid */
 	if (irq[0] < 0 || irq[1] < 0) {
 		poll_task = kthread_run(tps65217_charger_poll_task,
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index eac2857..d040062 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -103,8 +103,10 @@
 #define TPS65217_CHGCONFIG2_DYNTMR	BIT(7)
 #define TPS65217_CHGCONFIG2_VPREGHG	BIT(6)
 #define TPS65217_CHGCONFIG2_VOREG_MASK	0x30
+#define TPS65217_CHGCONFIG2_VOREG_SHIFT	4
 
 #define TPS65217_CHGCONFIG3_ICHRG_MASK	0xC0
+#define TPS65217_CHGCONFIG3_ICHRG_SHIFT	6
 #define TPS65217_CHGCONFIG3_DPPMTH_MASK	0x30
 #define TPS65217_CHGCONFIG2_PCHRGT	BIT(3)
 #define TPS65217_CHGCONFIG2_TERMIF	0x06
-- 
2.9.3

Powered by blists - more mailing lists