From: "Rajanikanth H.V" rajanikanth.hv@linaro.org
This patch addes device tree support for battery temperature and fuel guage driver
Signed-off-by: Rajanikanth H.V rajanikanth.hv@linaro.org --- .../bindings/power_supply/ab8500/ab8500-btemp.txt | 209 +++++++++++++ .../bindings/power_supply/ab8500/ab8500-fg.txt | 51 +++ arch/arm/boot/dts/db8500.dtsi | 327 ++++++++++++++++++++ drivers/mfd/ab8500-core.c | 16 +- drivers/power/ab8500_btemp.c | 299 +++++++++++++++++- drivers/power/ab8500_fg.c | 58 +++- include/linux/mfd/abx500.h | 17 +- include/linux/of.h | 33 ++ 8 files changed, 966 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt new file mode 100644 index 0000000..9908934 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt @@ -0,0 +1,209 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC) + + battery temperature monitor: + +* Required properties: +- compatible: "stericsson,ab8500-btemp" + +* Sub-node: +- ab8500_bm_data: + +example: + ab8500-btemp { + compatible = "stericsson,ab8500-btemp"; + ... + ... + bat = <&ab8500_bm_data>; + }; + +ab8500_bm_data: + Contain the battery management/monitor node with the following + information to support different battery types. + +{ + temp_under under this temp, charging is stopped + temp_low between this temp and temp_under charging is reduced + temp_high between this temp and temp_over charging is reduced + temp_over over this temp, charging is stopped + temp_now present battery temperature + temp_interval_chg temperature measurement interval in s when charging + temp_interval_nochg temperature measurement interval in s when not charging + main_safety_tmr_h safety timer for main charger + usb_safety_tmr_h safety timer for usb charger + bkup_bat_v voltage which we charge the backup battery with + bkup_bat_i current which we charge the backup battery with + no_maintenance indicates that maintenance charging is disabled + abx500_adc_therm placement of thermistor, batctrl or battemp adc + chg_unknown_bat flag to enable charging of unknown batteries + enable_overshoot flag to enable VBAT overshoot control + auto_trig flag to enable auto adc trigger + fg_res resistance of FG resistor in 0.1mOhm + n_btypes number of elements in array bat_type + batt_id index of the identified battery in array bat_type + interval_charging charge alg cycle period time when charging (sec) + interval_not_charging charge alg cycle period time when not charging (sec) + temp_hysteresis temperature hysteresis + gnd_lift_resistance Battery ground to phone ground resistance (mOhm) +} +e.g: + ab8500_bm_data: bm_data { + temp_under = <3>; + temp_low = <8>; + temp_high = <43>; + temp_over = <48>; + temp_now = <0>; + temp_interval_chg = <20>; + temp_interval_nochg = <120>; + main_safety_tmr_h = <4>; + usb_safety_tmr_h = <4>; + bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */ + bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */ + no_maintenance = <0>; + chg_unknown_bat = <0>; + enable_overshoot = <0>; + auto_trig = <0>; + adc_therm = <0>; + fg_res = <100>; + batt_id = <0>; + interval_charging = <5>; + interval_not_charging = <120>; + temp_hysteresis = <3>; + gnd_lift_resistance = <34>; + }; + +* subnodes for the node 'ab8500_bm_data': + - maxi : maximization parameters + - cap_levels: capacity in percent for the different capacity levels + - bat_type : table of supported battery types + - chg_params: charger parameters + - fg_params : fuel gauge parameters + +example: +ab8500_bm_data: bm_data { + ... + ... + n_btypes = <3>; /* number of battery types */ + ... + maxi = <&ab8500_bm_data_maxim_parameters>; + cap_levels = <&ab8500_bm_data_cap_levels>; + bat_type = <&ab8500_battery_type_0 &ab8500_battery_type_1 &ab8500_battery_type_2>; + chg_params = <&ab8500_bm_data_charger_parameters>; + fg_params = <&ab8500_bm_data_fuel_guage_parameters>; + +}; + +bx500_battery_type: + prepare battery type information from individual battery specification as: + { + name : battery technology + resis_high : battery upper resistance limit + resis_low : battery lower resistance limit + charge_full_design : Maximum battery capacity in mAh + nominal_voltage : Nominal voltage of the battery in mV + termination_vol : max voltage upto which battery can be charged + termination_curr : battery charging termination current in mA + recharge_vol : battery voltage limit that will trigger a new + full charging cycle in the case where maintenance + charging has been disabled + normal_cur_lvl : charger current in normal state in mA + normal_vol_lvl : charger voltage in normal state in mV + maint_a_cur_lvl : charger current in maintenance A state in mA + maint_a_vol_lvl : charger voltage in maintenance A state in mV + maint_a_chg_timer_h : charge time in maintenance A state + maint_b_cur_lvl : charger current in maintenance B state in mA + maint_b_vol_lvl : charger voltage in maintenance B state in mV + maint_b_chg_timer_h : charge time in maintenance B state + low_high_cur_lvl : charger current in temp low/high state in mA + low_high_vol_lvl : charger voltage in temp low/high state in mV' + battery_resistance : battery inner resistance in mOhm. + n_r_t_tbl_elements : number of elements in r_to_t_tbl + r_to_t_tbl : table containing resistance to temp points + n_v_cap_tbl_elements: number of elements in v_to_cap_tbl + v_to_cap_tbl : Voltage to capacity (in %) table + n_batres_tbl_elements: number of elements in the batres_tbl + batres_tbl : battery internal resistance vs temperature table + } + + Note: + Selected battery shall adhere to the specification provided in: + http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf + +-example: + + ab8500_battery_type_1: ab8500_battery_therm_on_batctrl { + bat_name = <3>; + resis_high = <53407>; + resis_low = <12500>; + 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>; + battery_resistance = <300>; + + n_temp_tbl_elements = <15>; + + r_to_t_tbl - defines one point in a temp to res curve. To be used + in battery packs that combines the identification resistor + with a NTC resistor. + + r_to_t_tbl = < + 0xfffffffb 53407 /* -5 */ + 0 48594 'battery pack temperature in Celcius' 'NTC resistor net total resistance' + 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>; + + n_v_cap_tbl_elements = <20>; + v_to_cap_tbl = < /* Table for translating voltage to capacity */ + 4171 100 'Voltage in mV' 'Capacity in percent' + 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>; + + n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */ + batres_tbl = < /* defines one point in a temp vs battery internal resistance curve. */ + 40 120 'battery pack temperature in Celcius' 'battery internal reistance in mOhm' + 30 135 + 20 165 + 10 230 + 00 325 + 0xfffffff6 445 /* -10 */ + 0xffffffec 595>; /* -20 */ + }; diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt new file mode 100644 index 0000000..5e84852 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt @@ -0,0 +1,51 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC) + fuel guage: + +* Required properties: +- compatible: "stericsson,ab8500-fg" + +* Sub-node: +- ab8500_bm_data: + +example: + ab8500-btemp { + compatible = "stericsson,ab8500-fg"; + ... + ... + bat = <&ab8500_bm_data>; + }; + +Refer: + Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt for + information on 'ab8500_bm_data' + +* subnode for the node 'ab8500_bm_data': + - fg_params : fuel gauge parameters + +example: + +ab8500_bm_data: bm_data { + ... + ... + ... + fg_params = <&ab8500_bm_data_fuel_guage_parameters>; +} + + /* Fuel gauge algorithm parameters, in seconds */ + ab8500_bm_data_fuel_guage_parameters: bm_data_fuel_guage_parameters { + recovery_sleep_timer = <10>; /* Time between measurements while recovering */ + recovery_total_time = <100>; /* Total recovery time */ + init_timer = <1>; /* Measurement interval during startup */ + init_discard_time = <5>; /* Time we discard voltage measurement at startup */ + init_total_time = <40>; /* Total init time during startup */ + high_curr_time = <60>; /* Time current has to be high to go to recovery */ + accu_charging = <30>; /* FG accumulation time while charging */ + accu_high_curr = <30>; /* FG accumulation time in high current mode */ + high_curr_threshold = <50>; /* High current threshold, in mA */ + lowbat_threshold = <3100>;/* Low battery threshold, in mV */ + battok_falling_th_sel0 = <2860>;/* Over battery threshold, in mV */ + battok_raising_th_sel1 = <2860>;/* Threshold in mV for battOk signal sel0 Resolution in 50 mV step. */ + user_cap_limit = <15>; /* Threshold in mV for battOk signal sel1 Resolution in 50 mV step. */ + maint_thres = <97>; /* Capacity reported from user must be within this limit to be considered as sane, in percentage points. + }; * This is the threshold where we stop reporting battery full while in maintenance, in per cent + */ diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi index 26f895f..6f3b5df 100644 --- a/arch/arm/boot/dts/db8500.dtsi +++ b/arch/arm/boot/dts/db8500.dtsi @@ -330,6 +330,333 @@ vddadc-supply = <&ab8500_ldo_tvout_reg>; };
+ ab8500-fg { + compatible = "stericsson,ab8500-fg"; + interrupts = <24 0x4 + 8 0x4 + 28 0x4 + 27 0x4 + 26 0x4>; + interrupt-names = "NCONV_ACCU", + "BATT_OVV", + "LOW_BAT_F", + "CC_INT_CALIB", + "CCEOC"; + supplied_to = "ab8500_chargalg", "ab8500_usb"; + num_supplicants = <2>; + bat = <&ab8500_bm_data>; + }; + + ab8500-btemp { + compatible = "stericsson,ab8500-btemp"; + interrupts = <20 0x04 + 80 0x04 + 81 0x04 + 82 0x04 + 83 0x04>; + interrupt-names = "BAT_CTRL_INDB", + "BTEMP_LOW", + "BTEMP_HIGH", + "BTEMP_LOW_MEDIUM", + "BTEMP_MEDIUM_HIGH"; + supplied_to = "ab8500_chargalg", "ab8500_fg"; + num_supplicants = <2>; + bat = <&ab8500_bm_data>; + }; + + ab8500_battery_type_0: ab8500_battery_unknown { + bat_name = <0>; + resis_high = <0>; + resis_low = <0>; + 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>; + battery_resistance = <300>; + + n_temp_tbl_elements = <15>; + r_to_t_tbl = < + 0xfffffffb 214834 /* -5 */ + 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>; + + n_v_cap_tbl_elements = <24>; + v_to_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>; + + n_batres_tbl_elements = <7>; + batres_tbl = < + 40 120 + 30 135 + 20 165 + 10 230 + 00 325 + 0xfffffff6 445 /* -10 */ + 0xffffffec 595>; /* -20 */ + }; + + ab8500_battery_type_1: ab8500_battery_therm_on_batctrl { + bat_name = <3>; + resis_high = <53407>; + resis_low = <12500>; + 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>; + battery_resistance = <300>; + + n_temp_tbl_elements = <15>; + r_to_t_tbl = < + 0xfffffffb 53407 /* -5 */ + 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>; + + n_v_cap_tbl_elements = <20>; + v_to_cap_tbl = < + 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>; + + n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */ + batres_tbl = < + 40 120 + 30 135 + 20 165 + 10 230 + 00 325 + 0xfffffff6 445 /* -10 */ + 0xffffffec 595>; /* -20 */ + }; + + ab8500_battery_type_2: ab8500_battery_therm_on_batctrl_1 { + bat_name = <3>; + resis_high = <165418>; + resis_low = <82869>; + 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>; + battery_resistance = <300>; + + n_temp_tbl_elements = <15>; + r_to_t_tbl = < + 0xfffffffb 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>; + + n_v_cap_tbl_elements = <20>; + v_to_cap_tbl = < + 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>; + + n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */ + batres_tbl = < + 40 120 + 30 135 + 20 165 + 10 230 + 00 325 + 0xfffffff6 445 /* -10 */ + 0xffffffec 595>; /* -20 */ + }; + + ab8500_bm_data_cap_levels: bm_data_cap_levels { + critical = <2>; + low = <10>; + normal = <70>; + high = <95>; + full = <100>; + }; + + ab8500_bm_data_maxim_parameters: bm_data_maxim_parameters { + ena_maxi = <1>; + chg_curr = <910>; + wait_cycles = <10>; + charger_curr_step = <100>; + }; + + ab8500_bm_data_charger_parameters: bm_data_charger_parameters { + usb_volt_max = <5500>; + usb_curr_max = <1500>; + ac_volt_max = <7500>; + ac_curr_max = <1500>; + }; + + ab8500_bm_data_fuel_guage_parameters: bm_data_fuel_guage_parameters { + 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>; + }; + + ab8500_bm_data: bm_data { + temp_under = <3>; + temp_low = <8>; + temp_high = <43>; + temp_over = <48>; + temp_now = <0>; + temp_interval_chg = <20>; + temp_interval_nochg = <120>; + main_safety_tmr_h = <4>; + usb_safety_tmr_h = <4>; + bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */ + bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */ + no_maintenance = <0>; /* CONFIG_AB8500_9100_LI_ION_BATTERY not considered */ + chg_unknown_bat = <0>; /* CONFIG_AB8500_9100_LI_ION_BATTERY not considered */ + enable_overshoot = <0>; + auto_trig = <0>; + adc_therm = <0>; + fg_res = <100>; + n_btypes = <3>; + batt_id = <0>; + interval_charging = <5>; + interval_not_charging = <120>; + temp_hysteresis = <3>; + gnd_lift_resistance = <34>; + maxi = <&ab8500_bm_data_maxim_parameters>; + cap_levels = <&ab8500_bm_data_cap_levels>; + bat_type = <&ab8500_battery_type_0 &ab8500_battery_type_1 &ab8500_battery_type_2>; + chg_params = <&ab8500_bm_data_charger_parameters>; + fg_params = <&ab8500_bm_data_fuel_guage_parameters>; + }; + ab8500-usb { compatible = "stericsson,ab8500-usb"; interrupts = < 90 0x4 diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6d613e8..837488b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1419,15 +1419,15 @@ static int __devinit ab8500_probe(struct platform_device *pdev) ab8500->irq_base); if (ret) goto out_freeirq; - }
- if (!no_bm) { - /* Add battery management devices */ - ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, - ARRAY_SIZE(ab8500_bm_devs), NULL, - ab8500->irq_base); - if (ret) - dev_err(ab8500->dev, "error adding bm devices\n"); + if (!no_bm) { + /* Add battery management devices */ + ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, + ARRAY_SIZE(ab8500_bm_devs), NULL, + ab8500->irq_base); + if (ret) + dev_err(ab8500->dev, "error adding bm devices\n"); + } }
if (is_ab9540(ab8500)) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index bba3cca..04da929 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -20,6 +20,7 @@ #include <linux/power_supply.h> #include <linux/completion.h> #include <linux/workqueue.h> +#include <linux/of.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500-bm.h> @@ -480,7 +481,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { dev_err(di->dev, - "%s gpadc conversion failed," + "%s gpadc conversion failed, " " using previous value\n", __func__); return prev; } @@ -960,15 +961,249 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev) return 0; }
+int populate_abx8500_bm_data(struct device *dev, + struct abx500_bm_data *bm_data, + struct device_node *np) +{ + int i, plen, itbl, ret = 0; + phandle *temp_phandle; + struct abx500_battery_type *temp_bat_type; + struct property *pbat_type; + struct device_node *np_bat; + const __be32 *p; + u32 u; + +#define get_bm_data_property(node_p, prop_name)\ + be32_to_cpup(of_get_property(node_p, prop_name, NULL)); + + temp_phandle = (phandle *)of_get_property(np, "bat", NULL); + BUG_ON(!temp_phandle); + np_bat = of_find_node_by_phandle(be32_to_cpup(temp_phandle)); + BUG_ON(!np_bat); + + bm_data->temp_under = get_bm_data_property(np_bat, "temp_under"); + bm_data->temp_low = get_bm_data_property(np_bat, "temp_low"); + bm_data->temp_high = get_bm_data_property(np_bat, "temp_high"); + bm_data->temp_over = get_bm_data_property(np_bat, "temp_over"); + bm_data->temp_now = get_bm_data_property(np_bat, "temp_now"); + bm_data->temp_interval_chg = + get_bm_data_property(np_bat, "temp_interval_chg"); + bm_data->temp_interval_nochg = + get_bm_data_property(np_bat, "temp_interval_nochg"); + bm_data->main_safety_tmr_h = + get_bm_data_property(np_bat, "main_safety_tmr_h"); + bm_data->usb_safety_tmr_h = + get_bm_data_property(np_bat, "usb_safety_tmr_h"); + bm_data->bkup_bat_v = + get_bm_data_property(np_bat, "bkup_bat_v"); + bm_data->bkup_bat_i = + get_bm_data_property(np_bat, "bkup_bat_i"); + bm_data->no_maintenance = + get_bm_data_property(np_bat, "no_maintenance"); + bm_data->chg_unknown_bat = + get_bm_data_property(np_bat, "chg_unknown_bat"); + bm_data->enable_overshoot = + get_bm_data_property(np_bat, "enable_overshoot"); + bm_data->auto_trig = + get_bm_data_property(np_bat, "auto_trig"); + bm_data->adc_therm = + get_bm_data_property(np_bat, "adc_therm"); + bm_data->fg_res = + get_bm_data_property(np_bat, "fg_res"); + bm_data->n_btypes = + get_bm_data_property(np_bat, "n_btypes"); + bm_data->batt_id = + get_bm_data_property(np_bat, "batt_id"); + bm_data->interval_charging = + get_bm_data_property(np_bat, "interval_charging"); + bm_data->interval_not_charging = + get_bm_data_property(np_bat, "interval_not_charging"); + bm_data->temp_hysteresis = + get_bm_data_property(np_bat, "temp_hysteresis"); + bm_data->gnd_lift_resistance = + get_bm_data_property(np_bat, "gnd_lift_resistance"); + + temp_phandle = (phandle *)of_get_property(np_bat, "bat_type", &plen); + if (temp_phandle == NULL) { + dev_warn(dev, "battery type not found\n"); + return -EINVAL; + } + + plen = plen/sizeof(u32); + + if (bm_data->n_btypes != plen) { + dev_crit(dev, "Invalid number of battery types\n"); + return -EINVAL; + } + + bm_data->bat_type = + kzalloc(plen * sizeof(struct abx500_battery_type), GFP_KERNEL); + if (bm_data->bat_type == NULL) { + dev_crit(dev, "no mem for bm_data->bat_type\n"); + return -ENOMEM; + } + + of_node_put(np_bat); + + /* + * traverse 'plen' times in 'allnext' for battery types and + * fillup bm_data->bat_type + */ + i = 0; + for_each_node_by_phandle(np_bat, plen, temp_phandle) + { + temp_bat_type = (struct abx500_battery_type *) + (bm_data->bat_type + i++); + temp_bat_type->name = + get_bm_data_property(np_bat, "bat_name"); + temp_bat_type->resis_high = + get_bm_data_property(np_bat, "resis_high"); + temp_bat_type->resis_low = + get_bm_data_property(np_bat, "resis_low"); + temp_bat_type->charge_full_design = + get_bm_data_property(np_bat, "charge_full_design"); + temp_bat_type->nominal_voltage = + get_bm_data_property(np_bat, "nominal_voltage"); + temp_bat_type->termination_vol = + get_bm_data_property(np_bat, "termination_vol"); + temp_bat_type->termination_curr = + get_bm_data_property(np_bat, "termination_curr"); + temp_bat_type->recharge_vol = + get_bm_data_property(np_bat, "recharge_vol"); + temp_bat_type->normal_cur_lvl = + get_bm_data_property(np_bat, "normal_cur_lvl"); + temp_bat_type->normal_vol_lvl = + get_bm_data_property(np_bat, "normal_vol_lvl"); + temp_bat_type->maint_a_cur_lvl = + get_bm_data_property(np_bat, "maint_a_cur_lvl"); + temp_bat_type->maint_a_vol_lvl = + get_bm_data_property(np_bat, "maint_a_vol_lvl"); + temp_bat_type->maint_a_chg_timer_h = + get_bm_data_property(np_bat, "maint_a_chg_timer_h"); + temp_bat_type->maint_b_cur_lvl = + get_bm_data_property(np_bat, "maint_b_cur_lvl"); + temp_bat_type->maint_b_vol_lvl = + get_bm_data_property(np_bat, "maint_b_vol_lvl"); + temp_bat_type->maint_b_chg_timer_h = + get_bm_data_property(np_bat, "maint_b_chg_timer_h"); + temp_bat_type->low_high_cur_lvl = + get_bm_data_property(np_bat, "low_high_cur_lvl"); + temp_bat_type->low_high_vol_lvl = + get_bm_data_property(np_bat, "low_high_vol_lvl"); + temp_bat_type->battery_resistance = + get_bm_data_property(np_bat, "battery_resistance"); + + temp_bat_type->n_temp_tbl_elements = + get_bm_data_property(np_bat, "n_temp_tbl_elements"); + temp_bat_type->r_to_t_tbl = (struct abx500_res_to_temp *) + kzalloc(sizeof(struct abx500_res_to_temp) * + temp_bat_type->n_temp_tbl_elements, GFP_KERNEL); + if (temp_bat_type->r_to_t_tbl == NULL) { + dev_crit(dev, "no mem for r_to_t_tbl\n"); + kfree(bm_data->bat_type); + return -ENOMEM; + } + itbl = 0; + of_property_for_each_u32(np_bat, "r_to_t_tbl", pbat_type, p, u) + *((int *)(temp_bat_type->r_to_t_tbl) + itbl++) = (int)u; + + temp_bat_type->n_v_cap_tbl_elements = + get_bm_data_property(np_bat, "n_v_cap_tbl_elements"); + temp_bat_type->v_to_cap_tbl = (struct abx500_v_to_cap *) + kzalloc(sizeof(struct abx500_v_to_cap) * + temp_bat_type->n_v_cap_tbl_elements, GFP_KERNEL); + if (temp_bat_type->v_to_cap_tbl == NULL) { + ret = -ENOMEM; + dev_crit(dev, "no mem for v_to_cap_tbl\n"); + goto out_free_mem1; + } + itbl = 0; + of_property_for_each_u32(np_bat, + "v_to_cap_tbl", pbat_type, p, u) + *((int *)(temp_bat_type->v_to_cap_tbl) + itbl++) = + (int)u; + + temp_bat_type->n_batres_tbl_elements = + get_bm_data_property(np_bat, "n_batres_tbl_elements"); + temp_bat_type->batres_tbl = (struct batres_vs_temp *) + kzalloc(sizeof(struct batres_vs_temp) * + temp_bat_type->n_temp_tbl_elements, GFP_KERNEL); + if (temp_bat_type->batres_tbl == NULL) { + ret = -ENOMEM; + dev_crit(dev, "no mem for batres_tbl\n"); + goto out_free_mem2; + } + itbl = 0; + of_property_for_each_u32(np_bat, "batres_tbl", pbat_type, p, u) + *((int *)(temp_bat_type->batres_tbl) + itbl++) = (int)u; + } + + of_node_put(np_bat); + + bm_data->chg_params = (struct abx500_bm_charger_parameters *) + kzalloc(sizeof(struct abx500_bm_charger_parameters), + GFP_KERNEL); + if (bm_data->chg_params == NULL) { + dev_crit(dev, "Failed to alloc memory for chg_params\n"); + ret = -ENOMEM; + goto out_free_mem3; + } + itbl = 0; + of_property_for_each_u32(np_bat, "chg_params", pbat_type, p, u) + *((int *)(bm_data->chg_params) + itbl++) = (int)u; + + bm_data->fg_params = (struct abx500_fg_parameters *) + kzalloc(sizeof(struct abx500_fg_parameters), GFP_KERNEL); + if (bm_data->fg_params == NULL) { + dev_crit(dev, "Failed to alloc memory for fg_params\n"); + ret = -ENOMEM; + goto out_free_mem4; + } + itbl = 0; + of_property_for_each_u32(np_bat, "fg_params", pbat_type, p, u) + *((int *)(bm_data->fg_params) + itbl++) = (int)u; + + return ret; + +out_free_mem1: + kfree(bm_data->bat_type); + kfree(temp_bat_type->r_to_t_tbl); + return ret; + +out_free_mem2: + kfree(bm_data->bat_type); + kfree(temp_bat_type->r_to_t_tbl); + kfree(temp_bat_type->v_to_cap_tbl); + return ret; + +out_free_mem3: + kfree(bm_data->bat_type); + kfree(temp_bat_type->r_to_t_tbl); + kfree(temp_bat_type->v_to_cap_tbl); + kfree(temp_bat_type->batres_tbl); + return ret; + +out_free_mem4: + kfree(bm_data->bat_type); + kfree(temp_bat_type->r_to_t_tbl); + kfree(temp_bat_type->v_to_cap_tbl); + kfree(temp_bat_type->batres_tbl); + kfree(bm_data->chg_params); + return ret; +} +EXPORT_SYMBOL_GPL(populate_abx8500_bm_data); + static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val; - struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; struct ab8500_btemp *di; + const unsigned int *btemp_p_val; + const char *pvalue = NULL;
- if (!plat_data) { - dev_err(&pdev->dev, "No platform data\n"); + if (!np) { + dev_err(&pdev->dev, "No platform data or DT found\n"); return -EINVAL; }
@@ -982,20 +1217,46 @@ 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; - if (!di->pdata) { - dev_err(di->dev, "no btemp platform data supplied\n"); - ret = -EINVAL; - goto free_device_info; + btemp_p_val = of_get_property(np, "num_supplicants", NULL); + BUG_ON(!btemp_p_val); + + di->pdata = + kzalloc(sizeof(struct abx500_btemp_platform_data), GFP_KERNEL); + if (di->pdata == NULL) { + kfree(di); + return -ENOMEM; }
- /* get battery specific platform data */ - di->bat = plat_data->battery; + di->pdata->num_supplicants = be32_to_cpup(btemp_p_val); + di->pdata->supplied_to = + kzalloc(di->pdata->num_supplicants * + sizeof(const char *), GFP_KERNEL); + if (di->pdata->supplied_to == NULL) { + kfree(di); + kfree(di->pdata); + return -ENOMEM; + } + + for (val = 0; val < di->pdata->num_supplicants; ++val) + if (of_property_read_string_index + (np, "supplied_to", val, &pvalue) == 0) + *(di->pdata->supplied_to + val) = (char *)pvalue; + else { + dev_warn(di->dev, "insufficient number of supplied_to data found\n"); + goto free_device_info; + } + dev_dbg(di->dev, "getting DT battery information\n"); + di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL); if (!di->bat) { - dev_err(di->dev, "no battery platform data supplied\n"); - ret = -EINVAL; + kfree(di); + kfree(di->pdata); + return -ENOMEM; + } + if (populate_abx8500_bm_data(di->dev, di->bat, np) < 0) { + dev_warn(di->dev, "Failed to bind DT\n"); goto free_device_info; } + dev_dbg(di->dev, "getting DT battery information...done\n");
/* BTEMP supply */ di->btemp_psy.name = "ab8500_btemp"; @@ -1008,7 +1269,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di->btemp_psy.external_power_changed = ab8500_btemp_external_power_changed;
- /* Create a work queue for the btemp */ di->btemp_wq = create_singlethread_workqueue("ab8500_btemp_wq"); @@ -1016,7 +1276,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) dev_err(di->dev, "failed to create work queue\n"); goto free_device_info; } - /* Init work for measuring temperature periodically */ INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work, ab8500_btemp_periodic_work); @@ -1090,14 +1349,23 @@ free_irq: irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); free_irq(irq, di); } + free_btemp_wq: destroy_workqueue(di->btemp_wq); + free_device_info: kfree(di); + kfree(di->pdata); + kfree(di->bat);
return ret; }
+static const struct of_device_id ab8500_btemp_match[] = { + {.compatible = "stericsson,ab8500-btemp",}, + {}, +}; + static struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, .remove = __devexit_p(ab8500_btemp_remove), @@ -1106,6 +1374,7 @@ static struct platform_driver ab8500_btemp_driver = { .driver = { .name = "ab8500-btemp", .owner = THIS_MODULE, + .of_match_table = ab8500_btemp_match, }, };
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index bf02225..1d0e32a 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -31,6 +31,7 @@ #include <linux/mfd/abx500.h> #include <linux/time.h> #include <linux/completion.h> +#include <linux/of.h>
#define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -2446,11 +2447,12 @@ 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; + const char *fg_p_val; + struct device_node *np = pdev->dev.of_node; struct ab8500_fg *di;
- if (!plat_data) { - dev_err(&pdev->dev, "No platform data\n"); + if (!np) { + dev_err(&pdev->dev, "No DT node for platform data available\n"); return -EINVAL; }
@@ -2464,20 +2466,42 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->dev = &pdev->dev; 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; + di->pdata = + kzalloc(sizeof(struct abx500_btemp_platform_data), GFP_KERNEL); + if (di->pdata == NULL) { + kfree(di); + return -ENOMEM; + } + di->pdata->num_supplicants = + be32_to_cpup(of_get_property(np, "num_supplicants", NULL)); + di->pdata->supplied_to = + kzalloc(di->pdata->num_supplicants * + sizeof(const char *), GFP_KERNEL); + if (di->pdata->supplied_to == NULL) { + kfree(di); + kfree(di->pdata); + return -ENOMEM; }
+ for (i = 0; i < di->pdata->num_supplicants; ++i) + if (of_property_read_string_index + (np, "supplied_to", i, &fg_p_val) == 0) + *(di->pdata->supplied_to + i) = (char *)fg_p_val; + else { + dev_warn(di->dev, "insufficient number of supplied_to data found\n"); + goto free_device_info; + } + /* get battery specific platform data */ - di->bat = plat_data->battery; + di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL); if (!di->bat) { - dev_err(di->dev, "no battery platform data supplied\n"); - ret = -EINVAL; + kfree(di); + kfree(di->pdata); + return -ENOMEM; + } + ret = populate_abx8500_bm_data(di->dev, di->bat, np); + if (ret < 0) { + dev_warn(di->dev, "Failed to bind DT\n"); goto free_device_info; }
@@ -2607,10 +2631,15 @@ free_inst_curr_wq: destroy_workqueue(di->fg_wq); free_device_info: kfree(di); + kfree(di->pdata);
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 +2648,7 @@ static struct platform_driver ab8500_fg_driver = { .driver = { .name = "ab8500-fg", .owner = THIS_MODULE, + .of_match_table = ab8500_fg_match, }, };
@@ -2632,7 +2662,7 @@ static void __exit ab8500_fg_exit(void) platform_driver_unregister(&ab8500_fg_driver); }
-subsys_initcall_sync(ab8500_fg_init); +subsys_initcall(ab8500_fg_init); module_exit(ab8500_fg_exit);
MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 1318ca6..9dbc4d1 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -113,13 +113,13 @@ struct ab3100 { * struct ab3100_platform_data * Data supplied to initialize board connections to the AB3100 * @reg_constraints: regulator constraints for target board - * the order of these constraints are: LDO A, C, D, E, - * F, G, H, K, EXT and BUCK. + * the order of these constraints are: LDO A, C, D, E, + * F, G, H, K, EXT and BUCK. * @reg_initvals: initial values for the regulator registers - * plus two sleep settings for LDO E and the BUCK converter. - * exactly AB3100_NUM_REGULATORS+2 values must be sent in. - * Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK, - * BUCK sleep, LDO D. (LDO D need to be initialized last.) + * plus two sleep settings for LDO E and the BUCK converter. + * exactly AB3100_NUM_REGULATORS+2 values must be sent in. + * Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK, + * BUCK sleep, LDO D. (LDO D need to be initialized last.) * @external_voltage: voltage level of the external regulator. */ struct ab3100_platform_data { @@ -131,7 +131,7 @@ struct ab3100_platform_data { int ab3100_event_register(struct ab3100 *ab3100, struct notifier_block *nb); int ab3100_event_unregister(struct ab3100 *ab3100, - struct notifier_block *nb); + struct notifier_block *nb);
/** * struct abx500_init_setting @@ -387,6 +387,9 @@ struct abx500_bm_data { const struct abx500_fg_parameters *fg_params; };
+int populate_abx8500_bm_data(struct device *, struct abx500_bm_data *, + struct device_node *); + struct abx500_chargalg_platform_data { char **supplied_to; size_t num_supplicants; diff --git a/include/linux/of.h b/include/linux/of.h index 2ec1083..61b4ac8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -183,6 +183,39 @@ extern struct device_node *of_find_matching_node(struct device_node *from, #define for_each_matching_node(dn, matches) \ for (dn = of_find_matching_node(NULL, matches); dn; \ dn = of_find_matching_node(dn, matches)) + +/* + * syntax: for_each_node_by_phandle(np, len, phandle); + * @np : pointer to node to start in the list + * @len: number of nodes expected + * @phandle: current phandle which is obtained through of_get_property(...) + * + * e.g: + * node_a: <> { + * ... + * }; + * node_b: <> { + * ... + * }; + * node_c: <> { + * ... + * }; + * + * node_x: <> { + * p1 = <v1>; + * p2 = <v2>; + * n_nodes = <3> + * p3 = <&node_a &node_b &node_c ....>; + * }; + * + * Note: + * - invoke of_node_put(...) as it uses of_find_node_by_phandle(...) + */ +#define for_each_node_by_phandle(np, len, phandle) \ + for (np = of_find_node_by_phandle(be32_to_cpup(phandle));\ + (len--);\ + np = np->allnext) + extern struct device_node *of_find_node_by_path(const char *path); extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node);
I'm in favour of cutting out the middle-man on this on. I'll do a very quick review, then you should just get it up to the LKML and LAKML.
On 29/06/12 13:59, Rajanikanth H.V wrote:
From: "Rajanikanth H.V" rajanikanth.hv@linaro.org
This patch addes device tree support for battery temperature and fuel guage driver
Spell check.
Signed-off-by: Rajanikanth H.V rajanikanth.hv@linaro.org
.../bindings/power_supply/ab8500/ab8500-btemp.txt | 209 +++++++++++++ .../bindings/power_supply/ab8500/ab8500-fg.txt | 51 +++ arch/arm/boot/dts/db8500.dtsi | 327 ++++++++++++++++++++ drivers/mfd/ab8500-core.c | 16 +- drivers/power/ab8500_btemp.c | 299 +++++++++++++++++- drivers/power/ab8500_fg.c | 58 +++- include/linux/mfd/abx500.h | 17 +- include/linux/of.h | 33 ++ 8 files changed, 966 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt
Consider breaking this down into multiple patches. Remembering to keep them orthogonal in case of a future revert.
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt new file mode 100644 index 0000000..9908934 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt @@ -0,0 +1,209 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC)
- battery temperature monitor:
+* Required properties: +- compatible: "stericsson,ab8500-btemp"
+* Sub-node: +- ab8500_bm_data:
+example:
- ab8500-btemp {
compatible = "stericsson,ab8500-btemp";
...
...
bat = <&ab8500_bm_data>;
- };
+ab8500_bm_data:
- Contain the battery management/monitor node with the following
- information to support different battery types.
+{
- temp_under under this temp, charging is stopped
- temp_low between this temp and temp_under charging is reduced
- temp_high between this temp and temp_over charging is reduced
- temp_over over this temp, charging is stopped
- temp_now present battery temperature
- temp_interval_chg temperature measurement interval in s when charging
- temp_interval_nochg temperature measurement interval in s when not charging
- main_safety_tmr_h safety timer for main charger
- usb_safety_tmr_h safety timer for usb charger
- bkup_bat_v voltage which we charge the backup battery with
- bkup_bat_i current which we charge the backup battery with
- no_maintenance indicates that maintenance charging is disabled
- abx500_adc_therm placement of thermistor, batctrl or battemp adc
- chg_unknown_bat flag to enable charging of unknown batteries
- enable_overshoot flag to enable VBAT overshoot control
- auto_trig flag to enable auto adc trigger
- fg_res resistance of FG resistor in 0.1mOhm
- n_btypes number of elements in array bat_type
- batt_id index of the identified battery in array bat_type
- interval_charging charge alg cycle period time when charging (sec)
- interval_not_charging charge alg cycle period time when not charging (sec)
- temp_hysteresis temperature hysteresis
- gnd_lift_resistance Battery ground to phone ground resistance (mOhm)
+} +e.g:
- ab8500_bm_data: bm_data {
temp_under = <3>;
temp_low = <8>;
temp_high = <43>;
temp_over = <48>;
temp_now = <0>;
temp_interval_chg = <20>;
temp_interval_nochg = <120>;
main_safety_tmr_h = <4>;
usb_safety_tmr_h = <4>;
bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */
bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */
no_maintenance = <0>;
chg_unknown_bat = <0>;
enable_overshoot = <0>;
auto_trig = <0>;
adc_therm = <0>;
fg_res = <100>;
batt_id = <0>;
interval_charging = <5>;
interval_not_charging = <120>;
temp_hysteresis = <3>;
gnd_lift_resistance = <34>;
- };
+* subnodes for the node 'ab8500_bm_data':
- maxi : maximization parameters
- cap_levels: capacity in percent for the different capacity levels
- bat_type : table of supported battery types
- chg_params: charger parameters
- fg_params : fuel gauge parameters
+example: +ab8500_bm_data: bm_data {
- ...
- ...
- n_btypes = <3>; /* number of battery types */
- ...
- maxi = <&ab8500_bm_data_maxim_parameters>;
- cap_levels = <&ab8500_bm_data_cap_levels>;
- bat_type = <&ab8500_battery_type_0 &ab8500_battery_type_1 &ab8500_battery_type_2>;
- chg_params = <&ab8500_bm_data_charger_parameters>;
- fg_params = <&ab8500_bm_data_fuel_guage_parameters>;
+};
+bx500_battery_type:
- prepare battery type information from individual battery specification as:
- {
name : battery technology
resis_high : battery upper resistance limit
resis_low : battery lower resistance limit
charge_full_design : Maximum battery capacity in mAh
nominal_voltage : Nominal voltage of the battery in mV
termination_vol : max voltage upto which battery can be charged
termination_curr : battery charging termination current in mA
recharge_vol : battery voltage limit that will trigger a new
full charging cycle in the case where maintenance
charging has been disabled
normal_cur_lvl : charger current in normal state in mA
normal_vol_lvl : charger voltage in normal state in mV
maint_a_cur_lvl : charger current in maintenance A state in mA
maint_a_vol_lvl : charger voltage in maintenance A state in mV
maint_a_chg_timer_h : charge time in maintenance A state
maint_b_cur_lvl : charger current in maintenance B state in mA
maint_b_vol_lvl : charger voltage in maintenance B state in mV
maint_b_chg_timer_h : charge time in maintenance B state
low_high_cur_lvl : charger current in temp low/high state in mA
low_high_vol_lvl : charger voltage in temp low/high state in mV'
battery_resistance : battery inner resistance in mOhm.
n_r_t_tbl_elements : number of elements in r_to_t_tbl
r_to_t_tbl : table containing resistance to temp points
n_v_cap_tbl_elements: number of elements in v_to_cap_tbl
v_to_cap_tbl : Voltage to capacity (in %) table
n_batres_tbl_elements: number of elements in the batres_tbl
batres_tbl : battery internal resistance vs temperature table
- }
- Note:
Selected battery shall adhere to the specification provided in:
http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf
+-example:
- ab8500_battery_type_1: ab8500_battery_therm_on_batctrl {
bat_name = <3>;
resis_high = <53407>;
resis_low = <12500>;
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>;
battery_resistance = <300>;
n_temp_tbl_elements = <15>;
r_to_t_tbl - defines one point in a temp to res curve. To be used
in battery packs that combines the identification resistor
with a NTC resistor.
r_to_t_tbl = <
0xfffffffb 53407 /* -5 */
0 48594 'battery pack temperature in Celcius' 'NTC resistor net total resistance'
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>;
n_v_cap_tbl_elements = <20>;
v_to_cap_tbl = < /* Table for translating voltage to capacity */
4171 100 'Voltage in mV' 'Capacity in percent'
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>;
n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */
batres_tbl = < /* defines one point in a temp vs battery internal resistance curve. */
40 120 'battery pack temperature in Celcius' 'battery internal reistance in mOhm'
30 135
20 165
10 230
00 325
0xfffffff6 445 /* -10 */
0xffffffec 595>; /* -20 */
- };
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt new file mode 100644 index 0000000..5e84852 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt @@ -0,0 +1,51 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC)
- fuel guage:
+* Required properties: +- compatible: "stericsson,ab8500-fg"
+* Sub-node: +- ab8500_bm_data:
+example:
- ab8500-btemp {
compatible = "stericsson,ab8500-fg";
...
...
bat = <&ab8500_bm_data>;
- };
+Refer:
- Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt for
- information on 'ab8500_bm_data'
+* subnode for the node 'ab8500_bm_data':
- fg_params : fuel gauge parameters
+example:
+ab8500_bm_data: bm_data {
- ...
- ...
- ...
- fg_params = <&ab8500_bm_data_fuel_guage_parameters>;
+}
- /* Fuel gauge algorithm parameters, in seconds */
- ab8500_bm_data_fuel_guage_parameters: bm_data_fuel_guage_parameters {
recovery_sleep_timer = <10>; /* Time between measurements while recovering */
recovery_total_time = <100>; /* Total recovery time */
init_timer = <1>; /* Measurement interval during startup */
init_discard_time = <5>; /* Time we discard voltage measurement at startup */
init_total_time = <40>; /* Total init time during startup */
high_curr_time = <60>; /* Time current has to be high to go to recovery */
accu_charging = <30>; /* FG accumulation time while charging */
accu_high_curr = <30>; /* FG accumulation time in high current mode */
high_curr_threshold = <50>; /* High current threshold, in mA */
lowbat_threshold = <3100>;/* Low battery threshold, in mV */
battok_falling_th_sel0 = <2860>;/* Over battery threshold, in mV */
battok_raising_th_sel1 = <2860>;/* Threshold in mV for battOk signal sel0 Resolution in 50 mV step. */
user_cap_limit = <15>; /* Threshold in mV for battOk signal sel1 Resolution in 50 mV step. */
maint_thres = <97>; /* Capacity reported from user must be within this limit to be considered as sane, in percentage points.
- }; * This is the threshold where we stop reporting battery full while in maintenance, in per cent
It looks like you've just copy and pasted lots of code into the documentation and commented on it, which isn't really documentation at all is it? Use the same layout as all the other docs in similar directories.
All vendor specific properties should have the vendor's name perpended e.g. stericsson,maint-thres. Also property names should contain '-', not '_'. */
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi index 26f895f..6f3b5df 100644 --- a/arch/arm/boot/dts/db8500.dtsi +++ b/arch/arm/boot/dts/db8500.dtsi @@ -330,6 +330,333 @@ vddadc-supply = <&ab8500_ldo_tvout_reg>; };
ab8500-fg {
compatible = "stericsson,ab8500-fg";
interrupts = <24 0x4
8 0x4
28 0x4
27 0x4
26 0x4>;
interrupt-names = "NCONV_ACCU",
"BATT_OVV",
"LOW_BAT_F",
"CC_INT_CALIB",
"CCEOC";
Formatting (throughout).
supplied_to = "ab8500_chargalg", "ab8500_usb";
num_supplicants = <2>;
bat = <&ab8500_bm_data>;
};
ab8500-btemp {
compatible = "stericsson,ab8500-btemp";
interrupts = <20 0x04
80 0x04
81 0x04
82 0x04
83 0x04>;
interrupt-names = "BAT_CTRL_INDB",
"BTEMP_LOW",
"BTEMP_HIGH",
"BTEMP_LOW_MEDIUM",
"BTEMP_MEDIUM_HIGH";
supplied_to = "ab8500_chargalg", "ab8500_fg";
num_supplicants = <2>;
bat = <&ab8500_bm_data>;
};
ab8500_battery_type_0: ab8500_battery_unknown {
bat_name = <0>;
resis_high = <0>;
resis_low = <0>;
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>;
battery_resistance = <300>;
n_temp_tbl_elements = <15>;
r_to_t_tbl = <
0xfffffffb 214834 /* -5 */
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>;
n_v_cap_tbl_elements = <24>;
v_to_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>;
n_batres_tbl_elements = <7>;
batres_tbl = <
40 120
30 135
20 165
10 230
00 325
0xfffffff6 445 /* -10 */
0xffffffec 595>; /* -20 */
};
ab8500_battery_type_1: ab8500_battery_therm_on_batctrl {
bat_name = <3>;
resis_high = <53407>;
resis_low = <12500>;
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>;
battery_resistance = <300>;
n_temp_tbl_elements = <15>;
r_to_t_tbl = <
0xfffffffb 53407 /* -5 */
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>;
n_v_cap_tbl_elements = <20>;
v_to_cap_tbl = <
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>;
n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */
batres_tbl = <
40 120
30 135
20 165
10 230
00 325
0xfffffff6 445 /* -10 */
0xffffffec 595>; /* -20 */
};
ab8500_battery_type_2: ab8500_battery_therm_on_batctrl_1 {
bat_name = <3>;
resis_high = <165418>;
resis_low = <82869>;
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>;
battery_resistance = <300>;
n_temp_tbl_elements = <15>;
r_to_t_tbl = <
0xfffffffb 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>;
n_v_cap_tbl_elements = <20>;
v_to_cap_tbl = <
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>;
n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */
batres_tbl = <
40 120
30 135
20 165
10 230
00 325
0xfffffff6 445 /* -10 */
0xffffffec 595>; /* -20 */
};
ab8500_bm_data_cap_levels: bm_data_cap_levels {
critical = <2>;
low = <10>;
normal = <70>;
high = <95>;
full = <100>;
};
ab8500_bm_data_maxim_parameters: bm_data_maxim_parameters {
ena_maxi = <1>;
chg_curr = <910>;
wait_cycles = <10>;
charger_curr_step = <100>;
};
ab8500_bm_data_charger_parameters: bm_data_charger_parameters {
usb_volt_max = <5500>;
usb_curr_max = <1500>;
ac_volt_max = <7500>;
ac_curr_max = <1500>;
};
ab8500_bm_data_fuel_guage_parameters: bm_data_fuel_guage_parameters {
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>;
};
ab8500_bm_data: bm_data {
temp_under = <3>;
temp_low = <8>;
temp_high = <43>;
temp_over = <48>;
temp_now = <0>;
temp_interval_chg = <20>;
temp_interval_nochg = <120>;
main_safety_tmr_h = <4>;
usb_safety_tmr_h = <4>;
bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */
bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */
no_maintenance = <0>; /* CONFIG_AB8500_9100_LI_ION_BATTERY not considered */
chg_unknown_bat = <0>; /* CONFIG_AB8500_9100_LI_ION_BATTERY not considered */
enable_overshoot = <0>;
auto_trig = <0>;
adc_therm = <0>;
fg_res = <100>;
n_btypes = <3>;
batt_id = <0>;
interval_charging = <5>;
interval_not_charging = <120>;
temp_hysteresis = <3>;
gnd_lift_resistance = <34>;
maxi = <&ab8500_bm_data_maxim_parameters>;
cap_levels = <&ab8500_bm_data_cap_levels>;
bat_type = <&ab8500_battery_type_0 &ab8500_battery_type_1 &ab8500_battery_type_2>;
chg_params = <&ab8500_bm_data_charger_parameters>;
fg_params = <&ab8500_bm_data_fuel_guage_parameters>;
};
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
ab8500-usb { compatible = "stericsson,ab8500-usb"; interrupts = < 90 0x4
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6d613e8..837488b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1419,15 +1419,15 @@ static int __devinit ab8500_probe(struct platform_device *pdev) ab8500->irq_base); if (ret) goto out_freeirq;
}
if (!no_bm) {
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
ARRAY_SIZE(ab8500_bm_devs), NULL,
ab8500->irq_base);
if (ret)
dev_err(ab8500->dev, "error adding bm devices\n");
if (!no_bm) {
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
ARRAY_SIZE(ab8500_bm_devs), NULL,
ab8500->irq_base);
if (ret)
dev_err(ab8500->dev, "error adding bm devices\n");
}}
Can you push you branch somewhere public, so I can get more context please?
if (is_ab9540(ab8500)) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index bba3cca..04da929 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -20,6 +20,7 @@ #include <linux/power_supply.h> #include <linux/completion.h> #include <linux/workqueue.h> +#include <linux/of.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500-bm.h> @@ -480,7 +481,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { dev_err(di->dev,
"%s gpadc conversion failed,"
"%s gpadc conversion failed, "
Unrelated white space change. Was this intentional?
" using previous value\n", __func__); return prev; }
@@ -960,15 +961,249 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev) return 0; }
+int populate_abx8500_bm_data(struct device *dev,
struct abx500_bm_data *bm_data,
struct device_node *np)
+{
- int i, plen, itbl, ret = 0;
- phandle *temp_phandle;
- struct abx500_battery_type *temp_bat_type;
- struct property *pbat_type;
- struct device_node *np_bat;
- const __be32 *p;
- u32 u;
+#define get_bm_data_property(node_p, prop_name)\
Whoa! Surely not?
Read Documentation/CodingStyle - Chapter 12.
... use an inline function instead.
- be32_to_cpup(of_get_property(node_p, prop_name, NULL));
- temp_phandle = (phandle *)of_get_property(np, "bat", NULL);
- BUG_ON(!temp_phandle);
- np_bat = of_find_node_by_phandle(be32_to_cpup(temp_phandle));
- BUG_ON(!np_bat);
Why have you killed the kernel here instead of returning an error?
- bm_data->temp_under = get_bm_data_property(np_bat, "temp_under");
- bm_data->temp_low = get_bm_data_property(np_bat, "temp_low");
- bm_data->temp_high = get_bm_data_property(np_bat, "temp_high");
- bm_data->temp_over = get_bm_data_property(np_bat, "temp_over");
- bm_data->temp_now = get_bm_data_property(np_bat, "temp_now");
- bm_data->temp_interval_chg =
get_bm_data_property(np_bat, "temp_interval_chg");
- bm_data->temp_interval_nochg =
get_bm_data_property(np_bat, "temp_interval_nochg");
- bm_data->main_safety_tmr_h =
get_bm_data_property(np_bat, "main_safety_tmr_h");
- bm_data->usb_safety_tmr_h =
get_bm_data_property(np_bat, "usb_safety_tmr_h");
- bm_data->bkup_bat_v =
get_bm_data_property(np_bat, "bkup_bat_v");
- bm_data->bkup_bat_i =
get_bm_data_property(np_bat, "bkup_bat_i");
- bm_data->no_maintenance =
get_bm_data_property(np_bat, "no_maintenance");
- bm_data->chg_unknown_bat =
get_bm_data_property(np_bat, "chg_unknown_bat");
- bm_data->enable_overshoot =
get_bm_data_property(np_bat, "enable_overshoot");
- bm_data->auto_trig =
get_bm_data_property(np_bat, "auto_trig");
- bm_data->adc_therm =
get_bm_data_property(np_bat, "adc_therm");
- bm_data->fg_res =
get_bm_data_property(np_bat, "fg_res");
- bm_data->n_btypes =
get_bm_data_property(np_bat, "n_btypes");
- bm_data->batt_id =
get_bm_data_property(np_bat, "batt_id");
- bm_data->interval_charging =
get_bm_data_property(np_bat, "interval_charging");
- bm_data->interval_not_charging =
get_bm_data_property(np_bat, "interval_not_charging");
- bm_data->temp_hysteresis =
get_bm_data_property(np_bat, "temp_hysteresis");
- bm_data->gnd_lift_resistance =
get_bm_data_property(np_bat, "gnd_lift_resistance");
- temp_phandle = (phandle *)of_get_property(np_bat, "bat_type", &plen);
Read Documentation/CodingStyle - Chapter 4.
- if (temp_phandle == NULL) {
dev_warn(dev, "battery type not found\n");
return -EINVAL;
- }
- plen = plen/sizeof(u32);
- if (bm_data->n_btypes != plen) {
dev_crit(dev, "Invalid number of battery types\n");
return -EINVAL;
- }
- bm_data->bat_type =
kzalloc(plen * sizeof(struct abx500_battery_type), GFP_KERNEL);
- if (bm_data->bat_type == NULL) {
dev_crit(dev, "no mem for bm_data->bat_type\n");
return -ENOMEM;
- }
- of_node_put(np_bat);
- /*
* traverse 'plen' times in 'allnext' for battery types and
* fillup bm_data->bat_type
*/
- i = 0;
- for_each_node_by_phandle(np_bat, plen, temp_phandle)
- {
temp_bat_type = (struct abx500_battery_type *)
(bm_data->bat_type + i++);
temp_bat_type->name =
get_bm_data_property(np_bat, "bat_name");
Random formatting (throughout)
temp_bat_type->resis_high =
get_bm_data_property(np_bat, "resis_high");
temp_bat_type->resis_low =
get_bm_data_property(np_bat, "resis_low");
temp_bat_type->charge_full_design =
get_bm_data_property(np_bat, "charge_full_design");
temp_bat_type->nominal_voltage =
get_bm_data_property(np_bat, "nominal_voltage");
temp_bat_type->termination_vol =
get_bm_data_property(np_bat, "termination_vol");
temp_bat_type->termination_curr =
get_bm_data_property(np_bat, "termination_curr");
temp_bat_type->recharge_vol =
get_bm_data_property(np_bat, "recharge_vol");
temp_bat_type->normal_cur_lvl =
get_bm_data_property(np_bat, "normal_cur_lvl");
temp_bat_type->normal_vol_lvl =
get_bm_data_property(np_bat, "normal_vol_lvl");
temp_bat_type->maint_a_cur_lvl =
get_bm_data_property(np_bat, "maint_a_cur_lvl");
temp_bat_type->maint_a_vol_lvl =
get_bm_data_property(np_bat, "maint_a_vol_lvl");
temp_bat_type->maint_a_chg_timer_h =
get_bm_data_property(np_bat, "maint_a_chg_timer_h");
temp_bat_type->maint_b_cur_lvl =
get_bm_data_property(np_bat, "maint_b_cur_lvl");
temp_bat_type->maint_b_vol_lvl =
get_bm_data_property(np_bat, "maint_b_vol_lvl");
temp_bat_type->maint_b_chg_timer_h =
get_bm_data_property(np_bat, "maint_b_chg_timer_h");
temp_bat_type->low_high_cur_lvl =
get_bm_data_property(np_bat, "low_high_cur_lvl");
temp_bat_type->low_high_vol_lvl =
get_bm_data_property(np_bat, "low_high_vol_lvl");
temp_bat_type->battery_resistance =
get_bm_data_property(np_bat, "battery_resistance");
temp_bat_type->n_temp_tbl_elements =
get_bm_data_property(np_bat, "n_temp_tbl_elements");
temp_bat_type->r_to_t_tbl = (struct abx500_res_to_temp *)
kzalloc(sizeof(struct abx500_res_to_temp) *
temp_bat_type->n_temp_tbl_elements, GFP_KERNEL);
if (temp_bat_type->r_to_t_tbl == NULL) {
dev_crit(dev, "no mem for r_to_t_tbl\n");
kfree(bm_data->bat_type);
return -ENOMEM;
}
itbl = 0;
of_property_for_each_u32(np_bat, "r_to_t_tbl", pbat_type, p, u)
*((int *)(temp_bat_type->r_to_t_tbl) + itbl++) = (int)u;
Eh!? Does this even compile?
It's also pretty ugly and unreadable.
temp_bat_type->n_v_cap_tbl_elements =
get_bm_data_property(np_bat, "n_v_cap_tbl_elements");
temp_bat_type->v_to_cap_tbl = (struct abx500_v_to_cap *)
kzalloc(sizeof(struct abx500_v_to_cap) *
temp_bat_type->n_v_cap_tbl_elements, GFP_KERNEL);
if (temp_bat_type->v_to_cap_tbl == NULL) {
ret = -ENOMEM;
dev_crit(dev, "no mem for v_to_cap_tbl\n");
goto out_free_mem1;
}
itbl = 0;
of_property_for_each_u32(np_bat,
"v_to_cap_tbl", pbat_type, p, u)
*((int *)(temp_bat_type->v_to_cap_tbl) + itbl++) =
(int)u;
And again. Am I missing something?
temp_bat_type->n_batres_tbl_elements =
get_bm_data_property(np_bat, "n_batres_tbl_elements");
temp_bat_type->batres_tbl = (struct batres_vs_temp *)
Is this (another other like it) cast nessersary?
kzalloc(sizeof(struct batres_vs_temp) *
temp_bat_type->n_temp_tbl_elements, GFP_KERNEL);
if (temp_bat_type->batres_tbl == NULL) {
ret = -ENOMEM;
dev_crit(dev, "no mem for batres_tbl\n");
goto out_free_mem2;
}
itbl = 0;
of_property_for_each_u32(np_bat, "batres_tbl", pbat_type, p, u)
*((int *)(temp_bat_type->batres_tbl) + itbl++) = (int)u;
- }
- of_node_put(np_bat);
- bm_data->chg_params = (struct abx500_bm_charger_parameters *)
kzalloc(sizeof(struct abx500_bm_charger_parameters),
GFP_KERNEL);
- if (bm_data->chg_params == NULL) {
dev_crit(dev, "Failed to alloc memory for chg_params\n");
ret = -ENOMEM;
goto out_free_mem3;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "chg_params", pbat_type, p, u)
*((int *)(bm_data->chg_params) + itbl++) = (int)u;
- bm_data->fg_params = (struct abx500_fg_parameters *)
kzalloc(sizeof(struct abx500_fg_parameters), GFP_KERNEL);
- if (bm_data->fg_params == NULL) {
dev_crit(dev, "Failed to alloc memory for fg_params\n");
ret = -ENOMEM;
goto out_free_mem4;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "fg_params", pbat_type, p, u)
*((int *)(bm_data->fg_params) + itbl++) = (int)u;
There seems like an awful lot of code duplication going on here.
- return ret;
+out_free_mem1:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- return ret;
+out_free_mem2:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- return ret;
+out_free_mem3:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- kfree(temp_bat_type->batres_tbl);
- return ret;
+out_free_mem4:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- kfree(temp_bat_type->batres_tbl);
- kfree(bm_data->chg_params);
- return ret;
+} +EXPORT_SYMBOL_GPL(populate_abx8500_bm_data);
- static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val;
- struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
- struct device_node *np = pdev->dev.of_node;
No, it's meant to work with _both_ platform and Device Tree registation.
struct ab8500_btemp *di;
- const unsigned int *btemp_p_val;
- const char *pvalue = NULL;
value is not a good variable name.
- if (!plat_data) {
dev_err(&pdev->dev, "No platform data\n");
- if (!np) {
dev_err(&pdev->dev, "No platform data or DT found\n");
How do you know there is no platform data found? You haven't even looked.
return -EINVAL;
}
@@ -982,20 +1217,46 @@ 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;
- if (!di->pdata) {
dev_err(di->dev, "no btemp platform data supplied\n");
ret = -EINVAL;
goto free_device_info;
- btemp_p_val = of_get_property(np, "num_supplicants", NULL);
- BUG_ON(!btemp_p_val);
DEAD!
- di->pdata =
kzalloc(sizeof(struct abx500_btemp_platform_data), GFP_KERNEL);
- if (di->pdata == NULL) {
kfree(di);
}return -ENOMEM;
- /* get battery specific platform data */
- di->bat = plat_data->battery;
- di->pdata->num_supplicants = be32_to_cpup(btemp_p_val);
- di->pdata->supplied_to =
kzalloc(di->pdata->num_supplicants *
sizeof(const char *), GFP_KERNEL);
- if (di->pdata->supplied_to == NULL) {
kfree(di);
kfree(di->pdata);
return -ENOMEM;
- }
- for (val = 0; val < di->pdata->num_supplicants; ++val)
if (of_property_read_string_index
(np, "supplied_to", val, &pvalue) == 0)
*(di->pdata->supplied_to + val) = (char *)pvalue;
else {
dev_warn(di->dev, "insufficient number of supplied_to data found\n");
goto free_device_info;
}
- dev_dbg(di->dev, "getting DT battery information\n");
- di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL); if (!di->bat) {
dev_err(di->dev, "no battery platform data supplied\n");
ret = -EINVAL;
kfree(di);
kfree(di->pdata);
return -ENOMEM;
}
if (populate_abx8500_bm_data(di->dev, di->bat, np) < 0) {
dev_warn(di->dev, "Failed to bind DT\n");
goto free_device_info; }
dev_dbg(di->dev, "getting DT battery information...done\n");
/* BTEMP supply */ di->btemp_psy.name = "ab8500_btemp";
@@ -1008,7 +1269,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di->btemp_psy.external_power_changed = ab8500_btemp_external_power_changed;
Unrelated whitespace change.
/* Create a work queue for the btemp */ di->btemp_wq = create_singlethread_workqueue("ab8500_btemp_wq"); @@ -1016,7 +1276,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) dev_err(di->dev, "failed to create work queue\n"); goto free_device_info; }
And again.
/* Init work for measuring temperature periodically */ INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work, ab8500_btemp_periodic_work); @@ -1090,14 +1349,23 @@ free_irq: irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); free_irq(irq, di); }
.
free_btemp_wq: destroy_workqueue(di->btemp_wq);
.
free_device_info: kfree(di);
kfree(di->pdata);
kfree(di->bat);
return ret; }
+static const struct of_device_id ab8500_btemp_match[] = {
- {.compatible = "stericsson,ab8500-btemp",},
- {},
+};
- static struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, .remove = __devexit_p(ab8500_btemp_remove),
@@ -1106,6 +1374,7 @@ static struct platform_driver ab8500_btemp_driver = { .driver = { .name = "ab8500-btemp", .owner = THIS_MODULE,
}, };.of_match_table = ab8500_btemp_match,
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index bf02225..1d0e32a 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -31,6 +31,7 @@ #include <linux/mfd/abx500.h> #include <linux/time.h> #include <linux/completion.h> +#include <linux/of.h>
#define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -2446,11 +2447,12 @@ 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;
As above.
- const char *fg_p_val;
- struct device_node *np = pdev->dev.of_node; struct ab8500_fg *di;
- if (!plat_data) {
dev_err(&pdev->dev, "No platform data\n");
- if (!np) {
return -EINVAL; }dev_err(&pdev->dev, "No DT node for platform data available\n");
@@ -2464,20 +2466,42 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->dev = &pdev->dev; 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;
di->pdata =
kzalloc(sizeof(struct abx500_btemp_platform_data), GFP_KERNEL);
if (di->pdata == NULL) {
kfree(di);
return -ENOMEM;
}
di->pdata->num_supplicants =
be32_to_cpup(of_get_property(np, "num_supplicants", NULL));
di->pdata->supplied_to =
kzalloc(di->pdata->num_supplicants *
sizeof(const char *), GFP_KERNEL);
if (di->pdata->supplied_to == NULL) {
kfree(di);
kfree(di->pdata);
return -ENOMEM;
}
for (i = 0; i < di->pdata->num_supplicants; ++i)
if (of_property_read_string_index
(np, "supplied_to", i, &fg_p_val) == 0)
*(di->pdata->supplied_to + i) = (char *)fg_p_val;
else {
dev_warn(di->dev, "insufficient number of supplied_to data found\n");
goto free_device_info;
}
/* get battery specific platform data */
- di->bat = plat_data->battery;
- di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL); if (!di->bat) {
dev_err(di->dev, "no battery platform data supplied\n");
ret = -EINVAL;
kfree(di);
kfree(di->pdata);
return -ENOMEM;
- }
- ret = populate_abx8500_bm_data(di->dev, di->bat, np);
- if (ret < 0) {
goto free_device_info; }dev_warn(di->dev, "Failed to bind DT\n");
@@ -2607,10 +2631,15 @@ free_inst_curr_wq: destroy_workqueue(di->fg_wq); free_device_info: kfree(di);
kfree(di->pdata);
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 +2648,7 @@ static struct platform_driver ab8500_fg_driver = { .driver = { .name = "ab8500-fg", .owner = THIS_MODULE,
}, };.of_match_table = ab8500_fg_match,
@@ -2632,7 +2662,7 @@ static void __exit ab8500_fg_exit(void) platform_driver_unregister(&ab8500_fg_driver); }
-subsys_initcall_sync(ab8500_fg_init); +subsys_initcall(ab8500_fg_init);
What does this do?
module_exit(ab8500_fg_exit);
MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 1318ca6..9dbc4d1 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -113,13 +113,13 @@ struct ab3100 {
- struct ab3100_platform_data
- Data supplied to initialize board connections to the AB3100
- @reg_constraints: regulator constraints for target board
the order of these constraints are: LDO A, C, D, E,
F, G, H, K, EXT and BUCK.
the order of these constraints are: LDO A, C, D, E,
F, G, H, K, EXT and BUCK.
- @reg_initvals: initial values for the regulator registers
plus two sleep settings for LDO E and the BUCK converter.
exactly AB3100_NUM_REGULATORS+2 values must be sent in.
Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
BUCK sleep, LDO D. (LDO D need to be initialized last.)
plus two sleep settings for LDO E and the BUCK converter.
exactly AB3100_NUM_REGULATORS+2 values must be sent in.
Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
*/ struct ab3100_platform_data {
BUCK sleep, LDO D. (LDO D need to be initialized last.)
- @external_voltage: voltage level of the external regulator.
@@ -131,7 +131,7 @@ struct ab3100_platform_data { int ab3100_event_register(struct ab3100 *ab3100, struct notifier_block *nb); int ab3100_event_unregister(struct ab3100 *ab3100,
struct notifier_block *nb);
struct notifier_block *nb);
Was this intentional?
/**
- struct abx500_init_setting
@@ -387,6 +387,9 @@ struct abx500_bm_data { const struct abx500_fg_parameters *fg_params; };
+int populate_abx8500_bm_data(struct device *, struct abx500_bm_data *,
struct device_node *);
- struct abx500_chargalg_platform_data { char **supplied_to; size_t num_supplicants;
diff --git a/include/linux/of.h b/include/linux/of.h index 2ec1083..61b4ac8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -183,6 +183,39 @@ extern struct device_node *of_find_matching_node(struct device_node *from, #define for_each_matching_node(dn, matches) \ for (dn = of_find_matching_node(NULL, matches); dn; \ dn = of_find_matching_node(dn, matches))
+/*
- syntax: for_each_node_by_phandle(np, len, phandle);
- @np : pointer to node to start in the list
- @len: number of nodes expected
- @phandle: current phandle which is obtained through of_get_property(...)
- e.g:
node_a: <> {
...
};
node_b: <> {
...
};
node_c: <> {
...
};
node_x: <> {
p1 = <v1>;
p2 = <v2>;
n_nodes = <3>
p3 = <&node_a &node_b &node_c ....>;
};
- Note:
- invoke of_node_put(...) as it uses of_find_node_by_phandle(...)
- */
+#define for_each_node_by_phandle(np, len, phandle) \
- for (np = of_find_node_by_phandle(be32_to_cpup(phandle));\
(len--);\
np = np->allnext)
Seperate patch. To be submitted first.
extern struct device_node *of_find_node_by_path(const char *path); extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node);
Did this pass checkpatch.pl?
Kind regards, Lee
thanks for your review comments, i will post it on public branch, how about a review from abx500 bm data structure perspective ref: arch/arm/mach-ux500/board-mop500-bm.c
Thanks, Rajanikanth On 29 June 2012 21:17, Lee Jones lee.jones@linaro.org wrote:
I'm in favour of cutting out the middle-man on this on. I'll do a very quick review, then you should just get it up to the LKML and LAKML.
On 29/06/12 13:59, Rajanikanth H.V wrote:
From: "Rajanikanth H.V" rajanikanth.hv@linaro.org
This patch addes device tree support for battery temperature and fuel guage driver
Spell check.
Signed-off-by: Rajanikanth H.V rajanikanth.hv@linaro.org
.../bindings/power_supply/ab8500/ab8500-btemp.txt | 209 +++++++++++++ .../bindings/power_supply/ab8500/ab8500-fg.txt | 51 +++ arch/arm/boot/dts/db8500.dtsi | 327 ++++++++++++++++++++ drivers/mfd/ab8500-core.c | 16 +- drivers/power/ab8500_btemp.c | 299 +++++++++++++++++- drivers/power/ab8500_fg.c | 58 +++- include/linux/mfd/abx500.h | 17 +- include/linux/of.h | 33 ++ 8 files changed, 966 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt create mode 100644 Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt
Consider breaking this down into multiple patches. Remembering to keep them orthogonal in case of a future revert.
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt new file mode 100644 index 0000000..9908934 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt @@ -0,0 +1,209 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC)
- battery temperature monitor:
+* Required properties: +- compatible: "stericsson,ab8500-btemp"
+* Sub-node: +- ab8500_bm_data:
+example:
- ab8500-btemp {
- compatible = "stericsson,ab8500-btemp";
- ...
- ...
- bat = <&ab8500_bm_data>;
- };
+ab8500_bm_data:
- Contain the battery management/monitor node with the following
- information to support different battery types.
+{
- temp_under under this temp, charging is
stopped
- temp_low between this temp and temp_under
charging is reduced
- temp_high between this temp and temp_over
charging is reduced
- temp_over over this temp, charging is
stopped
- temp_now present battery temperature
- temp_interval_chg temperature measurement interval in s when
charging
- temp_interval_nochg temperature measurement interval in s when
not charging
- main_safety_tmr_h safety timer for main charger
- usb_safety_tmr_h safety timer for usb charger
- bkup_bat_v voltage which we charge the backup
battery with
- bkup_bat_i current which we charge the backup
battery with
- no_maintenance indicates that maintenance charging is
disabled
- abx500_adc_therm placement of thermistor, batctrl or
battemp adc
- chg_unknown_bat flag to enable charging of unknown
batteries
- enable_overshoot flag to enable VBAT overshoot control
- auto_trig flag to enable auto adc trigger
- fg_res resistance of FG resistor in
0.1mOhm
- n_btypes number of elements in array
bat_type
- batt_id index of the identified battery in
array bat_type
- interval_charging charge alg cycle period time when charging
(sec)
- interval_not_charging charge alg cycle period time when not
charging (sec)
- temp_hysteresis temperature hysteresis
- gnd_lift_resistance Battery ground to phone ground resistance
(mOhm) +} +e.g:
- ab8500_bm_data: bm_data {
- temp_under = <3>;
- temp_low = <8>;
- temp_high = <43>;
- temp_over = <48>;
- temp_now = <0>;
- temp_interval_chg = <20>;
- temp_interval_nochg = <120>;
- main_safety_tmr_h = <4>;
- usb_safety_tmr_h = <4>;
- bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */
- bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */
- no_maintenance = <0>;
- chg_unknown_bat = <0>;
- enable_overshoot = <0>;
- auto_trig = <0>;
- adc_therm = <0>;
- fg_res = <100>;
- batt_id = <0>;
- interval_charging = <5>;
- interval_not_charging = <120>;
- temp_hysteresis = <3>;
- gnd_lift_resistance = <34>;
- };
+* subnodes for the node 'ab8500_bm_data':
- - maxi : maximization parameters
- - cap_levels: capacity in percent for the different capacity
levels
- - bat_type : table of supported battery types
- - chg_params: charger parameters
- - fg_params : fuel gauge parameters
+example: +ab8500_bm_data: bm_data {
- ...
- ...
- n_btypes = <3>; /* number of battery types */
- ...
- maxi = <&ab8500_bm_data_maxim_parameters>;
- cap_levels = <&ab8500_bm_data_cap_levels>;
- bat_type = <&ab8500_battery_type_0 &ab8500_battery_type_1
&ab8500_battery_type_2>;
- chg_params = <&ab8500_bm_data_charger_parameters>;
- fg_params = <&ab8500_bm_data_fuel_guage_parameters>;
+};
+bx500_battery_type:
- prepare battery type information from individual battery
specification as:
- {
- name : battery technology
- resis_high : battery upper resistance
limit
- resis_low : battery lower resistance
limit
- charge_full_design : Maximum battery capacity in mAh
- nominal_voltage : Nominal voltage of the battery
in mV
- termination_vol : max voltage upto which battery
can be charged
- termination_curr : battery charging termination
current in mA
- recharge_vol : battery voltage limit that will
trigger a new
- full
charging cycle in the case where maintenance
- charging
has been disabled
- normal_cur_lvl : charger current in normal state
in mA
- normal_vol_lvl : charger voltage in normal state
in mV
- maint_a_cur_lvl : charger current in maintenance A
state in mA
- maint_a_vol_lvl : charger voltage in maintenance A
state in mV
- maint_a_chg_timer_h : charge time in maintenance A
state
- maint_b_cur_lvl : charger current in maintenance B
state in mA
- maint_b_vol_lvl : charger voltage in maintenance B
state in mV
- maint_b_chg_timer_h : charge time in maintenance B
state
- low_high_cur_lvl : charger current in temp low/high
state in mA
- low_high_vol_lvl : charger voltage in temp low/high
state in mV'
- battery_resistance : battery inner resistance in
mOhm.
- n_r_t_tbl_elements : number of elements in r_to_t_tbl
- r_to_t_tbl : table containing
resistance to temp points
- n_v_cap_tbl_elements: number of elements in v_to_cap_tbl
- v_to_cap_tbl : Voltage to capacity (in %) table
- n_batres_tbl_elements: number of elements in the
batres_tbl
- batres_tbl : battery internal
resistance vs temperature table
- }
- Note:
- Selected battery shall adhere to the specification
provided in:
http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf
+-example:
- ab8500_battery_type_1: ab8500_battery_therm_on_batctrl {
- bat_name = <3>;
- resis_high = <53407>;
- resis_low = <12500>;
- 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>;
- battery_resistance = <300>;
- n_temp_tbl_elements = <15>;
- r_to_t_tbl - defines one point in a temp to res curve. To
be used
- in battery packs that combines the identification
resistor
- with a NTC resistor.
- r_to_t_tbl = <
- 0xfffffffb 53407 /* -5 */
- 0 48594 'battery pack temperature in Celcius' 'NTC
resistor net total resistance'
- 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>;
- n_v_cap_tbl_elements = <20>;
- v_to_cap_tbl = < /* Table for translating voltage to
capacity */
- 4171 100 'Voltage in mV' 'Capacity in percent'
- 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>;
- n_batres_tbl_elements = <7>; /* ARRAY_SIZE(batres_tbl), */
- batres_tbl = < /* defines one point in a temp vs battery internal
resistance curve. */
- 40 120 'battery pack temperature in Celcius' 'battery
internal reistance in mOhm'
- 30 135
- 20 165
- 10 230
- 00 325
- 0xfffffff6 445 /* -10 */
- 0xffffffec 595>; /* -20 */
- };
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt new file mode 100644 index 0000000..5e84852 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ab8500/ab8500-fg.txt @@ -0,0 +1,51 @@ +* St-Ericsson AB8500 Power Management Integrated Circuit (PMIC)
- fuel guage:
+* Required properties: +- compatible: "stericsson,ab8500-fg"
+* Sub-node: +- ab8500_bm_data:
+example:
- ab8500-btemp {
- compatible = "stericsson,ab8500-fg";
- ...
- ...
- bat = <&ab8500_bm_data>;
- };
+Refer:
Documentation/devicetree/bindings/power_supply/ab8500/ab8500-btemp.txt for
- information on 'ab8500_bm_data'
+* subnode for the node 'ab8500_bm_data':
- - fg_params : fuel gauge parameters
+example:
+ab8500_bm_data: bm_data {
- ...
- ...
- ...
- fg_params = <&ab8500_bm_data_fuel_guage_parameters>;
+}
- /* Fuel gauge algorithm parameters, in seconds */
- ab8500_bm_data_fuel_guage_parameters:
bm_data_fuel_guage_parameters {
- recovery_sleep_timer = <10>; /* Time between
measurements while recovering */
- recovery_total_time = <100>; /* Total recovery time */
- init_timer = <1>; /* Measurement interval
during startup */
- init_discard_time = <5>; /* Time we discard voltage
measurement at startup */
- init_total_time = <40>; /* Total init time during
startup */
- high_curr_time = <60>; /* Time current has to be
high to go to recovery */
- accu_charging = <30>; /* FG accumulation time
while charging */
- accu_high_curr = <30>; /* FG accumulation time in
high current mode */
- high_curr_threshold = <50>; /* High current threshold,
in mA */
- lowbat_threshold = <3100>;/* Low battery threshold,
in mV */
- battok_falling_th_sel0 = <2860>;/* Over battery threshold,
in mV */
- battok_raising_th_sel1 = <2860>;/* Threshold in mV for
battOk signal sel0 Resolution in 50 mV step. */
- user_cap_limit = <15>; /* Threshold in mV for
battOk signal sel1 Resolution in 50 mV step. */
- maint_thres = <97>; /* Capacity reported from
user must be within this limit to be considered as sane, in percentage points.
- }; * This is the threshold where
we stop reporting battery full while in maintenance, in per cent
It looks like you've just copy and pasted lots of code into the documentation and commented on it, which isn't really documentation at all is it? Use the same layout as all the other docs in similar directories.
All vendor specific properties should have the vendor's name perpended e.g. stericsson,maint-thres. Also property names should contain '-', not '_'. */
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi index 26f895f..6f3b5df 100644 --- a/arch/arm/boot/dts/db8500.dtsi +++ b/arch/arm/boot/dts/db8500.dtsi @@ -330,6 +330,333 @@ vddadc-supply = <&ab8500_ldo_tvout_reg>; };
- ab8500-fg {
- compatible = "stericsson,ab8500-fg";
- interrupts = <24 0x4
- 8 0x4
- 28 0x4
- 27 0x4
- 26 0x4>;
- interrupt-names = "NCONV_ACCU",
"BATT_OVV",
"LOW_BAT_F",
"CC_INT_CALIB",
"CCEOC";
Formatting (throughout).
- supplied_to = "ab8500_chargalg", "ab8500_usb";
- num_supplicants = <2>;
- bat = <&ab8500_bm_data>;
- };
- ab8500-btemp {
- compatible = "stericsson,ab8500-btemp";
- interrupts = <20 0x04
- 80 0x04
- 81 0x04
- 82 0x04
- 83 0x04>;
- interrupt-names = "BAT_CTRL_INDB",
"BTEMP_LOW",
"BTEMP_HIGH",
"BTEMP_LOW_MEDIUM",
"BTEMP_MEDIUM_HIGH";
- supplied_to = "ab8500_chargalg", "ab8500_fg";
- num_supplicants = <2>;
- bat = <&ab8500_bm_data>;
- };
- ab8500_battery_type_0: ab8500_battery_unknown {
- bat_name = <0>;
- resis_high = <0>;
- resis_low = <0>;
- 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>;
- battery_resistance = <300>;
- n_temp_tbl_elements = <15>;
- r_to_t_tbl = <
- 0xfffffffb 214834 /* -5 */
- 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>;
- n_v_cap_tbl_elements = <24>;
- v_to_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>;
- n_batres_tbl_elements = <7>;
- batres_tbl = <
- 40 120
- 30 135
- 20 165
- 10 230
- 00 325
- 0xfffffff6 445 /* -10 */
- 0xffffffec 595>; /* -20 */
- };
- ab8500_battery_type_1: ab8500_battery_therm_on_batctrl {
- bat_name = <3>;
- resis_high = <53407>;
- resis_low = <12500>;
- 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>;
- battery_resistance = <300>;
- n_temp_tbl_elements = <15>;
- r_to_t_tbl = <
- 0xfffffffb 53407 /* -5 */
- 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>;
- n_v_cap_tbl_elements = <20>;
- v_to_cap_tbl = <
- 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>;
- n_batres_tbl_elements = <7>; /*
ARRAY_SIZE(batres_tbl), */
- batres_tbl = <
- 40 120
- 30 135
- 20 165
- 10 230
- 00 325
- 0xfffffff6 445 /* -10 */
- 0xffffffec 595>; /* -20 */
- };
- ab8500_battery_type_2: ab8500_battery_therm_on_batctrl_1
{
- bat_name = <3>;
- resis_high = <165418>;
- resis_low = <82869>;
- 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>;
- battery_resistance = <300>;
- n_temp_tbl_elements = <15>;
- r_to_t_tbl = <
- 0xfffffffb 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>;
- n_v_cap_tbl_elements = <20>;
- v_to_cap_tbl = <
- 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>;
- n_batres_tbl_elements = <7>; /*
ARRAY_SIZE(batres_tbl), */
- batres_tbl = <
- 40 120
- 30 135
- 20 165
- 10 230
- 00 325
- 0xfffffff6 445 /* -10 */
- 0xffffffec 595>; /* -20 */
- };
- ab8500_bm_data_cap_levels: bm_data_cap_levels {
- critical = <2>;
- low = <10>;
- normal = <70>;
- high = <95>;
- full = <100>;
- };
- ab8500_bm_data_maxim_parameters: bm_data_maxim_parameters
{
- ena_maxi = <1>;
- chg_curr = <910>;
- wait_cycles = <10>;
- charger_curr_step = <100>;
- };
- ab8500_bm_data_charger_parameters:
bm_data_charger_parameters {
- usb_volt_max = <5500>;
- usb_curr_max = <1500>;
- ac_volt_max = <7500>;
- ac_curr_max = <1500>;
- };
- ab8500_bm_data_fuel_guage_parameters:
bm_data_fuel_guage_parameters {
- 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>;
- };
- ab8500_bm_data: bm_data {
- temp_under = <3>;
- temp_low = <8>;
- temp_high = <43>;
- temp_over = <48>;
- temp_now = <0>;
- temp_interval_chg = <20>;
- temp_interval_nochg = <120>;
- main_safety_tmr_h = <4>;
- usb_safety_tmr_h = <4>;
- bkup_bat_v = <1>; /* BUP_VCH_SEL_2P6V */
- bkup_bat_i = <4>; /* BUP_ICH_SEL_150UA */
- no_maintenance = <0>; /*
CONFIG_AB8500_9100_LI_ION_BATTERY not considered */
- chg_unknown_bat = <0>; /*
CONFIG_AB8500_9100_LI_ION_BATTERY not considered */
- enable_overshoot = <0>;
- auto_trig = <0>;
- adc_therm = <0>;
- fg_res = <100>;
- n_btypes = <3>;
- batt_id = <0>;
- interval_charging = <5>;
- interval_not_charging = <120>;
- temp_hysteresis = <3>;
- gnd_lift_resistance = <34>;
- maxi =
<&ab8500_bm_data_maxim_parameters>;
- cap_levels = <&ab8500_bm_data_cap_levels>;
- bat_type = <&ab8500_battery_type_0
&ab8500_battery_type_1 &ab8500_battery_type_2>;
- chg_params =
<&ab8500_bm_data_charger_parameters>;
- fg_params =
<&ab8500_bm_data_fuel_guage_parameters>;
- };
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
ab8500-usb { compatible = "stericsson,ab8500-usb"; interrupts = < 90 0x4 diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6d613e8..837488b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1419,15 +1419,15 @@ static int __devinit ab8500_probe(struct platform_device *pdev) ab8500->irq_base); if (ret) goto out_freeirq;
}
if (!no_bm) {
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
ARRAY_SIZE(ab8500_bm_devs), NULL,
ab8500->irq_base);
if (ret)
dev_err(ab8500->dev, "error adding bm devices\n");
- if (!no_bm) {
- /* Add battery management devices */
- ret = mfd_add_devices(ab8500->dev, 0,
ab8500_bm_devs,
- ARRAY_SIZE(ab8500_bm_devs), NULL,
- ab8500->irq_base);
- if (ret)
- dev_err(ab8500->dev, "error adding bm
devices\n");
- }
}
Can you push you branch somewhere public, so I can get more context please?
if (is_ab9540(ab8500)) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index bba3cca..04da929 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -20,6 +20,7 @@ #include <linux/power_supply.h> #include <linux/completion.h> #include <linux/workqueue.h> +#include <linux/of.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500-bm.h> @@ -480,7 +481,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { dev_err(di->dev,
- "%s gpadc conversion failed,"
- "%s gpadc conversion failed, "
Unrelated white space change. Was this intentional?
" using previous value\n", __func__); return prev; } @@ -960,15 +961,249 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev) return 0; }
+int populate_abx8500_bm_data(struct device *dev,
- struct abx500_bm_data *bm_data,
- struct device_node *np)
+{
- int i, plen, itbl, ret = 0;
- phandle *temp_phandle;
- struct abx500_battery_type *temp_bat_type;
- struct property *pbat_type;
- struct device_node *np_bat;
- const __be32 *p;
- u32 u;
+#define get_bm_data_property(node_p, prop_name)\
Whoa! Surely not?
Read Documentation/CodingStyle - Chapter 12.
... use an inline function instead.
- be32_to_cpup(of_get_property(node_p, prop_name, NULL));
- temp_phandle = (phandle *)of_get_property(np, "bat", NULL);
- BUG_ON(!temp_phandle);
- np_bat = of_find_node_by_phandle(be32_to_cpup(temp_phandle));
- BUG_ON(!np_bat);
Why have you killed the kernel here instead of returning an error?
- bm_data->temp_under = get_bm_data_property(np_bat, "temp_under");
- bm_data->temp_low = get_bm_data_property(np_bat, "temp_low");
- bm_data->temp_high = get_bm_data_property(np_bat, "temp_high");
- bm_data->temp_over = get_bm_data_property(np_bat, "temp_over");
- bm_data->temp_now = get_bm_data_property(np_bat, "temp_now");
- bm_data->temp_interval_chg =
- get_bm_data_property(np_bat, "temp_interval_chg");
- bm_data->temp_interval_nochg =
- get_bm_data_property(np_bat, "temp_interval_nochg");
- bm_data->main_safety_tmr_h =
- get_bm_data_property(np_bat, "main_safety_tmr_h");
- bm_data->usb_safety_tmr_h =
- get_bm_data_property(np_bat, "usb_safety_tmr_h");
- bm_data->bkup_bat_v =
- get_bm_data_property(np_bat, "bkup_bat_v");
- bm_data->bkup_bat_i =
- get_bm_data_property(np_bat, "bkup_bat_i");
- bm_data->no_maintenance =
- get_bm_data_property(np_bat, "no_maintenance");
- bm_data->chg_unknown_bat =
- get_bm_data_property(np_bat, "chg_unknown_bat");
- bm_data->enable_overshoot =
- get_bm_data_property(np_bat, "enable_overshoot");
- bm_data->auto_trig =
- get_bm_data_property(np_bat, "auto_trig");
- bm_data->adc_therm =
- get_bm_data_property(np_bat, "adc_therm");
- bm_data->fg_res =
- get_bm_data_property(np_bat, "fg_res");
- bm_data->n_btypes =
- get_bm_data_property(np_bat, "n_btypes");
- bm_data->batt_id =
- get_bm_data_property(np_bat, "batt_id");
- bm_data->interval_charging =
- get_bm_data_property(np_bat, "interval_charging");
- bm_data->interval_not_charging =
- get_bm_data_property(np_bat, "interval_not_charging");
- bm_data->temp_hysteresis =
- get_bm_data_property(np_bat, "temp_hysteresis");
- bm_data->gnd_lift_resistance =
- get_bm_data_property(np_bat, "gnd_lift_resistance");
- temp_phandle = (phandle *)of_get_property(np_bat, "bat_type",
&plen);
Read Documentation/CodingStyle - Chapter 4.
- if (temp_phandle == NULL) {
- dev_warn(dev, "battery type not found\n");
- return -EINVAL;
- }
- plen = plen/sizeof(u32);
- if (bm_data->n_btypes != plen) {
- dev_crit(dev, "Invalid number of battery types\n");
- return -EINVAL;
- }
- bm_data->bat_type =
- kzalloc(plen * sizeof(struct abx500_battery_type),
GFP_KERNEL);
- if (bm_data->bat_type == NULL) {
- dev_crit(dev, "no mem for bm_data->bat_type\n");
- return -ENOMEM;
- }
- of_node_put(np_bat);
- /*
- * traverse 'plen' times in 'allnext' for battery types and
- * fillup bm_data->bat_type
- */
- i = 0;
- for_each_node_by_phandle(np_bat, plen, temp_phandle)
- {
- temp_bat_type = (struct abx500_battery_type *)
- (bm_data->bat_type + i++);
- temp_bat_type->name =
- get_bm_data_property(np_bat, "bat_name");
Random formatting (throughout)
- temp_bat_type->resis_high =
- get_bm_data_property(np_bat, "resis_high");
- temp_bat_type->resis_low =
- get_bm_data_property(np_bat, "resis_low");
- temp_bat_type->charge_full_design =
- get_bm_data_property(np_bat, "charge_full_design");
- temp_bat_type->nominal_voltage =
- get_bm_data_property(np_bat, "nominal_voltage");
- temp_bat_type->termination_vol =
- get_bm_data_property(np_bat, "termination_vol");
- temp_bat_type->termination_curr =
- get_bm_data_property(np_bat, "termination_curr");
- temp_bat_type->recharge_vol =
- get_bm_data_property(np_bat, "recharge_vol");
- temp_bat_type->normal_cur_lvl =
- get_bm_data_property(np_bat, "normal_cur_lvl");
- temp_bat_type->normal_vol_lvl =
- get_bm_data_property(np_bat, "normal_vol_lvl");
- temp_bat_type->maint_a_cur_lvl =
- get_bm_data_property(np_bat, "maint_a_cur_lvl");
- temp_bat_type->maint_a_vol_lvl =
- get_bm_data_property(np_bat, "maint_a_vol_lvl");
- temp_bat_type->maint_a_chg_timer_h =
- get_bm_data_property(np_bat, "maint_a_chg_timer_h");
- temp_bat_type->maint_b_cur_lvl =
- get_bm_data_property(np_bat, "maint_b_cur_lvl");
- temp_bat_type->maint_b_vol_lvl =
- get_bm_data_property(np_bat, "maint_b_vol_lvl");
- temp_bat_type->maint_b_chg_timer_h =
- get_bm_data_property(np_bat, "maint_b_chg_timer_h");
- temp_bat_type->low_high_cur_lvl =
- get_bm_data_property(np_bat, "low_high_cur_lvl");
- temp_bat_type->low_high_vol_lvl =
- get_bm_data_property(np_bat, "low_high_vol_lvl");
- temp_bat_type->battery_resistance =
- get_bm_data_property(np_bat, "battery_resistance");
- temp_bat_type->n_temp_tbl_elements =
- get_bm_data_property(np_bat,
"n_temp_tbl_elements");
- temp_bat_type->r_to_t_tbl = (struct abx500_res_to_temp *)
- kzalloc(sizeof(struct abx500_res_to_temp) *
- temp_bat_type->n_temp_tbl_elements, GFP_KERNEL);
- if (temp_bat_type->r_to_t_tbl == NULL) {
- dev_crit(dev, "no mem for r_to_t_tbl\n");
- kfree(bm_data->bat_type);
- return -ENOMEM;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "r_to_t_tbl", pbat_type,
p, u)
- *((int *)(temp_bat_type->r_to_t_tbl) + itbl++) =
(int)u;
Eh!? Does this even compile?
It's also pretty ugly and unreadable.
- temp_bat_type->n_v_cap_tbl_elements =
- get_bm_data_property(np_bat,
"n_v_cap_tbl_elements");
- temp_bat_type->v_to_cap_tbl = (struct abx500_v_to_cap *)
- kzalloc(sizeof(struct abx500_v_to_cap) *
- temp_bat_type->n_v_cap_tbl_elements, GFP_KERNEL);
- if (temp_bat_type->v_to_cap_tbl == NULL) {
- ret = -ENOMEM;
- dev_crit(dev, "no mem for v_to_cap_tbl\n");
- goto out_free_mem1;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat,
- "v_to_cap_tbl", pbat_type, p, u)
- *((int *)(temp_bat_type->v_to_cap_tbl) + itbl++) =
- (int)u;
And again. Am I missing something?
- temp_bat_type->n_batres_tbl_elements =
- get_bm_data_property(np_bat,
"n_batres_tbl_elements");
- temp_bat_type->batres_tbl = (struct batres_vs_temp *)
Is this (another other like it) cast nessersary?
- kzalloc(sizeof(struct batres_vs_temp) *
- temp_bat_type->n_temp_tbl_elements, GFP_KERNEL);
- if (temp_bat_type->batres_tbl == NULL) {
- ret = -ENOMEM;
- dev_crit(dev, "no mem for batres_tbl\n");
- goto out_free_mem2;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "batres_tbl", pbat_type,
p, u)
- *((int *)(temp_bat_type->batres_tbl) + itbl++) =
(int)u;
- }
- of_node_put(np_bat);
- bm_data->chg_params = (struct abx500_bm_charger_parameters *)
- kzalloc(sizeof(struct abx500_bm_charger_parameters),
- GFP_KERNEL);
- if (bm_data->chg_params == NULL) {
- dev_crit(dev, "Failed to alloc memory for chg_params\n");
- ret = -ENOMEM;
- goto out_free_mem3;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "chg_params", pbat_type, p, u)
- *((int *)(bm_data->chg_params) + itbl++) = (int)u;
- bm_data->fg_params = (struct abx500_fg_parameters *)
- kzalloc(sizeof(struct abx500_fg_parameters), GFP_KERNEL);
- if (bm_data->fg_params == NULL) {
- dev_crit(dev, "Failed to alloc memory for fg_params\n");
- ret = -ENOMEM;
- goto out_free_mem4;
- }
- itbl = 0;
- of_property_for_each_u32(np_bat, "fg_params", pbat_type, p, u)
- *((int *)(bm_data->fg_params) + itbl++) = (int)u;
There seems like an awful lot of code duplication going on here.
- return ret;
+out_free_mem1:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- return ret;
+out_free_mem2:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- return ret;
+out_free_mem3:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- kfree(temp_bat_type->batres_tbl);
- return ret;
+out_free_mem4:
- kfree(bm_data->bat_type);
- kfree(temp_bat_type->r_to_t_tbl);
- kfree(temp_bat_type->v_to_cap_tbl);
- kfree(temp_bat_type->batres_tbl);
- kfree(bm_data->chg_params);
- return ret;
+} +EXPORT_SYMBOL_GPL(populate_abx8500_bm_data);
static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val;
- struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
- struct device_node *np = pdev->dev.of_node;
No, it's meant to work with _both_ platform and Device Tree registation.
struct ab8500_btemp *di;
- const unsigned int *btemp_p_val;
- const char *pvalue = NULL;
value is not a good variable name.
- if (!plat_data) {
- dev_err(&pdev->dev, "No platform data\n");
- if (!np) {
- dev_err(&pdev->dev, "No platform data or DT found\n");
How do you know there is no platform data found? You haven't even looked.
return -EINVAL; }
@@ -982,20 +1217,46 @@ 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;
- if (!di->pdata) {
- dev_err(di->dev, "no btemp platform data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
- btemp_p_val = of_get_property(np, "num_supplicants", NULL);
- BUG_ON(!btemp_p_val);
DEAD!
- di->pdata =
- kzalloc(sizeof(struct abx500_btemp_platform_data),
GFP_KERNEL);
- if (di->pdata == NULL) {
- kfree(di);
- return -ENOMEM;
}
- /* get battery specific platform data */
- di->bat = plat_data->battery;
- di->pdata->num_supplicants = be32_to_cpup(btemp_p_val);
- di->pdata->supplied_to =
- kzalloc(di->pdata->num_supplicants *
- sizeof(const char *), GFP_KERNEL);
- if (di->pdata->supplied_to == NULL) {
- kfree(di);
- kfree(di->pdata);
- return -ENOMEM;
- }
- for (val = 0; val < di->pdata->num_supplicants; ++val)
- if (of_property_read_string_index
- (np, "supplied_to", val, &pvalue) == 0)
- *(di->pdata->supplied_to + val) = (char *)pvalue;
- else {
- dev_warn(di->dev, "insufficient number of
supplied_to data found\n");
- goto free_device_info;
- }
- dev_dbg(di->dev, "getting DT battery information\n");
- di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL);
if (!di->bat) {
- dev_err(di->dev, "no battery platform data supplied\n");
- ret = -EINVAL;
- kfree(di);
- kfree(di->pdata);
- return -ENOMEM;
- }
- if (populate_abx8500_bm_data(di->dev, di->bat, np) < 0) {
- dev_warn(di->dev, "Failed to bind DT\n");
goto free_device_info; }
- dev_dbg(di->dev, "getting DT battery information...done\n");
/* BTEMP supply */ di->btemp_psy.name = "ab8500_btemp"; @@ -1008,7 +1269,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di->btemp_psy.external_power_changed = ab8500_btemp_external_power_changed;
Unrelated whitespace change.
/* Create a work queue for the btemp */ di->btemp_wq = create_singlethread_workqueue("ab8500_btemp_wq"); @@ -1016,7 +1276,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) dev_err(di->dev, "failed to create work queue\n"); goto free_device_info; }
And again.
/* Init work for measuring temperature periodically */ INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work, ab8500_btemp_periodic_work); @@ -1090,14 +1349,23 @@ free_irq: irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); free_irq(irq, di); }
.
free_btemp_wq: destroy_workqueue(di->btemp_wq);
.
free_device_info: kfree(di);
- kfree(di->pdata);
- kfree(di->bat);
return ret; }
+static const struct of_device_id ab8500_btemp_match[] = {
- {.compatible = "stericsson,ab8500-btemp",},
- {},
+};
static struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, .remove = __devexit_p(ab8500_btemp_remove), @@ -1106,6 +1374,7 @@ static struct platform_driver ab8500_btemp_driver = { .driver = { .name = "ab8500-btemp", .owner = THIS_MODULE,
- .of_match_table = ab8500_btemp_match,
}, };
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index bf02225..1d0e32a 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -31,6 +31,7 @@ #include <linux/mfd/abx500.h> #include <linux/time.h> #include <linux/completion.h> +#include <linux/of.h>
#define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -2446,11 +2447,12 @@ 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;
As above.
- const char *fg_p_val;
- struct device_node *np = pdev->dev.of_node;
struct ab8500_fg *di;
- if (!plat_data) {
- dev_err(&pdev->dev, "No platform data\n");
- if (!np) {
- dev_err(&pdev->dev, "No DT node for platform data
available\n"); return -EINVAL; }
@@ -2464,20 +2466,42 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->dev = &pdev->dev; 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;
- di->pdata =
- kzalloc(sizeof(struct abx500_btemp_platform_data),
GFP_KERNEL);
- if (di->pdata == NULL) {
- kfree(di);
- return -ENOMEM;
- }
- di->pdata->num_supplicants =
- be32_to_cpup(of_get_property(np, "num_supplicants",
NULL));
- di->pdata->supplied_to =
- kzalloc(di->pdata->num_supplicants *
- sizeof(const char *), GFP_KERNEL);
- if (di->pdata->supplied_to == NULL) {
- kfree(di);
- kfree(di->pdata);
- return -ENOMEM;
}
- for (i = 0; i < di->pdata->num_supplicants; ++i)
- if (of_property_read_string_index
- (np, "supplied_to", i, &fg_p_val) == 0)
- *(di->pdata->supplied_to + i) = (char *)fg_p_val;
- else {
- dev_warn(di->dev, "insufficient number of
supplied_to data found\n");
- goto free_device_info;
- }
/* get battery specific platform data */
- di->bat = plat_data->battery;
- di->bat = kzalloc(sizeof(struct abx500_bm_data), GFP_KERNEL);
if (!di->bat) {
- dev_err(di->dev, "no battery platform data supplied\n");
- ret = -EINVAL;
- kfree(di);
- kfree(di->pdata);
- return -ENOMEM;
- }
- ret = populate_abx8500_bm_data(di->dev, di->bat, np);
- if (ret < 0) {
- dev_warn(di->dev, "Failed to bind DT\n");
goto free_device_info; }
@@ -2607,10 +2631,15 @@ free_inst_curr_wq: destroy_workqueue(di->fg_wq); free_device_info: kfree(di);
- kfree(di->pdata);
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 +2648,7 @@ static struct platform_driver ab8500_fg_driver = { .driver = { .name = "ab8500-fg", .owner = THIS_MODULE,
- .of_match_table = ab8500_fg_match,
}, };
@@ -2632,7 +2662,7 @@ static void __exit ab8500_fg_exit(void) platform_driver_unregister(&ab8500_fg_driver); }
-subsys_initcall_sync(ab8500_fg_init); +subsys_initcall(ab8500_fg_init);
What does this do?
module_exit(ab8500_fg_exit);
MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 1318ca6..9dbc4d1 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -113,13 +113,13 @@ struct ab3100 { * struct ab3100_platform_data * Data supplied to initialize board connections to the AB3100 * @reg_constraints: regulator constraints for target board
- the order of these constraints are: LDO A, C, D, E,
- F, G, H, K, EXT and BUCK.
- the order of these constraints are: LDO A, C, D, E,
- F, G, H, K, EXT and BUCK.
* @reg_initvals: initial values for the regulator registers
- plus two sleep settings for LDO E and the BUCK converter.
- exactly AB3100_NUM_REGULATORS+2 values must be sent in.
- Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
- BUCK sleep, LDO D. (LDO D need to be initialized last.)
- plus two sleep settings for LDO E and the BUCK converter.
- exactly AB3100_NUM_REGULATORS+2 values must be sent in.
- Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
- BUCK sleep, LDO D. (LDO D need to be initialized last.)
* @external_voltage: voltage level of the external regulator. */ struct ab3100_platform_data { @@ -131,7 +131,7 @@ struct ab3100_platform_data { int ab3100_event_register(struct ab3100 *ab3100, struct notifier_block *nb); int ab3100_event_unregister(struct ab3100 *ab3100,
- struct notifier_block *nb);
- struct notifier_block *nb);
Was this intentional?
/** * struct abx500_init_setting @@ -387,6 +387,9 @@ struct abx500_bm_data { const struct abx500_fg_parameters *fg_params; };
+int populate_abx8500_bm_data(struct device *, struct abx500_bm_data *,
- struct device_node *);
struct abx500_chargalg_platform_data { char **supplied_to; size_t num_supplicants; diff --git a/include/linux/of.h b/include/linux/of.h index 2ec1083..61b4ac8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -183,6 +183,39 @@ extern struct device_node *of_find_matching_node(struct device_node *from, #define for_each_matching_node(dn, matches) \ for (dn = of_find_matching_node(NULL, matches); dn; \ dn = of_find_matching_node(dn, matches))
+/*
- syntax: for_each_node_by_phandle(np, len, phandle);
- @np : pointer to node to start in the list
- @len: number of nodes expected
- @phandle: current phandle which is obtained through
of_get_property(...)
- e.g:
- node_a: <> {
- ...
- };
- node_b: <> {
- ...
- };
- node_c: <> {
- ...
- };
- node_x: <> {
- p1 = <v1>;
- p2 = <v2>;
- n_nodes = <3>
- p3 = <&node_a &node_b &node_c ....>;
- };
- Note:
- - invoke of_node_put(...) as it uses of_find_node_by_phandle(...)
- */
+#define for_each_node_by_phandle(np, len, phandle) \
- for (np = of_find_node_by_phandle(be32_to_cpup(phandle));\
- (len--);\
- np = np->allnext)
Seperate patch. To be submitted first.
extern struct device_node *of_find_node_by_path(const char *path); extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node);
Did this pass checkpatch.pl?
Kind regards, Lee
-- Lee Jones Linaro ST-Ericsson Landing Team Lead M: +44 77 88 633 515 Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
On 29/06/12 20:44, Rajanikanth HV wrote:
thanks for your review comments, i will post it on public branch, how about a review from abx500 bm data structure perspective ref: arch/arm/mach-ux500/board-mop500-bm.c
I already did:
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
The values you put into the Device Tree should be Snowball specific, but it looks like you've loaded it up with _everything_. You need to make sure that all of the information you put in makes sense when booting the Snowball board. Any values which will never be used need to be extracted.
Kind regards, Lee
In order to accommodate allowable Batteries with in the ab8500 parameters limit battery type information got bloated. (Ref: board-mop500-bm.c)
Recommended battery for snowball is: 3.7v 2600ma Ref: http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf
However, i currently i am using "SonyEricsson BST41", 3.6v. 1500mAh, 5.4w
Thanks, Rajanikanth
On 2 July 2012 14:30, Lee Jones lee.jones@linaro.org wrote:
On 29/06/12 20:44, Rajanikanth HV wrote:
thanks for your review comments, i will post it on public branch, how about a review from abx500 bm data structure perspective ref: arch/arm/mach-ux500/board-mop500-bm.c
I already did:
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
The values you put into the Device Tree should be Snowball specific, but it looks like you've loaded it up with _everything_. You need to make sure that all of the information you put in makes sense when booting the Snowball board. Any values which will never be used need to be extracted.
Kind regards, Lee
-- Lee Jones Linaro ST-Ericsson Landing Team Lead M: +44 77 88 633 515 Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
On 02/07/12 10:49, Rajanikanth HV wrote:
In order to accommodate allowable Batteries with in the ab8500 parameters limit battery type information got bloated. (Ref: board-mop500-bm.c)
Then maybe we should move the settings from platform data and into the driver itself? I'm not keen on the way it looks now.
Arnd, do you have an opinion?
Recommended battery for snowball is: 3.7v 2600ma Ref: http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf
However, i currently i am using "SonyEricsson BST41", 3.6v. 1500mAh, 5.4w
Thanks, Rajanikanth
On 2 July 2012 14:30, Lee Jones lee.jones@linaro.org wrote:
On 29/06/12 20:44, Rajanikanth HV wrote:
thanks for your review comments, i will post it on public branch, how about a review from abx500 bm data structure perspective ref: arch/arm/mach-ux500/board-mop500-bm.c
I already did:
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
The values you put into the Device Tree should be Snowball specific, but it looks like you've loaded it up with _everything_. You need to make sure that all of the information you put in makes sense when booting the Snowball board. Any values which will never be used need to be extracted.
Kind regards, Lee
-- Lee Jones Linaro ST-Ericsson Landing Team Lead M: +44 77 88 633 515 Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
how will you accommodate new battery types information then?
Thanks, Rajanikanth
On 2 July 2012 15:55, Lee Jones lee.jones@linaro.org wrote:
On 02/07/12 10:49, Rajanikanth HV wrote:
In order to accommodate allowable Batteries with in the ab8500 parameters limit battery type information got bloated. (Ref: board-mop500-bm.c)
Then maybe we should move the settings from platform data and into the driver itself? I'm not keen on the way it looks now.
Arnd, do you have an opinion?
Recommended battery for snowball is: 3.7v 2600ma Ref: http://www.giga-concept.fr/media/uploads/products/documents/2008/09/9100.pdf
However, i currently i am using "SonyEricsson BST41", 3.6v. 1500mAh, 5.4w
Thanks, Rajanikanth
On 2 July 2012 14:30, Lee Jones lee.jones@linaro.org wrote:
On 29/06/12 20:44, Rajanikanth HV wrote:
thanks for your review comments, i will post it on public branch, how about a review from abx500 bm data structure perspective ref: arch/arm/mach-ux500/board-mop500-bm.c
I already did:
It looks like you've just taken values for all of the possible combinations. Is this to support different batteries, or different platforms/machines?
The values you put into the Device Tree should be Snowball specific, but it looks like you've loaded it up with _everything_. You need to make sure that all of the information you put in makes sense when booting the Snowball board. Any values which will never be used need to be extracted.
Kind regards, Lee
-- Lee Jones Linaro ST-Ericsson Landing Team Lead M: +44 77 88 633 515 Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
-- Lee Jones Linaro ST-Ericsson Landing Team Lead M: +44 77 88 633 515 Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
On 02/07/12 11:38, Rajanikanth HV wrote:
how will you accommodate new battery types information then?
Add them to the driver too?
From what I can see, the structs in board-mop500-bm.c are more of a capability thing than saying "this is what we have".
Please correct my snap-judgment if I'm incorrect.
On Monday 02 July 2012, Lee Jones wrote:
On 02/07/12 11:38, Rajanikanth HV wrote:
how will you accommodate new battery types information then?
Add them to the driver too?
From what I can see, the structs in board-mop500-bm.c are more of a capability thing than saying "this is what we have".
Please correct my snap-judgment if I'm incorrect.
My first reaction to this would have been to put it all into the device tree, but I agree that the amount of data is a bit excessive.
Looking at the Sony xperia sola source code, it seems that the same data is used for *all* boards, and nothing in it looks board specific, so putting it all into the driver itself sounds like the easiest solution. We can always add some form of abstraction if we later need something more complex.
The version I'm looking at uses a compile-time configuration symbol "CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL". This has to get removed and turned into a run-time option.
The regulator names in the platform data look should probably be taken from the device tree.
Arnd
On 29 June 2012 12:44, Rajanikanth HV rajanikanth.hv@linaro.org wrote:
thanks for your review comments, i will post it on public branch,
Posting on a public branch once you have your git issues sorted is good, but we want the patches themselves posted on the relevant email lists. Please make the cleanups suggested and repost directly for upstream review and Lee and Arnd can directly comment on those lists. Rease Documentation/SubmittingPatches if you have not done so yet.
Thanks, ~Deepak