mfd: Implement devicetree support for AB8500 Btemp

Rajanikanth HV rajanikanth.hv at linaro.org
Mon Sep 10 07:21:54 EDT 2012


This patch adds device tree support for
battery temperature monitor driver

Signed-off-by: Rajanikanth H.V <rajanikanth.hv at stericsson.com>
---
 .../bindings/power_supply/ab8500/btemp.txt         |   52 ++++++
 arch/arm/boot/dts/dbx5x0.dtsi                      |    8 +
 drivers/mfd/ab8500-core.c                          |    1 +
 drivers/power/Kconfig                              |    6 -
 drivers/power/ab8500_bmdata.h                      |    4 +-
 drivers/power/ab8500_btemp.c                       |  181 ++++++++++++++++----
 6 files changed, 213 insertions(+), 39 deletions(-)
 create mode 100644
Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt

diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
b/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
new file mode 100644
index 0000000..b214efc
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
@@ -0,0 +1,52 @@
+=== AB8500 Battery Temperature Monitor Driver ===
+
+The properties below describes the node for battery
+temperature monitor driver.
+
+Required Properties:
+- compatible = "stericsson,ab8500-btemp"
+
+supplied-to:
+	This is a logical binding w.r.t power supply event change
+	across energy-management-module drivers where in the
+	runtime battery properties are shared along with uevent
+	notification.
+	ref: di->btemp_psy.external_power_changed =
+		ab8500_btemp_external_power_changed;
+		ab8500_btemp.c
+
+	Need for this property:
+		btemp, fg and charger updates power-supply properties
+		based on the events listed above.
+		Event handler invokes power supply change notifier
+		which in-turn invokes registered power supply class call-back
+		based on the 'supplied_to' string.
+		ref:
+		power_supply_changed_work(..) ./drivers/power/power_supply_core.c
+
+	example:
+	ab8500-btemp {
+		/* Other enery management module */
+		supplied-to = "ab8500_chargalg", "ab8500_fg";
+		num_supplicants = <2>;
+	};
+
+thermister-interface:
+	'btemp' and 'batctrl' are the pins interfaced for battery temperature
+	measurement, btemp is used when NTC(negative temperature coefficient)
+	resister is interfaced external to battery and batctrl is used when
+	NTC resister is internal to battery.
+
+
+li-ion-9100-battery:
+	use this to add support for the 9100 Li-ION battery,
+	this adjust the bkup battery charger parameters
+	Note: this property is used for tablet version of snowball board.
+
+	example:
+	ab8500-btemp {
+		thermister-internal-to-battery = <1>;
+		li_ion_9100_battery = <0>;
+	};
+Note:
+interrupts are defined and registered in the driver
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index d69c087..643e7fd 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -360,6 +360,14 @@
 					li_ion_9100  = <0>;
 				};

+				ab8500-btemp {
+					compatible = "stericsson,ab8500-btemp";
+					supplied_to = "ab8500_chargalg", "ab8500_fg";
+					num_supplicants = <2>;
+					thermister_on_batctrl = <1>;
+					li_ion_9100  = <0>;
+				};
+
 				ab8500-usb {
 					compatible = "stericsson,ab8500-usb";
 					interrupts = < 90 0x4
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index c413cfa..7ffba9b 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1047,6 +1047,7 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 	},
 	{
 		.name = "ab8500-btemp",
+		.of_compatible = "stericsson,ab8500-btemp",
 		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
 		.resources = ab8500_btemp_resources,
 	},
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index c1892f3..1434871 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -304,12 +304,6 @@ config AB8500_BM
 	help
 	  Say Y to include support for AB8500 battery management.

-config AB8500_BATTERY_THERM_ON_BATCTRL
-	bool "Thermistor connected on BATCTRL ADC"
-	depends on AB8500_BM
-	help
-	  Say Y to enable battery temperature measurements using
-	  thermistor connected on BATCTRL ADC.
 endif # POWER_SUPPLY

 source "drivers/power/avs/Kconfig"
