linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Implement device tree support for ab8500 BM Devices
@ 2012-11-22 18:43 Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Rajanikanth H.V @ 2012-11-22 18:43 UTC (permalink / raw)
  To: rob.herring, robherring2, francescolavra.fl, anton.vorontsov
  Cc: lee.jones, arnd, linus.walleij, linux-arm-kernel, linux-kernel,
	linaro-dev, patches, STEricsson_nomadik_linux, rajanikanth.hv,
	Rajanikanth H.V

From: "Rajanikanth H.V" <rajanikanth.hv@linaro.org>

This patch-set adds device tree binding for ab8500 battery-managed
devices. Removes the redundant platform structure maintained
across bm devices and implements common DT probe routine across all the
modules.

Test status:
a) Tested across 'legacy platform data' and DT binding support
	a.1) ab8500_charger driver fails to get regulator in the
		legacy platform mode.
b) Interrupt numbers assigned differs between legacy and FDT mode.
    (a) Legacy platform_data Mode:
    root@ME:/ cat /proc/interrupts
               CPU0       CPU1
    483:          0          0    ab8500  ab8500-ponkey-dbf
    484:          0          0    ab8500  ab8500-ponkey-dbr
    485:          0          0    ab8500  BATT_OVV
    494:          0          1    ab8500
    495:          0          0    ab8500  ab8500-rtc
    501:          0         13    ab8500  NCONV_ACCU
    503:          7         22    ab8500  CCEOC
    504:          0          1    ab8500  CC_INT_CALIB
    505:          0          0    ab8500  LOW_BAT_F
    516:          0         34    ab8500  ab8500-gpadc
    556:          0          0    ab8500  usb-link-status
    
    (b) FDT Mode:
    root@ME:/ cat /proc/interrupts
               CPU0       CPU1
      6:          0          0    ab8500  ab8500-ponkey-dbf
      7:          0          0    ab8500  ab8500-ponkey-dbr
      8:          0          0    ab8500  BATT_OVV
    162:          0          7    ab8500  ab8500-gpadc
    163:          0          1    ab8500
    164:          0          0    ab8500  ab8500-rtc
    484:          0          0    ab8500  usb-link-status
    499:          0          4    ab8500  NCONV_ACCU
    500:          0          0    ab8500  LOW_BAT_F
    502:          0          1    ab8500  CC_INT_CALIB
    503:          0          6    ab8500  CCEOC

c) Event handlers across bm-modules have been verified only
   during 'battery discharge process' as 'battery charging process'
   depends on ab8500-usb code

d) observed nested IRQ issue, log below:

root@ME:/ ------------[ cut here ]------------
WARNING: at /home/rhv00000/linaro_work/linux/kernel/irq/manage.c:635 irq_nested_primary_handler+0x20/0x28()
Primary handler called for nested irq 193
Modules linked in:
[<c0014884>] (unwind_backtrace+0x0/0xf8) from [<c001cbb4>] (warn_slowpath_common+0x4c/0x64)
[<c001cbb4>] (warn_slowpath_common+0x4c/0x64) from [<c001cc60>] (warn_slowpath_fmt+0x30/0x40)
[<c001cc60>] (warn_slowpath_fmt+0x30/0x40) from [<c0060f00>] (irq_nested_primary_handler+0x20/0x28)
[<c0060f00>] (irq_nested_primary_handler+0x20/0x28) from [<c0060b80>] (handle_irq_event_percpu+0x50/0x194)
[<c0060b80>] (handle_irq_event_percpu+0x50/0x194) from [<c0060d00>] (handle_irq_event+0x3c/0x5c)
[<c0060d00>] (handle_irq_event+0x3c/0x5c) from [<c0063034>] (handle_simple_irq+0x8c/0xc4)
[<c0063034>] (handle_simple_irq+0x8c/0xc4) from [<c0062d84>] (resend_irqs+0x40/0x68)
[<c0062d84>] (resend_irqs+0x40/0x68) from [<c00236d8>] (tasklet_action+0x84/0x120)
[<c00236d8>] (tasklet_action+0x84/0x120) from [<c0023ae4>] (__do_softirq+0xd8/0x198)
[<c0023ae4>] (__do_softirq+0xd8/0x198) from [<c0023ed4>] (irq_exit+0x90/0x98)
[<c0023ed4>] (irq_exit+0x90/0x98) from [<c000f2cc>] (handle_IRQ+0x50/0xb0)
[<c000f2cc>] (handle_IRQ+0x50/0xb0) from [<c00084f0>] (gic_handle_irq+0x28/0x5c)
[<c00084f0>] (gic_handle_irq+0x28/0x5c) from [<c000df80>] (__irq_svc+0x40/0x70)
Exception stack(0xebc5dea8 to 0xebc5def0)
dea0:                   c0f45340 ebc4cf00 00000000 1f321f32 eb196600 ebc4cf00
dec0: c05a3340 00000002 ebc4c600 00000000 eb1b2c00 ebc5df0c 00000000 ebc5def0
dee0: c0040c7c c02ca5ec 60000013 ffffffff
[<c000df80>] (__irq_svc+0x40/0x70) from [<c02ca5ec>] (_raw_spin_unlock_irq+0x28/0x50)
[<c02ca5ec>] (_raw_spin_unlock_irq+0x28/0x50) from [<c0040c7c>] (finish_task_switch+0x28/0xf0)
[<c0040c7c>] (finish_task_switch+0x28/0xf0) from [<c02c93f0>] (__schedule+0x254/0x548)
[<c02c93f0>] (__schedule+0x254/0x548) from [<c0040088>] (smpboot_thread_fn+0x11c/0x250)
[<c0040088>] (smpboot_thread_fn+0x11c/0x250) from [<c0037fc8>] (kthread+0xa4/0xb0)
[<c0037fc8>] (kthread+0xa4/0xb0) from [<c000e418>] (ret_from_fork+0x14/0x3c)
---[ end trace 1b75b31a2719ed1e ]---

Rajanikanth H.V (4):
  mfd: ab8500: add devicetree support for fuelgauge
  mfd: ab8500: add devicetree support for btemp
  mfd: ab8500: add devicetree support for charger
  mfd: ab8500: add devicetree support for chargalg

 Documentation/devicetree/bindings/mfd/ab8500.txt   |   27 +-
 .../bindings/power_supply/ab8500/btemp.txt         |   16 +
 .../bindings/power_supply/ab8500/chargalg.txt      |   16 +
 .../bindings/power_supply/ab8500/charger.txt       |   25 +
 .../devicetree/bindings/power_supply/ab8500/fg.txt |   58 +++
 arch/arm/boot/dts/dbx5x0.dtsi                      |   26 +
 drivers/mfd/ab8500-core.c                          |   20 +
 drivers/power/Kconfig                              |    6 -
 drivers/power/Makefile                             |    2 +-
 drivers/power/ab8500_bmdata.c                      |  514 ++++++++++++++++++++
 drivers/power/ab8500_btemp.c                       |   75 +--
 drivers/power/ab8500_charger.c                     |   83 ++--
 drivers/power/ab8500_fg.c                          |   81 +--
 drivers/power/abx500_chargalg.c                    |   57 ++-
 include/linux/mfd/abx500.h                         |   34 +-
 15 files changed, 879 insertions(+), 161 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/charger.txt
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
 create mode 100644 drivers/power/ab8500_bmdata.c

-- 
1.7.10.4


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

* [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-22 18:43 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
@ 2012-11-22 18:43 ` Rajanikanth H.V
  2012-11-22 20:08   ` Anton Vorontsov
  2012-11-22 18:43 ` [PATCH 2/4] mfd: ab8500: add devicetree support for btemp Rajanikanth H.V
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 20+ messages in thread
From: Rajanikanth H.V @ 2012-11-22 18:43 UTC (permalink / raw)
  To: rob.herring, robherring2, francescolavra.fl, anton.vorontsov
  Cc: lee.jones, arnd, linus.walleij, linux-arm-kernel, linux-kernel,
	linaro-dev, patches, STEricsson_nomadik_linux, rajanikanth.hv,
	Rajanikanth H.V

From: "Rajanikanth H.V" <rajanikanth.hv@linaro.org>

- This patch adds device tree support for fuelgauge driver
- optimize bm devices platform_data usage and of_probe(...)
  Note: of_probe() routine for battery managed devices is made
  common across all bm drivers.
- test status:
  - interrupt numbers assigned differs between legacy and FDT mode.

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@linaro.org>
---
 Documentation/devicetree/bindings/mfd/ab8500.txt   |    7 +-
 .../devicetree/bindings/power_supply/ab8500/fg.txt |   58 +++
 arch/arm/boot/dts/dbx5x0.dtsi                      |   10 +
 drivers/mfd/ab8500-core.c                          |    5 +
 drivers/power/Makefile                             |    2 +-
 drivers/power/ab8500_bmdata.c                      |  514 ++++++++++++++++++++
 drivers/power/ab8500_btemp.c                       |   16 +-
 drivers/power/ab8500_charger.c                     |   16 +-
 drivers/power/ab8500_fg.c                          |   81 +--
 drivers/power/abx500_chargalg.c                    |    7 +-
 include/linux/mfd/abx500.h                         |   36 +-
 11 files changed, 659 insertions(+), 93 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
 create mode 100644 drivers/power/ab8500_bmdata.c

diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
index ce83c8d..6ca8d81 100644
--- a/Documentation/devicetree/bindings/mfd/ab8500.txt
+++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
@@ -24,7 +24,12 @@ ab8500-bm                :                      :              : Battery Manager
 ab8500-btemp             :                      :              : Battery Temperature
 ab8500-charger           :                      :              : Battery Charger
 ab8500-codec             :                      :              : Audio Codec
-ab8500-fg                :                      :              : Fuel Gauge
+ab8500-fg                : 			: vddadc       : Fuel Gauge
+			 : NCONV_ACCU           :	       : Accumulate N Sample Conversion
+			 : BATT_OVV		:	       : Battery Over Voltage
+			 : LOW_BAT_F		:	       : LOW threshold battery voltage
+			 : CC_INT_CALIB		:	       : Coulomb Counter Internal Calibration
+			 : CCEOC		:	       : Coulomb Counter End of Conversion
 ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
                            SW_CONV_END          :              :
 ab8500-gpio              :                      :              : GPIO Controller
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
new file mode 100644
index 0000000..ccafcb9
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
@@ -0,0 +1,58 @@
+=== AB8500 Fuel Gauge Driver ===
+
+AB8500 is a mixed signal multimedia and power management
+device comprising: power and energy-management-module,
+wall-charger, usb-charger, audio codec, general purpose adc,
+tvout, clock management and sim card interface.
+
+Fuelgauge support is part of energy-management-modules, other
+components of this module are:
+main-charger, usb-combo-charger and battery-temperature-monitoring.
+
+The properties below describes the node for fuelgauge driver.
+
+Required Properties:
+- compatible = This shall be: "stericsson,ab8500-fg"
+- battery = Shall be battery specific information
+	Example:
+	ab8500_fg {
+		compatible = "stericsson,ab8500-fg";
+		battery	   = <&ab8500_battery>;
+	};
+
+dependent node:
+	ab8500_battery: ab8500_battery {
+	};
+	This node will provide information on 'thermistor interface' and
+	'battery technology type' used.
+
+Properties of this node are:
+thermistor-on-batctrl:
+	A boolean value indicating thermistor interface	to battery
+
+	Note:
+	'btemp' and 'batctrl' are the pins interfaced for battery temperature
+	measurement, 'btemp' signal is used when NTC(negative temperature
+	coefficient) resister is interfaced external to battery whereas
+	'batctrl' pin is used when NTC resister is internal to battery.
+
+	Example:
+	ab8500_battery: ab8500_battery {
+		thermistor-on-batctrl;
+	};
+	indicates: NTC resister is internal to battery, 'batctrl' is used
+		for thermal measurement.
+
+	The absence of property 'thermal-on-batctrl' indicates
+	NTC resister is external to battery and  'btemp' signal is used
+	for thermal measurement.
+
+battery-type:
+	This shall be the battery manufacturing technology type,
+	allowed types are:
+		"UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
+	Example:
+	ab8500_battery: ab8500_battery {
+		stericsson,battery-type = "LIPO";
+	}
+
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 4b0e0ca..155cf53 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -352,6 +352,16 @@
 					vddadc-supply = <&ab8500_ldo_tvout_reg>;
 				};
 
+				ab8500_battery: ab8500_battery {
+					stericsson,battery-type = "LIPO";
+					thermistor-on-batctrl;
+				};
+
+				ab8500-fg {
+					compatible = "stericsson,ab8500-fg";
+					battery	   = <&ab8500_battery>;
+				};
+
 				ab8500-usb {
 					compatible = "stericsson,ab8500-usb";
 					interrupts = < 90 0x4
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 1667c77..7c3017b 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1051,8 +1051,13 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 	},
 	{
 		.name = "ab8500-fg",
+		.of_compatible = "stericsson,ab8500-fg",
 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
 		.resources = ab8500_fg_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
 	},
 	{
 		.name = "ab8500-chargalg",
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b949cf8..9103665 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_CHARGER_88PM860X)	+= 88pm860x_charger.o
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
-obj-$(CONFIG_AB8500_BM)		+= ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM)		+= ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
 obj-$(CONFIG_CHARGER_ISP1704)	+= isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)	+= max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)	+= twl4030_charger.o
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
new file mode 100644
index 0000000..0366270
--- /dev/null
+++ b/drivers/power/ab8500_bmdata.c
@@ -0,0 +1,514 @@
+#include <linux/export.h>
+#include <linux/power_supply.h>
+#include <linux/of.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+
+/*
+ * These are the defined batteries that uses a NTC and ID resistor placed
+ * inside of the battery pack.
+ * Note that the res_to_temp table must be strictly sorted by falling resistance
+ * values to work.
+ */
+static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
+	{-5, 53407},
+	{ 0, 48594},
+	{ 5, 43804},
+	{10, 39188},
+	{15, 34870},
+	{20, 30933},
+	{25, 27422},
+	{30, 24347},
+	{35, 21694},
+	{40, 19431},
+	{45, 17517},
+	{50, 15908},
+	{55, 14561},
+	{60, 13437},
+	{65, 12500},
+};
+static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
+	{-5, 165418},
+	{ 0, 159024},
+	{ 5, 151921},
+	{10, 144300},
+	{15, 136424},
+	{20, 128565},
+	{25, 120978},
+	{30, 113875},
+	{35, 107397},
+	{40, 101629},
+	{45,  96592},
+	{50,  92253},
+	{55,  88569},
+	{60,  85461},
+	{65,  82869},
+};
+static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
+	{4171,	100},
+	{4114,	 95},
+	{4009,	 83},
+	{3947,	 74},
+	{3907,	 67},
+	{3863,	 59},
+	{3830,	 56},
+	{3813,	 53},
+	{3791,	 46},
+	{3771,	 33},
+	{3754,	 25},
+	{3735,	 20},
+	{3717,	 17},
+	{3681,	 13},
+	{3664,	  8},
+	{3651,	  6},
+	{3635,	  5},
+	{3560,	  3},
+	{3408,    1},
+	{3247,	  0},
+};
+static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
+	{4161,	100},
+	{4124,	 98},
+	{4044,	 90},
+	{4003,	 85},
+	{3966,	 80},
+	{3933,	 75},
+	{3888,	 67},
+	{3849,	 60},
+	{3813,	 55},
+	{3787,	 47},
+	{3772,	 30},
+	{3751,	 25},
+	{3718,	 20},
+	{3681,	 16},
+	{3660,	 14},
+	{3589,	 10},
+	{3546,	  7},
+	{3495,	  4},
+	{3404,	  2},
+	{3250,	  0},
+};
+
+static struct abx500_v_to_cap cap_tbl[] = {
+	{4186,	100},
+	{4163,	 99},
+	{4114,	 95},
+	{4068,	 90},
+	{3990,	 80},
+	{3926,	 70},
+	{3898,	 65},
+	{3866,	 60},
+	{3833,	 55},
+	{3812,	 50},
+	{3787,	 40},
+	{3768,	 30},
+	{3747,	 25},
+	{3730,	 20},
+	{3705,	 15},
+	{3699,	 14},
+	{3684,	 12},
+	{3672,	  9},
+	{3657,	  7},
+	{3638,	  6},
+	{3556,	  4},
+	{3424,	  2},
+	{3317,	  1},
+	{3094,	  0},
+};
+
+/*
+ * Note that the res_to_temp table must be strictly sorted by falling
+ * resistance values to work.
+ */
+static struct abx500_res_to_temp temp_tbl[] = {
+	{-5, 214834},
+	{ 0, 162943},
+	{ 5, 124820},
+	{10,  96520},
+	{15,  75306},
+	{20,  59254},
+	{25,  47000},
+	{30,  37566},
+	{35,  30245},
+	{40,  24520},
+	{45,  20010},
+	{50,  16432},
+	{55,  13576},
+	{60,  11280},
+	{65,   9425},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
+	{ 40, 120},
+	{ 30, 135},
+	{ 20, 165},
+	{ 10, 230},
+	{ 00, 325},
+	{-10, 445},
+	{-20, 595},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
+	{ 60, 300},
+	{ 30, 300},
+	{ 20, 300},
+	{ 10, 300},
+	{ 00, 300},
+	{-10, 300},
+	{-20, 300},
+};
+
+/* battery resistance table for LI ION 9100 battery */
+struct batres_vs_temp temp_to_batres_tbl_9100[] = {
+	{ 60, 180},
+	{ 30, 180},
+	{ 20, 180},
+	{ 10, 180},
+	{ 00, 180},
+	{-10, 180},
+	{-20, 180},
+};
+
+struct abx500_battery_type bat_type_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+	/* First element always represent the UNKNOWN battery */
+	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+	.resis_high = 0,
+	.resis_low = 0,
+	.battery_resistance = 300,
+	.charge_full_design = 612,
+	.nominal_voltage = 3700,
+	.termination_vol = 4050,
+	.termination_curr = 200,
+	.recharge_vol = 3990,
+	.normal_cur_lvl = 400,
+	.normal_vol_lvl = 4100,
+	.maint_a_cur_lvl = 400,
+	.maint_a_vol_lvl = 4050,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 400,
+	.maint_b_vol_lvl = 4000,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 53407,
+	.resis_low = 12500,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3600,
+	.termination_vol = 4150,
+	.termination_curr = 80,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
+	.r_to_t_tbl = temp_tbl_A_thermistor,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
+	.v_to_cap_tbl = cap_tbl_A_thermistor,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 165418,
+	.resis_low = 82869,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3600,
+	.termination_vol = 4150,
+	.termination_curr = 80,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
+	.r_to_t_tbl = temp_tbl_B_thermistor,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
+	.v_to_cap_tbl = cap_tbl_B_thermistor,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+
+struct abx500_battery_type bat_type_ext_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+	/* First element always represent the UNKNOWN battery */
+	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+	.resis_high = 0,
+	.resis_low = 0,
+	.battery_resistance = 300,
+	.charge_full_design = 612,
+	.nominal_voltage = 3700,
+	.termination_vol = 4050,
+	.termination_curr = 200,
+	.recharge_vol = 3990,
+	.normal_cur_lvl = 400,
+	.normal_vol_lvl = 4100,
+	.maint_a_cur_lvl = 400,
+	.maint_a_vol_lvl = 4050,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 400,
+	.maint_b_vol_lvl = 4000,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+/*
+ * These are the batteries that doesn't have an internal NTC resistor to measure
+ * its temperature. The temperature in this case is measure with a NTC placed
+ * near the battery but on the PCB.
+ */
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 76000,
+	.resis_low = 53000,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LION,
+	.resis_high = 30000,
+	.resis_low = 10000,
+	.battery_resistance = 300,
+	.charge_full_design = 950,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LION,
+	.resis_high = 95000,
+	.resis_low = 76001,
+	.battery_resistance = 300,
+	.charge_full_design = 950,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+
+static const struct abx500_bm_capacity_levels cap_levels = {
+	.critical	= 2,
+	.low		= 10,
+	.normal		= 70,
+	.high		= 95,
+	.full		= 100,
+};
+
+static const struct abx500_fg_parameters fg = {
+	.recovery_sleep_timer = 10,
+	.recovery_total_time = 100,
+	.init_timer = 1,
+	.init_discard_time = 5,
+	.init_total_time = 40,
+	.high_curr_time = 60,
+	.accu_charging = 30,
+	.accu_high_curr = 30,
+	.high_curr_threshold = 50,
+	.lowbat_threshold = 3100,
+	.battok_falling_th_sel0 = 2860,
+	.battok_raising_th_sel1 = 2860,
+	.user_cap_limit = 15,
+	.maint_thres = 97,
+};
+
+static const struct abx500_maxim_parameters maxi_params = {
+	.ena_maxi = true,
+	.chg_curr = 910,
+	.wait_cycles = 10,
+	.charger_curr_step = 100,
+};
+
+static const struct abx500_bm_charger_parameters chg = {
+	.usb_volt_max		= 5500,
+	.usb_curr_max		= 1500,
+	.ac_volt_max		= 7500,
+	.ac_curr_max		= 1500,
+};
+
+struct abx500_bm_data ab8500_bm_data = {
+	.temp_under		= 3,
+	.temp_low		= 8,
+	.temp_high		= 43,
+	.temp_over		= 48,
+	.main_safety_tmr_h	= 4,
+	.temp_interval_chg	= 20,
+	.temp_interval_nochg	= 120,
+	.usb_safety_tmr_h	= 4,
+	.bkup_bat_v		= BUP_VCH_SEL_2P6V,
+	.bkup_bat_i		= BUP_ICH_SEL_150UA,
+	.no_maintenance		= false,
+	.adc_therm		= ABx500_ADC_THERM_BATCTRL,
+	.chg_unknown_bat	= false,
+	.enable_overshoot	= false,
+	.fg_res			= 100,
+	.cap_levels		= &cap_levels,
+	.bat_type		= bat_type_thermistor,
+	.n_btypes		= 3,
+	.batt_id		= 0,
+	.interval_charging	= 5,
+	.interval_not_charging	= 120,
+	.temp_hysteresis	= 3,
+	.gnd_lift_resistance	= 34,
+	.maxi			= &maxi_params,
+	.chg_params		= &chg,
+	.fg_params		= &fg,
+};
+
+int __devinit
+bmdevs_of_probe(struct device *dev,
+		struct device_node *np,
+		struct abx500_bm_data **battery)
+{
+	struct	abx500_battery_type *btype;
+	struct  device_node *np_bat_supply;
+	struct	abx500_bm_data *bat;
+	const char *btech;
+	int i, thermistor;
+
+	*battery = &ab8500_bm_data;
+
+	/* get phandle to 'battery-info' node */
+	np_bat_supply = of_parse_phandle(np, "battery", 0);
+	if (!np_bat_supply) {
+		dev_err(dev, "missing property battery\n");
+		return -EINVAL;
+	}
+	if (of_property_read_bool(np_bat_supply,
+			"thermistor-on-batctrl"))
+		thermistor = NTC_INTERNAL;
+	else
+		thermistor = NTC_EXTERNAL;
+
+	bat = *battery;
+	if (thermistor == NTC_EXTERNAL) {
+		bat->n_btypes  = 4;
+		bat->bat_type  = bat_type_ext_thermistor;
+		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
+	}
+	btech = of_get_property(np_bat_supply,
+		"stericsson,battery-type", NULL);
+	if (!btech) {
+		dev_warn(dev, "missing property battery-name/type\n");
+		return -EINVAL;
+	}
+	if (strncmp(btech, "LION", 4) == 0) {
+		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;
+	}
+	/* select the battery resolution table */
+	for (i = 0; i < bat->n_btypes; ++i) {
+		btype = (bat->bat_type + i);
+		if (thermistor == NTC_EXTERNAL) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_ext_thermistor;
+		} else if (strncmp(btech, "LION", 4) == 0) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_9100;
+		} else {
+			btype->batres_tbl =
+				temp_to_batres_tbl_thermistor;
+		}
+	}
+	of_node_put(np_bat_supply);
+	return 0;
+}
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index e3b6395..abc2abc 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -93,7 +93,7 @@ struct ab8500_btemp {
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
 	struct ab8500_fg *fg;
-	struct abx500_btemp_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply btemp_psy;
 	struct ab8500_btemp_events events;
@@ -962,10 +962,10 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev)
 
 static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 {
+	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
+	struct ab8500_btemp *di;
 	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");
@@ -982,21 +982,13 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
 	/* get btemp specific platform data */
-	di->pdata = plat_data->btemp;
+	di->pdata = plat_data;
 	if (!di->pdata) {
 		dev_err(di->dev, "no btemp platform data supplied\n");
 		ret = -EINVAL;
 		goto free_device_info;
 	}
 
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	/* BTEMP supply */
 	di->btemp_psy.name = "ab8500_btemp";
 	di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 26ff759..723edb4 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -220,7 +220,7 @@ struct ab8500_charger {
 	bool autopower;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_charger_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct ab8500_charger_event_flags flags;
 	struct ab8500_charger_usb_state usb_state;
@@ -2533,9 +2533,9 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
 
 static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 {
-	int irq, i, charger_status, ret = 0;
-	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
 	struct ab8500_charger *di;
+	int irq, i, charger_status, ret = 0;
 
 	if (!plat_data) {
 		dev_err(&pdev->dev, "No platform data\n");
@@ -2555,21 +2555,13 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 	spin_lock_init(&di->usb_state.usb_lock);
 
 	/* get charger specific platform data */
-	di->pdata = plat_data->charger;
+	di->pdata = plat_data;
 	if (!di->pdata) {
 		dev_err(di->dev, "no charger platform data supplied\n");
 		ret = -EINVAL;
 		goto free_device_info;
 	}
 
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	di->autopower = false;
 
 	/* AC supply */
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 2db8cc2..20ac3b8 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -22,15 +22,16 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/kobject.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500.h>
 #include <linux/slab.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/delay.h>
-#include <linux/mfd/abx500/ab8500-gpadc.h>
-#include <linux/mfd/abx500.h>
 #include <linux/time.h>
+#include <linux/of.h>
 #include <linux/completion.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
 
 #define MILLI_TO_MICRO			1000
 #define FG_LSB_IN_MA			1627
@@ -172,7 +173,6 @@ struct inst_curr_result_list {
  * @avg_cap:		Average capacity filter
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
- * @pdata:		Pointer to the abx500_fg platform data
  * @bat:		Pointer to the abx500_bm platform data
  * @fg_psy:		Structure that holds the FG specific battery properties
  * @fg_wq:		Work queue for running the FG algorithm
@@ -212,7 +212,6 @@ struct ab8500_fg {
 	struct ab8500_fg_avg_cap avg_cap;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_fg_platform_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply fg_psy;
 	struct workqueue_struct *fg_wq;
@@ -2429,7 +2428,6 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev)
 	flush_scheduled_work();
 	power_supply_unregister(&di->fg_psy);
 	platform_set_drvdata(pdev, NULL);
-	kfree(di);
 	return ret;
 }
 
@@ -2442,21 +2440,39 @@ static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
 	{"CCEOC", ab8500_fg_cc_data_end_handler},
 };
 
+static char *supply_interface[] = {
+	"ab8500_chargalg",
+	"ab8500_usb",
+};
+
 static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
+	struct ab8500_fg *di;
 	int i, irq;
 	int ret = 0;
-	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
-	struct ab8500_fg *di;
-
-	if (!plat_data) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
-	}
 
-	di = kzalloc(sizeof(*di), GFP_KERNEL);
-	if (!di)
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
 		return -ENOMEM;
+	}
+	di->bat = pdev->mfd_cell->platform_data;
+	if (!di->bat) {
+		if (np) {
+			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to get battery information\n");
+				return ret;
+			}
+		} else {
+			dev_err(&pdev->dev, "missing dt node for ab8500_fg\n");
+			return -EINVAL;
+		}
+	} else {
+		dev_info(&pdev->dev, "falling back to legacy platform data\n");
+	}
 
 	mutex_init(&di->cc_lock);
 
@@ -2465,29 +2481,13 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 	di->parent = dev_get_drvdata(pdev->dev.parent);
 	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
-	/* get fg specific platform data */
-	di->pdata = plat_data->fg;
-	if (!di->pdata) {
-		dev_err(di->dev, "no fg platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	di->fg_psy.name = "ab8500_fg";
 	di->fg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 	di->fg_psy.properties = ab8500_fg_props;
 	di->fg_psy.num_properties = ARRAY_SIZE(ab8500_fg_props);
 	di->fg_psy.get_property = ab8500_fg_get_property;
-	di->fg_psy.supplied_to = di->pdata->supplied_to;
-	di->fg_psy.num_supplicants = di->pdata->num_supplicants;
+	di->fg_psy.supplied_to = supply_interface;
+	di->fg_psy.num_supplicants = ARRAY_SIZE(supply_interface),
 	di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
 
 	di->bat_cap.max_mah_design = MILLI_TO_MICRO *
@@ -2506,8 +2506,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 	di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
 	if (di->fg_wq == NULL) {
 		dev_err(di->dev, "failed to create work queue\n");
-		ret = -ENOMEM;
-		goto free_device_info;
+		return -ENOMEM;
 	}
 
 	/* Init work for running the fg algorithm instantly */
@@ -2606,12 +2605,15 @@ free_irq:
 	}
 free_inst_curr_wq:
 	destroy_workqueue(di->fg_wq);
-free_device_info:
-	kfree(di);
 
 	return ret;
 }
 
+static const struct of_device_id ab8500_fg_match[] = {
+	{ .compatible = "stericsson,ab8500-fg", },
+	{ },
+};
+
 static struct platform_driver ab8500_fg_driver = {
 	.probe = ab8500_fg_probe,
 	.remove = __devexit_p(ab8500_fg_remove),
@@ -2620,6 +2622,7 @@ static struct platform_driver ab8500_fg_driver = {
 	.driver = {
 		.name = "ab8500-fg",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_fg_match,
 	},
 };
 
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 4d30280..94bf69b 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -231,7 +231,7 @@ struct abx500_chargalg {
 	struct abx500_chargalg_charger_info chg_info;
 	struct abx500_chargalg_battery_data batt_data;
 	struct abx500_chargalg_suspension_status susp_status;
-	struct abx500_chargalg_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply chargalg_psy;
 	struct ux500_charger *ac_chg;
@@ -1802,7 +1802,7 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev)
 
 static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 {
-	struct abx500_bm_plat_data *plat_data;
+	struct abx500_bmdevs_plat_data *plat_data;
 	int ret = 0;
 
 	struct abx500_chargalg *di =
@@ -1814,8 +1814,7 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 	di->dev = &pdev->dev;
 
 	plat_data = pdev->dev.platform_data;
-	di->pdata = plat_data->chargalg;
-	di->bat = plat_data->battery;
+	di->pdata = plat_data;
 
 	/* chargalg supply */
 	di->chargalg_psy.name = "abx500_chargalg";
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 5d5298d..33f2c58 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -267,39 +267,27 @@ struct abx500_bm_data {
 	int gnd_lift_resistance;
 	const struct abx500_maxim_parameters *maxi;
 	const struct abx500_bm_capacity_levels *cap_levels;
-	const struct abx500_battery_type *bat_type;
+	struct abx500_battery_type *bat_type;
 	const struct abx500_bm_charger_parameters *chg_params;
 	const struct abx500_fg_parameters *fg_params;
 };
 
-struct abx500_chargalg_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
-};
-
-struct abx500_charger_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
-	bool autopower_cfg;
-};
+extern struct abx500_bm_data ab8500_bm_data;
 
-struct abx500_btemp_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
+struct abx500_bmdevs_plat_data {
+	char	**supplied_to;
+	size_t	num_supplicants;
+	bool	autopower_cfg;
 };
 
-struct abx500_fg_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
+enum {
+	NTC_EXTERNAL = 0,
+	NTC_INTERNAL,
 };
 
-struct abx500_bm_plat_data {
-	struct abx500_bm_data *battery;
-	struct abx500_charger_platform_data *charger;
-	struct abx500_btemp_platform_data *btemp;
-	struct abx500_fg_platform_data *fg;
-	struct abx500_chargalg_platform_data *chargalg;
-};
+int bmdevs_of_probe(struct device *dev,
+		struct device_node *np,
+		struct abx500_bm_data **battery);
 
 int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
 	u8 value);
-- 
1.7.10.4


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

* [PATCH 2/4] mfd: ab8500: add devicetree support for btemp
  2012-11-22 18:43 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
@ 2012-11-22 18:43 ` Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 3/4] mfd: ab8500: add devicetree support for charger Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 4/4] mfd: ab8500: add devicetree support for chargalg Rajanikanth H.V
  3 siblings, 0 replies; 20+ messages in thread
