@@ -24,7 +24,13 @@ ab8500-bm : : : Battery Manager
ab8500-btemp : : : Battery Temperature
ab8500-charger : : : Battery Charger
ab8500-codec : : : Audio Codec
-ab8500-fg : : : Fuel Gauge
+ab8500-fg : : vddadc : Fuel Gauge
+ : NCONV_ACCU : : Accumulate N Sample Conversion
+ : BATT_OVV : : Battery Over Voltage
+ : LOW_BAT_F : : LOW threshold battery voltage
+ : CC_INT_CALIB : : Counter Counter Internal Calibration
+ : CCEOC : : Coulomb Counter End of Conversion
+ : : :
ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter
SW_CONV_END : :
ab8500-gpio : : : GPIO Controller
new file mode 100644
@@ -0,0 +1,86 @@
+=== AB8500 Fuel Gauge Driver ===
+
+AB8500 is a mixed signal multimedia and power management
+device comprising: power and energy-management-module,
+wall-charger, usb-charger, audio codec, general purpose adc,
+tvout, clock management and sim card interface.
+
+Fuel-guage support is part of energy-management-module, the other
+components of this module are:
+main-charger, usb-combo-charger and Battery temperature monitoring.
+
+The properties below describes the node for fuel guage driver.
+
+Required Properties:
+- compatible = "stericsson,ab8500-fg"
+- interface-name:
+ Name of the controller/driver which is part of energy-management-module
+- supplied-to:
+ This property shall have dependent nodes which represent other
+ energy-management-module.
+ This is a logical binding w.r.t power supply events
+ across energy-management-module drivers where-in, the
+ runtime battery properties are shared along with uevent
+ notification.
+ ref: di->fg.external_power_changed =
+ ab8500_fg_external_power_changed;
+ ab8500_fg.c
+
+ Need for this property:
+ energy-management-module driver updates power-supply properties
+ which are subset of events listed in 'enum power_supply_property',
+ ref: power_supply.h file
+ Event handler invokes power supply change notifier
+ which in-turn invokes registered power supply class call-back
+ based on the 'supplied-to' string.
+ ref:
+ power_supply_changed_work(..) ./drivers/power/power_supply_core.c
+ di->fg_psy.external_power_changed
+
+ example:
+ ab8500-fg {
+ /* Other enery management module */
+ supplied-to = <&ab8500_chargalg &ab8500_usb>;
+ };
+
+ ab8500_battery_info: ab8500_bat_type {
+ battery-type = <2>;
+ thermistor-on-batctrl = <1>;
+ };
+
+Other dependent node for fuel-gauge is:
+ ab8500_battery_info: ab8500_bat_type {
+ };
+ This node will provide information on 'thermistor interface' and
+ 'battery technology type' used.
+
+Properties of this node are:
+thermistor-on-batctrl:
+ A boolean value indicating thermistor interface to battery
+
+ Note:
+ 'btemp' and 'batctrl' are the pins interfaced for battery temperature
+ measurement, 'btemp' signal is used when NTC(negative temperature
+ coefficient) resister is interfaced external to battery whereas
+ 'batctrl' pin is used when NTC resister is internal to battery.
+
+ e.g:
+ ab8500_battery_info: ab8500_bat_type {
+ thermistor-on-batctrl;
+ };
+ indiactes: NTC resister is internal to battery, 'batctrl' is used
+ for thermal measurement.
+
+ The absence of property 'thermal-on-batctrl' indicates
+ NTC resister is external to battery and 'btemp' signal is used
+ for thermal measurement.
+
+battery-type:
+ This shall be the battery manufacturing technology type,
+ allowed types are:
+ "UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
+ e.g:
+ ab8500_battery_info: ab8500_bat_type {
+ battery-name = "LION";
+ }
+
@@ -352,8 +352,28 @@
vddadc-supply = <&ab8500_ldo_tvout_reg>;
};
- ab8500-usb {
+ ab8500_battery_info: ab8500_bat_type {
+ battery-name = "LION";
+ thermistor-on-batctrl;
+ };
+
+ ab8500_chargalg: ab8500_chalg {
+ compatible = "stericsson,ab8500-chargalg";
+ interface-name = "ab8500_chargalg";
+ battery-info = <&ab8500_battery_info>;
+ supplied-to = <&ab8500_fuel_guage>;
+ };
+
+ ab8500_fuel_guage: ab8500_fg {
+ compatible = "stericsson,ab8500-fg";
+ interface-name = "ab8500_fg";
+ battery-info = <&ab8500_battery_info>;
+ supplied-to = <&ab8500_chargalg &ab8500_usb>;
+ };
+
+ ab8500_usb: ab8500_usb_if {
compatible = "stericsson,ab8500-usb";
+ interface-name = "ab8500_usb";
interrupts = < 90 0x4
96 0x4
14 0x4
@@ -1051,6 +1051,7 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
},
{
.name = "ab8500-fg",
+ .of_compatible = "stericsson,ab8500-fg",
.num_resources = ARRAY_SIZE(ab8500_fg_resources),
.resources = ab8500_fg_resources,
},
@@ -34,7 +34,7 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
-obj-$(CONFIG_AB8500_BM) += ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
new file mode 100644
@@ -0,0 +1,454 @@
+#include <linux/export.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+
+/*
+ * These are the defined batteries that uses a NTC and ID resistor placed
+ * inside of the battery pack.
+ * Note that the res_to_temp table must be strictly sorted by falling resistance
+ * values to work.
+ */
+static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
+ {-5, 53407},
+ { 0, 48594},
+ { 5, 43804},
+ {10, 39188},
+ {15, 34870},
+ {20, 30933},
+ {25, 27422},
+ {30, 24347},
+ {35, 21694},
+ {40, 19431},
+ {45, 17517},
+ {50, 15908},
+ {55, 14561},
+ {60, 13437},
+ {65, 12500},
+};
+static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
+ {-5, 165418},
+ { 0, 159024},
+ { 5, 151921},
+ {10, 144300},
+ {15, 136424},
+ {20, 128565},
+ {25, 120978},
+ {30, 113875},
+ {35, 107397},
+ {40, 101629},
+ {45, 96592},
+ {50, 92253},
+ {55, 88569},
+ {60, 85461},
+ {65, 82869},
+};
+static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
+ {4171, 100},
+ {4114, 95},
+ {4009, 83},
+ {3947, 74},
+ {3907, 67},
+ {3863, 59},
+ {3830, 56},
+ {3813, 53},
+ {3791, 46},
+ {3771, 33},
+ {3754, 25},
+ {3735, 20},
+ {3717, 17},
+ {3681, 13},
+ {3664, 8},
+ {3651, 6},
+ {3635, 5},
+ {3560, 3},
+ {3408, 1},
+ {3247, 0},
+};
+static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
+ {4161, 100},
+ {4124, 98},
+ {4044, 90},
+ {4003, 85},
+ {3966, 80},
+ {3933, 75},
+ {3888, 67},
+ {3849, 60},
+ {3813, 55},
+ {3787, 47},
+ {3772, 30},
+ {3751, 25},
+ {3718, 20},
+ {3681, 16},
+ {3660, 14},
+ {3589, 10},
+ {3546, 7},
+ {3495, 4},
+ {3404, 2},
+ {3250, 0},
+};
+
+static struct abx500_v_to_cap cap_tbl[] = {
+ {4186, 100},
+ {4163, 99},
+ {4114, 95},
+ {4068, 90},
+ {3990, 80},
+ {3926, 70},
+ {3898, 65},
+ {3866, 60},
+ {3833, 55},
+ {3812, 50},
+ {3787, 40},
+ {3768, 30},
+ {3747, 25},
+ {3730, 20},
+ {3705, 15},
+ {3699, 14},
+ {3684, 12},
+ {3672, 9},
+ {3657, 7},
+ {3638, 6},
+ {3556, 4},
+ {3424, 2},
+ {3317, 1},
+ {3094, 0},
+};
+
+/*
+ * Note that the res_to_temp table must be strictly sorted by falling
+ * resistance values to work.
+ */
+static struct abx500_res_to_temp temp_tbl[] = {
+ {-5, 214834},
+ { 0, 162943},
+ { 5, 124820},
+ {10, 96520},
+ {15, 75306},
+ {20, 59254},
+ {25, 47000},
+ {30, 37566},
+ {35, 30245},
+ {40, 24520},
+ {45, 20010},
+ {50, 16432},
+ {55, 13576},
+ {60, 11280},
+ {65, 9425},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
+ { 40, 120},
+ { 30, 135},
+ { 20, 165},
+ { 10, 230},
+ { 00, 325},
+ {-10, 445},
+ {-20, 595},
+};
+
+/*
+ * Note that the batres_vs_temp table must be strictly sorted by falling
+ * temperature values to work.
+ */
+struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
+ { 60, 300},
+ { 30, 300},
+ { 20, 300},
+ { 10, 300},
+ { 00, 300},
+ {-10, 300},
+ {-20, 300},
+};
+EXPORT_SYMBOL(temp_to_batres_tbl_ext_thermistor);
+
+/* battery resistance table for LI ION 9100 battery */
+struct batres_vs_temp temp_to_batres_tbl_9100[] = {
+ { 60, 180},
+ { 30, 180},
+ { 20, 180},
+ { 10, 180},
+ { 00, 180},
+ {-10, 180},
+ {-20, 180},
+};
+EXPORT_SYMBOL(temp_to_batres_tbl_9100);
+
+struct abx500_battery_type bat_type_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+ /* First element always represent the UNKNOWN battery */
+ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+ .resis_high = 0,
+ .resis_low = 0,
+ .battery_resistance = 300,
+ .charge_full_design = 612,
+ .nominal_voltage = 3700,
+ .termination_vol = 4050,
+ .termination_curr = 200,
+ .recharge_vol = 3990,
+ .normal_cur_lvl = 400,
+ .normal_vol_lvl = 4100,
+ .maint_a_cur_lvl = 400,
+ .maint_a_vol_lvl = 4050,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 400,
+ .maint_b_vol_lvl = 4000,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 53407,
+ .resis_low = 12500,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3600,
+ .termination_vol = 4150,
+ .termination_curr = 80,
+ .recharge_vol = 4130,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
+ .r_to_t_tbl = temp_tbl_A_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
+ .v_to_cap_tbl = cap_tbl_A_thermistor,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+
+},
+{
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 165418,
+ .resis_low = 82869,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3600,
+ .termination_vol = 4150,
+ .termination_curr = 80,
+ .recharge_vol = 4130,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
+ .r_to_t_tbl = temp_tbl_B_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
+ .v_to_cap_tbl = cap_tbl_B_thermistor,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+EXPORT_SYMBOL(bat_type_thermistor);
+
+struct abx500_battery_type bat_type_ext_thermistor[] = {
+[BATTERY_UNKNOWN] = {
+ /* First element always represent the UNKNOWN battery */
+ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+ .resis_high = 0,
+ .resis_low = 0,
+ .battery_resistance = 300,
+ .charge_full_design = 612,
+ .nominal_voltage = 3700,
+ .termination_vol = 4050,
+ .termination_curr = 200,
+ .recharge_vol = 3990,
+ .normal_cur_lvl = 400,
+ .normal_vol_lvl = 4100,
+ .maint_a_cur_lvl = 400,
+ .maint_a_vol_lvl = 4050,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 400,
+ .maint_b_vol_lvl = 4000,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+/*
+ * These are the batteries that doesn't have an internal NTC resistor to measure
+ * its temperature. The temperature in this case is measure with a NTC placed
+ * near the battery but on the PCB.
+ */
+{
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 76000,
+ .resis_low = 53000,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_vol = 4130,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+ .name = POWER_SUPPLY_TECHNOLOGY_LION,
+ .resis_high = 30000,
+ .resis_low = 10000,
+ .battery_resistance = 300,
+ .charge_full_design = 950,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_vol = 4130,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+{
+ .name = POWER_SUPPLY_TECHNOLOGY_LION,
+ .resis_high = 95000,
+ .resis_low = 76001,
+ .battery_resistance = 300,
+ .charge_full_design = 950,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_vol = 4130,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+},
+};
+EXPORT_SYMBOL(bat_type_ext_thermistor);
+
+static const struct abx500_bm_capacity_levels cap_levels = {
+ .critical = 2,
+ .low = 10,
+ .normal = 70,
+ .high = 95,
+ .full = 100,
+};
+
+static const struct abx500_fg_parameters fg = {
+ .recovery_sleep_timer = 10,
+ .recovery_total_time = 100,
+ .init_timer = 1,
+ .init_discard_time = 5,
+ .init_total_time = 40,
+ .high_curr_time = 60,
+ .accu_charging = 30,
+ .accu_high_curr = 30,
+ .high_curr_threshold = 50,
+ .lowbat_threshold = 3100,
+ .battok_falling_th_sel0 = 2860,
+ .battok_raising_th_sel1 = 2860,
+ .user_cap_limit = 15,
+ .maint_thres = 97,
+};
+
+static const struct abx500_maxim_parameters maxi_params = {
+ .ena_maxi = true,
+ .chg_curr = 910,
+ .wait_cycles = 10,
+ .charger_curr_step = 100,
+};
+
+static const struct abx500_bm_charger_parameters chg = {
+ .usb_volt_max = 5500,
+ .usb_curr_max = 1500,
+ .ac_volt_max = 7500,
+ .ac_curr_max = 1500,
+};
+
+struct abx500_bm_data ab8500_bm_data = {
+ .temp_under = 3,
+ .temp_low = 8,
+ .temp_high = 43,
+ .temp_over = 48,
+ .main_safety_tmr_h = 4,
+ .temp_interval_chg = 20,
+ .temp_interval_nochg = 120,
+ .usb_safety_tmr_h = 4,
+ .bkup_bat_v = BUP_VCH_SEL_2P6V,
+ .bkup_bat_i = BUP_ICH_SEL_150UA,
+ .no_maintenance = false,
+ .adc_therm = ABx500_ADC_THERM_BATCTRL,
+ .chg_unknown_bat = false,
+ .enable_overshoot = false,
+ .fg_res = 100,
+ .cap_levels = &cap_levels,
+ .bat_type = bat_type_thermistor,
+ .n_btypes = 3,
+ .batt_id = 0,
+ .interval_charging = 5,
+ .interval_not_charging = 120,
+ .temp_hysteresis = 3,
+ .gnd_lift_resistance = 34,
+ .maxi = &maxi_params,
+ .chg_params = &chg,
+ .fg_params = &fg,
+};
+EXPORT_SYMBOL(ab8500_bm_data);
@@ -22,15 +22,15 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/kobject.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500.h>
#include <linux/slab.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/of.h>
#include <linux/delay.h>
-#include <linux/mfd/abx500/ab8500-gpadc.h>
-#include <linux/mfd/abx500.h>
#include <linux/time.h>
#include <linux/completion.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
#define MILLI_TO_MICRO 1000
#define FG_LSB_IN_MA 1627
@@ -544,14 +544,14 @@ cc_err:
ret = abx500_set_register_interruptible(di->dev,
AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
SEC_TO_SAMPLE(10));
- if (ret)
+ if (ret < 0)
goto fail;
/* Start the CC */
ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
AB8500_RTC_CC_CONF_REG,
(CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
- if (ret)
+ if (ret < 0)
goto fail;
} else {
di->turn_off_fg = false;
@@ -2429,7 +2429,6 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev)
flush_scheduled_work();
power_supply_unregister(&di->fg_psy);
platform_set_drvdata(pdev, NULL);
- kfree(di);
return ret;
}
@@ -2442,22 +2441,149 @@ static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
{"CCEOC", ab8500_fg_cc_data_end_handler},
};
+static int __devinit
+fg_of_probe(struct device *dev,
+ struct device_node *np,
+ struct abx500_bm_plat_data *bm_pdata)
+{
+ int i, ret = 0, thermistor = NTC_INTERNAL;
+ const __be32 *ph;
+ const char *bat_tech;
+ struct abx500_fg_platform_data *fg = bm_pdata->fg;
+ struct abx500_bm_data *bat;
+ struct abx500_battery_type *btype;
+ struct device_node *np_bat_supply;
+
+ /* get phandle to 'supplied-to' node */
+ ph = of_get_property(np, "supplied-to", &fg->num_supplicants);
+ if (ph == NULL) {
+ dev_err(dev, "no supplied_to property specified\n");
+ return -EINVAL;
+ }
+ fg->num_supplicants /= sizeof(int);
+ fg->supplied_to =
+ devm_kzalloc(dev, fg->num_supplicants *
+ sizeof(const char *), GFP_KERNEL);
+ if (fg->supplied_to == NULL) {
+ dev_err(dev, "%s no mem for supplied-to\n", __func__);
+ return -ENOMEM;
+ }
+ for (i = 0; i < fg->num_supplicants; ++i) {
+ np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph) + i);
+ if (np_bat_supply == NULL) {
+ dev_err(dev, "invalid supplied_to property\n");
+ return -EINVAL;
+ }
+ ret = of_property_read_string(np_bat_supply, "interface-name",
+ (const char **)(fg->supplied_to + i));
+ if (ret < 0) {
+ of_node_put(np_bat_supply);
+ dev_err(dev, "supply/interface name not found\n");
+ return ret;
+ }
+ dev_dbg(dev, "%s power supply interface_name:%s\n",
+ __func__, *(fg->supplied_to + i));
+ }
+ /* get phandle to 'battery-info' node */
+ ph = of_get_property(np, "battery-info", NULL);
+ if (ph == NULL) {
+ dev_err(dev, "missing property battery-info\n");
+ return -EINVAL;
+ }
+ np_bat_supply = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (np_bat_supply == NULL) {
+ dev_err(dev, "invalid battery-info node\n");
+ return -EINVAL;
+ }
+ if (of_property_read_bool(np_bat_supply,
+ "thermistor-on-batctrl") == false){
+ dev_warn(dev, "missing property thermistor-on-batctrl\n");
+ thermistor = NTC_EXTERNAL;
+ }
+ bm_pdata->battery = &ab8500_bm_data;
+ bat = bm_pdata->battery;
+ if (thermistor == NTC_EXTERNAL) {
+ bat->n_btypes = 4;
+ bat->bat_type = bat_type_ext_thermistor;
+ bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
+ }
+ ret = of_property_read_string(np_bat_supply, "battery-name", &bat_tech);
+ if (ret < 0) {
+ dev_warn(dev, "missing property battery-name/type\n");
+ bat_tech = "UNKNOWN";
+ }
+ of_node_put(np_bat_supply);
+ if (strcmp(bat_tech, "LION") == 0) {
+ bat->no_maintenance = true;
+ bat->chg_unknown_bat = true;
+ bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
+ bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
+ bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130;
+ bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
+ bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
+ }
+ /* select the battery resolution table */
+ for (i = 0; i < bat->n_btypes; ++i) {
+ btype = (bat->bat_type + i);
+ if (thermistor == NTC_EXTERNAL) {
+ btype->batres_tbl =
+ temp_to_batres_tbl_ext_thermistor;
+ } else if (strcmp(bat_tech, "LION") == 0) {
+ btype->batres_tbl =
+ temp_to_batres_tbl_9100;
+ } else {
+ btype->batres_tbl =
+ temp_to_batres_tbl_thermistor;
+ }
+ }
+ return 0;
+}
+
static int __devinit ab8500_fg_probe(struct platform_device *pdev)
{
int i, irq;
int ret = 0;
struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+ struct device_node *np = pdev->dev.of_node;
struct ab8500_fg *di;
+ di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+ if (!di) {
+ dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
+ return -ENOMEM;
+ }
+ if (np) {
+ if (!plat_data) {
+ plat_data =
+ devm_kzalloc(&pdev->dev, sizeof(*plat_data), GFP_KERNEL);
+ if (!plat_data) {
+ dev_err(&pdev->dev,
+ "%s no mem for plat_data\n", __func__);
+ return -ENOMEM;
+ }
+ plat_data->fg = devm_kzalloc(&pdev->dev,
+ sizeof(*plat_data->fg), GFP_KERNEL);
+ if (!plat_data->fg) {
+ devm_kfree(&pdev->dev, plat_data);
+ dev_err(&pdev->dev,
+ "%s no mem for pdata->fg\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+ /* get battery specific platform data */
+ ret = fg_of_probe(&pdev->dev, np, plat_data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get platform data\n");
+ return ret;
+ }
+ }
if (!plat_data) {
- dev_err(&pdev->dev, "No platform data\n");
+ dev_err(&pdev->dev,
+ "%s no fg platform data found\n", __func__);
return -EINVAL;
}
- di = kzalloc(sizeof(*di), GFP_KERNEL);
- if (!di)
- return -ENOMEM;
-
mutex_init(&di->cc_lock);
/* get parent data */
@@ -2469,16 +2595,14 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
di->pdata = plat_data->fg;
if (!di->pdata) {
dev_err(di->dev, "no fg platform data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
+ return -EINVAL;
}
/* get battery specific platform data */
di->bat = plat_data->battery;
if (!di->bat) {
dev_err(di->dev, "no battery platform data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
+ return -EINVAL;
}
di->fg_psy.name = "ab8500_fg";
@@ -2506,7 +2630,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev)
di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
if (di->fg_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
- goto free_device_info;
+ return -ENOMEM;
}
/* Init work for running the fg algorithm instantly */
@@ -2605,12 +2729,14 @@ free_irq:
}
free_inst_curr_wq:
destroy_workqueue(di->fg_wq);
-free_device_info:
- kfree(di);
-
return ret;
}
+static const struct of_device_id ab8500_fg_match[] = {
+ {.compatible = "stericsson,ab8500-fg",},
+ {},
+};
+
static struct platform_driver ab8500_fg_driver = {
.probe = ab8500_fg_probe,
.remove = __devexit_p(ab8500_fg_remove),
@@ -2619,6 +2745,7 @@ static struct platform_driver ab8500_fg_driver = {
.driver = {
.name = "ab8500-fg",
.owner = THIS_MODULE,
+ .of_match_table = ab8500_fg_match,
},
};
@@ -382,7 +382,7 @@ struct abx500_bm_data {
int gnd_lift_resistance;
const struct abx500_maxim_parameters *maxi;
const struct abx500_bm_capacity_levels *cap_levels;
- const struct abx500_battery_type *bat_type;
+ struct abx500_battery_type *bat_type;
const struct abx500_bm_charger_parameters *chg_params;
const struct abx500_fg_parameters *fg_params;
};
@@ -416,6 +416,11 @@ struct abx500_bm_plat_data {
struct abx500_chargalg_platform_data *chargalg;
};
+enum {
+ NTC_EXTERNAL = 0,
+ NTC_INTERNAL,
+};
+
int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value);
int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
@@ -422,6 +422,13 @@ struct ab8500_chargalg_platform_data {
struct ab8500_btemp;
struct ab8500_gpadc;
struct ab8500_fg;
+
+extern struct abx500_bm_data ab8500_bm_data;
+extern struct abx500_battery_type bat_type_ext_thermistor[];
+extern struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[];
+extern struct batres_vs_temp temp_to_batres_tbl_9100[];
+extern struct batres_vs_temp temp_to_batres_tbl_thermistor[];
+
#ifdef CONFIG_AB8500_BM
void ab8500_fg_reinit(void);
void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);