diff --git a/drivers/power/ab8500_bmdata.h b/drivers/power/ab8500_bmdata.h
index 748334a..0bd0a45 100644
--- a/drivers/power/ab8500_bmdata.h
+++ b/drivers/power/ab8500_bmdata.h
@@ -22,7 +22,7 @@ static struct abx500_res_to_temp temp_tbl_A_thermister[] = {
 	{65, 12500},
 };
 static struct abx500_res_to_temp temp_tbl_B_thermister[] = {
-	{-5, 165418},
+	{-5, 200000},
 	{ 0, 159024},
 	{ 5, 151921},
 	{10, 144300},
@@ -229,7 +229,7 @@ static struct abx500_battery_type bat_type_thermister[] = {
 },
 {
 	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
-	.resis_high = 165418,
+	.resis_high = 200000,
 	.resis_low = 82869,
 	.battery_resistance = 300,
 	.charge_full_design = 900,
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index bba3cca..ac08f1a 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/completion.h>
@@ -25,6 +26,7 @@
 #include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/mfd/abx500/ab8500-gpadc.h>
 #include <linux/jiffies.h>
+#include "ab8500_bmdata.h"

 #define VTVOUT_V			1800

@@ -960,42 +962,153 @@ static int __devexit ab8500_btemp_remove(struct
platform_device *pdev)
 	return 0;
 }

-static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
+static int __devinit
+btemp_of_probe(struct device *dev,
+		struct device_node *np,
+		struct abx500_bm_plat_data *bm_pdata)
 {
-	int irq, i, ret = 0;
-	u8 val;
-	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
-	struct ab8500_btemp *di;
-
-	if (!plat_data) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
+	u8	val;
+	u32	pval;
+	int	i;
+	int	ext_thermister, lion_battery, ret = 0;
+	const char *bm_dev_name;
+	struct	abx500_btemp_platform_data *btemp = bm_pdata->btemp;
+	struct	abx500_bm_data		   *bat;
+	struct	abx500_battery_type	   *btype;
+
+	ret = of_property_read_u32(np, "num_supplicants", &pval);
+	if (ret) {
+		dev_err(dev, "missing property num_supplicants\n");
+		ret = -EINVAL;
+		goto inval_pval;
 	}
-
-	di = kzalloc(sizeof(*di), GFP_KERNEL);
-	if (!di)
-		return -ENOMEM;
-
-	/* get parent data */
-	di->dev = &pdev->dev;
-	di->parent = dev_get_drvdata(pdev->dev.parent);
-	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-
-	/* get btemp specific platform data */
-	di->pdata = plat_data->btemp;
-	if (!di->pdata) {
-		dev_err(di->dev, "no btemp platform data supplied\n");
+	btemp->num_supplicants = pval;
+	btemp->supplied_to =
+		devm_kzalloc(dev, btemp->num_supplicants *
+			sizeof(const char *), GFP_KERNEL);
+	if (btemp->supplied_to == NULL) {
+		dev_err(dev, "%s no mem for supplied_to\n", __func__);
+		ret = -ENOMEM;
+		goto inval_pval;
+	}
+	for (val = 0; val < btemp->num_supplicants; ++val)
+		if (of_property_read_string_index
+			(np, "supplied_to", val, &bm_dev_name) == 0)
+			*(btemp->supplied_to + val) = (char *)bm_dev_name;
+		else {
+			dev_err(dev, "insufficient number of supplied_to data found\n");
+			ret = -EINVAL;
+			goto free_dev_mem;
+		}
+	ret = of_property_read_u32(np, "thermister_on_batctrl", &pval);
+	if (ret) {
+		dev_err(dev, "missing property thermister_on_batctrl\n");
 		ret = -EINVAL;
-		goto free_device_info;
+		goto free_dev_mem;
+	}
+	bm_pdata->battery = &ab8500_bm_data;
+	bat = bm_pdata->battery;
+	ext_thermister = 0;
+	if (pval == 0) {
+		bat->n_btypes = 4;
+		bat->bat_type = bat_type_ext_thermister;
+		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
+		ext_thermister = 1;
+	}
+	ret = of_property_read_u32(np, "li_ion_9100", &pval);
+	if (ret) {
+		dev_err(dev, "missing property li_ion_9100\n");
+		ret = -EINVAL;
+		goto free_dev_mem;
+	}
+	lion_battery = 0;
+	if (pval == 1) {
+		bat->no_maintenance = true;
+		bat->chg_unknown_bat = true;
+		bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
+		bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
+		bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130;
+		bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
+		bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
+		lion_battery = 1;
+	}
+	/* select the battery resolution table */
+	for (i = 0; i < bat->n_btypes; ++i) {
+		btype = (bat->bat_type + i);
+		if (ext_thermister) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_ext_thermister;
+		} else if (lion_battery) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_9100;
+		} else {
+			btype->batres_tbl =
+				temp_to_batres_tbl_thermister;
+		}
+	}
+	return ret;
+free_dev_mem:
+	devm_kfree(dev, btemp->supplied_to);
+inval_pval:
+	return ret;
+}
+
+static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
+{
+	u8	val;
+	int	i;
+	int	irq, ret = 0;
+	struct	abx500_bm_plat_data *pdata = pdev->dev.platform_data;
+	struct	device_node	*np = pdev->dev.of_node;
+	struct	ab8500_btemp	*di;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
+		ret = -ENOMEM;
 	}