From: Rajanikanth H.V @ 2012-11-22 18:43 UTC (permalink / raw)
  To: rob.herring, robherring2, francescolavra.fl, anton.vorontsov
  Cc: lee.jones, arnd, linus.walleij, linux-arm-kernel, linux-kernel,
	linaro-dev, patches, STEricsson_nomadik_linux, rajanikanth.hv,
	Rajanikanth H.V

From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>

This patch adds device tree support for
battery-temperature-monitor driver

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@linaro.org>
---
 Documentation/devicetree/bindings/mfd/ab8500.txt   |    6 ++
 .../bindings/power_supply/ab8500/btemp.txt         |   16 +++++
 arch/arm/boot/dts/dbx5x0.dtsi                      |    5 ++
 drivers/mfd/ab8500-core.c                          |    5 ++
 drivers/power/Kconfig                              |    6 --
 drivers/power/ab8500_bmdata.c                      |    4 +-
 drivers/power/ab8500_btemp.c                       |   65 ++++++++++++--------
 7 files changed, 73 insertions(+), 34 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt

diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
index 6ca8d81..f2ee0e7 100644
--- a/Documentation/devicetree/bindings/mfd/ab8500.txt
+++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
@@ -30,6 +30,12 @@ ab8500-fg                : 			: vddadc       : Fuel Gauge
 			 : LOW_BAT_F		:	       : LOW threshold battery voltage
 			 : CC_INT_CALIB		:	       : Coulomb Counter Internal Calibration
 			 : CCEOC		:	       : Coulomb Counter End of Conversion
+ab8500-btemp		 :			: vtvout       : Battery Temperature
+			 : BAT_CTRL_INDB        :              : Battery Removal Indicator
+			 : BTEMP_LOW            :              : Btemp < BtempLow, if battery temperature is lower than -10°C
+			 : BTEMP_LOW_MEDIUM     :              : BtempLow < Btemp < BtempMedium,if battery temperature is between -10 and 0°C
+			 : BTEMP_MEDIUM_HIGH    :	       : BtempMedium < Btemp < BtempHigh,if battery temperature is between 0°C and“MaxTemp
+			 : BTEMP_HIGH           :              : Btemp > BtempHigh, if battery temperature is higher than “MaxTemp
 ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
                            SW_CONV_END          :              :
 ab8500-gpio              :                      :              : GPIO Controller
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..0ba1bcc
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
@@ -0,0 +1,16 @@
+=== AB8500 Battery Temperature Monitor Driver ===
+
+The properties below describes the node for btemp driver.
+
+Required Properties:
+- compatible = Shall be: "stericsson,ab8500-btemp"
+- battery = Shall be battery specific information
+
+	Example:
+	ab8500_btemp {
+		compatible = "stericsson,ab8500-btemp";
+		battery	   = <&ab8500_battery>;
+	};
+
+For information on battery specific node, Ref:
+Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 155cf53..3f1d899 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -357,6 +357,11 @@
 					thermistor-on-batctrl;
 				};
 
+				ab8500-btemp {
+					compatible = "stericsson,ab8500-btemp";
+					battery	   = <&ab8500_battery>;
+				};
+
 				ab8500-fg {
 					compatible = "stericsson,ab8500-fg";
 					battery	   = <&ab8500_battery>;
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 7c3017b..94d45be 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1046,8 +1046,13 @@ 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,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
 	},
 	{
 		.name = "ab8500-fg",
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 49a8939..027f74e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -329,12 +329,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.c b/drivers/power/ab8500_bmdata.c
index 0366270..ff8f055 100644
--- a/drivers/power/ab8500_bmdata.c
+++ b/drivers/power/ab8500_bmdata.c
@@ -29,7 +29,7 @@ static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
 	{65, 12500},
 };
 static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
-	{-5, 165418},
+	{-5, 200000},
 	{ 0, 159024},
 	{ 5, 151921},
 	{10, 144300},
@@ -237,7 +237,7 @@ struct abx500_battery_type bat_type_thermistor[] = {
 },
 {
 	.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 abc2abc..b5dfc77 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -20,11 +20,13 @@
 #include <linux/power_supply.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
-#include <linux/mfd/abx500/ab8500.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/mfd/abx500/ab8500-gpadc.h>
-#include <linux/jiffies.h>
 
 #define VTVOUT_V			1800
 
@@ -76,7 +78,6 @@ struct ab8500_btemp_ranges {
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
  * @fg:			Pointer to the struct fg
- * @pdata:		Pointer to the abx500_btemp platform data
  * @bat:		Pointer to the abx500_bm platform data
  * @btemp_psy:		Structure for BTEMP specific battery properties
  * @events:		Structure for information about events triggered
@@ -93,7 +94,6 @@ struct ab8500_btemp {
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
 	struct ab8500_fg *fg;
-	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply btemp_psy;
 	struct ab8500_btemp_events events;
@@ -955,48 +955,58 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev)
 	flush_scheduled_work();
 	power_supply_unregister(&di->btemp_psy);
 	platform_set_drvdata(pdev, NULL);
-	kfree(di);
 
 	return 0;
 }
 
+static char *supply_interface[] = {
+	"ab8500_chargalg",
+	"ab8500_fg",
+};
+
 static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 {
-	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
+	struct device_node *np = pdev->dev.of_node;
 	struct ab8500_btemp *di;
 	int irq, i, ret = 0;
 	u8 val;
 
-	if (!plat_data) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
+		return -ENOMEM;
 	}
 
-	di = kzalloc(sizeof(*di), GFP_KERNEL);
-	if (!di)
-		return -ENOMEM;
+	di->bat = pdev->mfd_cell->platform_data;
+	if (!di->bat) {
+		if (np) {
+			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to get battery information\n");
+				return ret;
+			}
+		} else {
+			dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n");
+			return -EINVAL;
+		}
+	} else {
+		dev_info(&pdev->dev, "falling back to legacy platform data\n");
+	}
 
 	/* 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;
-	if (!di->pdata) {
-		dev_err(di->dev, "no btemp platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	/* BTEMP supply */
 	di->btemp_psy.name = "ab8500_btemp";
 	di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 	di->btemp_psy.properties = ab8500_btemp_props;
 	di->btemp_psy.num_properties = ARRAY_SIZE(ab8500_btemp_props);
 	di->btemp_psy.get_property = ab8500_btemp_get_property;
-	di->btemp_psy.supplied_to = di->pdata->supplied_to;
-	di->btemp_psy.num_supplicants = di->pdata->num_supplicants;
+	di->btemp_psy.supplied_to = supply_interface;
+	di->btemp_psy.num_supplicants = ARRAY_SIZE(supply_interface);
 	di->btemp_psy.external_power_changed =
 		ab8500_btemp_external_power_changed;
 
@@ -1006,8 +1016,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 		create_singlethread_workqueue("ab8500_btemp_wq");
 	if (di->btemp_wq == NULL) {
 		dev_err(di->dev, "failed to create work queue\n");
-		ret = -ENOMEM;
-		goto free_device_info;
+		return -ENOMEM;
 	}
 
 	/* Init work for measuring temperature periodically */
@@ -1085,12 +1094,15 @@ free_irq:
 	}
 free_btemp_wq:
 	destroy_workqueue(di->btemp_wq);
-free_device_info:
-	kfree(di);
 
 	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),
@@ -1099,6 +1111,7 @@ static struct platform_driver ab8500_btemp_driver = {
 	.driver = {
 		.name = "ab8500-btemp",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_btemp_match,
 	},
 };
 
-- 
1.7.10.4


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

* [PATCH 3/4] mfd: ab8500: add devicetree support for charger
  2012-11-22 18:43 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 2/4] mfd: ab8500: add devicetree support for btemp Rajanikanth H.V
@ 2012-11-22 18:43 ` Rajanikanth H.V
  2012-11-22 18:43 ` [PATCH 4/4] mfd: ab8500: add devicetree support for chargalg Rajanikanth H.V
  3 siblings, 0 replies; 20+ messages in thread
From: Rajanikanth H.V @ 2012-11-22 18:43 UTC (permalink / raw)
  To: rob.herring, robherring2, francescolavra.fl, anton.vorontsov
  Cc: lee.jones, arnd, linus.walleij, linux-arm-kernel, linux-kernel,
	linaro-dev, patches, STEricsson_nomadik_linux, rajanikanth.hv,
	Rajanikanth H.V

From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>

This patch adds device tree support for ab8500-charger
driver

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@linaro.org>
---
 Documentation/devicetree/bindings/mfd/ab8500.txt   |   14 ++++
 .../bindings/power_supply/ab8500/charger.txt       |   25 +++++++
 arch/arm/boot/dts/dbx5x0.dtsi                      |    6 ++
 drivers/mfd/ab8500-core.c                          |    5 ++
 drivers/power/ab8500_charger.c                     |   73 ++++++++++++--------
 5 files changed, 96 insertions(+), 27 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/charger.txt

diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
index f2ee0e7..13b707b 100644
--- a/Documentation/devicetree/bindings/mfd/ab8500.txt
+++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
@@ -36,6 +36,20 @@ ab8500-btemp		 :			: vtvout       : Battery Temperature
 			 : BTEMP_LOW_MEDIUM     :              : BtempLow < Btemp < BtempMedium,if battery temperature is between -10 and 0°C
 			 : BTEMP_MEDIUM_HIGH    :	       : BtempMedium < Btemp < BtempHigh,if battery temperature is between 0°C and“MaxTemp
 			 : BTEMP_HIGH           :              : Btemp > BtempHigh, if battery temperature is higher than “MaxTemp
+ab8500-charger		 :			: vddadc       : Charger interface
+			 : MAIN_CH_UNPLUG_DET	:	       : main charger unplug detection management (not in 8505)
+			 : MAIN_CHARGE_PLUG_DET	:	       : main charger plug detection management (not in 8505)
+			 : MAIN_EXT_CH_NOT_OK	:	       : main charger not OK
+			 : MAIN_CH_TH_PROT_R	:	       : Die temp is above main charger
+			 : MAIN_CH_TH_PROT_F	:	       : Die temp is below main charger
+			 : VBUS_DET_F		:	       : VBUS falling detected
+			 : VBUS_DET_R		:	       : VBUS rising detected
+			 : USB_LINK_STATUS	:	       : USB link status has changed
+			 : USB_CH_TH_PROT_R	:	       : Die temp is above usb charger
+			 : USB_CH_TH_PROT_F	:	       : Die temp is below usb charger
+			 : USB_CHARGER_NOT_OKR	:	       : allowed USB charger not ok detection
+			 : VBUS_OVV		:	       : Overvoltage on Vbus ball detected (USB charge is stopped)
+			 : CH_WD_EXP		:	       : Charger watchdog detected
 ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
                            SW_CONV_END          :              :
 ab8500-gpio              :                      :              : GPIO Controller
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/charger.txt b/Documentation/devicetree/bindings/power_supply/ab8500/charger.txt
new file mode 100644
index 0000000..6bdbb08
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/charger.txt
@@ -0,0 +1,25 @@
+=== AB8500 Charger Driver ===
+
+Required Properties:
+- compatible = Shall be "stericsson,ab8500-charger"
+- battery = Shall be battery specific information
+	Example:
+	ab8500_charger {
+		compatible = "stericsson,ab8500-charger";
+		battery	   = <&ab8500_battery>;
+	};
+
+- vddadc-supply: Supply for USB and Main charger
+	Example:
+	ab8500-charger {
+		vddadc-supply	= <&ab8500_ldo_tvout_reg>;
+	}
+- autopower_cfg:
+	Boolean value depicting the presence of 'automatic poweron after powerloss'
+	Example:
+	ab8500-charger {
+		autopower_cfg;
+	};
+
+For information on battery specific node, Ref:
+Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 3f1d899..7e9c01a 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -357,6 +357,12 @@
 					thermistor-on-batctrl;
 				};
 
