mfd: Implement devicetree support for AB8500 Btemp

From: Rajanikanth HV
Date: Mon Sep 10 2012 - 07:22:02 EST


This patch adds device tree support for
battery temperature monitor driver

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@xxxxxxxxxxxxxx>
---
.../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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/