-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
+	if (np) {
+		if (!pdata) {
+			pdata =
+			devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+			if (!pdata) {
+				dev_err(&pdev->dev,
+					"%s no mem for pdata\n", __func__);
+				ret = -ENOMEM;
+				goto err_no_mem;
+			}
+			pdata->btemp = devm_kzalloc(&pdev->dev,
+					sizeof(*pdata->btemp), GFP_KERNEL);
+			if (!pdata->btemp) {
+				devm_kfree(&pdev->dev, pdata);
+				dev_err(&pdev->dev,
+					"%s no mem for pdata->btemp\n",
+					__func__);
+				ret = -ENOMEM;
+				goto free_device_info;
+			}
+		}
+		/* get battery specific platform data */
+		ret = btemp_of_probe(&pdev->dev, np, pdata);
+		if (ret) {
+			devm_kfree(&pdev->dev, pdata->btemp);
+			devm_kfree(&pdev->dev, pdata);
+			goto free_device_info;
+		}
+	}
+	if (!pdata) {
+		dev_err(&pdev->dev,
+			"%s no btemp platform data found\n", __func__);
 		ret = -EINVAL;
 		goto free_device_info;
 	}
+	di->pdata = pdata->btemp;
+	di->bat = pdata->battery;
+	/* get parent data */
+	di->dev = &pdev->dev;
+	di->parent = dev_get_drvdata(pdev->dev.parent);
+	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");

 	/* BTEMP supply */
 	di->btemp_psy.name = "ab8500_btemp";
@@ -1008,7 +1121,6 @@ static int __devinit ab8500_btemp_probe(struct
platform_device *pdev)
 	di->btemp_psy.external_power_changed =
 		ab8500_btemp_external_power_changed;

-
 	/* Create a work queue for the btemp */
 	di->btemp_wq =
 		create_singlethread_workqueue("ab8500_btemp_wq");
@@ -1065,7 +1177,7 @@ static int __devinit ab8500_btemp_probe(struct
platform_device *pdev)
 			IRQF_SHARED | IRQF_NO_SUSPEND,
 			ab8500_btemp_irq[i].name, di);

-		if (ret) {
+		if (ret < 0) {
 			dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
 				, ab8500_btemp_irq[i].name, irq, ret);
 			goto free_irq;
@@ -1093,11 +1205,17 @@ free_irq:
 free_btemp_wq:
 	destroy_workqueue(di->btemp_wq);
 free_device_info:
-	kfree(di);
+	devm_kfree(&pdev->dev, di);
+err_no_mem:

 	return ret;
 }

+static const struct of_device_id ab8500_btemp_match[] = {
+	{.compatible = "stericsson,ab8500-btemp",},
+	{},
+};
+
 static struct platform_driver ab8500_btemp_driver = {
 	.probe = ab8500_btemp_probe,
 	.remove = __devexit_p(ab8500_btemp_remove),
@@ -1106,6 +1224,7 @@ static struct platform_driver ab8500_btemp_driver = {
 	.driver = {
 		.name = "ab8500-btemp",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_btemp_match,
 	},
 };

-- 
1.7.9.5



More information about the linux-arm-kernel mailing list