+				ab8500-charger {
+					compatible	= "stericsson,ab8500-charger";
+					battery		= <&ab8500_battery>;
+					vddadc-supply	= <&ab8500_ldo_tvout_reg>;
+				};
+
 				ab8500-btemp {
 					compatible = "stericsson,ab8500-btemp";
 					battery	   = <&ab8500_battery>;
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 94d45be..c7a120b 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1041,8 +1041,13 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = {
 static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 	{
 		.name = "ab8500-charger",
+		.of_compatible = "stericsson,ab8500-charger",
 		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
 		.resources = ab8500_charger_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
 	},
 	{
 		.name = "ab8500-btemp",
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 723edb4..5156a98 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -23,6 +23,8 @@
 #include <linux/err.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500-bm.h>
@@ -181,9 +183,9 @@ struct ab8500_charger_usb_state {
  * @vbat		Battery voltage
  * @old_vbat		Previously measured battery voltage
  * @autopower		Indicate if we should have automatic pwron after pwrloss
+ * @autopower_cfg	platform specific power config support for "pwron after pwrloss"
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
- * @pdata:		Pointer to the abx500_charger platform data
  * @bat:		Pointer to the abx500_bm platform data
  * @flags:		Structure for information about events triggered
  * @usb_state:		Structure for usb stack information
@@ -218,9 +220,9 @@ struct ab8500_charger {
 	int vbat;
 	int old_vbat;
 	bool autopower;
+	bool autopower_cfg;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct ab8500_charger_event_flags flags;
 	struct ab8500_charger_usb_state usb_state;
@@ -322,7 +324,7 @@ static void ab8500_power_loss_handling(struct ab8500_charger *di)
 static void ab8500_power_supply_changed(struct ab8500_charger *di,
 					struct power_supply *psy)
 {
-	if (di->pdata->autopower_cfg) {
+	if (di->autopower_cfg) {
 		if (!di->usb.charger_connected &&
 		    !di->ac.charger_connected &&
 		    di->autopower) {
@@ -2526,25 +2528,47 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
 	power_supply_unregister(&di->usb_chg.psy);
 	power_supply_unregister(&di->ac_chg.psy);
 	platform_set_drvdata(pdev, NULL);
-	kfree(di);
 
 	return 0;
 }
 
+static char *supply_interface[] = {
+	"ab8500_chargalg",
+	"ab8500_fg",
+	"ab8500_btemp",
+};
+
 static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 {
-	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
+	struct device_node *np = pdev->dev.of_node;
 	struct ab8500_charger *di;
 	int irq, i, charger_status, ret = 0;
 
-	if (!plat_data) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
+		return -ENOMEM;
 	}
 
-	di = kzalloc(sizeof(*di), GFP_KERNEL);
-	if (!di)
-		return -ENOMEM;
+	di->bat = pdev->mfd_cell->platform_data;
+	if (!di->bat) {
+		if (np) {
+			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to get battery information\n");
+				return ret;
+			}
+			di->autopower_cfg =
+				of_property_read_bool(np, "autopower_cfg");
+		} else {
+			dev_err(&pdev->dev, "missing dt node for ab8500_charger\n");
+			return -EINVAL;
+		}
+	} else {
+		dev_info(&pdev->dev, "falling back to legacy platform data\n");
+		di->autopower_cfg = false;
+	}
 
 	/* get parent data */
 	di->dev = &pdev->dev;
@@ -2554,14 +2578,6 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 	/* initialize lock */
 	spin_lock_init(&di->usb_state.usb_lock);
 
-	/* get charger specific platform data */
-	di->pdata = plat_data;
-	if (!di->pdata) {
-		dev_err(di->dev, "no charger platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	di->autopower = false;
 
 	/* AC supply */
@@ -2571,8 +2587,8 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 	di->ac_chg.psy.properties = ab8500_charger_ac_props;
 	di->ac_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_ac_props);
 	di->ac_chg.psy.get_property = ab8500_charger_ac_get_property;
-	di->ac_chg.psy.supplied_to = di->pdata->supplied_to;
-	di->ac_chg.psy.num_supplicants = di->pdata->num_supplicants;
+	di->ac_chg.psy.supplied_to = supply_interface;
+	di->ac_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
 	/* ux500_charger sub-class */
 	di->ac_chg.ops.enable = &ab8500_charger_ac_en;
 	di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
@@ -2589,8 +2605,8 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 	di->usb_chg.psy.properties = ab8500_charger_usb_props;
 	di->usb_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_usb_props);
 	di->usb_chg.psy.get_property = ab8500_charger_usb_get_property;
-	di->usb_chg.psy.supplied_to = di->pdata->supplied_to;
-	di->usb_chg.psy.num_supplicants = di->pdata->num_supplicants;
+	di->usb_chg.psy.supplied_to = supply_interface;
+	di->usb_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
 	/* ux500_charger sub-class */
 	di->usb_chg.ops.enable = &ab8500_charger_usb_en;
 	di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
@@ -2606,8 +2622,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 		create_singlethread_workqueue("ab8500_charger_wq");
 	if (di->charger_wq == NULL) {
 		dev_err(di->dev, "failed to create work queue\n");
-		ret = -ENOMEM;
-		goto free_device_info;
+		return -ENOMEM;
 	}
 
 	/* Init work for HW failure check */
@@ -2749,12 +2764,15 @@ free_regulator:
 	regulator_put(di->regu);
 free_charger_wq:
 	destroy_workqueue(di->charger_wq);
-free_device_info:
-	kfree(di);
 
 	return ret;
 }
 
+static const struct of_device_id ab8500_charger_match[] = {
+	{ .compatible = "stericsson,ab8500-charger", },
+	{ },
+};
+
 static struct platform_driver ab8500_charger_driver = {
 	.probe = ab8500_charger_probe,
 	.remove = __devexit_p(ab8500_charger_remove),
@@ -2763,6 +2781,7 @@ static struct platform_driver ab8500_charger_driver = {
 	.driver = {
 		.name = "ab8500-charger",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_charger_match,
 	},
 };
 
-- 
1.7.10.4


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

* [PATCH 4/4] mfd: ab8500: add devicetree support for chargalg
  2012-11-22 18:43 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
                   ` (2 preceding siblings ...)
  2012-11-22 18:43 ` [PATCH 3/4] mfd: ab8500: add devicetree support for charger Rajanikanth H.V
@ 2012-11-22 18:43 ` Rajanikanth H.V
  3 siblings, 0 replies; 20+ messages in thread
From: Rajanikanth H.V @ 2012-11-22 18:43 UTC (permalink / raw)
  To: rob.herring, robherring2, francescolavra.fl, anton.vorontsov
  Cc: lee.jones, arnd, linus.walleij, linux-arm-kernel, linux-kernel,
	linaro-dev, patches, STEricsson_nomadik_linux, rajanikanth.hv,
	Rajanikanth H.V

From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>

This patch adds device tree support for charging algorithm
driver

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@linaro.org>
---
 .../bindings/power_supply/ab8500/chargalg.txt      |   16 ++++++
 arch/arm/boot/dts/dbx5x0.dtsi                      |    5 ++
 drivers/mfd/ab8500-core.c                          |    5 ++
 drivers/power/abx500_chargalg.c                    |   56 ++++++++++++++------
 include/linux/mfd/abx500.h                         |    6 ---
 5 files changed, 66 insertions(+), 22 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt

diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt
new file mode 100644
index 0000000..ef53283
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt
@@ -0,0 +1,16 @@
+=== AB8500 Charging Algorithm Driver ===
+
+The properties below describes the node for chargalg driver.
+
+Required Properties:
+- compatible = Shall be: "stericsson,ab8500-chargalg"
+- battery = Shall be battery specific information
+
+Example:
+ab8500_chargalg {
+	compatible = "stericsson,ab8500-chargalg";
+	battery	   = <&ab8500_battery>;
+};
+
+For information on battery specific node, Ref:
+Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 7e9c01a..f1661b3 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -357,6 +357,11 @@
 					thermistor-on-batctrl;
 				};
 
+				ab8500-chargalg {
+					compatible	= "stericsson,ab8500-chargalg";
+					battery		= <&ab8500_battery>;
+				};
+
 				ab8500-charger {
 					compatible	= "stericsson,ab8500-charger";
 					battery		= <&ab8500_battery>;
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index c7a120b..5ec70f2 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1071,8 +1071,13 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 	},
 	{
 		.name = "ab8500-chargalg",
+		.of_compatible = "stericsson,ab8500-chargalg",
 		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
 		.resources = ab8500_chargalg_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
 	},
 };
 
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 94bf69b..96eb2c5 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -21,6 +21,8 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ux500_chargalg.h>
 #include <linux/mfd/abx500/ab8500-bm.h>
@@ -205,7 +207,6 @@ enum maxim_ret {
  * @chg_info:		information about connected charger types
  * @batt_data:		data of the battery
  * @susp_status:	current charger suspension status
- * @pdata:		pointer to the abx500_chargalg platform data
  * @bat:		pointer to the abx500_bm platform data
  * @chargalg_psy:	structure that holds the battery properties exposed by
  *			the charging algorithm
@@ -231,7 +232,6 @@ struct abx500_chargalg {
 	struct abx500_chargalg_charger_info chg_info;
 	struct abx500_chargalg_battery_data batt_data;
 	struct abx500_chargalg_suspension_status susp_status;
-	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply chargalg_psy;
 	struct ux500_charger *ac_chg;
@@ -1795,35 +1795,55 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev)
 	flush_scheduled_work();
 	power_supply_unregister(&di->chargalg_psy);
 	platform_set_drvdata(pdev, NULL);
-	kfree(di);
 
 	return 0;
 }
 
+static char *supply_interface[] = {
+	"ab8500_fg",
+};
+
 static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 {
-	struct abx500_bmdevs_plat_data *plat_data;
+	struct device_node *np = pdev->dev.of_node;
+	struct abx500_chargalg *di;
 	int ret = 0;
 
-	struct abx500_chargalg *di =
-		kzalloc(sizeof(struct abx500_chargalg), GFP_KERNEL);
-	if (!di)
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n",
+			__func__);
 		return -ENOMEM;
+	}
+
+	di->bat = pdev->mfd_cell->platform_data;
+	if (!di->bat) {
+		if (np) {
+			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to get battery information\n");
+				return ret;
+			}
+		} else {
+			dev_err(&pdev->dev, "missing dt node for ab8500_chargalg\n");
+			return -EINVAL;
+		}
+	} else {
+		dev_info(&pdev->dev, "falling back to legacy platform data\n");
+	}
 
 	/* get device struct */
 	di->dev = &pdev->dev;
 
-	plat_data = pdev->dev.platform_data;
-	di->pdata = plat_data;
-
 	/* chargalg supply */
 	di->chargalg_psy.name = "abx500_chargalg";
 	di->chargalg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 	di->chargalg_psy.properties = abx500_chargalg_props;
 	di->chargalg_psy.num_properties = ARRAY_SIZE(abx500_chargalg_props);
 	di->chargalg_psy.get_property = abx500_chargalg_get_property;
-	di->chargalg_psy.supplied_to = di->pdata->supplied_to;
-	di->chargalg_psy.num_supplicants = di->pdata->num_supplicants;
+	di->chargalg_psy.supplied_to = supply_interface;
+	di->chargalg_psy.num_supplicants = ARRAY_SIZE(supply_interface),
 	di->chargalg_psy.external_power_changed =
 		abx500_chargalg_external_power_changed;
 
@@ -1843,7 +1863,7 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 		create_singlethread_workqueue("abx500_chargalg_wq");
 	if (di->chargalg_wq == NULL) {
 		dev_err(di->dev, "failed to create work queue\n");
-		goto free_device_info;
+		return -ENOMEM;
 	}
 
 	/* Init work for chargalg */
@@ -1884,20 +1904,24 @@ free_psy:
 	power_supply_unregister(&di->chargalg_psy);
 free_chargalg_wq:
 	destroy_workqueue(di->chargalg_wq);
-free_device_info:
-	kfree(di);
 
 	return ret;
 }
 
+static const struct of_device_id ab8500_chargalg_match[] = {
+	{ .compatible = "stericsson,ab8500-chargalg", },
+	{ },
+};
+
 static struct platform_driver abx500_chargalg_driver = {
 	.probe = abx500_chargalg_probe,
 	.remove = __devexit_p(abx500_chargalg_remove),
 	.suspend = abx500_chargalg_suspend,
 	.resume = abx500_chargalg_resume,
 	.driver = {
-		.name = "abx500-chargalg",
+		.name = "ab8500-chargalg",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_chargalg_match,
 	},
 };
 
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 33f2c58..2138bd3 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -274,12 +274,6 @@ struct abx500_bm_data {
 
 extern struct abx500_bm_data ab8500_bm_data;
 
-struct abx500_bmdevs_plat_data {
-	char	**supplied_to;
-	size_t	num_supplicants;
-	bool	autopower_cfg;
-};
-
 enum {
 	NTC_EXTERNAL = 0,
 	NTC_INTERNAL,
-- 
1.7.10.4


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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-22 18:43 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
@ 2012-11-22 20:08   ` Anton Vorontsov
  2012-11-23  9:50     ` Lee Jones
  0 siblings, 1 reply; 20+ messages in thread
From: Anton Vorontsov @ 2012-11-22 20:08 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: rob.herring, robherring2, francescolavra.fl, lee.jones, arnd,
	linus.walleij, linux-arm-kernel, linux-kernel, linaro-dev,
	patches, STEricsson_nomadik_linux, rajanikanth.hv

On Fri, Nov 23, 2012 at 12:13:44AM +0530, Rajanikanth H.V wrote:
[...]
> +/*
> + * Note that the batres_vs_temp table must be strictly sorted by falling
> + * temperature values to work.
> + */
> +struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {

It must be static.

[..]
> +struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {

Ditto.

> +	{ 60, 300},
> +	{ 30, 300},
> +	{ 20, 300},
> +	{ 10, 300},
> +	{ 00, 300},
> +	{-10, 300},
> +	{-20, 300},
> +};
> +
> +/* battery resistance table for LI ION 9100 battery */
> +struct batres_vs_temp temp_to_batres_tbl_9100[] = {

Ditto.

There are other issues, which I fixed in my tree for the previous series.
So the previous series already merged, please post patches on top of it.

Thanks,
Anton.

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-22 20:08   ` Anton Vorontsov
@ 2012-11-23  9:50     ` Lee Jones
  0 siblings, 0 replies; 20+ messages in thread
From: Lee Jones @ 2012-11-23  9:50 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Rajanikanth H.V, rob.herring, robherring2, francescolavra.fl,
	arnd, linus.walleij, linux-arm-kernel, linux-kernel, linaro-dev,
	patches, STEricsson_nomadik_linux, rajanikanth.hv


> On Fri, Nov 23, 2012 at 12:13:44AM +0530, Rajanikanth H.V wrote:
> [...]
> > +/*
> > + * Note that the batres_vs_temp table must be strictly sorted by falling
> > + * temperature values to work.
> > + */
> > +struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
> 
> It must be static.
> 
> [..]
> > +struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
> 
> Ditto.
> 
> > +	{ 60, 300},
> > +	{ 30, 300},
> > +	{ 20, 300},
> > +	{ 10, 300},
> > +	{ 00, 300},
> > +	{-10, 300},
> > +	{-20, 300},
> > +};
> > +
> > +/* battery resistance table for LI ION 9100 battery */
> > +struct batres_vs_temp temp_to_batres_tbl_9100[] = {
> 
> Ditto.
> 
> There are other issues, which I fixed in my tree for the previous series.
> So the previous series already merged, please post patches on top of it.

Ah, I see now. My apologies, I'll re-comment.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-10 16:53       ` Francesco Lavra
@ 2012-11-15 11:34         ` Rajanikanth HV
  0 siblings, 0 replies; 20+ messages in thread
From: Rajanikanth HV @ 2012-11-15 11:34 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: Rajanikanth H V, rob.herring, lee.jones, arnd, anton.vorontsov,
	Linus WALLEIJ, linux-arm-kernel, linux-kernel, linaro-dev,
	patches, STEricsson_nomadik_linux



On Saturday 10 November 2012 10:23 PM, Francesco Lavra wrote:
>>> I don't get the point of declaring the char array and copying the string
>>> in it, when you could simply use just the pointer returned by
>>> of_get_property().
>>
>> I am considering a corner case where in 'battery-type' property is not
>> present and battery is connected.In this case i promote battery to
>> UNKNOWN from null.
> 
> You could achieve the same result without using the char array, with
> this assignment:
> 
> btech = "UNKNOWN";
> 
>> FYI: Further, btemp driver will identify the connected battery based on
>> resistance value and decide to use.
>> Ref: ab8500_btemp_id(...) ab8500_btemp.c
>>
>>> Anyway, if the string property is longer than 8 characters, you are
>>> writing past the size of the destination array.
>>
>> i believe it is safe as power_supply.h comprises defines having battery
>> technology type in 4 characters length which is normally the case and
>> 7 chars length being "UNKNOWN" seldom referred
> 
> You should be able to handle whatever the device tree contains, and if
> it contains unexpected data this is not a good excuse for locking up the
> system.
agreed, if we were to go by what device tree contains then explicit
assignment for battery type as "UNKNOWN" is not required, hence only 2
use case persist as :
a) property name with one of the said value be present
	(as per documentation)
b) property name not present

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-07 18:45     ` Rajanikanth H V
@ 2012-11-10 16:53       ` Francesco Lavra
  2012-11-15 11:34         ` Rajanikanth HV
  0 siblings, 1 reply; 20+ messages in thread
From: Francesco Lavra @ 2012-11-10 16:53 UTC (permalink / raw)
  To: Rajanikanth H V
  Cc: rob.herring, lee.jones, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux, rajanikanth.hv

On 11/07/2012 07:45 PM, Rajanikanth H V wrote:
> On Thu, 1 Nov 2012, Francesco Lavra wrote:
> [...]
>>> +    btech = of_get_property(np_bat_supply,
>>> +        "stericsson,battery-type", NULL);
>>> +    if (!btech) {
>>> +        dev_warn(dev, "missing property battery-name/type\n");
>>> +        strcpy(bat_tech, "UNKNOWN");
>>> +    } else {
>>> +        strcpy(bat_tech, btech);
>>> +    }
>>
>> I don't get the point of declaring the char array and copying the string
>> in it, when you could simply use just the pointer returned by
>> of_get_property().
> 
> I am considering a corner case where in 'battery-type' property is not
> present and battery is connected.In this case i promote battery to
> UNKNOWN from null.

You could achieve the same result without using the char array, with
this assignment:

btech = "UNKNOWN";

> FYI: Further, btemp driver will identify the connected battery based on
> resistance value and decide to use.
> Ref: ab8500_btemp_id(...) ab8500_btemp.c
> 
>> Anyway, if the string property is longer than 8 characters, you are
>> writing past the size of the destination array.
> 
> i believe it is safe as power_supply.h comprises defines having battery
> technology type in 4 characters length which is normally the case and
> 7 chars length being "UNKNOWN" seldom referred

You should be able to handle whatever the device tree contains, and if
it contains unexpected data this is not a good excuse for locking up the
system.

--
Francesco

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-11-01 15:15   ` Francesco Lavra
@ 2012-11-07 18:45     ` Rajanikanth H V
  2012-11-10 16:53       ` Francesco Lavra
  0 siblings, 1 reply; 20+ messages in thread
From: Rajanikanth H V @ 2012-11-07 18:45 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: Rajanikanth H.V, rob.herring, lee.jones, arnd, anton.vorontsov,
	linus.walleij, linux-arm-kernel, linux-kernel, linaro-dev,
	patches, STEricsson_nomadik_linux, rajanikanth.hv

On Thu, 1 Nov 2012, Francesco Lavra wrote:
[...]
>> +	btech = of_get_property(np_bat_supply,
>> +		"stericsson,battery-type", NULL);
>> +	if (!btech) {
>> +		dev_warn(dev, "missing property battery-name/type\n");
>> +		strcpy(bat_tech, "UNKNOWN");
>> +	} else {
>> +		strcpy(bat_tech, btech);
>> +	}
>
> I don't get the point of declaring the char array and copying the string
> in it, when you could simply use just the pointer returned by
> of_get_property().

I am considering a corner case where in 'battery-type' property is not
present and battery is connected.In this case i promote battery to
UNKNOWN from null.
FYI: Further, btemp driver will identify the connected battery based on
resistance value and decide to use.
Ref: ab8500_btemp_id(...) ab8500_btemp.c

> Anyway, if the string property is longer than 8 characters, you are
> writing past the size of the destination array.

i believe it is safe as power_supply.h comprises defines having battery
technology type in 4 characters length which is normally the case and
7 chars length being "UNKNOWN" seldom referred


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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-31 15:40 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
@ 2012-11-01 15:15   ` Francesco Lavra
  2012-11-07 18:45     ` Rajanikanth H V
  0 siblings, 1 reply; 20+ messages in thread
From: Francesco Lavra @ 2012-11-01 15:15 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: rob.herring, lee.jones, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux, rajanikanth.hv

On 10/31/2012 04:40 PM, Rajanikanth H.V wrote:
> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
> 
> - This patch adds device tree support for fuelgauge driver
> - optimize bm devices platform_data usage and of_probe(...)
>   Note: of_probe() routine for battery managed devices is made
>   common across all bm drivers.
> - test status:
>   - interrupt numbers assigned differs between legacy and FDT mode.
> 
> Signed-off-by: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
[...]
> +int __devinit
> +bmdevs_of_probe(struct device *dev,
> +		struct device_node *np,
> +		struct abx500_bm_data **battery)
> +{
> +	struct	abx500_battery_type *btype;
> +	struct  device_node *np_bat_supply;
> +	struct	abx500_bm_data *bat;
> +	const char *btech;
> +	char bat_tech[8];
> +	int i, thermistor;
> +
> +	*battery = &ab8500_bm_data;
> +
> +	/* get phandle to 'battery-info' node */
> +	np_bat_supply = of_parse_phandle(np, "battery", 0);
> +	if (!np_bat_supply) {
> +		dev_err(dev, "missing property battery\n");
> +		return -EINVAL;
> +	}
> +	if (of_property_read_bool(np_bat_supply,
> +			"thermistor-on-batctrl"))
> +		thermistor = NTC_INTERNAL;
> +	else
> +		thermistor = NTC_EXTERNAL;
> +
> +	bat = *battery;
> +	if (thermistor == NTC_EXTERNAL) {
> +		bat->n_btypes  = 4;
> +		bat->bat_type  = bat_type_ext_thermistor;
> +		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
> +	}
> +	btech = of_get_property(np_bat_supply,
> +		"stericsson,battery-type", NULL);
> +	if (!btech) {
> +		dev_warn(dev, "missing property battery-name/type\n");
> +		strcpy(bat_tech, "UNKNOWN");
> +	} else {
> +		strcpy(bat_tech, btech);
> +	}

I don't get the point of declaring the char array and copying the string
in it, when you could simply use just the pointer returned by
of_get_property().
Anyway, if the string property is longer than 8 characters, you are
writing past the size of the destination array.

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

* [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-31 15:40 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
@ 2012-10-31 15:40 ` Rajanikanth H.V
  2012-11-01 15:15   ` Francesco Lavra
  0 siblings, 1 reply; 20+ messages in thread
From: Rajanikanth H.V @ 2012-10-31 15:40 UTC (permalink / raw)
  To: rob.herring, lee.jones, francescolavra.fl
  Cc: arnd, anton.vorontsov, linus.walleij, linux-arm-kernel,
	linux-kernel, linaro-dev, patches, STEricsson_nomadik_linux,
	rajanikanth.hv

From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>

- This patch adds device tree support for fuelgauge driver
- optimize bm devices platform_data usage and of_probe(...)
  Note: of_probe() routine for battery managed devices is made
  common across all bm drivers.
- test status:
  - interrupt numbers assigned differs between legacy and FDT mode.

Signed-off-by: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
---
 Documentation/devicetree/bindings/mfd/ab8500.txt   |    7 +-
 .../devicetree/bindings/power_supply/ab8500/fg.txt |   58 +++
 arch/arm/boot/dts/dbx5x0.dtsi                      |   12 +-
 drivers/mfd/ab8500-core.c                          |    5 +
 drivers/power/Makefile                             |    2 +-
 drivers/power/ab8500_bmdata.c                      |  518 ++++++++++++++++++++
 drivers/power/ab8500_btemp.c                       |   16 +-
 drivers/power/ab8500_charger.c                     |   16 +-
 drivers/power/ab8500_fg.c                          |   81 +--
 drivers/power/abx500_chargalg.c                    |    8 +-
 include/linux/mfd/abx500.h                         |   36 +-
 11 files changed, 664 insertions(+), 95 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
 create mode 100644 drivers/power/ab8500_bmdata.c

diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
index ce83c8d..6ca8d81 100644
--- a/Documentation/devicetree/bindings/mfd/ab8500.txt
+++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
@@ -24,7 +24,12 @@ ab8500-bm                :                      :              : Battery Manager
 ab8500-btemp             :                      :              : Battery Temperature
 ab8500-charger           :                      :              : Battery Charger
 ab8500-codec             :                      :              : Audio Codec
-ab8500-fg                :                      :              : Fuel Gauge
+ab8500-fg                : 			: vddadc       : Fuel Gauge
+			 : NCONV_ACCU           :	       : Accumulate N Sample Conversion
+			 : BATT_OVV		:	       : Battery Over Voltage
+			 : LOW_BAT_F		:	       : LOW threshold battery voltage
+			 : CC_INT_CALIB		:	       : Coulomb Counter Internal Calibration
+			 : CCEOC		:	       : Coulomb Counter End of Conversion
 ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
                            SW_CONV_END          :              :
 ab8500-gpio              :                      :              : GPIO Controller
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
new file mode 100644
index 0000000..ccafcb9
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
@@ -0,0 +1,58 @@
+=== AB8500 Fuel Gauge Driver ===
+
+AB8500 is a mixed signal multimedia and power management
+device comprising: power and energy-management-module,
+wall-charger, usb-charger, audio codec, general purpose adc,
+tvout, clock management and sim card interface.
+
+Fuelgauge support is part of energy-management-modules, other
+components of this module are:
+main-charger, usb-combo-charger and battery-temperature-monitoring.
+
+The properties below describes the node for fuelgauge driver.
+
+Required Properties:
+- compatible = This shall be: "stericsson,ab8500-fg"
+- battery = Shall be battery specific information
+	Example:
+	ab8500_fg {
+		compatible = "stericsson,ab8500-fg";
+		battery	   = <&ab8500_battery>;
+	};
+
+dependent node:
+	ab8500_battery: ab8500_battery {
+	};
+	This node will provide information on 'thermistor interface' and
+	'battery technology type' used.
+
+Properties of this node are:
+thermistor-on-batctrl:
+	A boolean value indicating thermistor interface	to battery
+
+	Note:
+	'btemp' and 'batctrl' are the pins interfaced for battery temperature
+	measurement, 'btemp' signal is used when NTC(negative temperature
+	coefficient) resister is interfaced external to battery whereas
+	'batctrl' pin is used when NTC resister is internal to battery.
+
+	Example:
+	ab8500_battery: ab8500_battery {
+		thermistor-on-batctrl;
+	};
+	indicates: NTC resister is internal to battery, 'batctrl' is used
+		for thermal measurement.
+
+	The absence of property 'thermal-on-batctrl' indicates
+	NTC resister is external to battery and  'btemp' signal is used
+	for thermal measurement.
+
+battery-type:
+	This shall be the battery manufacturing technology type,
+	allowed types are:
+		"UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
+	Example:
+	ab8500_battery: ab8500_battery {
+		stericsson,battery-type = "LIPO";
+	}
+
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 748ba7a..68317f5 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -352,7 +352,17 @@
 					vddadc-supply = <&ab8500_ldo_tvout_reg>;
 				};
 
-				ab8500-usb {
+				ab8500_battery: ab8500_battery {
+					stericsson,battery-type = "LIPO";
+					thermistor-on-batctrl;
+				};
+
+				ab8500_fg {
+					compatible = "stericsson,ab8500-fg";
+					battery	   = <&ab8500_battery>;
+				};
+
+				ab8500_usb {
 					compatible = "stericsson,ab8500-usb";
 					interrupts = < 90 0x4
 						       96 0x4
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 1667c77..7c3017b 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1051,8 +1051,13 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 	},
 	{
 		.name = "ab8500-fg",
+		.of_compatible = "stericsson,ab8500-fg",
 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
 		.resources = ab8500_fg_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
 	},
 	{
 		.name = "ab8500-chargalg",
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee58afb..2c58d4e 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
-obj-$(CONFIG_AB8500_BM)		+= ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM)		+= ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
 obj-$(CONFIG_CHARGER_ISP1704)	+= isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)	+= max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)	+= twl4030_charger.o
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
new file mode 100644
index 0000000..fa6ea52
--- /dev/null
+++ b/drivers/power/ab8500_bmdata.c
@@ -0,0 +1,518 @@
+#include <linux/export.h>
+#include <linux/power_supply.h>
+#include <linux/of.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+
+/*
+ * These are the defined batteries that uses a NTC and ID resistor placed
+ * inside of the battery pack.
+ * Note that the res_to_temp table must be strictly sorted by falling resistance
+ * values to work.
+ */
+static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
+	{-5, 53407},
+	{ 0, 48594},
+	{ 5, 43804},
+	{10, 39188},
+	{15, 34870},
+	{20, 30933},
+	{25, 27422},
+	{30, 24347},
+	{35, 21694},
+	{40, 19431},
+	{45, 17517},
+	{50, 15908},
+	{55, 14561},
+	{60, 13437},
+	{65, 12500},
+};
+static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
+	{-5, 165418},
+	{ 0, 159024},
+	{ 5, 151921},
+	{10, 144300},
+	{15, 136424},
+	{20, 128565},
+	{25, 120978},
+	{30, 113875},
+	{35, 107397},
+	{40, 101629},
+	{45,  96592},
+	{50,  92253},
+	{55,  88569},
+	{60,  85461},
+	{65,  82869},
+};
+static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
+	{4171,	100},
+	{4114,	 95},
+	{4009,	 83},
+	{3947,	 74},
+	{3907,	 67},
+	{3863,	 59},
+	{3830,	 56},
+	{3813,	 53},
+	{3791,	 46},
+	{3771,	 33},
+	{3754,	 25},
+	{3735,	 20},
+	{3717,	 17},
+	{3681,	 13},
+	{3664,	  8},
+	{3651,	  6},
+	{3635,	  5},
+	{3560,	  3},
+	{3408,    1},
+	{3247,	  0},
+};
+static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
+	{4161,	100},
+	{4124,	 98},
+	{4044,	 90},
+	{4003,	 85},
+	{3966,	 80},
+	{3933,	 75},
+	{3888,	 67},
+	{3849,	 60},
+	{3813,	 55},
+	{3787,	 47},
+	{3772,	 30},
+	{3751,	 25},
+	{3718,	 20},
+	{3681,	 16},
+	{3660,	 14},
+	{3589,	 10},
+	{3546,	  7},
+	{3495,	  4},
+	{3404,	  2},
+	{3250,	  0},
+};
+
+static struct abx500_v_to_cap cap_tbl[] = {
+	{4186,	100},
+	{4163,	 99},
+	{4114,	 95},
+	{4068,	 90},
+	{3990,	 80},
+	{3926,	 70},
+	{3898,	 65},
+	{3866,	 60},
+	{3833,	 55},
+	{3812,	 50},
+	{3787,	 40},
+	{3768,	 30},
+	{3747,	 25},
+	{3730,	 20},
+	{3705,	 15},
+	{3699,	 14},
+	{3684,	 12},
+	{3672,	  9},
+	{3657,	  7},
+	{3638,	  6},
+	{3556,	  4},
+	{3424,	  2},
+	{3317,	  1},
+	{3094,	  0},
+};
+
+/*
+ * Note that the res_to_temp table must be strictly sorted by falling
+ * resistance values to work.
+ */
+static struct abx500_res_to_temp temp_tbl[] = {
+	{-5, 214834},
+	{ 0, 162943},
+	{ 5, 124820},
+	{10,  96520},
+	{15,  75306},
+	{20,  59254},
+	{25,  47000},
+	{30,  37566},
+	{35,  30245},
+	{40,  24520},
+	{45,  20010},
+	{50,  16432},
+	{55,  13576},
+	{60,  11280},
+	{65,   9425},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
+	{ 40, 120},
+	{ 30, 135},
+	{ 20, 165},
+	{ 10, 230},
+	{ 00, 325},
+	{-10, 445},
+	{-20, 595},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
+	{ 60, 300},
+	{ 30, 300},
+	{ 20, 300},
+	{ 10, 300},
+	{ 00, 300},
+	{-10, 300},
+	{-20, 300},
+};
+
+/* battery resistance table for LI ION 9100 battery */
+struct batres_vs_temp temp_to_batres_tbl_9100[] = {
+	{ 60, 180},
+	{ 30, 180},
+	{ 20, 180},
+	{ 10, 180},
+	{ 00, 180},
+	{-10, 180},
+	{-20, 180},
+};
+
+struct abx500_battery_type bat_type_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+	/* First element always represent the UNKNOWN battery */
+	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+	.resis_high = 0,
+	.resis_low = 0,
+	.battery_resistance = 300,
+	.charge_full_design = 612,
+	.nominal_voltage = 3700,
+	.termination_vol = 4050,
+	.termination_curr = 200,
+	.recharge_vol = 3990,
+	.normal_cur_lvl = 400,
+	.normal_vol_lvl = 4100,
+	.maint_a_cur_lvl = 400,
+	.maint_a_vol_lvl = 4050,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 400,
+	.maint_b_vol_lvl = 4000,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 53407,
+	.resis_low = 12500,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3600,
+	.termination_vol = 4150,
+	.termination_curr = 80,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
+	.r_to_t_tbl = temp_tbl_A_thermistor,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
+	.v_to_cap_tbl = cap_tbl_A_thermistor,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 165418,
+	.resis_low = 82869,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3600,
+	.termination_vol = 4150,
+	.termination_curr = 80,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
+	.r_to_t_tbl = temp_tbl_B_thermistor,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
+	.v_to_cap_tbl = cap_tbl_B_thermistor,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+
+struct abx500_battery_type bat_type_ext_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+	/* First element always represent the UNKNOWN battery */
+	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+	.resis_high = 0,
+	.resis_low = 0,
+	.battery_resistance = 300,
+	.charge_full_design = 612,
+	.nominal_voltage = 3700,
+	.termination_vol = 4050,
+	.termination_curr = 200,
+	.recharge_vol = 3990,
+	.normal_cur_lvl = 400,
+	.normal_vol_lvl = 4100,
+	.maint_a_cur_lvl = 400,
+	.maint_a_vol_lvl = 4050,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 400,
+	.maint_b_vol_lvl = 4000,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+/*
+ * These are the batteries that doesn't have an internal NTC resistor to measure
+ * its temperature. The temperature in this case is measure with a NTC placed
+ * near the battery but on the PCB.
+ */
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.resis_high = 76000,
+	.resis_low = 53000,
+	.battery_resistance = 300,
+	.charge_full_design = 900,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LION,
+	.resis_high = 30000,
+	.resis_low = 10000,
+	.battery_resistance = 300,
+	.charge_full_design = 950,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+	.name = POWER_SUPPLY_TECHNOLOGY_LION,
+	.resis_high = 95000,
+	.resis_low = 76001,
+	.battery_resistance = 300,
+	.charge_full_design = 950,
+	.nominal_voltage = 3700,
+	.termination_vol = 4150,
+	.termination_curr = 100,
+	.recharge_vol = 4130,
+	.normal_cur_lvl = 700,
+	.normal_vol_lvl = 4200,
+	.maint_a_cur_lvl = 600,
+	.maint_a_vol_lvl = 4150,
+	.maint_a_chg_timer_h = 60,
+	.maint_b_cur_lvl = 600,
+	.maint_b_vol_lvl = 4100,
+	.maint_b_chg_timer_h = 200,
+	.low_high_cur_lvl = 300,
+	.low_high_vol_lvl = 4000,
+	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+	.r_to_t_tbl = temp_tbl,
+	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+	.v_to_cap_tbl = cap_tbl,
+	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+	.batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+
+static const struct abx500_bm_capacity_levels cap_levels = {
+	.critical	= 2,
+	.low		= 10,
+	.normal		= 70,
+	.high		= 95,
+	.full		= 100,
+};
+
+static const struct abx500_fg_parameters fg = {
+	.recovery_sleep_timer = 10,
+	.recovery_total_time = 100,
+	.init_timer = 1,
+	.init_discard_time = 5,
+	.init_total_time = 40,
+	.high_curr_time = 60,
+	.accu_charging = 30,
+	.accu_high_curr = 30,
+	.high_curr_threshold = 50,
+	.lowbat_threshold = 3100,
+	.battok_falling_th_sel0 = 2860,
+	.battok_raising_th_sel1 = 2860,
+	.user_cap_limit = 15,
+	.maint_thres = 97,
+};
+
+static const struct abx500_maxim_parameters maxi_params = {
+	.ena_maxi = true,
+	.chg_curr = 910,
+	.wait_cycles = 10,
+	.charger_curr_step = 100,
+};
+
+static const struct abx500_bm_charger_parameters chg = {
+	.usb_volt_max		= 5500,
+	.usb_curr_max		= 1500,
+	.ac_volt_max		= 7500,
+	.ac_curr_max		= 1500,
+};
+
+struct abx500_bm_data ab8500_bm_data = {
+	.temp_under		= 3,
+	.temp_low		= 8,
+	.temp_high		= 43,
+	.temp_over		= 48,
+	.main_safety_tmr_h	= 4,
+	.temp_interval_chg	= 20,
+	.temp_interval_nochg	= 120,
+	.usb_safety_tmr_h	= 4,
+	.bkup_bat_v		= BUP_VCH_SEL_2P6V,
+	.bkup_bat_i		= BUP_ICH_SEL_150UA,
+	.no_maintenance		= false,
+	.adc_therm		= ABx500_ADC_THERM_BATCTRL,
+	.chg_unknown_bat	= false,
+	.enable_overshoot	= false,
+	.fg_res			= 100,
+	.cap_levels		= &cap_levels,
+	.bat_type		= bat_type_thermistor,
+	.n_btypes		= 3,
+	.batt_id		= 0,
+	.interval_charging	= 5,
+	.interval_not_charging	= 120,
+	.temp_hysteresis	= 3,
+	.gnd_lift_resistance	= 34,
+	.maxi			= &maxi_params,
+	.chg_params		= &chg,
+	.fg_params		= &fg,
+};
+
+int __devinit
+bmdevs_of_probe(struct device *dev,
+		struct device_node *np,
+		struct abx500_bm_data **battery)
+{
+	struct	abx500_battery_type *btype;
+	struct  device_node *np_bat_supply;
+	struct	abx500_bm_data *bat;
+	const char *btech;
+	char bat_tech[8];
+	int i, thermistor;
+
+	*battery = &ab8500_bm_data;
+
+	/* get phandle to 'battery-info' node */
+	np_bat_supply = of_parse_phandle(np, "battery", 0);
+	if (!np_bat_supply) {
+		dev_err(dev, "missing property battery\n");
+		return -EINVAL;
+	}
+	if (of_property_read_bool(np_bat_supply,
+			"thermistor-on-batctrl"))
+		thermistor = NTC_INTERNAL;
+	else
+		thermistor = NTC_EXTERNAL;
+
+	bat = *battery;
+	if (thermistor == NTC_EXTERNAL) {
+		bat->n_btypes  = 4;
+		bat->bat_type  = bat_type_ext_thermistor;
+		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
+	}
+	btech = of_get_property(np_bat_supply,
+		"stericsson,battery-type", NULL);
+	if (!btech) {
+		dev_warn(dev, "missing property battery-name/type\n");
+		strcpy(bat_tech, "UNKNOWN");
+	} else {
+		strcpy(bat_tech, btech);
+	}
+
+	if (strncmp(bat_tech, "LION", 4) == 0) {
+		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;
+	}
+	/* select the battery resolution table */
+	for (i = 0; i < bat->n_btypes; ++i) {
+		btype = (bat->bat_type + i);
+		if (thermistor == NTC_EXTERNAL) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_ext_thermistor;
+		} else if (strncmp(bat_tech, "LION", 4) == 0) {
+			btype->batres_tbl =
+				temp_to_batres_tbl_9100;
+		} else {
+			btype->batres_tbl =
+				temp_to_batres_tbl_thermistor;
+		}
+	}
+	of_node_put(np_bat_supply);
+	return 0;
+}
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index bba3cca..803870e 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -93,7 +93,7 @@ struct ab8500_btemp {
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
 	struct ab8500_fg *fg;
-	struct abx500_btemp_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply btemp_psy;
 	struct ab8500_btemp_events events;
@@ -962,10 +962,10 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev)
 
 static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 {
+	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
+	struct ab8500_btemp *di;
 	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");
@@ -982,21 +982,13 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
 	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
 	/* get btemp specific platform data */
-	di->pdata = plat_data->btemp;
+	di->pdata = plat_data;
 	if (!di->pdata) {
 		dev_err(di->dev, "no btemp platform data supplied\n");
 		ret = -EINVAL;
 		goto free_device_info;
 	}
 
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	/* BTEMP supply */
 	di->btemp_psy.name = "ab8500_btemp";
 	di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index d4f0c98..78a730c 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -220,7 +220,7 @@ struct ab8500_charger {
 	bool autopower;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_charger_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct ab8500_charger_event_flags flags;
 	struct ab8500_charger_usb_state usb_state;
@@ -2533,9 +2533,9 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
 
 static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 {
-	int irq, i, charger_status, ret = 0;
-	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+	struct abx500_bmdevs_plat_data *plat_data = pdev->dev.platform_data;
 	struct ab8500_charger *di;
+	int irq, i, charger_status, ret = 0;
 
 	if (!plat_data) {
 		dev_err(&pdev->dev, "No platform data\n");
@@ -2555,21 +2555,13 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 	spin_lock_init(&di->usb_state.usb_lock);
 
 	/* get charger specific platform data */
-	di->pdata = plat_data->charger;
+	di->pdata = plat_data;
 	if (!di->pdata) {
 		dev_err(di->dev, "no charger platform data supplied\n");
 		ret = -EINVAL;
 		goto free_device_info;
 	}
 
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	di->autopower = false;
 
 	/* AC supply */
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index bf02225..3207154 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -22,15 +22,16 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/kobject.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500.h>
 #include <linux/slab.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/delay.h>
-#include <linux/mfd/abx500/ab8500-gpadc.h>
-#include <linux/mfd/abx500.h>
 #include <linux/time.h>
+#include <linux/of.h>
 #include <linux/completion.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
 
 #define MILLI_TO_MICRO			1000
 #define FG_LSB_IN_MA			1627
@@ -172,7 +173,6 @@ struct inst_curr_result_list {
  * @avg_cap:		Average capacity filter
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
- * @pdata:		Pointer to the abx500_fg platform data
  * @bat:		Pointer to the abx500_bm platform data
  * @fg_psy:		Structure that holds the FG specific battery properties
  * @fg_wq:		Work queue for running the FG algorithm
@@ -212,7 +212,6 @@ struct ab8500_fg {
 	struct ab8500_fg_avg_cap avg_cap;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_fg_platform_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply fg_psy;
 	struct workqueue_struct *fg_wq;
@@ -2429,7 +2428,6 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev)
 	flush_scheduled_work();
 	power_supply_unregister(&di->fg_psy);
 	platform_set_drvdata(pdev, NULL);
-	kfree(di);
 	return ret;
 }
 
@@ -2442,21 +2440,39 @@ static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
 	{"CCEOC", ab8500_fg_cc_data_end_handler},
 };
 
+static char *supply_interface[] = {
+	"ab8500_chargalg",
+	"ab8500_usb",
+};
+
 static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
+	struct ab8500_fg *di;
 	int i, irq;
 	int ret = 0;
-	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
-	struct ab8500_fg *di;
-
-	if (!plat_data) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
-	}
 
-	di = kzalloc(sizeof(*di), GFP_KERNEL);
-	if (!di)
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
 		return -ENOMEM;
+	}
+	di->bat = pdev->mfd_cell->platform_data;
+	if (!di->bat) {
+		if (np) {
+			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to get battery information\n");
+				return ret;
+			}
+		} else {
+			dev_err(&pdev->dev, "missing dt node for ab8500_fg\n");
+			return -EINVAL;
+		}
+	} else {
+		dev_info(&pdev->dev, "falling back to legacy platform data\n");
+	}
 
 	mutex_init(&di->cc_lock);
 
@@ -2465,29 +2481,13 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 	di->parent = dev_get_drvdata(pdev->dev.parent);
 	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
-	/* get fg specific platform data */
-	di->pdata = plat_data->fg;
-	if (!di->pdata) {
-		dev_err(di->dev, "no fg platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
-	/* get battery specific platform data */
-	di->bat = plat_data->battery;
-	if (!di->bat) {
-		dev_err(di->dev, "no battery platform data supplied\n");
-		ret = -EINVAL;
-		goto free_device_info;
-	}
-
 	di->fg_psy.name = "ab8500_fg";
 	di->fg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 	di->fg_psy.properties = ab8500_fg_props;
 	di->fg_psy.num_properties = ARRAY_SIZE(ab8500_fg_props);
 	di->fg_psy.get_property = ab8500_fg_get_property;
-	di->fg_psy.supplied_to = di->pdata->supplied_to;
-	di->fg_psy.num_supplicants = di->pdata->num_supplicants;
+	di->fg_psy.supplied_to = supply_interface;
+	di->fg_psy.num_supplicants = ARRAY_SIZE(supply_interface),
 	di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
 
 	di->bat_cap.max_mah_design = MILLI_TO_MICRO *
@@ -2506,7 +2506,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
 	di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
 	if (di->fg_wq == NULL) {
 		dev_err(di->dev, "failed to create work queue\n");
-		goto free_device_info;
+		return -ENOMEM;
 	}
 
 	/* Init work for running the fg algorithm instantly */
@@ -2605,12 +2605,14 @@ free_irq:
 	}
 free_inst_curr_wq:
 	destroy_workqueue(di->fg_wq);
-free_device_info:
-	kfree(di);
-
 	return ret;
 }
 
+static const struct of_device_id ab8500_fg_match[] = {
+	{ .compatible = "stericsson,ab8500-fg", },
+	{ },
+};
+
 static struct platform_driver ab8500_fg_driver = {
 	.probe = ab8500_fg_probe,
 	.remove = __devexit_p(ab8500_fg_remove),
@@ -2619,6 +2621,7 @@ static struct platform_driver ab8500_fg_driver = {
 	.driver = {
 		.name = "ab8500-fg",
 		.owner = THIS_MODULE,
+		.of_match_table = ab8500_fg_match,
 	},
 };
 
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 804b88c..88b5cc1 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -231,7 +231,7 @@ struct abx500_chargalg {
 	struct abx500_chargalg_charger_info chg_info;
 	struct abx500_chargalg_battery_data batt_data;
 	struct abx500_chargalg_suspension_status susp_status;
-	struct abx500_chargalg_platform_data *pdata;
+	struct abx500_bmdevs_plat_data *pdata;
 	struct abx500_bm_data *bat;
 	struct power_supply chargalg_psy;
 	struct ux500_charger *ac_chg;
@@ -1802,7 +1802,7 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev)
 
 static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 {
-	struct abx500_bm_plat_data *plat_data;
+	struct abx500_bmdevs_plat_data *plat_data;
 	int ret = 0;
 
 	struct abx500_chargalg *di =
@@ -1812,10 +1812,8 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 
 	/* get device struct */
 	di->dev = &pdev->dev;
-
 	plat_data = pdev->dev.platform_data;
-	di->pdata = plat_data->chargalg;
-	di->bat = plat_data->battery;
+	di->pdata = plat_data;
 
 	/* chargalg supply */
 	di->chargalg_psy.name = "abx500_chargalg";
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 1318ca6..bbf3ad6 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -382,39 +382,27 @@ struct abx500_bm_data {
 	int gnd_lift_resistance;
 	const struct abx500_maxim_parameters *maxi;
 	const struct abx500_bm_capacity_levels *cap_levels;
-	const struct abx500_battery_type *bat_type;
+	struct abx500_battery_type *bat_type;
 	const struct abx500_bm_charger_parameters *chg_params;
 	const struct abx500_fg_parameters *fg_params;
 };
 
-struct abx500_chargalg_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
-};
-
-struct abx500_charger_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
-	bool autopower_cfg;
-};
+extern struct abx500_bm_data ab8500_bm_data;
 
-struct abx500_btemp_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
+struct abx500_bmdevs_plat_data {
+	char	**supplied_to;
+	size_t	num_supplicants;
+	bool	autopower_cfg;
 };
 
-struct abx500_fg_platform_data {
-	char **supplied_to;
-	size_t num_supplicants;
+enum {
+	NTC_EXTERNAL = 0,
+	NTC_INTERNAL,
 };
 
-struct abx500_bm_plat_data {
-	struct abx500_bm_data *battery;
-	struct abx500_charger_platform_data *charger;
-	struct abx500_btemp_platform_data *btemp;
-	struct abx500_fg_platform_data *fg;
-	struct abx500_chargalg_platform_data *chargalg;
-};
+int bmdevs_of_probe(struct device *dev,
+		struct device_node *np,
+		struct abx500_bm_data **battery);
 
 int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
 	u8 value);
-- 
1.7.10.4


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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-27 16:00     ` Rajanikanth HV
@ 2012-10-27 16:18       ` Francesco Lavra
  0 siblings, 0 replies; 20+ messages in thread
From: Francesco Lavra @ 2012-10-27 16:18 UTC (permalink / raw)
  To: Rajanikanth HV
  Cc: Rajanikanth H.V, linaro-dev, linus.walleij, arnd, patches,
	linux-kernel, anton.vorontsov, STEricsson_nomadik_linux,
	linux-arm-kernel

On 10/27/2012 06:00 PM, Rajanikanth HV wrote:
> On 27 October 2012 20:37, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
>> On 10/25/2012 08:30 AM, Rajanikanth H.V wrote:
>>> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
>>> +     bat_tech = of_get_property(np_bat_supply,
>>> +                     "stericsson,battery-type", NULL);
>>> +     if (!bat_tech)
>>> +             dev_warn(dev, "missing property battery-name/type\n");
>>> +
>>> +     if (strncmp(bat_tech, "LION", 4) == 0) {
>>
>> What if bat_tech is NULL?
> It will be UNKNOWN

I wanted to draw your attention to the fact that if bat_tech is NULL you
are passing a NULL pointer to strncmp(), which is not good.
So you should assign a default value to bat_tech in case the battery
type property is not found in the DT, as below:

if (!bat_tech) {
	dev_warn(dev, "missing property battery-name/type\n");
	bat_tech = "UNKNOWN";
}

--
Francesco

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-27 15:07   ` Francesco Lavra
@ 2012-10-27 16:00     ` Rajanikanth HV
  2012-10-27 16:18       ` Francesco Lavra
  0 siblings, 1 reply; 20+ messages in thread
From: Rajanikanth HV @ 2012-10-27 16:00 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: Rajanikanth H.V, linaro-dev, linus.walleij, arnd, patches,
	linux-kernel, anton.vorontsov, STEricsson_nomadik_linux,
	linux-arm-kernel

On 27 October 2012 20:37, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
> On 10/25/2012 08:30 AM, Rajanikanth H.V wrote:
>> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
>> +     bat_tech = of_get_property(np_bat_supply,
>> +                     "stericsson,battery-type", NULL);
>> +     if (!bat_tech)
>> +             dev_warn(dev, "missing property battery-name/type\n");
>> +
>> +     if (strncmp(bat_tech, "LION", 4) == 0) {
>
> What if bat_tech is NULL?
It will be UNKNOWN

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
       [not found] ` <1351146654-9110-2-git-send-email-rajanikanth.hv@stericsson.com>
@ 2012-10-27 15:07   ` Francesco Lavra
  2012-10-27 16:00     ` Rajanikanth HV
  0 siblings, 1 reply; 20+ messages in thread
From: Francesco Lavra @ 2012-10-27 15:07 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: lee.jones, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

On 10/25/2012 08:30 AM, Rajanikanth H.V wrote:
> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
> 
> - This patch adds device tree support for fuelgauge driver
> - optimize bm devices platform_data usage and of_probe(...)
>   Note: of_probe() routine for battery managed devices is made
>   common across all bm drivers.
> - test status:
>   - interrupt numbers assigned differs between legacy and FDT mode.
> 
> Signed-off-by: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
[...]
> diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
> new file mode 100644
> index 0000000..28eaf35
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
> @@ -0,0 +1,58 @@
> +=== AB8500 Fuel Gauge Driver ===
> +
> +AB8500 is a mixed signal multimedia and power management
> +device comprising: power and energy-management-module,
> +wall-charger, usb-charger, audio codec, general purpose adc,
> +tvout, clock management and sim card interface.
> +
> +Fuelgauge support is part of energy-management-modules, other
> +components of this module are:
> +main-charger, usb-combo-charger and battery-temperature-monitoring.
> +
> +The properties below describes the node for fuelgauge driver.
> +
> +Required Properties:
> +- compatible = This shall be: "stericsson,ab8500-fg"
> +- battery = Shall be battery specific information
> +	Example:
> +	ab8500_fg {
> +		compatible = "stericsson,ab8500-fg";
> +		battery	   = <&ab8500_battery>;
> +	};
> +
> +dependent node:
> +	ab8500_battery: ab8500_battery {
> +	};
> +	This node will provide information on 'thermistor interface' and
> +	'battery technology type' used.
> +
> +Properties of this node are:
> +thermistor-on-batctrl:
> +	A boolean value indicating thermistor interface	to battery
> +
> +	Note:
> +	'btemp' and 'batctrl' are the pins interfaced for battery temperature
> +	measurement, 'btemp' signal is used when NTC(negative temperature
> +	coefficient) resister is interfaced external to battery whereas
> +	'batctrl' pin is used when NTC resister is internal to battery.
> +
> +	Example:
> +	ab8500_battery: ab8500_battery {
> +		thermistor-on-batctrl;
> +	};
> +	indiactes: NTC resister is internal to battery, 'batctrl' is used

s/indiactes/indicates

[...]
> +int __devinit
> +bmdevs_of_probe(struct device *dev,
> +		struct device_node *np,
> +		struct abx500_bm_data **battery)
> +{
> +	struct	abx500_battery_type *btype;
> +	struct  device_node *np_bat_supply;
> +	struct	abx500_bm_data *bat;
> +	const char *bat_tech;
> +	int i, thermistor;
> +
> +	*battery = &ab8500_bm_data;
> +
> +	/* get phandle to 'battery-info' node */
> +	np_bat_supply = of_parse_phandle(np, "battery", 0);
> +	if (!np_bat_supply) {
> +		dev_err(dev, "missing property battery\n");
> +		return -EINVAL;
> +	}
> +	if (of_property_read_bool(np_bat_supply,
> +			"thermistor-on-batctrl"))
> +		thermistor = NTC_INTERNAL;
> +	else
> +		thermistor = NTC_EXTERNAL;
> +
> +	bat = *battery;
> +	if (thermistor == NTC_EXTERNAL) {
> +		bat->n_btypes  = 4;
> +		bat->bat_type  = bat_type_ext_thermistor;
> +		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
> +	}
> +	bat_tech = of_get_property(np_bat_supply,
> +			"stericsson,battery-type", NULL);
> +	if (!bat_tech)
> +		dev_warn(dev, "missing property battery-name/type\n");
> +
> +	if (strncmp(bat_tech, "LION", 4) == 0) {

What if bat_tech is NULL?

[...]
> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
> index bf02225..e117920 100644
> --- a/drivers/power/ab8500_fg.c
> +++ b/drivers/power/ab8500_fg.c
> @@ -22,15 +22,16 @@
>  #include <linux/platform_device.h>
>  #include <linux/power_supply.h>
>  #include <linux/kobject.h>
> -#include <linux/mfd/abx500/ab8500.h>
> -#include <linux/mfd/abx500.h>
>  #include <linux/slab.h>
> -#include <linux/mfd/abx500/ab8500-bm.h>
>  #include <linux/delay.h>
> -#include <linux/mfd/abx500/ab8500-gpadc.h>
> -#include <linux/mfd/abx500.h>
>  #include <linux/time.h>
> +#include <linux/of.h>
>  #include <linux/completion.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/abx500.h>
> +#include <linux/mfd/abx500/ab8500.h>
> +#include <linux/mfd/abx500/ab8500-bm.h>
> +#include <linux/mfd/abx500/ab8500-gpadc.h>
>  
>  #define MILLI_TO_MICRO			1000
>  #define FG_LSB_IN_MA			1627
> @@ -212,7 +213,6 @@ struct ab8500_fg {
>  	struct ab8500_fg_avg_cap avg_cap;
>  	struct ab8500 *parent;
>  	struct ab8500_gpadc *gpadc;
> -	struct abx500_fg_platform_data *pdata;

pdata should be removed from the description of the struct members as well.

--
Francesco

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
       [not found] ` <1349064513-31301-2-git-send-email-rajanikanth.hv@stericsson.com>
  2012-10-01  9:49   ` Lee Jones
@ 2012-10-06 14:01   ` Francesco Lavra
  1 sibling, 0 replies; 20+ messages in thread
From: Francesco Lavra @ 2012-10-06 14:01 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: lee.jones, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

Hi,

On 10/01/2012 06:08 AM, Rajanikanth H.V wrote:
> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
> 
> - This patch adds device tree support for fuelguage driver
> - optimize bm devices platform_data usage and of_probe(...)
>   Note: of_probe() routine for battery managed devices is made
>   common across all bm drivers.
[...]
> +int __devinit
> +bmdevs_of_probe(struct device *dev,
> +		struct device_node *np,
> +		struct abx500_bm_plat_data *pdata)
> +{
> +	int	i, ret = 0, thermistor = NTC_INTERNAL;
> +	const	__be32 *ph;
> +	const	char *bat_tech;
> +	struct	abx500_bm_data		 *bat;
> +	struct	abx500_battery_type	 *btype;
> +	struct  device_node		 *np_bat_supply;
> +	struct  abx500_bmdevs_plat_data  *plat_data = pdata->bmdev_pdata;
> +
> +	/* get phandle to 'supplied-to' node */
> +	ph = of_get_property(np, "supplied-to", &plat_data->num_supplicants);
> +	if (ph == NULL) {
> +		dev_err(dev, "no supplied_to property specified\n");
> +		return -EINVAL;
> +	}
> +	plat_data->num_supplicants /= sizeof(int);
> +	plat_data->supplied_to =
> +		devm_kzalloc(dev, plat_data->num_supplicants *
> +			sizeof(const char *), GFP_KERNEL);
> +	if (plat_data->supplied_to == NULL) {
> +		dev_err(dev, "%s no mem for supplied-to\n", __func__);
> +		return -ENOMEM;
> +	}
> +	for (i = 0; i < plat_data->num_supplicants; ++i) {
> +		np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph) + i);
> +		if (np_bat_supply == NULL) {
> +			dev_err(dev, "invalid supplied_to property\n");
> +			return -EINVAL;
> +		}
> +		ret = of_property_read_string(np_bat_supply, "interface-name",
> +				(const char **)(plat_data->supplied_to + i));
> +		if (ret < 0) {
> +			of_node_put(np_bat_supply);
> +			dev_err(dev, "supply/interface name not found\n");
> +			return ret;
> +		}

If an error is encountered here, of_node_put() should be called for all
nodes previously referenced with of_find_node_by_phandle (or
of_parse_phandle, as Lee suggested).
Also, if I'm not mistaken we have a leak here, because the refcount of
these nodes is never decremented, not even in the driver remove routine.

[...]
> @@ -2446,18 +2444,47 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>  {
>  	int i, irq;
>  	int ret = 0;
> -	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
> +	struct abx500_bm_plat_data *plat_data
> +				= pdev->dev.platform_data;
> +	struct device_node *np	= pdev->dev.of_node;
>  	struct ab8500_fg *di;
>  
> +	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
> +	if (!di) {
> +		dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
> +		return -ENOMEM;
> +	}
> +	if (np) {
> +		if (!plat_data) {
> +			plat_data =
> +			devm_kzalloc(&pdev->dev, sizeof(*plat_data),
> +					GFP_KERNEL);
> +			if (!plat_data) {
> +				dev_err(&pdev->dev,
> +					"%s no mem for plat_data\n", __func__);
> +				return -ENOMEM;
> +			}
> +			plat_data->bmdev_pdata = devm_kzalloc(&pdev->dev,
> +				sizeof(*plat_data->bmdev_pdata), GFP_KERNEL);
> +			if (!plat_data->bmdev_pdata) {
> +				dev_err(&pdev->dev,
> +					"%s no mem for pdata->fg\n",
> +					__func__);
> +				return -ENOMEM;
> +			}
> +		}
> +		ret = bmdevs_of_probe(&pdev->dev, np, plat_data);

I think it's better to move allocation of bmdev_pdata and corresponding
error check to bmdevs_of_probe(), because this code is shared by all
battery management drivers.

--
Francesco

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-01  9:59     ` Rajanikanth HV
@ 2012-10-01 10:36       ` Lee Jones
  0 siblings, 0 replies; 20+ messages in thread
From: Lee Jones @ 2012-10-01 10:36 UTC (permalink / raw)
  To: Rajanikanth HV
  Cc: francescolavra.fl, arnd, anton.vorontsov, Linus WALLEIJ,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

> did you have a look at arnd and anton comments regarding
> 'supplied-to' and boolean property

Try to keep your comments inline, situated below the relevant comment.

> >> +     ab8500_battery_info: ab8500_bat_type {
> >> +             battery-type = <2>;
> >> +             thermistor-on-batctrl = <1>;

> > You have this as a bool here, and ...

> >> +     e.g:
> >> +     ab8500_battery_info: ab8500_bat_type {
> >> +             thermistor-on-batctrl;

> > ... a standard property here. I suggest you drop the bool value.

I'm guessing it's just the documentation that needs amending.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-01  9:49   ` Lee Jones
  2012-10-01  9:59     ` Rajanikanth HV
@ 2012-10-01 10:22     ` Lee Jones
  1 sibling, 0 replies; 20+ messages in thread
From: Lee Jones @ 2012-10-01 10:22 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: francescolavra.fl, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

Sorry, some mistakes:

> > From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
> > 
> > - This patch adds device tree support for fuelguage driver
> > - optimize bm devices platform_data usage and of_probe(...)
> >   Note: of_probe() routine for battery managed devices is made
> >   common across all bm drivers.

Spelling errors in here.

> > +		dev_err(dev, "invalid battery-info node\n");
> > +		return -EINVAL;
> > +	}
> > +	if (of_property_read_bool(np_bat_supply,
> > +			"thermistor-on-batctrl") == false){
> 
> Replace with: 
>         if (of_get_property(np_bat_supply, "thermistor-on-batctr", NULL))
> 	        np_bat_supply =  true;

This should be: 

         if (of_get_property(np_bat_supply, "thermistor-on-batctr", NULL))
 	        thermistor = NTC_INTERNAL;
         else
                thermistor = NTC_EXTERNAL;

> <remove>
> 
> > +		dev_warn(dev, "missing property thermistor-on-batctrl\n");
> > +		thermistor = NTC_EXTERNAL;
> > +	}
> 
> </remove>

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
  2012-10-01  9:49   ` Lee Jones
@ 2012-10-01  9:59     ` Rajanikanth HV
  2012-10-01 10:36       ` Lee Jones
  2012-10-01 10:22     ` Lee Jones
  1 sibling, 1 reply; 20+ messages in thread
From: Rajanikanth HV @ 2012-10-01  9:59 UTC (permalink / raw)
  To: Lee Jones
  Cc: francescolavra.fl, arnd, anton.vorontsov, Linus WALLEIJ,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

did you have a look at arnd and anton comments regarding
'supplied-to' and boolean property

On Monday 01 October 2012 03:19 PM, Lee Jones wrote:
> On Mon, 01 Oct 2012, Rajanikanth H.V wrote:
> 
>> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
>>
>> - This patch adds device tree support for fuelguage driver
>> - optimize bm devices platform_data usage and of_probe(...)
>>   Note: of_probe() routine for battery managed devices is made
>>   common across all bm drivers.
>>
>> Signed-off-by: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
>> ---
>>  Documentation/devicetree/bindings/mfd/ab8500.txt   |    8 +-
>>  .../devicetree/bindings/power_supply/ab8500/fg.txt |   86 +++
>>  arch/arm/boot/dts/dbx5x0.dtsi                      |   22 +-
>>  drivers/mfd/ab8500-core.c                          |    1 +
>>  drivers/power/Makefile                             |    2 +-
>>  drivers/power/ab8500_bmdata.c                      |  549 ++++++++++++++++++++
>>  drivers/power/ab8500_btemp.c                       |    4 +-
>>  drivers/power/ab8500_charger.c                     |    4 +-
>>  drivers/power/ab8500_fg.c                          |   76 ++-
>>  drivers/power/abx500_chargalg.c                    |    4 +-
>>  include/linux/mfd/abx500.h                         |   37 +-
>>  include/linux/mfd/abx500/ab8500-bm.h               |    7 +
>>  12 files changed, 744 insertions(+), 56 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
>>  create mode 100644 drivers/power/ab8500_bmdata.c
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
>> index ce83c8d..762dc11 100644
>> --- a/Documentation/devicetree/bindings/mfd/ab8500.txt
>> +++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
>> @@ -24,7 +24,13 @@ ab8500-bm                :                      :              : Battery Manager
>>  ab8500-btemp             :                      :              : Battery Temperature
>>  ab8500-charger           :                      :              : Battery Charger
>>  ab8500-codec             :                      :              : Audio Codec
>> -ab8500-fg                :                      :              : Fuel Gauge
>> +ab8500-fg                :                   : vddadc       : Fuel Gauge
>> +                      : NCONV_ACCU           :              : Accumulate N Sample Conversion
>> +                      : BATT_OVV             :              : Battery Over Voltage
>> +                      : LOW_BAT_F            :              : LOW threshold battery voltage
>> +                      : CC_INT_CALIB         :              : Counter Counter Internal Calibration
> 
> I think you mean: Coulomb Counter.
> 
>> +                      : CCEOC                :              : Coulomb Counter End of Conversion
>> +                      :                      :              :
> 
> Random empty entry.
> 
>>  ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
>>                             SW_CONV_END          :              :
>>  ab8500-gpio              :                      :              : GPIO Controller
>> diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
>> new file mode 100644
>> index 0000000..caa33b0
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
>> @@ -0,0 +1,86 @@
>> +=== AB8500 Fuel Gauge Driver ===
>> +
>> +AB8500 is a mixed signal multimedia and power management
>> +device comprising: power and energy-management-module,
>> +wall-charger, usb-charger, audio codec, general purpose adc,
>> +tvout, clock management and sim card interface.
>> +
>> +Fuel-guage support is part of energy-management-module, the other
> 
> Spelling.
> 
>> +components of this module are:
>> +main-charger, usb-combo-charger and Battery temperature monitoring.
>> +
>> +The properties below describes the node for fuel guage driver.
> 
> Spelling.
> 
>> +
>> +Required Properties:
>> +- compatible = "stericsson,ab8500-fg"
>> +- interface-name:
>> +     Name of the controller/driver which is part of energy-management-module
>> +- supplied-to:
> 
> Still not sure about this property, or your justification for use.
> 
>> +     This property shall have dependent nodes which represent other
>> +     energy-management-module.
> 
> Plural?
> 
>> +     This is a logical binding w.r.t power supply events
> 
> Proper English please, no slang.
> 
>> +     across energy-management-module drivers where-in, the
> 
> Ill placed comma?
> 
>> +     runtime battery properties are shared along with uevent
>> +     notification.
> 
> Plural?
> 
>> +     ref: di->fg.external_power_changed =
>> +             ab8500_fg_external_power_changed;
>> +             ab8500_fg.c
>> +
>> +     Need for this property:
>> +             energy-management-module driver updates power-supply properties
>> +             which are subset of events listed in 'enum power_supply_property',
>> +             ref: power_supply.h file
>> +             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
>> +             di->fg_psy.external_power_changed
>> +
>> +     example:
>> +     ab8500-fg {
>> +             /* dependent energy management modules */
>> +             supplied-to  = <&ab8500_chargalg &ab8500_usb>;
>> +     };
>> +
>> +     ab8500_battery_info: ab8500_bat_type {
>> +             battery-type = <2>;
>> +             thermistor-on-batctrl = <1>;
> 
> You have this as a bool here, and ...
>> +     };
>> +
>> +Other dependent node for fuel-gauge is:
>> +     ab8500_battery_info: ab8500_bat_type {
>> +     };
>> +     This node will provide information on 'thermistor interface' and
>> +     'battery technology type' used.
>> +
>> +Properties of this node are:
>> +thermistor-on-batctrl:
>> +     A boolean value indicating thermistor interface to battery
>> +
>> +     Note:
>> +     'btemp' and 'batctrl' are the pins interfaced for battery temperature
>> +     measurement, 'btemp' signal is used when NTC(negative temperature
>> +     coefficient) resister is interfaced external to battery whereas
>> +     'batctrl' pin is used when NTC resister is internal to battery.
>> +
>> +     e.g:
>> +     ab8500_battery_info: ab8500_bat_type {
>> +             thermistor-on-batctrl;
> 
> ... a standard property here. I suggest you drop the bool value.
> 
>> +     };
>> +     indiactes: NTC resister is internal to battery, 'batctrl' is used
>> +             for thermal measurement.
>> +
>> +     The absence of property 'thermal-on-batctrl' indicates
>> +     NTC resister is external to battery and  'btemp' signal is used
>> +     for thermal measurement.
>> +
>> +battery-type:
>> +     This shall be the battery manufacturing technology type,
>> +     allowed types are:
>> +             "UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
>> +     e.g:
>> +     ab8500_battery_info: ab8500_bat_type {
>> +             battery-name = "LION";
>> +     }
>> +
>> diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
>> index 748ba7a..bd22c56 100644
>> --- a/arch/arm/boot/dts/dbx5x0.dtsi
>> +++ b/arch/arm/boot/dts/dbx5x0.dtsi
>> @@ -352,8 +352,28 @@
>>                                       vddadc-supply = <&ab8500_ldo_tvout_reg>;
>>                               };
>>
>> -                             ab8500-usb {
>> +                             ab8500_battery_info: ab8500_bat_type {
>> +                                     battery-name = "LION";
> 
> All new properties have to be documented.
> 
> Vendor specific properties should be prepended with the vendor name, so
> either write a generic binding document for all to use or prefix with
> 'stericsson,".
> 
>> +                                     thermistor-on-batctrl;
>> +                             };
>> +
>> +                             ab8500_chargalg: ab8500_chalg {
>> +                                     compatible     = "stericsson,ab8500-chargalg";
>> +                                     interface-name = "ab8500_chargalg";
> 
> Same with all of your new properties (I'll stop mentioning them now).
> 
>> +                                     battery-info   = <&ab8500_battery_info>;
>> +                                     supplied-to    = <&ab8500_fuel_gauge>;
> 
> Weren't you going to reverse this logic to be more inline with how
> the reset of Device Tree works?
> 
>> +                             };
>> +
>> +                             ab8500_fuel_gauge: ab8500_fg {
>> +                                     compatible     = "stericsson,ab8500-fg";
>> +                                     interface-name = "ab8500_fg";
>> +                                     battery-info   = <&ab8500_battery_info>;
>> +                                     supplied-to    = <&ab8500_chargalg &ab8500_usb>;
> 
> As above.
> 
>> +                             };
>> +
>> +                             ab8500_usb: ab8500_usb_if {
> 
> What does 'if' mean?
> 
>>                                       compatible = "stericsson,ab8500-usb";
>> +                                     interface-name = "ab8500_usb";
> 
> Why is this required?
> 
>>                                       interrupts = < 90 0x4
>>                                                      96 0x4
>>                                                      14 0x4
>> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
>> index 1667c77..6c3d7c2 100644
>> --- a/drivers/mfd/ab8500-core.c
>> +++ b/drivers/mfd/ab8500-core.c
>> @@ -1051,6 +1051,7 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
>>       },
>>       {
>>               .name = "ab8500-fg",
>> +             .of_compatible = "stericsson,ab8500-fg",
>>               .num_resources = ARRAY_SIZE(ab8500_fg_resources),
>>               .resources = ab8500_fg_resources,
>>       },
>> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
>> index ee58afb..2c58d4e 100644
>> --- a/drivers/power/Makefile
>> +++ b/drivers/power/Makefile
>> @@ -34,7 +34,7 @@ obj-$(CONFIG_BATTERY_S3C_ADC)       += s3c_adc_battery.o
>>  obj-$(CONFIG_CHARGER_PCF50633)       += pcf50633-charger.o
>>  obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
>>  obj-$(CONFIG_BATTERY_INTEL_MID)      += intel_mid_battery.o
>> -obj-$(CONFIG_AB8500_BM)              += ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
>> +obj-$(CONFIG_AB8500_BM)              += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
>>  obj-$(CONFIG_CHARGER_ISP1704)        += isp1704_charger.o
>>  obj-$(CONFIG_CHARGER_MAX8903)        += max8903_charger.o
>>  obj-$(CONFIG_CHARGER_TWL4030)        += twl4030_charger.o
>> diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
>> new file mode 100644
>> index 0000000..d0def3b
>> --- /dev/null
>> +++ b/drivers/power/ab8500_bmdata.c
>> @@ -0,0 +1,549 @@
>> +#include <linux/export.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/of.h>
>> +#include <linux/mfd/abx500.h>
>> +#include <linux/mfd/abx500/ab8500.h>
>> +#include <linux/mfd/abx500/ab8500-bm.h>
>> +
>> +/*
>> + * These are the defined batteries that uses a NTC and ID resistor placed
>> + * inside of the battery pack.
>> + * Note that the res_to_temp table must be strictly sorted by falling resistance
>> + * values to work.
>> + */
>> +static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
>> +     {-5, 53407},
>> +     { 0, 48594},
>> +     { 5, 43804},
>> +     {10, 39188},
>> +     {15, 34870},
>> +     {20, 30933},
>> +     {25, 27422},
>> +     {30, 24347},
>> +     {35, 21694},
>> +     {40, 19431},
>> +     {45, 17517},
>> +     {50, 15908},
>> +     {55, 14561},
>> +     {60, 13437},
>> +     {65, 12500},
>> +};
>> +static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
>> +     {-5, 165418},
>> +     { 0, 159024},
>> +     { 5, 151921},
>> +     {10, 144300},
>> +     {15, 136424},
>> +     {20, 128565},
>> +     {25, 120978},
>> +     {30, 113875},
>> +     {35, 107397},
>> +     {40, 101629},
>> +     {45,  96592},
>> +     {50,  92253},
>> +     {55,  88569},
>> +     {60,  85461},
>> +     {65,  82869},
>> +};
>> +static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
>> +     {4171,  100},
>> +     {4114,   95},
>> +     {4009,   83},
>> +     {3947,   74},
>> +     {3907,   67},
>> +     {3863,   59},
>> +     {3830,   56},
>> +     {3813,   53},
>> +     {3791,   46},
>> +     {3771,   33},
>> +     {3754,   25},
>> +     {3735,   20},
>> +     {3717,   17},
>> +     {3681,   13},
>> +     {3664,    8},
>> +     {3651,    6},
>> +     {3635,    5},
>> +     {3560,    3},
>> +     {3408,    1},
>> +     {3247,    0},
>> +};
>> +static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
>> +     {4161,  100},
>> +     {4124,   98},
>> +     {4044,   90},
>> +     {4003,   85},
>> +     {3966,   80},
>> +     {3933,   75},
>> +     {3888,   67},
>> +     {3849,   60},
>> +     {3813,   55},
>> +     {3787,   47},
>> +     {3772,   30},
>> +     {3751,   25},
>> +     {3718,   20},
>> +     {3681,   16},
>> +     {3660,   14},
>> +     {3589,   10},
>> +     {3546,    7},
>> +     {3495,    4},
>> +     {3404,    2},
>> +     {3250,    0},
>> +};
>> +
>> +static struct abx500_v_to_cap cap_tbl[] = {
>> +     {4186,  100},
>> +     {4163,   99},
>> +     {4114,   95},
>> +     {4068,   90},
>> +     {3990,   80},
>> +     {3926,   70},
>> +     {3898,   65},
>> +     {3866,   60},
>> +     {3833,   55},
>> +     {3812,   50},
>> +     {3787,   40},
>> +     {3768,   30},
>> +     {3747,   25},
>> +     {3730,   20},
>> +     {3705,   15},
>> +     {3699,   14},
>> +     {3684,   12},
>> +     {3672,    9},
>> +     {3657,    7},
>> +     {3638,    6},
>> +     {3556,    4},
>> +     {3424,    2},
>> +     {3317,    1},
>> +     {3094,    0},
>> +};
>> +
>> +/*
>> + * Note that the res_to_temp table must be strictly sorted by falling
>> + * resistance values to work.
>> + */
>> +static struct abx500_res_to_temp temp_tbl[] = {
>> +     {-5, 214834},
>> +     { 0, 162943},
>> +     { 5, 124820},
>> +     {10,  96520},
>> +     {15,  75306},
>> +     {20,  59254},
>> +     {25,  47000},
>> +     {30,  37566},
>> +     {35,  30245},
>> +     {40,  24520},
>> +     {45,  20010},
>> +     {50,  16432},
>> +     {55,  13576},
>> +     {60,  11280},
>> +     {65,   9425},
>> +};
>> +
>> +/*
>> + * Note that the batres_vs_temp table must be strictly sorted by falling
>> + * temperature values to work.
>> + */
>> +struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
>> +     { 40, 120},
>> +     { 30, 135},
>> +     { 20, 165},
>> +     { 10, 230},
>> +     { 00, 325},
>> +     {-10, 445},
>> +     {-20, 595},
>> +};
>> +
>> +/*
>> + * Note that the batres_vs_temp table must be strictly sorted by falling
>> + * temperature values to work.
>> + */
>> +struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
>> +     { 60, 300},
>> +     { 30, 300},
>> +     { 20, 300},
>> +     { 10, 300},
>> +     { 00, 300},
>> +     {-10, 300},
>> +     {-20, 300},
>> +};
>> +
>> +/* battery resistance table for LI ION 9100 battery */
>> +struct batres_vs_temp temp_to_batres_tbl_9100[] = {
>> +     { 60, 180},
>> +     { 30, 180},
>> +     { 20, 180},
>> +     { 10, 180},
>> +     { 00, 180},
>> +     {-10, 180},
>> +     {-20, 180},
>> +};
>> +
>> +struct abx500_battery_type bat_type_thermistor[] = {
>> +[BATTERY_UNKNOWN] = {
>> +     /* First element always represent the UNKNOWN battery */
>> +     .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
>> +     .resis_high = 0,
>> +     .resis_low = 0,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 612,
>> +     .nominal_voltage = 3700,
>> +     .termination_vol = 4050,
>> +     .termination_curr = 200,
>> +     .recharge_vol = 3990,
>> +     .normal_cur_lvl = 400,
>> +     .normal_vol_lvl = 4100,
>> +     .maint_a_cur_lvl = 400,
>> +     .maint_a_vol_lvl = 4050,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 400,
>> +     .maint_b_vol_lvl = 4000,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
>> +     .r_to_t_tbl = temp_tbl,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
>> +     .v_to_cap_tbl = cap_tbl,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +{
>> +     .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
>> +     .resis_high = 53407,
>> +     .resis_low = 12500,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 900,
>> +     .nominal_voltage = 3600,
>> +     .termination_vol = 4150,
>> +     .termination_curr = 80,
>> +     .recharge_vol = 4130,
>> +     .normal_cur_lvl = 700,
>> +     .normal_vol_lvl = 4200,
>> +     .maint_a_cur_lvl = 600,
>> +     .maint_a_vol_lvl = 4150,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 600,
>> +     .maint_b_vol_lvl = 4100,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
>> +     .r_to_t_tbl = temp_tbl_A_thermistor,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
>> +     .v_to_cap_tbl = cap_tbl_A_thermistor,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +
>> +},
>> +{
>> +     .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
>> +     .resis_high = 165418,
>> +     .resis_low = 82869,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 900,
>> +     .nominal_voltage = 3600,
>> +     .termination_vol = 4150,
>> +     .termination_curr = 80,
>> +     .recharge_vol = 4130,
>> +     .normal_cur_lvl = 700,
>> +     .normal_vol_lvl = 4200,
>> +     .maint_a_cur_lvl = 600,
>> +     .maint_a_vol_lvl = 4150,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 600,
>> +     .maint_b_vol_lvl = 4100,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
>> +     .r_to_t_tbl = temp_tbl_B_thermistor,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
>> +     .v_to_cap_tbl = cap_tbl_B_thermistor,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +};
>> +
>> +struct abx500_battery_type bat_type_ext_thermistor[] = {
>> +[BATTERY_UNKNOWN] = {
>> +     /* First element always represent the UNKNOWN battery */
>> +     .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
>> +     .resis_high = 0,
>> +     .resis_low = 0,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 612,
>> +     .nominal_voltage = 3700,
>> +     .termination_vol = 4050,
>> +     .termination_curr = 200,
>> +     .recharge_vol = 3990,
>> +     .normal_cur_lvl = 400,
>> +     .normal_vol_lvl = 4100,
>> +     .maint_a_cur_lvl = 400,
>> +     .maint_a_vol_lvl = 4050,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 400,
>> +     .maint_b_vol_lvl = 4000,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
>> +     .r_to_t_tbl = temp_tbl,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
>> +     .v_to_cap_tbl = cap_tbl,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +/*
>> + * These are the batteries that doesn't have an internal NTC resistor to measure
>> + * its temperature. The temperature in this case is measure with a NTC placed
>> + * near the battery but on the PCB.
>> + */
>> +{
>> +     .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
>> +     .resis_high = 76000,
>> +     .resis_low = 53000,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 900,
>> +     .nominal_voltage = 3700,
>> +     .termination_vol = 4150,
>> +     .termination_curr = 100,
>> +     .recharge_vol = 4130,
>> +     .normal_cur_lvl = 700,
>> +     .normal_vol_lvl = 4200,
>> +     .maint_a_cur_lvl = 600,
>> +     .maint_a_vol_lvl = 4150,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 600,
>> +     .maint_b_vol_lvl = 4100,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
>> +     .r_to_t_tbl = temp_tbl,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
>> +     .v_to_cap_tbl = cap_tbl,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +{
>> +     .name = POWER_SUPPLY_TECHNOLOGY_LION,
>> +     .resis_high = 30000,
>> +     .resis_low = 10000,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 950,
>> +     .nominal_voltage = 3700,
>> +     .termination_vol = 4150,
>> +     .termination_curr = 100,
>> +     .recharge_vol = 4130,
>> +     .normal_cur_lvl = 700,
>> +     .normal_vol_lvl = 4200,
>> +     .maint_a_cur_lvl = 600,
>> +     .maint_a_vol_lvl = 4150,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 600,
>> +     .maint_b_vol_lvl = 4100,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
>> +     .r_to_t_tbl = temp_tbl,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
>> +     .v_to_cap_tbl = cap_tbl,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +{
>> +     .name = POWER_SUPPLY_TECHNOLOGY_LION,
>> +     .resis_high = 95000,
>> +     .resis_low = 76001,
>> +     .battery_resistance = 300,
>> +     .charge_full_design = 950,
>> +     .nominal_voltage = 3700,
>> +     .termination_vol = 4150,
>> +     .termination_curr = 100,
>> +     .recharge_vol = 4130,
>> +     .normal_cur_lvl = 700,
>> +     .normal_vol_lvl = 4200,
>> +     .maint_a_cur_lvl = 600,
>> +     .maint_a_vol_lvl = 4150,
>> +     .maint_a_chg_timer_h = 60,
>> +     .maint_b_cur_lvl = 600,
>> +     .maint_b_vol_lvl = 4100,
>> +     .maint_b_chg_timer_h = 200,
>> +     .low_high_cur_lvl = 300,
>> +     .low_high_vol_lvl = 4000,
>> +     .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
>> +     .r_to_t_tbl = temp_tbl,
>> +     .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
>> +     .v_to_cap_tbl = cap_tbl,
>> +     .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
>> +     .batres_tbl = temp_to_batres_tbl_thermistor,
>> +},
>> +};
>> +
>> +static const struct abx500_bm_capacity_levels cap_levels = {
>> +     .critical       = 2,
>> +     .low            = 10,
>> +     .normal         = 70,
>> +     .high           = 95,
>> +     .full           = 100,
>> +};
>> +
>> +static const struct abx500_fg_parameters fg = {
>> +     .recovery_sleep_timer = 10,
>> +     .recovery_total_time = 100,
>> +     .init_timer = 1,
>> +     .init_discard_time = 5,
>> +     .init_total_time = 40,
>> +     .high_curr_time = 60,
>> +     .accu_charging = 30,
>> +     .accu_high_curr = 30,
>> +     .high_curr_threshold = 50,
>> +     .lowbat_threshold = 3100,
>> +     .battok_falling_th_sel0 = 2860,
>> +     .battok_raising_th_sel1 = 2860,
>> +     .user_cap_limit = 15,
>> +     .maint_thres = 97,
>> +};
>> +
>> +static const struct abx500_maxim_parameters maxi_params = {
>> +     .ena_maxi = true,
>> +     .chg_curr = 910,
>> +     .wait_cycles = 10,
>> +     .charger_curr_step = 100,
>> +};
>> +
>> +static const struct abx500_bm_charger_parameters chg = {
>> +     .usb_volt_max           = 5500,
>> +     .usb_curr_max           = 1500,
>> +     .ac_volt_max            = 7500,
>> +     .ac_curr_max            = 1500,
>> +};
>> +
>> +struct abx500_bm_data ab8500_bm_data = {
>> +     .temp_under             = 3,
>> +     .temp_low               = 8,
>> +     .temp_high              = 43,
>> +     .temp_over              = 48,
>> +     .main_safety_tmr_h      = 4,
>> +     .temp_interval_chg      = 20,
>> +     .temp_interval_nochg    = 120,
>> +     .usb_safety_tmr_h       = 4,
>> +     .bkup_bat_v             = BUP_VCH_SEL_2P6V,
>> +     .bkup_bat_i             = BUP_ICH_SEL_150UA,
>> +     .no_maintenance         = false,
>> +     .adc_therm              = ABx500_ADC_THERM_BATCTRL,
>> +     .chg_unknown_bat        = false,
>> +     .enable_overshoot       = false,
>> +     .fg_res                 = 100,
>> +     .cap_levels             = &cap_levels,
>> +     .bat_type               = bat_type_thermistor,
>> +     .n_btypes               = 3,
>> +     .batt_id                = 0,
>> +     .interval_charging      = 5,
>> +     .interval_not_charging  = 120,
>> +     .temp_hysteresis        = 3,
>> +     .gnd_lift_resistance    = 34,
>> +     .maxi                   = &maxi_params,
>> +     .chg_params             = &chg,
>> +     .fg_params              = &fg,
>> +};
>> +
>> +int __devinit
>> +bmdevs_of_probe(struct device *dev,
>> +             struct device_node *np,
>> +             struct abx500_bm_plat_data *pdata)
>> +{
>> +     int     i, ret = 0, thermistor = NTC_INTERNAL;
>> +     const   __be32 *ph;
>> +     const   char *bat_tech;
>> +     struct  abx500_bm_data           *bat;
>> +     struct  abx500_battery_type      *btype;
>> +     struct  device_node              *np_bat_supply;
>> +     struct  abx500_bmdevs_plat_data  *plat_data = pdata->bmdev_pdata;
> 
> <nit>
> 
> This spacing is uncharacteristic of Linux drivers.
> 
> Usually, struct declarations come first.
> 
> </nit>
> 
>> +     /* get phandle to 'supplied-to' node */
> 
> I thought you were going to reverse this?
> 
>> +     ph = of_get_property(np, "supplied-to", &plat_data->num_supplicants);
>> +     if (ph == NULL) {
> 
> if (!ph) {
> 
>> +             dev_err(dev, "no supplied_to property specified\n");
>> +             return -EINVAL;
>> +     }
>> +     plat_data->num_supplicants /= sizeof(int);
>> +     plat_data->supplied_to =
>> +             devm_kzalloc(dev, plat_data->num_supplicants *
>> +                     sizeof(const char *), GFP_KERNEL);
>> +     if (plat_data->supplied_to == NULL) {
>> +             dev_err(dev, "%s no mem for supplied-to\n", __func__);
>> +             return -ENOMEM;
>> +     }
>> +     for (i = 0; i < plat_data->num_supplicants; ++i) {
>> +             np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph) + i);
> 
> Use: of_parse_phandle(np, "supplied-to", i) instead.
> 
>> +             if (np_bat_supply == NULL) {
> 
> if (!np_bat_supply) {
> 
>> +                     dev_err(dev, "invalid supplied_to property\n");
>> +                     return -EINVAL;
>> +             }
>> +             ret = of_property_read_string(np_bat_supply, "interface-name",
>> +                             (const char **)(plat_data->supplied_to + i));
>> +             if (ret < 0) {
>> +                     of_node_put(np_bat_supply);
>> +                     dev_err(dev, "supply/interface name not found\n");
>> +                     return ret;
>> +             }
>> +             dev_dbg(dev, "%s power supply interface_name:%s\n",
>> +                     __func__, *(plat_data->supplied_to + i));
>> +     }
> 
> <remove>
> 
>> +     /* get phandle to 'battery-info' node */
>> +     ph = of_get_property(np, "battery-info", NULL);
>> +     if (ph == NULL) {
>> +             dev_err(dev, "missing property battery-info\n");
>> +             return -EINVAL;
>> +     }
>> +     np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph));
> 
> </remove>
> 
> ... and replace with: np_bat_supply = of_parse_phandle(np, "battery-info", 0) instead.
> 
>> +     if (np_bat_supply == NULL) {
> 
> if (!np_bat_supply) {
> 
> I'll not mention this again.
> 
>> +             dev_err(dev, "invalid battery-info node\n");
>> +             return -EINVAL;
>> +     }
>> +     if (of_property_read_bool(np_bat_supply,
>> +                     "thermistor-on-batctrl") == false){
> 
> Replace with:
>         if (of_get_property(np_bat_supply, "thermistor-on-batctr", NULL))
>                 np_bat_supply =  true;
> 
> <remove>
> 
>> +             dev_warn(dev, "missing property thermistor-on-batctrl\n");
>> +             thermistor = NTC_EXTERNAL;
>> +     }
> 
> </remove>
> 
>> +     pdata->battery = &ab8500_bm_data;
>> +     bat = pdata->battery;
> 
> Why not: bat = &ab8500_bm_data
> 
> Or just use ab8500_bm_data in its own right?
> 
>> +     if (thermistor == NTC_EXTERNAL) {
>> +             bat->n_btypes  = 4;
>> +             bat->bat_type  = bat_type_ext_thermistor;
>> +             bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
>> +     }
>> +     ret = of_property_read_string(np_bat_supply, "battery-name", &bat_tech);
>> +     if (ret < 0) {
>> +             dev_warn(dev, "missing property battery-name/type\n");
>> +             bat_tech = "UNKNOWN";
>> +     }
>> +     of_node_put(np_bat_supply);
>> +     if (strcmp(bat_tech, "LION") == 0) {
>> +             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;
>> +     }
>> +     /* select the battery resolution table */
>> +     for (i = 0; i < bat->n_btypes; ++i) {
>> +             btype = (bat->bat_type + i);
>> +             if (thermistor == NTC_EXTERNAL) {
>> +                     btype->batres_tbl =
>> +                             temp_to_batres_tbl_ext_thermistor;
>> +             } else if (strcmp(bat_tech, "LION") == 0) {
> 
> Isn't strncmp safer, since you know the size of the comparison?
> 
>> +                     btype->batres_tbl =
>> +                             temp_to_batres_tbl_9100;
>> +             } else {
>> +                     btype->batres_tbl =
>> +                             temp_to_batres_tbl_thermistor;
>> +             }
>> +     }
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(bmdevs_of_probe);
> 
> Why are you exporting?
> 
>> diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
>> index bba3cca..8e427e7 100644
>> --- a/drivers/power/ab8500_btemp.c
>> +++ b/drivers/power/ab8500_btemp.c
>> @@ -93,7 +93,7 @@ struct ab8500_btemp {
>>       struct ab8500 *parent;
>>       struct ab8500_gpadc *gpadc;
>>       struct ab8500_fg *fg;
>> -     struct abx500_btemp_platform_data *pdata;
>> +     struct abx500_bmdevs_plat_data *pdata;
>>       struct abx500_bm_data *bat;
>>       struct power_supply btemp_psy;
>>       struct ab8500_btemp_events events;
>> @@ -982,7 +982,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
>>       di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
>>
>>       /* get btemp specific platform data */
>> -     di->pdata = plat_data->btemp;
>> +     di->pdata = plat_data->bmdev_pdata;
>>       if (!di->pdata) {
>>               dev_err(di->dev, "no btemp platform data supplied\n");
>>               ret = -EINVAL;
>> diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
>> index d4f0c98..5ff0d83 100644
>> --- a/drivers/power/ab8500_charger.c
>> +++ b/drivers/power/ab8500_charger.c
>> @@ -220,7 +220,7 @@ struct ab8500_charger {
>>       bool autopower;
>>       struct ab8500 *parent;
>>       struct ab8500_gpadc *gpadc;
>> -     struct abx500_charger_platform_data *pdata;
>> +     struct abx500_bmdevs_plat_data *pdata;
>>       struct abx500_bm_data *bat;
>>       struct ab8500_charger_event_flags flags;
>>       struct ab8500_charger_usb_state usb_state;
>> @@ -2555,7 +2555,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
>>       spin_lock_init(&di->usb_state.usb_lock);
>>
>>       /* get charger specific platform data */
>> -     di->pdata = plat_data->charger;
>> +     di->pdata = plat_data->bmdev_pdata;
>>       if (!di->pdata) {
>>               dev_err(di->dev, "no charger platform data supplied\n");
>>               ret = -EINVAL;
>> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
>> index bf02225..96741b8 100644
>> --- a/drivers/power/ab8500_fg.c
>> +++ b/drivers/power/ab8500_fg.c
>> @@ -22,15 +22,14 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/power_supply.h>
>>  #include <linux/kobject.h>
>> -#include <linux/mfd/abx500/ab8500.h>
>> -#include <linux/mfd/abx500.h>
>>  #include <linux/slab.h>
>> -#include <linux/mfd/abx500/ab8500-bm.h>
>>  #include <linux/delay.h>
>> -#include <linux/mfd/abx500/ab8500-gpadc.h>
>> -#include <linux/mfd/abx500.h>
>>  #include <linux/time.h>
>>  #include <linux/completion.h>
>> +#include <linux/mfd/abx500.h>
>> +#include <linux/mfd/abx500/ab8500.h>
>> +#include <linux/mfd/abx500/ab8500-bm.h>
>> +#include <linux/mfd/abx500/ab8500-gpadc.h>
>>
>>  #define MILLI_TO_MICRO                       1000
>>  #define FG_LSB_IN_MA                 1627
>> @@ -212,7 +211,7 @@ struct ab8500_fg {
>>       struct ab8500_fg_avg_cap avg_cap;
>>       struct ab8500 *parent;
>>       struct ab8500_gpadc *gpadc;
>> -     struct abx500_fg_platform_data *pdata;
>> +     struct abx500_bmdevs_plat_data *pdata;
>>       struct abx500_bm_data *bat;
>>       struct power_supply fg_psy;
>>       struct workqueue_struct *fg_wq;
>> @@ -544,14 +543,14 @@ cc_err:
>>               ret = abx500_set_register_interruptible(di->dev,
>>                       AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
>>                       SEC_TO_SAMPLE(10));
>> -             if (ret)
>> +             if (ret < 0)
> 
> I don't 'think' this change is required. abx500_set_register_interruptible
> will only return !0 on error.
> 
>>                       goto fail;
>>
>>               /* Start the CC */
>>               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
>>                       AB8500_RTC_CC_CONF_REG,
>>                       (CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
>> -             if (ret)
>> +             if (ret < 0)
>>                       goto fail;
>>       } else {
>>               di->turn_off_fg = false;
>> @@ -2429,7 +2428,6 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev)
>>       flush_scheduled_work();
>>       power_supply_unregister(&di->fg_psy);
>>       platform_set_drvdata(pdev, NULL);
>> -     kfree(di);
>>       return ret;
>>  }
>>
>> @@ -2446,18 +2444,47 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>>  {
>>       int i, irq;
>>       int ret = 0;
>> -     struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
>> +     struct abx500_bm_plat_data *plat_data
>> +                             = pdev->dev.platform_data;
>> +     struct device_node *np  = pdev->dev.of_node;
>>       struct ab8500_fg *di;
>>
>> +     di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
>> +     if (!di) {
>> +             dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
>> +             return -ENOMEM;
>> +     }
>> +     if (np) {
>> +             if (!plat_data) {
> 
> Change these around.
> 
> if (!plat_data) {
>         if (np) {
>                 <snip>
>         } else {
>                 <ERROR>
>         }
> }
> 
>> +                     plat_data =
>> +                     devm_kzalloc(&pdev->dev, sizeof(*plat_data),
>> +                                     GFP_KERNEL);
>> +                     if (!plat_data) {
>> +                             dev_err(&pdev->dev,
>> +                                     "%s no mem for plat_data\n", __func__);
>> +                             return -ENOMEM;
>> +                     }
>> +                     plat_data->bmdev_pdata = devm_kzalloc(&pdev->dev,
>> +                             sizeof(*plat_data->bmdev_pdata), GFP_KERNEL);
>> +                     if (!plat_data->bmdev_pdata) {
>> +                             dev_err(&pdev->dev,
>> +                                     "%s no mem for pdata->fg\n",
>> +                                     __func__);
>> +                             return -ENOMEM;
>> +                     }
>> +             }
>> +             ret = bmdevs_of_probe(&pdev->dev, np, plat_data);
>> +             if (ret < 0) {
>> +                     dev_err(&pdev->dev, "failed to get platform data\n");
>> +                     return ret;
>> +             }
>> +     }
> 
> <remove>
> 
>>       if (!plat_data) {
>> -             dev_err(&pdev->dev, "No platform data\n");
>> +             dev_err(&pdev->dev,
>> +                     "%s no fg platform data found\n", __func__);
>>               return -EINVAL;
>>       }
> </remove>
> 
>> -     di = kzalloc(sizeof(*di), GFP_KERNEL);
>> -     if (!di)
>> -             return -ENOMEM;
>> -
>>       mutex_init(&di->cc_lock);
>>
>>       /* get parent data */
>> @@ -2466,19 +2493,17 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>>       di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
>>
>>       /* get fg specific platform data */
>> -     di->pdata = plat_data->fg;
>> +     di->pdata = plat_data->bmdev_pdata;
>>       if (!di->pdata) {
>>               dev_err(di->dev, "no fg platform data supplied\n");
>> -             ret = -EINVAL;
>> -             goto free_device_info;
>> +             return -EINVAL;
>>       }
>>
>>       /* get battery specific platform data */
>>       di->bat = plat_data->battery;
>>       if (!di->bat) {
>>               dev_err(di->dev, "no battery platform data supplied\n");
>> -             ret = -EINVAL;
>> -             goto free_device_info;
>> +             return -EINVAL;
>>       }
>>
>>       di->fg_psy.name = "ab8500_fg";
>> @@ -2506,7 +2531,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>>       di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
>>       if (di->fg_wq == NULL) {
>>               dev_err(di->dev, "failed to create work queue\n");
>> -             goto free_device_info;
>> +             return -ENOMEM;
>>       }
>>
>>       /* Init work for running the fg algorithm instantly */
>> @@ -2605,12 +2630,14 @@ free_irq:
>>       }
>>  free_inst_curr_wq:
>>       destroy_workqueue(di->fg_wq);
>> -free_device_info:
>> -     kfree(di);
>> -
>>       return ret;
>>  }
>>
>> +static const struct of_device_id ab8500_fg_match[] = {
>> +     {.compatible = "stericsson,ab8500-fg",},
> 
> <nit>
> 
> Spaces:
> 
> { .compatible = "stericsson,ab8500-fg", },
> 
> </nit>
> 
>> +     {},
>> +};
>> +
>>  static struct platform_driver ab8500_fg_driver = {
>>       .probe = ab8500_fg_probe,
>>       .remove = __devexit_p(ab8500_fg_remove),
>> @@ -2619,6 +2646,7 @@ static struct platform_driver ab8500_fg_driver = {
>>       .driver = {
>>               .name = "ab8500-fg",
>>               .owner = THIS_MODULE,
>> +             .of_match_table = ab8500_fg_match,
>>       },
>>  };
>>
>> diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
>> index 804b88c..ba548e4 100644
>> --- a/drivers/power/abx500_chargalg.c
>> +++ b/drivers/power/abx500_chargalg.c
>> @@ -231,7 +231,7 @@ struct abx500_chargalg {
>>       struct abx500_chargalg_charger_info chg_info;
>>       struct abx500_chargalg_battery_data batt_data;
>>       struct abx500_chargalg_suspension_status susp_status;
>> -     struct abx500_chargalg_platform_data *pdata;
>> +     struct abx500_bmdevs_plat_data *pdata;
>>       struct abx500_bm_data *bat;
>>       struct power_supply chargalg_psy;
>>       struct ux500_charger *ac_chg;
>> @@ -1814,7 +1814,7 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
>>       di->dev = &pdev->dev;
>>
>>       plat_data = pdev->dev.platform_data;
>> -     di->pdata = plat_data->chargalg;
>> +     di->pdata = plat_data->bmdev_pdata;
>>       di->bat = plat_data->battery;
>>
>>       /* chargalg supply */
>> diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
>> index 1318ca6..286f8ac 100644
>> --- a/include/linux/mfd/abx500.h
>> +++ b/include/linux/mfd/abx500.h
>> @@ -382,39 +382,30 @@ struct abx500_bm_data {
>>       int gnd_lift_resistance;
>>       const struct abx500_maxim_parameters *maxi;
>>       const struct abx500_bm_capacity_levels *cap_levels;
>> -     const struct abx500_battery_type *bat_type;
>> +     struct abx500_battery_type *bat_type;
>>       const struct abx500_bm_charger_parameters *chg_params;
>>       const struct abx500_fg_parameters *fg_params;
>>  };
>>
>> -struct abx500_chargalg_platform_data {
>> -     char **supplied_to;
>> -     size_t num_supplicants;
>> +struct abx500_bmdevs_plat_data {
>> +     char    **supplied_to;
>> +     size_t  num_supplicants;
>> +     bool    autopower_cfg;
>>  };
>>
>> -struct abx500_charger_platform_data {
>> -     char **supplied_to;
>> -     size_t num_supplicants;
>> -     bool autopower_cfg;
>> -};
>> -
>> -struct abx500_btemp_platform_data {
>> -     char **supplied_to;
>> -     size_t num_supplicants;
>> +struct abx500_bm_plat_data {
>> +     struct abx500_bm_data *battery;
>> +     struct abx500_bmdevs_plat_data *bmdev_pdata;
>>  };
>>
>> -struct abx500_fg_platform_data {
>> -     char **supplied_to;
>> -     size_t num_supplicants;
>> +enum {
>> +     NTC_EXTERNAL = 0,
>> +     NTC_INTERNAL,
>>  };
>>
>> -struct abx500_bm_plat_data {
>> -     struct abx500_bm_data *battery;
>> -     struct abx500_charger_platform_data *charger;
>> -     struct abx500_btemp_platform_data *btemp;
>> -     struct abx500_fg_platform_data *fg;
>> -     struct abx500_chargalg_platform_data *chargalg;
>> -};
>> +int bmdevs_of_probe(struct device *dev,
>> +             struct device_node *np,
>> +             struct abx500_bm_plat_data *pdata);
>>
>>  int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
>>       u8 value);
>> diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
>> index 44310c9..d15b7f1 100644
>> --- a/include/linux/mfd/abx500/ab8500-bm.h
>> +++ b/include/linux/mfd/abx500/ab8500-bm.h
>> @@ -422,6 +422,13 @@ struct ab8500_chargalg_platform_data {
>>  struct ab8500_btemp;
>>  struct ab8500_gpadc;
>>  struct ab8500_fg;
>> +
>> +extern struct abx500_bm_data ab8500_bm_data;
>> +extern struct abx500_battery_type bat_type_ext_thermistor[];
>> +extern struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[];
>> +extern struct batres_vs_temp temp_to_batres_tbl_9100[];
>> +extern struct batres_vs_temp temp_to_batres_tbl_thermistor[];
>> +
>>  #ifdef CONFIG_AB8500_BM
>>  void ab8500_fg_reinit(void);
>>  void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
>> --
>> 1.7.9.5
>>
> 
> --
> Lee Jones
> Linaro ST-Ericsson Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
> 

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

* Re: [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge
       [not found] ` <1349064513-31301-2-git-send-email-rajanikanth.hv@stericsson.com>
@ 2012-10-01  9:49   ` Lee Jones
  2012-10-01  9:59     ` Rajanikanth HV
  2012-10-01 10:22     ` Lee Jones
  2012-10-06 14:01   ` Francesco Lavra
  1 sibling, 2 replies; 20+ messages in thread
From: Lee Jones @ 2012-10-01  9:49 UTC (permalink / raw)
  To: Rajanikanth H.V
  Cc: francescolavra.fl, arnd, anton.vorontsov, linus.walleij,
	linux-arm-kernel, linux-kernel, linaro-dev, patches,
	STEricsson_nomadik_linux

On Mon, 01 Oct 2012, Rajanikanth H.V wrote:

> From: "Rajanikanth H.V" <rajanikanth.hv@stericsson.com>
> 
> - This patch adds device tree support for fuelguage driver
> - optimize bm devices platform_data usage and of_probe(...)
>   Note: of_probe() routine for battery managed devices is made
>   common across all bm drivers.
> 
> Signed-off-by: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
> ---
>  Documentation/devicetree/bindings/mfd/ab8500.txt   |    8 +-
>  .../devicetree/bindings/power_supply/ab8500/fg.txt |   86 +++
>  arch/arm/boot/dts/dbx5x0.dtsi                      |   22 +-
>  drivers/mfd/ab8500-core.c                          |    1 +
>  drivers/power/Makefile                             |    2 +-
>  drivers/power/ab8500_bmdata.c                      |  549 ++++++++++++++++++++
>  drivers/power/ab8500_btemp.c                       |    4 +-
>  drivers/power/ab8500_charger.c                     |    4 +-
>  drivers/power/ab8500_fg.c                          |   76 ++-
>  drivers/power/abx500_chargalg.c                    |    4 +-
>  include/linux/mfd/abx500.h                         |   37 +-
>  include/linux/mfd/abx500/ab8500-bm.h               |    7 +
>  12 files changed, 744 insertions(+), 56 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
>  create mode 100644 drivers/power/ab8500_bmdata.c
> 
> diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
> index ce83c8d..762dc11 100644
> --- a/Documentation/devicetree/bindings/mfd/ab8500.txt
> +++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
> @@ -24,7 +24,13 @@ ab8500-bm                :                      :              : Battery Manager
>  ab8500-btemp             :                      :              : Battery Temperature
>  ab8500-charger           :                      :              : Battery Charger
>  ab8500-codec             :                      :              : Audio Codec
> -ab8500-fg                :                      :              : Fuel Gauge
> +ab8500-fg                : 			: vddadc       : Fuel Gauge
> +			 : NCONV_ACCU           :	       : Accumulate N Sample Conversion
> +			 : BATT_OVV		:	       : Battery Over Voltage
> +			 : LOW_BAT_F		:	       : LOW threshold battery voltage
> +			 : CC_INT_CALIB		:	       : Counter Counter Internal Calibration

I think you mean: Coulomb Counter.

> +			 : CCEOC		:	       : Coulomb Counter End of Conversion
> +			 :			:	       :

Random empty entry.

>  ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
>                             SW_CONV_END          :              :
>  ab8500-gpio              :                      :              : GPIO Controller
> diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
> new file mode 100644
> index 0000000..caa33b0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
> @@ -0,0 +1,86 @@
> +=== AB8500 Fuel Gauge Driver ===
> +
> +AB8500 is a mixed signal multimedia and power management
> +device comprising: power and energy-management-module,
> +wall-charger, usb-charger, audio codec, general purpose adc,
> +tvout, clock management and sim card interface.
> +
> +Fuel-guage support is part of energy-management-module, the other

Spelling.

> +components of this module are:
> +main-charger, usb-combo-charger and Battery temperature monitoring.
> +
> +The properties below describes the node for fuel guage driver.

Spelling.

> +
> +Required Properties:
> +- compatible = "stericsson,ab8500-fg"
> +- interface-name:
> +	Name of the controller/driver which is part of energy-management-module
> +- supplied-to:

Still not sure about this property, or your justification for use.

> +	This property shall have dependent nodes which represent other
> +	energy-management-module.

Plural?

> +	This is a logical binding w.r.t power supply events

Proper English please, no slang.

> +	across energy-management-module drivers where-in, the

Ill placed comma?

> +	runtime battery properties are shared along with uevent
> +	notification.

Plural?

> +	ref: di->fg.external_power_changed =
> +		ab8500_fg_external_power_changed;
> +		ab8500_fg.c
> +
> +	Need for this property:
> +		energy-management-module driver updates power-supply properties
> +		which are subset of events listed in 'enum power_supply_property',
> +		ref: power_supply.h file
> +		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
> +		di->fg_psy.external_power_changed
> +
> +	example:
> +	ab8500-fg {
> +		/* dependent energy management modules */
> +		supplied-to  = <&ab8500_chargalg &ab8500_usb>;
> +	};
> +
> +	ab8500_battery_info: ab8500_bat_type {
> +		battery-type = <2>;
> +		thermistor-on-batctrl = <1>;

You have this as a bool here, and ...
> +	};
> +
> +Other dependent node for fuel-gauge is:
> +	ab8500_battery_info: ab8500_bat_type {
> +	};
> +	This node will provide information on 'thermistor interface' and
> +	'battery technology type' used.
> +
> +Properties of this node are:
> +thermistor-on-batctrl:
> +	A boolean value indicating thermistor interface	to battery
> +
> +	Note:
> +	'btemp' and 'batctrl' are the pins interfaced for battery temperature
> +	measurement, 'btemp' signal is used when NTC(negative temperature
> +	coefficient) resister is interfaced external to battery whereas
> +	'batctrl' pin is used when NTC resister is internal to battery.
> +
> +	e.g:
> +	ab8500_battery_info: ab8500_bat_type {
> +		thermistor-on-batctrl;

... a standard property here. I suggest you drop the bool value.

> +	};
> +	indiactes: NTC resister is internal to battery, 'batctrl' is used
> +		for thermal measurement.
> +
> +	The absence of property 'thermal-on-batctrl' indicates
> +	NTC resister is external to battery and  'btemp' signal is used
> +	for thermal measurement.
> +
> +battery-type:
> +	This shall be the battery manufacturing technology type,
> +	allowed types are:
> +		"UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
> +	e.g:
> +	ab8500_battery_info: ab8500_bat_type {
> +		battery-name = "LION";
> +	}
> +
> diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
> index 748ba7a..bd22c56 100644
> --- a/arch/arm/boot/dts/dbx5x0.dtsi
> +++ b/arch/arm/boot/dts/dbx5x0.dtsi
> @@ -352,8 +352,28 @@
>  					vddadc-supply = <&ab8500_ldo_tvout_reg>;
>  				};
>  
> -				ab8500-usb {
> +				ab8500_battery_info: ab8500_bat_type {
> +					battery-name = "LION";

All new properties have to be documented.

Vendor specific properties should be prepended with the vendor name, so
either write a generic binding document for all to use or prefix with
'stericsson,".

> +					thermistor-on-batctrl;
> +				};
> +
> +				ab8500_chargalg: ab8500_chalg {
> +					compatible     = "stericsson,ab8500-chargalg";
> +					interface-name = "ab8500_chargalg";

Same with all of your new properties (I'll stop mentioning them now).

> +					battery-info   = <&ab8500_battery_info>;
> +					supplied-to    = <&ab8500_fuel_gauge>;

Weren't you going to reverse this logic to be more inline with how
the reset of Device Tree works?

> +				};
> +
> +				ab8500_fuel_gauge: ab8500_fg {
> +					compatible     = "stericsson,ab8500-fg";
> +					interface-name = "ab8500_fg";
> +					battery-info   = <&ab8500_battery_info>;
> +					supplied-to    = <&ab8500_chargalg &ab8500_usb>;

As above.

> +				};
> +
> +				ab8500_usb: ab8500_usb_if {

What does 'if' mean?

>  					compatible = "stericsson,ab8500-usb";
> +					interface-name = "ab8500_usb";

Why is this required?

>  					interrupts = < 90 0x4
>  						       96 0x4
>  						       14 0x4
> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
> index 1667c77..6c3d7c2 100644
> --- a/drivers/mfd/ab8500-core.c
> +++ b/drivers/mfd/ab8500-core.c
> @@ -1051,6 +1051,7 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
>  	},
>  	{
>  		.name = "ab8500-fg",
> +		.of_compatible = "stericsson,ab8500-fg",
>  		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
>  		.resources = ab8500_fg_resources,
>  	},
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index ee58afb..2c58d4e 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -34,7 +34,7 @@ obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
>  obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
>  obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
>  obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
> -obj-$(CONFIG_AB8500_BM)		+= ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
> +obj-$(CONFIG_AB8500_BM)		+= ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
>  obj-$(CONFIG_CHARGER_ISP1704)	+= isp1704_charger.o
>  obj-$(CONFIG_CHARGER_MAX8903)	+= max8903_charger.o
>  obj-$(CONFIG_CHARGER_TWL4030)	+= twl4030_charger.o
> diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
> new file mode 100644
> index 0000000..d0def3b
> --- /dev/null
> +++ b/drivers/power/ab8500_bmdata.c
> @@ -0,0 +1,549 @@
> +#include <linux/export.h>
> +#include <linux/power_supply.h>
> +#include <linux/of.h>
> +#include <linux/mfd/abx500.h>
> +#include <linux/mfd/abx500/ab8500.h>
> +#include <linux/mfd/abx500/ab8500-bm.h>
> +
> +/*
> + * These are the defined batteries that uses a NTC and ID resistor placed
> + * inside of the battery pack.
> + * Note that the res_to_temp table must be strictly sorted by falling resistance
> + * values to work.
> + */
> +static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
> +	{-5, 53407},
> +	{ 0, 48594},
> +	{ 5, 43804},
> +	{10, 39188},
> +	{15, 34870},
> +	{20, 30933},
> +	{25, 27422},
> +	{30, 24347},
> +	{35, 21694},
> +	{40, 19431},
> +	{45, 17517},
> +	{50, 15908},
> +	{55, 14561},
> +	{60, 13437},
> +	{65, 12500},
> +};
> +static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
> +	{-5, 165418},
> +	{ 0, 159024},
> +	{ 5, 151921},
> +	{10, 144300},
> +	{15, 136424},
> +	{20, 128565},
> +	{25, 120978},
> +	{30, 113875},
> +	{35, 107397},
> +	{40, 101629},
> +	{45,  96592},
> +	{50,  92253},
> +	{55,  88569},
> +	{60,  85461},
> +	{65,  82869},
> +};
> +static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
> +	{4171,	100},
> +	{4114,	 95},
> +	{4009,	 83},
> +	{3947,	 74},
> +	{3907,	 67},
> +	{3863,	 59},
> +	{3830,	 56},
> +	{3813,	 53},
> +	{3791,	 46},
> +	{3771,	 33},
> +	{3754,	 25},
> +	{3735,	 20},
> +	{3717,	 17},
> +	{3681,	 13},
> +	{3664,	  8},
> +	{3651,	  6},
> +	{3635,	  5},
> +	{3560,	  3},
> +	{3408,    1},
> +	{3247,	  0},
> +};
> +static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
> +	{4161,	100},
> +	{4124,	 98},
> +	{4044,	 90},
> +	{4003,	 85},
> +	{3966,	 80},
> +	{3933,	 75},
> +	{3888,	 67},
> +	{3849,	 60},
> +	{3813,	 55},
> +	{3787,	 47},
> +	{3772,	 30},
> +	{3751,	 25},
> +	{3718,	 20},
> +	{3681,	 16},
> +	{3660,	 14},
> +	{3589,	 10},
> +	{3546,	  7},
> +	{3495,	  4},
> +	{3404,	  2},
> +	{3250,	  0},
> +};
> +
> +static struct abx500_v_to_cap cap_tbl[] = {
> +	{4186,	100},
> +	{4163,	 99},
> +	{4114,	 95},
> +	{4068,	 90},
> +	{3990,	 80},
> +	{3926,	 70},
> +	{3898,	 65},
> +	{3866,	 60},
> +	{3833,	 55},
> +	{3812,	 50},
> +	{3787,	 40},
> +	{3768,	 30},
> +	{3747,	 25},
> +	{3730,	 20},
> +	{3705,	 15},
> +	{3699,	 14},
> +	{3684,	 12},
> +	{3672,	  9},
> +	{3657,	  7},
> +	{3638,	  6},
> +	{3556,	  4},
> +	{3424,	  2},
> +	{3317,	  1},
> +	{3094,	  0},
> +};
> +
> +/*
> + * Note that the res_to_temp table must be strictly sorted by falling
> + * resistance values to work.
> + */
> +static struct abx500_res_to_temp temp_tbl[] = {
> +	{-5, 214834},
> +	{ 0, 162943},
> +	{ 5, 124820},
> +	{10,  96520},
> +	{15,  75306},
> +	{20,  59254},
> +	{25,  47000},
> +	{30,  37566},
> +	{35,  30245},
> +	{40,  24520},
> +	{45,  20010},
> +	{50,  16432},
> +	{55,  13576},
> +	{60,  11280},
> +	{65,   9425},
> +};
> +
> +/*
> + * Note that the batres_vs_temp table must be strictly sorted by falling
> + * temperature values to work.
> + */
> +struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
> +	{ 40, 120},
> +	{ 30, 135},
> +	{ 20, 165},
> +	{ 10, 230},
> +	{ 00, 325},
> +	{-10, 445},
> +	{-20, 595},
> +};
> +
> +/*
> + * Note that the batres_vs_temp table must be strictly sorted by falling
> + * temperature values to work.
> + */
> +struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
> +	{ 60, 300},
> +	{ 30, 300},
> +	{ 20, 300},
> +	{ 10, 300},
> +	{ 00, 300},
> +	{-10, 300},
> +	{-20, 300},
> +};
> +
> +/* battery resistance table for LI ION 9100 battery */
> +struct batres_vs_temp temp_to_batres_tbl_9100[] = {
> +	{ 60, 180},
> +	{ 30, 180},
> +	{ 20, 180},
> +	{ 10, 180},
> +	{ 00, 180},
> +	{-10, 180},
> +	{-20, 180},
> +};
> +
> +struct abx500_battery_type bat_type_thermistor[] = {
> +[BATTERY_UNKNOWN] = {
> +	/* First element always represent the UNKNOWN battery */
> +	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
> +	.resis_high = 0,
> +	.resis_low = 0,
> +	.battery_resistance = 300,
> +	.charge_full_design = 612,
> +	.nominal_voltage = 3700,
> +	.termination_vol = 4050,
> +	.termination_curr = 200,
> +	.recharge_vol = 3990,
> +	.normal_cur_lvl = 400,
> +	.normal_vol_lvl = 4100,
> +	.maint_a_cur_lvl = 400,
> +	.maint_a_vol_lvl = 4050,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 400,
> +	.maint_b_vol_lvl = 4000,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
> +	.r_to_t_tbl = temp_tbl,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
> +	.v_to_cap_tbl = cap_tbl,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +{
> +	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
> +	.resis_high = 53407,
> +	.resis_low = 12500,
> +	.battery_resistance = 300,
> +	.charge_full_design = 900,
> +	.nominal_voltage = 3600,
> +	.termination_vol = 4150,
> +	.termination_curr = 80,
> +	.recharge_vol = 4130,
> +	.normal_cur_lvl = 700,
> +	.normal_vol_lvl = 4200,
> +	.maint_a_cur_lvl = 600,
> +	.maint_a_vol_lvl = 4150,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 600,
> +	.maint_b_vol_lvl = 4100,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
> +	.r_to_t_tbl = temp_tbl_A_thermistor,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
> +	.v_to_cap_tbl = cap_tbl_A_thermistor,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +
> +},
> +{
> +	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
> +	.resis_high = 165418,
> +	.resis_low = 82869,
> +	.battery_resistance = 300,
> +	.charge_full_design = 900,
> +	.nominal_voltage = 3600,
> +	.termination_vol = 4150,
> +	.termination_curr = 80,
> +	.recharge_vol = 4130,
> +	.normal_cur_lvl = 700,
> +	.normal_vol_lvl = 4200,
> +	.maint_a_cur_lvl = 600,
> +	.maint_a_vol_lvl = 4150,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 600,
> +	.maint_b_vol_lvl = 4100,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
> +	.r_to_t_tbl = temp_tbl_B_thermistor,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
> +	.v_to_cap_tbl = cap_tbl_B_thermistor,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +};
> +
> +struct abx500_battery_type bat_type_ext_thermistor[] = {
> +[BATTERY_UNKNOWN] = {
> +	/* First element always represent the UNKNOWN battery */
> +	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
> +	.resis_high = 0,
> +	.resis_low = 0,
> +	.battery_resistance = 300,
> +	.charge_full_design = 612,
> +	.nominal_voltage = 3700,
> +	.termination_vol = 4050,
> +	.termination_curr = 200,
> +	.recharge_vol = 3990,
> +	.normal_cur_lvl = 400,
> +	.normal_vol_lvl = 4100,
> +	.maint_a_cur_lvl = 400,
> +	.maint_a_vol_lvl = 4050,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 400,
> +	.maint_b_vol_lvl = 4000,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
> +	.r_to_t_tbl = temp_tbl,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
> +	.v_to_cap_tbl = cap_tbl,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +/*
> + * These are the batteries that doesn't have an internal NTC resistor to measure
> + * its temperature. The temperature in this case is measure with a NTC placed
> + * near the battery but on the PCB.
> + */
> +{
> +	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
> +	.resis_high = 76000,
> +	.resis_low = 53000,
> +	.battery_resistance = 300,
> +	.charge_full_design = 900,
> +	.nominal_voltage = 3700,
> +	.termination_vol = 4150,
> +	.termination_curr = 100,
> +	.recharge_vol = 4130,
> +	.normal_cur_lvl = 700,
> +	.normal_vol_lvl = 4200,
> +	.maint_a_cur_lvl = 600,
> +	.maint_a_vol_lvl = 4150,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 600,
> +	.maint_b_vol_lvl = 4100,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
> +	.r_to_t_tbl = temp_tbl,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
> +	.v_to_cap_tbl = cap_tbl,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +{
> +	.name = POWER_SUPPLY_TECHNOLOGY_LION,
> +	.resis_high = 30000,
> +	.resis_low = 10000,
> +	.battery_resistance = 300,
> +	.charge_full_design = 950,
> +	.nominal_voltage = 3700,
> +	.termination_vol = 4150,
> +	.termination_curr = 100,
> +	.recharge_vol = 4130,
> +	.normal_cur_lvl = 700,
> +	.normal_vol_lvl = 4200,
> +	.maint_a_cur_lvl = 600,
> +	.maint_a_vol_lvl = 4150,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 600,
> +	.maint_b_vol_lvl = 4100,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
> +	.r_to_t_tbl = temp_tbl,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
> +	.v_to_cap_tbl = cap_tbl,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +{
> +	.name = POWER_SUPPLY_TECHNOLOGY_LION,
> +	.resis_high = 95000,
> +	.resis_low = 76001,
> +	.battery_resistance = 300,
> +	.charge_full_design = 950,
> +	.nominal_voltage = 3700,
> +	.termination_vol = 4150,
> +	.termination_curr = 100,
> +	.recharge_vol = 4130,
> +	.normal_cur_lvl = 700,
> +	.normal_vol_lvl = 4200,
> +	.maint_a_cur_lvl = 600,
> +	.maint_a_vol_lvl = 4150,
> +	.maint_a_chg_timer_h = 60,
> +	.maint_b_cur_lvl = 600,
> +	.maint_b_vol_lvl = 4100,
> +	.maint_b_chg_timer_h = 200,
> +	.low_high_cur_lvl = 300,
> +	.low_high_vol_lvl = 4000,
> +	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
> +	.r_to_t_tbl = temp_tbl,
> +	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
> +	.v_to_cap_tbl = cap_tbl,
> +	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
> +	.batres_tbl = temp_to_batres_tbl_thermistor,
> +},
> +};
> +
> +static const struct abx500_bm_capacity_levels cap_levels = {
> +	.critical	= 2,
> +	.low		= 10,
> +	.normal		= 70,
> +	.high		= 95,
> +	.full		= 100,
> +};
> +
> +static const struct abx500_fg_parameters fg = {
> +	.recovery_sleep_timer = 10,
> +	.recovery_total_time = 100,
> +	.init_timer = 1,
> +	.init_discard_time = 5,
> +	.init_total_time = 40,
> +	.high_curr_time = 60,
> +	.accu_charging = 30,
> +	.accu_high_curr = 30,
> +	.high_curr_threshold = 50,
> +	.lowbat_threshold = 3100,
> +	.battok_falling_th_sel0 = 2860,
> +	.battok_raising_th_sel1 = 2860,
> +	.user_cap_limit = 15,
> +	.maint_thres = 97,
> +};
> +
> +static const struct abx500_maxim_parameters maxi_params = {
> +	.ena_maxi = true,
> +	.chg_curr = 910,
> +	.wait_cycles = 10,
> +	.charger_curr_step = 100,
> +};
> +
> +static const struct abx500_bm_charger_parameters chg = {
> +	.usb_volt_max		= 5500,
> +	.usb_curr_max		= 1500,
> +	.ac_volt_max		= 7500,
> +	.ac_curr_max		= 1500,
> +};
> +
> +struct abx500_bm_data ab8500_bm_data = {
> +	.temp_under		= 3,
> +	.temp_low		= 8,
> +	.temp_high		= 43,
> +	.temp_over		= 48,
> +	.main_safety_tmr_h	= 4,
> +	.temp_interval_chg	= 20,
> +	.temp_interval_nochg	= 120,
> +	.usb_safety_tmr_h	= 4,
> +	.bkup_bat_v		= BUP_VCH_SEL_2P6V,
> +	.bkup_bat_i		= BUP_ICH_SEL_150UA,
> +	.no_maintenance		= false,
> +	.adc_therm		= ABx500_ADC_THERM_BATCTRL,
> +	.chg_unknown_bat	= false,
> +	.enable_overshoot	= false,
> +	.fg_res			= 100,
> +	.cap_levels		= &cap_levels,
> +	.bat_type		= bat_type_thermistor,
> +	.n_btypes		= 3,
> +	.batt_id		= 0,
> +	.interval_charging	= 5,
> +	.interval_not_charging	= 120,
> +	.temp_hysteresis	= 3,
> +	.gnd_lift_resistance	= 34,
> +	.maxi			= &maxi_params,
> +	.chg_params		= &chg,
> +	.fg_params		= &fg,
> +};
> +
> +int __devinit
> +bmdevs_of_probe(struct device *dev,
> +		struct device_node *np,
> +		struct abx500_bm_plat_data *pdata)
> +{
> +	int	i, ret = 0, thermistor = NTC_INTERNAL;
> +	const	__be32 *ph;
> +	const	char *bat_tech;
> +	struct	abx500_bm_data		 *bat;
> +	struct	abx500_battery_type	 *btype;
> +	struct  device_node		 *np_bat_supply;
> +	struct  abx500_bmdevs_plat_data  *plat_data = pdata->bmdev_pdata;

<nit> 

This spacing is uncharacteristic of Linux drivers. 

Usually, struct declarations come first.

</nit>

> +	/* get phandle to 'supplied-to' node */

I thought you were going to reverse this?

> +	ph = of_get_property(np, "supplied-to", &plat_data->num_supplicants);
> +	if (ph == NULL) {

if (!ph) {

> +		dev_err(dev, "no supplied_to property specified\n");
> +		return -EINVAL;
> +	}
> +	plat_data->num_supplicants /= sizeof(int);
> +	plat_data->supplied_to =
> +		devm_kzalloc(dev, plat_data->num_supplicants *
> +			sizeof(const char *), GFP_KERNEL);
> +	if (plat_data->supplied_to == NULL) {
> +		dev_err(dev, "%s no mem for supplied-to\n", __func__);
> +		return -ENOMEM;
> +	}
> +	for (i = 0; i < plat_data->num_supplicants; ++i) {
> +		np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph) + i);

Use: of_parse_phandle(np, "supplied-to", i) instead.

> +		if (np_bat_supply == NULL) {

if (!np_bat_supply) {

> +			dev_err(dev, "invalid supplied_to property\n");
> +			return -EINVAL;
> +		}
> +		ret = of_property_read_string(np_bat_supply, "interface-name",
> +				(const char **)(plat_data->supplied_to + i));
> +		if (ret < 0) {
> +			of_node_put(np_bat_supply);
> +			dev_err(dev, "supply/interface name not found\n");
> +			return ret;
> +		}
> +		dev_dbg(dev, "%s power supply interface_name:%s\n",
> +			__func__, *(plat_data->supplied_to + i));
> +	}

<remove>

> +	/* get phandle to 'battery-info' node */
> +	ph = of_get_property(np, "battery-info", NULL);
> +	if (ph == NULL) {
> +		dev_err(dev, "missing property battery-info\n");
> +		return -EINVAL;
> +	}
> +	np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph));

</remove>

... and replace with: np_bat_supply = of_parse_phandle(np, "battery-info", 0) instead.

> +	if (np_bat_supply == NULL) {

if (!np_bat_supply) {

I'll not mention this again.

> +		dev_err(dev, "invalid battery-info node\n");
> +		return -EINVAL;
> +	}
> +	if (of_property_read_bool(np_bat_supply,
> +			"thermistor-on-batctrl") == false){

Replace with: 
        if (of_get_property(np_bat_supply, "thermistor-on-batctr", NULL))
	        np_bat_supply =  true;

<remove>

> +		dev_warn(dev, "missing property thermistor-on-batctrl\n");
> +		thermistor = NTC_EXTERNAL;
> +	}

</remove>

> +	pdata->battery = &ab8500_bm_data;
> +	bat = pdata->battery;

Why not: bat = &ab8500_bm_data

Or just use ab8500_bm_data in its own right?

> +	if (thermistor == NTC_EXTERNAL) {
> +		bat->n_btypes  = 4;
> +		bat->bat_type  = bat_type_ext_thermistor;
> +		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
> +	}
> +	ret = of_property_read_string(np_bat_supply, "battery-name", &bat_tech);
> +	if (ret < 0) {
> +		dev_warn(dev, "missing property battery-name/type\n");
> +		bat_tech = "UNKNOWN";
> +	}
> +	of_node_put(np_bat_supply);
> +	if (strcmp(bat_tech, "LION") == 0) {
> +		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;
> +	}
> +	/* select the battery resolution table */
> +	for (i = 0; i < bat->n_btypes; ++i) {
> +		btype = (bat->bat_type + i);
> +		if (thermistor == NTC_EXTERNAL) {
> +			btype->batres_tbl =
> +				temp_to_batres_tbl_ext_thermistor;
> +		} else if (strcmp(bat_tech, "LION") == 0) {

Isn't strncmp safer, since you know the size of the comparison?

> +			btype->batres_tbl =
> +				temp_to_batres_tbl_9100;
> +		} else {
> +			btype->batres_tbl =
> +				temp_to_batres_tbl_thermistor;
> +		}
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL(bmdevs_of_probe);

Why are you exporting?

> diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
> index bba3cca..8e427e7 100644
> --- a/drivers/power/ab8500_btemp.c
> +++ b/drivers/power/ab8500_btemp.c
> @@ -93,7 +93,7 @@ struct ab8500_btemp {
>  	struct ab8500 *parent;
>  	struct ab8500_gpadc *gpadc;
>  	struct ab8500_fg *fg;
> -	struct abx500_btemp_platform_data *pdata;
> +	struct abx500_bmdevs_plat_data *pdata;
>  	struct abx500_bm_data *bat;
>  	struct power_supply btemp_psy;
>  	struct ab8500_btemp_events events;
> @@ -982,7 +982,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
>  	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
>  
>  	/* get btemp specific platform data */
> -	di->pdata = plat_data->btemp;
> +	di->pdata = plat_data->bmdev_pdata;
>  	if (!di->pdata) {
>  		dev_err(di->dev, "no btemp platform data supplied\n");
>  		ret = -EINVAL;
> diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
> index d4f0c98..5ff0d83 100644
> --- a/drivers/power/ab8500_charger.c
> +++ b/drivers/power/ab8500_charger.c
> @@ -220,7 +220,7 @@ struct ab8500_charger {
>  	bool autopower;
>  	struct ab8500 *parent;
>  	struct ab8500_gpadc *gpadc;
> -	struct abx500_charger_platform_data *pdata;
> +	struct abx500_bmdevs_plat_data *pdata;
>  	struct abx500_bm_data *bat;
>  	struct ab8500_charger_event_flags flags;
>  	struct ab8500_charger_usb_state usb_state;
> @@ -2555,7 +2555,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
>  	spin_lock_init(&di->usb_state.usb_lock);
>  
>  	/* get charger specific platform data */
> -	di->pdata = plat_data->charger;
> +	di->pdata = plat_data->bmdev_pdata;
>  	if (!di->pdata) {
>  		dev_err(di->dev, "no charger platform data supplied\n");
>  		ret = -EINVAL;
> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
> index bf02225..96741b8 100644
> --- a/drivers/power/ab8500_fg.c
> +++ b/drivers/power/ab8500_fg.c
> @@ -22,15 +22,14 @@
>  #include <linux/platform_device.h>
>  #include <linux/power_supply.h>
>  #include <linux/kobject.h>
> -#include <linux/mfd/abx500/ab8500.h>
> -#include <linux/mfd/abx500.h>
>  #include <linux/slab.h>
> -#include <linux/mfd/abx500/ab8500-bm.h>
>  #include <linux/delay.h>
> -#include <linux/mfd/abx500/ab8500-gpadc.h>
> -#include <linux/mfd/abx500.h>
>  #include <linux/time.h>
>  #include <linux/completion.h>
> +#include <linux/mfd/abx500.h>
> +#include <linux/mfd/abx500/ab8500.h>
> +#include <linux/mfd/abx500/ab8500-bm.h>
> +#include <linux/mfd/abx500/ab8500-gpadc.h>
>  
>  #define MILLI_TO_MICRO			1000
>  #define FG_LSB_IN_MA			1627
> @@ -212,7 +211,7 @@ struct ab8500_fg {
>  	struct ab8500_fg_avg_cap avg_cap;
>  	struct ab8500 *parent;
>  	struct ab8500_gpadc *gpadc;
> -	struct abx500_fg_platform_data *pdata;
> +	struct abx500_bmdevs_plat_data *pdata;
>  	struct abx500_bm_data *bat;
>  	struct power_supply fg_psy;
>  	struct workqueue_struct *fg_wq;
> @@ -544,14 +543,14 @@ cc_err:
>  		ret = abx500_set_register_interruptible(di->dev,
>  			AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
>  			SEC_TO_SAMPLE(10));
> -		if (ret)
> +		if (ret < 0)

I don't 'think' this change is required. abx500_set_register_interruptible
will only return !0 on error.

>  			goto fail;
>  
>  		/* Start the CC */
>  		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
>  			AB8500_RTC_CC_CONF_REG,
>  			(CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
> -		if (ret)
> +		if (ret < 0)
>  			goto fail;
>  	} else {
>  		di->turn_off_fg = false;
> @@ -2429,7 +2428,6 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev)
>  	flush_scheduled_work();
>  	power_supply_unregister(&di->fg_psy);
>  	platform_set_drvdata(pdev, NULL);
> -	kfree(di);
>  	return ret;
>  }
>  
> @@ -2446,18 +2444,47 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>  {
>  	int i, irq;
>  	int ret = 0;
> -	struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
> +	struct abx500_bm_plat_data *plat_data
> +				= pdev->dev.platform_data;
> +	struct device_node *np	= pdev->dev.of_node;
>  	struct ab8500_fg *di;
>  
> +	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
> +	if (!di) {
> +		dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
> +		return -ENOMEM;
> +	}
> +	if (np) {
> +		if (!plat_data) {

Change these around.

if (!plat_data) {
        if (np) {
                <snip>
        } else {
                <ERROR>
        }
}

> +			plat_data =
> +			devm_kzalloc(&pdev->dev, sizeof(*plat_data),
> +					GFP_KERNEL);
> +			if (!plat_data) {
> +				dev_err(&pdev->dev,
> +					"%s no mem for plat_data\n", __func__);
> +				return -ENOMEM;
> +			}
> +			plat_data->bmdev_pdata = devm_kzalloc(&pdev->dev,
> +				sizeof(*plat_data->bmdev_pdata), GFP_KERNEL);
> +			if (!plat_data->bmdev_pdata) {
> +				dev_err(&pdev->dev,
> +					"%s no mem for pdata->fg\n",
> +					__func__);
> +				return -ENOMEM;
> +			}
> +		}
> +		ret = bmdevs_of_probe(&pdev->dev, np, plat_data);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "failed to get platform data\n");
> +			return ret;
> +		}
> +	}

<remove>

>  	if (!plat_data) {
> -		dev_err(&pdev->dev, "No platform data\n");
> +		dev_err(&pdev->dev,
> +			"%s no fg platform data found\n", __func__);
>  		return -EINVAL;
>  	}
</remove>

> -	di = kzalloc(sizeof(*di), GFP_KERNEL);
> -	if (!di)
> -		return -ENOMEM;
> -
>  	mutex_init(&di->cc_lock);
>  
>  	/* get parent data */
> @@ -2466,19 +2493,17 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>  	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
>  
>  	/* get fg specific platform data */
> -	di->pdata = plat_data->fg;
> +	di->pdata = plat_data->bmdev_pdata;
>  	if (!di->pdata) {
>  		dev_err(di->dev, "no fg platform data supplied\n");
> -		ret = -EINVAL;
> -		goto free_device_info;
> +		return -EINVAL;
>  	}
>  
>  	/* get battery specific platform data */
>  	di->bat = plat_data->battery;
>  	if (!di->bat) {
>  		dev_err(di->dev, "no battery platform data supplied\n");
> -		ret = -EINVAL;
> -		goto free_device_info;
> +		return -EINVAL;
>  	}
>  
>  	di->fg_psy.name = "ab8500_fg";
> @@ -2506,7 +2531,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
>  	di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
>  	if (di->fg_wq == NULL) {
>  		dev_err(di->dev, "failed to create work queue\n");
> -		goto free_device_info;
> +		return -ENOMEM;
>  	}
>  
>  	/* Init work for running the fg algorithm instantly */
> @@ -2605,12 +2630,14 @@ free_irq:
>  	}
>  free_inst_curr_wq:
>  	destroy_workqueue(di->fg_wq);
> -free_device_info:
> -	kfree(di);
> -
>  	return ret;
>  }
>  
> +static const struct of_device_id ab8500_fg_match[] = {
> +	{.compatible = "stericsson,ab8500-fg",},

<nit>

Spaces:

{ .compatible = "stericsson,ab8500-fg", },

</nit>

> +	{},
> +};
> +
>  static struct platform_driver ab8500_fg_driver = {
>  	.probe = ab8500_fg_probe,
>  	.remove = __devexit_p(ab8500_fg_remove),
> @@ -2619,6 +2646,7 @@ static struct platform_driver ab8500_fg_driver = {
>  	.driver = {
>  		.name = "ab8500-fg",
>  		.owner = THIS_MODULE,
> +		.of_match_table = ab8500_fg_match,
>  	},
>  };
>  
> diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
> index 804b88c..ba548e4 100644
> --- a/drivers/power/abx500_chargalg.c
> +++ b/drivers/power/abx500_chargalg.c
> @@ -231,7 +231,7 @@ struct abx500_chargalg {
>  	struct abx500_chargalg_charger_info chg_info;
>  	struct abx500_chargalg_battery_data batt_data;
>  	struct abx500_chargalg_suspension_status susp_status;
> -	struct abx500_chargalg_platform_data *pdata;
> +	struct abx500_bmdevs_plat_data *pdata;
>  	struct abx500_bm_data *bat;
>  	struct power_supply chargalg_psy;
>  	struct ux500_charger *ac_chg;
> @@ -1814,7 +1814,7 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
>  	di->dev = &pdev->dev;
>  
>  	plat_data = pdev->dev.platform_data;
> -	di->pdata = plat_data->chargalg;
> +	di->pdata = plat_data->bmdev_pdata;
>  	di->bat = plat_data->battery;
>  
>  	/* chargalg supply */
> diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
> index 1318ca6..286f8ac 100644
> --- a/include/linux/mfd/abx500.h
> +++ b/include/linux/mfd/abx500.h
> @@ -382,39 +382,30 @@ struct abx500_bm_data {
>  	int gnd_lift_resistance;
>  	const struct abx500_maxim_parameters *maxi;
>  	const struct abx500_bm_capacity_levels *cap_levels;
> -	const struct abx500_battery_type *bat_type;
> +	struct abx500_battery_type *bat_type;
>  	const struct abx500_bm_charger_parameters *chg_params;
>  	const struct abx500_fg_parameters *fg_params;
>  };
>  
> -struct abx500_chargalg_platform_data {
> -	char **supplied_to;
> -	size_t num_supplicants;
> +struct abx500_bmdevs_plat_data {
> +	char	**supplied_to;
> +	size_t	num_supplicants;
> +	bool	autopower_cfg;
>  };
>  
> -struct abx500_charger_platform_data {
> -	char **supplied_to;
> -	size_t num_supplicants;
> -	bool autopower_cfg;
> -};
> -
> -struct abx500_btemp_platform_data {
> -	char **supplied_to;
> -	size_t num_supplicants;
> +struct abx500_bm_plat_data {
> +	struct abx500_bm_data *battery;
> +	struct abx500_bmdevs_plat_data *bmdev_pdata;
>  };
>  
> -struct abx500_fg_platform_data {
> -	char **supplied_to;
> -	size_t num_supplicants;
> +enum {
> +	NTC_EXTERNAL = 0,
> +	NTC_INTERNAL,
>  };
>  
> -struct abx500_bm_plat_data {
> -	struct abx500_bm_data *battery;
> -	struct abx500_charger_platform_data *charger;
> -	struct abx500_btemp_platform_data *btemp;
> -	struct abx500_fg_platform_data *fg;
> -	struct abx500_chargalg_platform_data *chargalg;
> -};
> +int bmdevs_of_probe(struct device *dev,
> +		struct device_node *np,
> +		struct abx500_bm_plat_data *pdata);
>  
>  int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
>  	u8 value);
> diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
> index 44310c9..d15b7f1 100644
> --- a/include/linux/mfd/abx500/ab8500-bm.h
> +++ b/include/linux/mfd/abx500/ab8500-bm.h
> @@ -422,6 +422,13 @@ struct ab8500_chargalg_platform_data {
>  struct ab8500_btemp;
>  struct ab8500_gpadc;
>  struct ab8500_fg;
> +
> +extern struct abx500_bm_data ab8500_bm_data;
> +extern struct abx500_battery_type bat_type_ext_thermistor[];
> +extern struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[];
> +extern struct batres_vs_temp temp_to_batres_tbl_9100[];
> +extern struct batres_vs_temp temp_to_batres_tbl_thermistor[];
> +
>  #ifdef CONFIG_AB8500_BM
>  void ab8500_fg_reinit(void);
>  void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
> -- 
> 1.7.9.5
> 

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

end of thread, other threads:[~2012-11-23  9:50 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-22 18:43 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
2012-11-22 18:43 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
2012-11-22 20:08   ` Anton Vorontsov
2012-11-23  9:50     ` Lee Jones
2012-11-22 18:43 ` [PATCH 2/4] mfd: ab8500: add devicetree support for btemp Rajanikanth H.V
2012-11-22 18:43 ` [PATCH 3/4] mfd: ab8500: add devicetree support for charger Rajanikanth H.V
2012-11-22 18:43 ` [PATCH 4/4] mfd: ab8500: add devicetree support for chargalg Rajanikanth H.V
  -- strict thread matches above, loose matches on Subject: below --
2012-10-31 15:40 [PATCH 0/4] Implement device tree support for ab8500 BM Devices Rajanikanth H.V
2012-10-31 15:40 ` [PATCH 1/4] mfd: ab8500: add devicetree support for fuelgauge Rajanikanth H.V
2012-11-01 15:15   ` Francesco Lavra
2012-11-07 18:45     ` Rajanikanth H V
2012-11-10 16:53       ` Francesco Lavra
2012-11-15 11:34         ` Rajanikanth HV
     [not found] <1351146654-9110-1-git-send-email-rajanikanth.hv@stericsson.com>
     [not found] ` <1351146654-9110-2-git-send-email-rajanikanth.hv@stericsson.com>
2012-10-27 15:07   ` Francesco Lavra
2012-10-27 16:00     ` Rajanikanth HV
2012-10-27 16:18       ` Francesco Lavra
     [not found] <1349064513-31301-1-git-send-email-rajanikanth.hv@stericsson.com>
     [not found] ` <1349064513-31301-2-git-send-email-rajanikanth.hv@stericsson.com>
2012-10-01  9:49   ` Lee Jones
2012-10-01  9:59     ` Rajanikanth HV
2012-10-01 10:36       ` Lee Jones
2012-10-01 10:22     ` Lee Jones
2012-10-06 14:01   ` Francesco Lavra

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).