Message ID | 1340974792-26016-1-git-send-email-rajanikanth.hv@stericsson.com |
---|---|
State | New |
Headers | show |
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
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
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);