Loading drivers/mfd/ab8500-core.c +0 −8 Original line number Diff line number Diff line Loading @@ -1011,40 +1011,32 @@ static struct mfd_cell ab8500_bm_devs[] = { .of_compatible = "stericsson,ab8500-charger", .num_resources = ARRAY_SIZE(ab8500_charger_resources), .resources = ab8500_charger_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-btemp", .of_compatible = "stericsson,ab8500-btemp", .num_resources = ARRAY_SIZE(ab8500_btemp_resources), .resources = ab8500_btemp_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-fg", .of_compatible = "stericsson,ab8500-fg", .num_resources = ARRAY_SIZE(ab8500_fg_resources), .resources = ab8500_fg_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-chargalg", .of_compatible = "stericsson,ab8500-chargalg", .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), .resources = ab8500_chargalg_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, }; Loading drivers/power/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ 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_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o 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 Loading drivers/power/ab8500_bmdata.c +254 −269 Original line number Diff line number Diff line Loading @@ -452,70 +452,55 @@ struct abx500_bm_data ab8500_bm_data = { .fg_params = &fg, }; int __devinit bmdevs_of_probe(struct device *dev, int __devinit ab8500_bm_of_probe(struct device *dev, struct device_node *np, struct abx500_bm_data **battery) struct abx500_bm_data *bm) { struct abx500_battery_type *btype; struct device_node *np_bat_supply; struct abx500_bm_data *bat; struct batres_vs_temp *tmp_batres_tbl; struct device_node *battery_node; const char *btech; char bat_tech[8]; int i, thermistor; *battery = &ab8500_bm_data; int i; /* get phandle to 'battery-info' node */ np_bat_supply = of_parse_phandle(np, "battery", 0); if (!np_bat_supply) { dev_err(dev, "missing property battery\n"); battery_node = of_parse_phandle(np, "battery", 0); if (!battery_node) { dev_err(dev, "battery node or reference missing\n"); return -EINVAL; } if (of_property_read_bool(np_bat_supply, "thermistor-on-batctrl")) thermistor = NTC_INTERNAL; else thermistor = NTC_EXTERNAL; bat = *battery; if (thermistor == NTC_EXTERNAL) { bat->n_btypes = 4; bat->bat_type = bat_type_ext_thermistor; bat->adc_therm = ABx500_ADC_THERM_BATTEMP; } btech = of_get_property(np_bat_supply, "stericsson,battery-type", NULL); btech = of_get_property(battery_node, "stericsson,battery-type", NULL); if (!btech) { dev_warn(dev, "missing property battery-name/type\n"); strcpy(bat_tech, "UNKNOWN"); } else { strcpy(bat_tech, btech); return -EINVAL; } if (strncmp(bat_tech, "LION", 4) == 0) { bat->no_maintenance = true; bat->chg_unknown_bat = true; bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; if (strncmp(btech, "LION", 4) == 0) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; bm->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } /* select the battery resolution table */ for (i = 0; i < bat->n_btypes; ++i) { btype = (bat->bat_type + i); if (thermistor == NTC_EXTERNAL) { btype->batres_tbl = temp_to_batres_tbl_ext_thermistor; } else if (strncmp(bat_tech, "LION", 4) == 0) { btype->batres_tbl = temp_to_batres_tbl_9100; if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) { if (strncmp(btech, "LION", 4) == 0) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; } else { btype->batres_tbl = temp_to_batres_tbl_thermistor; } bm->n_btypes = 4; bm->bat_type = bat_type_ext_thermistor; bm->adc_therm = ABx500_ADC_THERM_BATTEMP; tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; } of_node_put(np_bat_supply); /* select the battery resolution table */ for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; of_node_put(battery_node); return 0; } drivers/power/ab8500_btemp.c +51 −45 Original line number Diff line number Diff line Loading @@ -78,12 +78,13 @@ struct ab8500_btemp_ranges { * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @fg: Pointer to the struct fg * @bat: Pointer to the abx500_bm platform data * @bm: Platform specific battery management information * @btemp_psy: Structure for BTEMP specific battery properties * @events: Structure for information about events triggered * @btemp_ranges: Battery temperature range structure * @btemp_wq: Work queue for measuring the temperature periodically * @btemp_periodic_work: Work for measuring the temperature periodically * @initialized: True if battery id read. */ struct ab8500_btemp { struct device *dev; Loading @@ -94,12 +95,13 @@ struct ab8500_btemp { struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct ab8500_fg *fg; struct abx500_bm_data *bat; struct abx500_bm_data *bm; struct power_supply btemp_psy; struct ab8500_btemp_events events; struct ab8500_btemp_ranges btemp_ranges; struct workqueue_struct *btemp_wq; struct delayed_work btemp_periodic_work; bool initialized; }; /* BTEMP power supply properties */ Loading Loading @@ -147,13 +149,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di, return (450000 * (v_batctrl)) / (1800 - v_batctrl); } if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) { /* * If the battery has internal NTC, we use the current * source to calculate the resistance, 7uA or 20uA */ rbs = (v_batctrl * 1000 - di->bat->gnd_lift_resistance * inst_curr) - di->bm->gnd_lift_resistance * inst_curr) / di->curr_source; } else { /* Loading Loading @@ -209,7 +211,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, return 0; /* Only do this for batteries with internal NTC */ if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) curr = BAT_CTRL_7U_ENA; else Loading Loading @@ -241,7 +243,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, __func__); goto disable_curr_source; } } else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { } else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { dev_dbg(di->dev, "Disable BATCTRL curr source\n"); /* Write 0 to the curr bits */ Loading Loading @@ -457,9 +459,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int rbat, rntc, vntc; u8 id; id = di->bat->batt_id; id = di->bm->batt_id; if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && id != BATTERY_UNKNOWN) { rbat = ab8500_btemp_get_batctrl_res(di); Loading @@ -474,8 +476,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) } temp = ab8500_btemp_res_to_temp(di, di->bat->bat_type[id].r_to_t_tbl, di->bat->bat_type[id].n_temp_tbl_elements, rbat); di->bm->bat_type[id].r_to_t_tbl, di->bm->bat_type[id].n_temp_tbl_elements, rbat); } else { vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { Loading @@ -491,8 +493,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) rntc = 230000 * vntc / (VTVOUT_V - vntc); temp = ab8500_btemp_res_to_temp(di, di->bat->bat_type[id].r_to_t_tbl, di->bat->bat_type[id].n_temp_tbl_elements, rntc); di->bm->bat_type[id].r_to_t_tbl, di->bm->bat_type[id].n_temp_tbl_elements, rntc); prev = temp; } dev_dbg(di->dev, "Battery temperature is %d\n", temp); Loading @@ -513,7 +515,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) u8 i; di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; di->bat->batt_id = BATTERY_UNKNOWN; di->bm->batt_id = BATTERY_UNKNOWN; res = ab8500_btemp_get_batctrl_res(di); if (res < 0) { Loading @@ -522,23 +524,23 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) } /* BATTERY_UNKNOWN is defined on position 0, skip it! */ for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) { if ((res <= di->bat->bat_type[i].resis_high) && (res >= di->bat->bat_type[i].resis_low)) { for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { if ((res <= di->bm->bat_type[i].resis_high) && (res >= di->bm->bat_type[i].resis_low)) { dev_dbg(di->dev, "Battery detected on %s" " low %d < res %d < high: %d" " index: %d\n", di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ? di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ? "BATCTRL" : "BATTEMP", di->bat->bat_type[i].resis_low, res, di->bat->bat_type[i].resis_high, i); di->bm->bat_type[i].resis_low, res, di->bm->bat_type[i].resis_high, i); di->bat->batt_id = i; di->bm->batt_id = i; break; } } if (di->bat->batt_id == BATTERY_UNKNOWN) { if (di->bm->batt_id == BATTERY_UNKNOWN) { dev_warn(di->dev, "Battery identified as unknown" ", resistance %d Ohm\n", res); return -ENXIO; Loading @@ -548,13 +550,13 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * We only have to change current source if the * detected type is Type 1, else we use the 7uA source */ if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && di->bat->batt_id == 1) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && di->bm->batt_id == 1) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; } return di->bat->batt_id; return di->bm->batt_id; } /** Loading @@ -569,6 +571,13 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) struct ab8500_btemp *di = container_of(work, struct ab8500_btemp, btemp_periodic_work.work); if (!di->initialized) { di->initialized = true; /* Identify the battery */ if (ab8500_btemp_id(di) < 0) dev_warn(di->dev, "failed to identify the battery\n"); } di->bat_temp = ab8500_btemp_measure_temp(di); if (di->bat_temp != di->prev_bat_temp) { Loading @@ -577,9 +586,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) } if (di->events.ac_conn || di->events.usb_conn) interval = di->bat->temp_interval_chg; interval = di->bm->temp_interval_chg; else interval = di->bat->temp_interval_nochg; interval = di->bm->temp_interval_nochg; /* Schedule a new measurement */ queue_delayed_work(di->btemp_wq, Loading Loading @@ -806,7 +815,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = di->bat->bat_type[di->bat->batt_id].name; val->intval = di->bm->bat_type[di->bm->batt_id].name; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); Loading Loading @@ -967,6 +976,7 @@ static char *supply_interface[] = { static int ab8500_btemp_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct abx500_bm_data *plat = pdev->dev.platform_data; struct ab8500_btemp *di; int irq, i, ret = 0; u8 val; Loading @@ -976,21 +986,19 @@ static int ab8500_btemp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__); return -ENOMEM; } di->bat = pdev->mfd_cell->platform_data; if (!di->bat) { if (!plat) { dev_err(&pdev->dev, "no battery management data supplied\n"); return -EINVAL; } di->bm = plat; if (np) { ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); dev_err(&pdev->dev, "failed to get battery information\n"); return ret; } } else { dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n"); return -EINVAL; } } else { dev_info(&pdev->dev, "falling back to legacy platform data\n"); } /* get parent data */ Loading @@ -998,6 +1006,8 @@ static int ab8500_btemp_probe(struct platform_device *pdev) di->parent = dev_get_drvdata(pdev->dev.parent); di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); di->initialized = false; /* BTEMP supply */ di->btemp_psy.name = "ab8500_btemp"; di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY; Loading @@ -1022,10 +1032,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, ab8500_btemp_periodic_work); /* Identify the battery */ if (ab8500_btemp_id(di) < 0) dev_warn(di->dev, "failed to identify the battery\n"); /* Set BTEMP thermal limits. Low and Med are fixed */ di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; Loading drivers/power/ab8500_charger.c +158 −64 Original line number Diff line number Diff line Loading @@ -79,6 +79,9 @@ /* Lowest charger voltage is 3.39V -> 0x4E */ #define LOW_VOLT_REG 0x4E /* Step up/down delay in us */ #define STEP_UDELAY 1000 /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, Loading Loading @@ -186,7 +189,7 @@ struct ab8500_charger_usb_state { * @autopower_cfg platform specific power config support for "pwron after pwrloss" * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @bat: Pointer to the abx500_bm platform data * @bm: Platform specific battery management information * @flags: Structure for information about events triggered * @usb_state: Structure for usb stack information * @ac_chg: AC charger power supply Loading Loading @@ -223,7 +226,7 @@ struct ab8500_charger { bool autopower_cfg; struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct abx500_bm_data *bat; struct abx500_bm_data *bm; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; struct ux500_charger ac_chg; Loading Loading @@ -935,6 +938,88 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) return 0; } /** * ab8500_charger_set_current() - set charger current * @di: pointer to the ab8500_charger structure * @ich: charger current, in mA * @reg: select what charger register to set * * Set charger current. * There is no state machine in the AB to step up/down the charger * current to avoid dips and spikes on MAIN, VBUS and VBAT when * charging is started. Instead we need to implement * this charger current step-up/down here. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_current(struct ab8500_charger *di, int ich, int reg) { int ret, i; int curr_index, prev_curr_index, shift_value; u8 reg_value; switch (reg) { case AB8500_MCH_IPT_CURLVL_REG: shift_value = MAIN_CH_INPUT_CURR_SHIFT; curr_index = ab8500_current_to_regval(ich); break; case AB8500_USBCH_IPT_CRNTLVL_REG: shift_value = VBUS_IN_CURR_LIM_SHIFT; curr_index = ab8500_vbus_in_curr_to_regval(ich); break; case AB8500_CH_OPT_CRNTLVL_REG: shift_value = 0; curr_index = ab8500_current_to_regval(ich); break; default: dev_err(di->dev, "%s current register not valid\n", __func__); return -ENXIO; } if (curr_index < 0) { dev_err(di->dev, "requested current limit out-of-range\n"); return -ENXIO; } ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, reg, ®_value); if (ret < 0) { dev_err(di->dev, "%s read failed\n", __func__); return ret; } prev_curr_index = (reg_value >> shift_value); /* only update current if it's been changed */ if (prev_curr_index == curr_index) return 0; dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", __func__, ich, reg); if (prev_curr_index > curr_index) { for (i = prev_curr_index - 1; i >= curr_index; i--) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, reg, (u8) i << shift_value); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); return ret; } usleep_range(STEP_UDELAY, STEP_UDELAY * 2); } } else { for (i = prev_curr_index + 1; i <= curr_index; i++) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, reg, (u8) i << shift_value); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); return ret; } usleep_range(STEP_UDELAY, STEP_UDELAY * 2); } } return ret; } /** * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit * @di: pointer to the ab8500_charger structure Loading @@ -946,12 +1031,10 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, int ich_in) { int ret; int input_curr_index; int min_value; /* We should always use to lowest current limit */ min_value = min(di->bat->chg_params->usb_curr_max, ich_in); min_value = min(di->bm->chg_params->usb_curr_max, ich_in); switch (min_value) { case 100: Loading @@ -966,19 +1049,38 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, break; } input_curr_index = ab8500_vbus_in_curr_to_regval(min_value); if (input_curr_index < 0) { dev_err(di->dev, "VBUS input current limit too high\n"); return -ENXIO; return ab8500_charger_set_current(di, min_value, AB8500_USBCH_IPT_CRNTLVL_REG); } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_USBCH_IPT_CRNTLVL_REG, input_curr_index << VBUS_IN_CURR_LIM_SHIFT); if (ret) dev_err(di->dev, "%s write failed\n", __func__); /** * ab8500_charger_set_main_in_curr() - set main charger input current * @di: pointer to the ab8500_charger structure * @ich_in: input charger current, in mA * * Set main charger input current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, int ich_in) { return ab8500_charger_set_current(di, ich_in, AB8500_MCH_IPT_CURLVL_REG); } return ret; /** * ab8500_charger_set_output_curr() - set charger output current * @di: pointer to the ab8500_charger structure * @ich_out: output charger current, in mA * * Set charger output current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_output_curr(struct ab8500_charger *di, int ich_out) { return ab8500_charger_set_current(di, ich_out, AB8500_CH_OPT_CRNTLVL_REG); } /** Loading Loading @@ -1074,7 +1176,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, volt_index = ab8500_voltage_to_regval(vset); curr_index = ab8500_current_to_regval(iset); input_curr_index = ab8500_current_to_regval( di->bat->chg_params->ac_curr_max); di->bm->chg_params->ac_curr_max); if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " Loading @@ -1090,23 +1192,24 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, return ret; } /* MainChInputCurr: current that can be drawn from the charger*/ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_MCH_IPT_CURLVL_REG, input_curr_index << MAIN_CH_INPUT_CURR_SHIFT); ret = ab8500_charger_set_main_in_curr(di, di->bm->chg_params->ac_curr_max); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s Failed to set MainChInputCurr\n", __func__); return ret; } /* ChOutputCurentLevel: protected output current */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, iset); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } /* Check if VBAT overshoot control should be enabled */ if (!di->bat->enable_overshoot) if (!di->bm->enable_overshoot) overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; /* Enable Main Charger */ Loading Loading @@ -1158,12 +1261,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, return ret; } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1); ret = ab8500_charger_set_output_curr(di, 0); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } } else { Loading Loading @@ -1266,14 +1368,15 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return ret; } /* ChOutputCurentLevel: protected output current */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, ich_out); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } /* Check if VBAT overshoot control should be enabled */ if (!di->bat->enable_overshoot) if (!di->bm->enable_overshoot) overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; /* Enable USB Charger */ Loading Loading @@ -1366,7 +1469,6 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, int ich_out) { int ret; int curr_index; struct ab8500_charger *di; if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS) Loading @@ -1376,18 +1478,11 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, else return -ENXIO; curr_index = ab8500_current_to_regval(ich_out); if (curr_index < 0) { dev_err(di->dev, "Charger current too high, " "charging not started\n"); return -ENXIO; } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, ich_out); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } Loading Loading @@ -2359,8 +2454,8 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_BACKUP_CHG_REG, di->bat->bkup_bat_v | di->bat->bkup_bat_i); di->bm->bkup_bat_v | di->bm->bkup_bat_i); if (ret) { dev_err(di->dev, "failed to setup backup battery charging\n"); goto out; Loading Loading @@ -2541,6 +2636,7 @@ static char *supply_interface[] = { static int ab8500_charger_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct abx500_bm_data *plat = pdev->dev.platform_data; struct ab8500_charger *di; int irq, i, charger_status, ret = 0; Loading @@ -2549,24 +2645,22 @@ static int ab8500_charger_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); return -ENOMEM; } di->bat = pdev->mfd_cell->platform_data; if (!di->bat) { if (!plat) { dev_err(&pdev->dev, "no battery management data supplied\n"); return -EINVAL; } di->bm = plat; if (np) { ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); dev_err(&pdev->dev, "failed to get battery information\n"); return ret; } di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); } else { dev_err(&pdev->dev, "missing dt node for ab8500_charger\n"); return -EINVAL; } } else { dev_info(&pdev->dev, "falling back to legacy platform data\n"); } else di->autopower_cfg = false; } /* get parent data */ di->dev = &pdev->dev; Loading Loading
drivers/mfd/ab8500-core.c +0 −8 Original line number Diff line number Diff line Loading @@ -1011,40 +1011,32 @@ static struct mfd_cell ab8500_bm_devs[] = { .of_compatible = "stericsson,ab8500-charger", .num_resources = ARRAY_SIZE(ab8500_charger_resources), .resources = ab8500_charger_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-btemp", .of_compatible = "stericsson,ab8500-btemp", .num_resources = ARRAY_SIZE(ab8500_btemp_resources), .resources = ab8500_btemp_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-fg", .of_compatible = "stericsson,ab8500-fg", .num_resources = ARRAY_SIZE(ab8500_fg_resources), .resources = ab8500_fg_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, { .name = "ab8500-chargalg", .of_compatible = "stericsson,ab8500-chargalg", .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), .resources = ab8500_chargalg_resources, #ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), #endif }, }; Loading
drivers/power/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ 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_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o 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 Loading
drivers/power/ab8500_bmdata.c +254 −269 Original line number Diff line number Diff line Loading @@ -452,70 +452,55 @@ struct abx500_bm_data ab8500_bm_data = { .fg_params = &fg, }; int __devinit bmdevs_of_probe(struct device *dev, int __devinit ab8500_bm_of_probe(struct device *dev, struct device_node *np, struct abx500_bm_data **battery) struct abx500_bm_data *bm) { struct abx500_battery_type *btype; struct device_node *np_bat_supply; struct abx500_bm_data *bat; struct batres_vs_temp *tmp_batres_tbl; struct device_node *battery_node; const char *btech; char bat_tech[8]; int i, thermistor; *battery = &ab8500_bm_data; int i; /* get phandle to 'battery-info' node */ np_bat_supply = of_parse_phandle(np, "battery", 0); if (!np_bat_supply) { dev_err(dev, "missing property battery\n"); battery_node = of_parse_phandle(np, "battery", 0); if (!battery_node) { dev_err(dev, "battery node or reference missing\n"); return -EINVAL; } if (of_property_read_bool(np_bat_supply, "thermistor-on-batctrl")) thermistor = NTC_INTERNAL; else thermistor = NTC_EXTERNAL; bat = *battery; if (thermistor == NTC_EXTERNAL) { bat->n_btypes = 4; bat->bat_type = bat_type_ext_thermistor; bat->adc_therm = ABx500_ADC_THERM_BATTEMP; } btech = of_get_property(np_bat_supply, "stericsson,battery-type", NULL); btech = of_get_property(battery_node, "stericsson,battery-type", NULL); if (!btech) { dev_warn(dev, "missing property battery-name/type\n"); strcpy(bat_tech, "UNKNOWN"); } else { strcpy(bat_tech, btech); return -EINVAL; } if (strncmp(bat_tech, "LION", 4) == 0) { bat->no_maintenance = true; bat->chg_unknown_bat = true; bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; if (strncmp(btech, "LION", 4) == 0) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; bm->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } /* select the battery resolution table */ for (i = 0; i < bat->n_btypes; ++i) { btype = (bat->bat_type + i); if (thermistor == NTC_EXTERNAL) { btype->batres_tbl = temp_to_batres_tbl_ext_thermistor; } else if (strncmp(bat_tech, "LION", 4) == 0) { btype->batres_tbl = temp_to_batres_tbl_9100; if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) { if (strncmp(btech, "LION", 4) == 0) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; } else { btype->batres_tbl = temp_to_batres_tbl_thermistor; } bm->n_btypes = 4; bm->bat_type = bat_type_ext_thermistor; bm->adc_therm = ABx500_ADC_THERM_BATTEMP; tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; } of_node_put(np_bat_supply); /* select the battery resolution table */ for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; of_node_put(battery_node); return 0; }
drivers/power/ab8500_btemp.c +51 −45 Original line number Diff line number Diff line Loading @@ -78,12 +78,13 @@ struct ab8500_btemp_ranges { * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @fg: Pointer to the struct fg * @bat: Pointer to the abx500_bm platform data * @bm: Platform specific battery management information * @btemp_psy: Structure for BTEMP specific battery properties * @events: Structure for information about events triggered * @btemp_ranges: Battery temperature range structure * @btemp_wq: Work queue for measuring the temperature periodically * @btemp_periodic_work: Work for measuring the temperature periodically * @initialized: True if battery id read. */ struct ab8500_btemp { struct device *dev; Loading @@ -94,12 +95,13 @@ struct ab8500_btemp { struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct ab8500_fg *fg; struct abx500_bm_data *bat; struct abx500_bm_data *bm; struct power_supply btemp_psy; struct ab8500_btemp_events events; struct ab8500_btemp_ranges btemp_ranges; struct workqueue_struct *btemp_wq; struct delayed_work btemp_periodic_work; bool initialized; }; /* BTEMP power supply properties */ Loading Loading @@ -147,13 +149,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di, return (450000 * (v_batctrl)) / (1800 - v_batctrl); } if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) { /* * If the battery has internal NTC, we use the current * source to calculate the resistance, 7uA or 20uA */ rbs = (v_batctrl * 1000 - di->bat->gnd_lift_resistance * inst_curr) - di->bm->gnd_lift_resistance * inst_curr) / di->curr_source; } else { /* Loading Loading @@ -209,7 +211,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, return 0; /* Only do this for batteries with internal NTC */ if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) curr = BAT_CTRL_7U_ENA; else Loading Loading @@ -241,7 +243,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, __func__); goto disable_curr_source; } } else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { } else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { dev_dbg(di->dev, "Disable BATCTRL curr source\n"); /* Write 0 to the curr bits */ Loading Loading @@ -457,9 +459,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int rbat, rntc, vntc; u8 id; id = di->bat->batt_id; id = di->bm->batt_id; if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && id != BATTERY_UNKNOWN) { rbat = ab8500_btemp_get_batctrl_res(di); Loading @@ -474,8 +476,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) } temp = ab8500_btemp_res_to_temp(di, di->bat->bat_type[id].r_to_t_tbl, di->bat->bat_type[id].n_temp_tbl_elements, rbat); di->bm->bat_type[id].r_to_t_tbl, di->bm->bat_type[id].n_temp_tbl_elements, rbat); } else { vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { Loading @@ -491,8 +493,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) rntc = 230000 * vntc / (VTVOUT_V - vntc); temp = ab8500_btemp_res_to_temp(di, di->bat->bat_type[id].r_to_t_tbl, di->bat->bat_type[id].n_temp_tbl_elements, rntc); di->bm->bat_type[id].r_to_t_tbl, di->bm->bat_type[id].n_temp_tbl_elements, rntc); prev = temp; } dev_dbg(di->dev, "Battery temperature is %d\n", temp); Loading @@ -513,7 +515,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) u8 i; di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; di->bat->batt_id = BATTERY_UNKNOWN; di->bm->batt_id = BATTERY_UNKNOWN; res = ab8500_btemp_get_batctrl_res(di); if (res < 0) { Loading @@ -522,23 +524,23 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) } /* BATTERY_UNKNOWN is defined on position 0, skip it! */ for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) { if ((res <= di->bat->bat_type[i].resis_high) && (res >= di->bat->bat_type[i].resis_low)) { for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { if ((res <= di->bm->bat_type[i].resis_high) && (res >= di->bm->bat_type[i].resis_low)) { dev_dbg(di->dev, "Battery detected on %s" " low %d < res %d < high: %d" " index: %d\n", di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ? di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ? "BATCTRL" : "BATTEMP", di->bat->bat_type[i].resis_low, res, di->bat->bat_type[i].resis_high, i); di->bm->bat_type[i].resis_low, res, di->bm->bat_type[i].resis_high, i); di->bat->batt_id = i; di->bm->batt_id = i; break; } } if (di->bat->batt_id == BATTERY_UNKNOWN) { if (di->bm->batt_id == BATTERY_UNKNOWN) { dev_warn(di->dev, "Battery identified as unknown" ", resistance %d Ohm\n", res); return -ENXIO; Loading @@ -548,13 +550,13 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * We only have to change current source if the * detected type is Type 1, else we use the 7uA source */ if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && di->bat->batt_id == 1) { if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && di->bm->batt_id == 1) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; } return di->bat->batt_id; return di->bm->batt_id; } /** Loading @@ -569,6 +571,13 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) struct ab8500_btemp *di = container_of(work, struct ab8500_btemp, btemp_periodic_work.work); if (!di->initialized) { di->initialized = true; /* Identify the battery */ if (ab8500_btemp_id(di) < 0) dev_warn(di->dev, "failed to identify the battery\n"); } di->bat_temp = ab8500_btemp_measure_temp(di); if (di->bat_temp != di->prev_bat_temp) { Loading @@ -577,9 +586,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) } if (di->events.ac_conn || di->events.usb_conn) interval = di->bat->temp_interval_chg; interval = di->bm->temp_interval_chg; else interval = di->bat->temp_interval_nochg; interval = di->bm->temp_interval_nochg; /* Schedule a new measurement */ queue_delayed_work(di->btemp_wq, Loading Loading @@ -806,7 +815,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = di->bat->bat_type[di->bat->batt_id].name; val->intval = di->bm->bat_type[di->bm->batt_id].name; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); Loading Loading @@ -967,6 +976,7 @@ static char *supply_interface[] = { static int ab8500_btemp_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct abx500_bm_data *plat = pdev->dev.platform_data; struct ab8500_btemp *di; int irq, i, ret = 0; u8 val; Loading @@ -976,21 +986,19 @@ static int ab8500_btemp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__); return -ENOMEM; } di->bat = pdev->mfd_cell->platform_data; if (!di->bat) { if (!plat) { dev_err(&pdev->dev, "no battery management data supplied\n"); return -EINVAL; } di->bm = plat; if (np) { ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); dev_err(&pdev->dev, "failed to get battery information\n"); return ret; } } else { dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n"); return -EINVAL; } } else { dev_info(&pdev->dev, "falling back to legacy platform data\n"); } /* get parent data */ Loading @@ -998,6 +1006,8 @@ static int ab8500_btemp_probe(struct platform_device *pdev) di->parent = dev_get_drvdata(pdev->dev.parent); di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); di->initialized = false; /* BTEMP supply */ di->btemp_psy.name = "ab8500_btemp"; di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY; Loading @@ -1022,10 +1032,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, ab8500_btemp_periodic_work); /* Identify the battery */ if (ab8500_btemp_id(di) < 0) dev_warn(di->dev, "failed to identify the battery\n"); /* Set BTEMP thermal limits. Low and Med are fixed */ di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; Loading
drivers/power/ab8500_charger.c +158 −64 Original line number Diff line number Diff line Loading @@ -79,6 +79,9 @@ /* Lowest charger voltage is 3.39V -> 0x4E */ #define LOW_VOLT_REG 0x4E /* Step up/down delay in us */ #define STEP_UDELAY 1000 /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, Loading Loading @@ -186,7 +189,7 @@ struct ab8500_charger_usb_state { * @autopower_cfg platform specific power config support for "pwron after pwrloss" * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @bat: Pointer to the abx500_bm platform data * @bm: Platform specific battery management information * @flags: Structure for information about events triggered * @usb_state: Structure for usb stack information * @ac_chg: AC charger power supply Loading Loading @@ -223,7 +226,7 @@ struct ab8500_charger { bool autopower_cfg; struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct abx500_bm_data *bat; struct abx500_bm_data *bm; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; struct ux500_charger ac_chg; Loading Loading @@ -935,6 +938,88 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) return 0; } /** * ab8500_charger_set_current() - set charger current * @di: pointer to the ab8500_charger structure * @ich: charger current, in mA * @reg: select what charger register to set * * Set charger current. * There is no state machine in the AB to step up/down the charger * current to avoid dips and spikes on MAIN, VBUS and VBAT when * charging is started. Instead we need to implement * this charger current step-up/down here. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_current(struct ab8500_charger *di, int ich, int reg) { int ret, i; int curr_index, prev_curr_index, shift_value; u8 reg_value; switch (reg) { case AB8500_MCH_IPT_CURLVL_REG: shift_value = MAIN_CH_INPUT_CURR_SHIFT; curr_index = ab8500_current_to_regval(ich); break; case AB8500_USBCH_IPT_CRNTLVL_REG: shift_value = VBUS_IN_CURR_LIM_SHIFT; curr_index = ab8500_vbus_in_curr_to_regval(ich); break; case AB8500_CH_OPT_CRNTLVL_REG: shift_value = 0; curr_index = ab8500_current_to_regval(ich); break; default: dev_err(di->dev, "%s current register not valid\n", __func__); return -ENXIO; } if (curr_index < 0) { dev_err(di->dev, "requested current limit out-of-range\n"); return -ENXIO; } ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, reg, ®_value); if (ret < 0) { dev_err(di->dev, "%s read failed\n", __func__); return ret; } prev_curr_index = (reg_value >> shift_value); /* only update current if it's been changed */ if (prev_curr_index == curr_index) return 0; dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", __func__, ich, reg); if (prev_curr_index > curr_index) { for (i = prev_curr_index - 1; i >= curr_index; i--) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, reg, (u8) i << shift_value); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); return ret; } usleep_range(STEP_UDELAY, STEP_UDELAY * 2); } } else { for (i = prev_curr_index + 1; i <= curr_index; i++) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, reg, (u8) i << shift_value); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); return ret; } usleep_range(STEP_UDELAY, STEP_UDELAY * 2); } } return ret; } /** * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit * @di: pointer to the ab8500_charger structure Loading @@ -946,12 +1031,10 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, int ich_in) { int ret; int input_curr_index; int min_value; /* We should always use to lowest current limit */ min_value = min(di->bat->chg_params->usb_curr_max, ich_in); min_value = min(di->bm->chg_params->usb_curr_max, ich_in); switch (min_value) { case 100: Loading @@ -966,19 +1049,38 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, break; } input_curr_index = ab8500_vbus_in_curr_to_regval(min_value); if (input_curr_index < 0) { dev_err(di->dev, "VBUS input current limit too high\n"); return -ENXIO; return ab8500_charger_set_current(di, min_value, AB8500_USBCH_IPT_CRNTLVL_REG); } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_USBCH_IPT_CRNTLVL_REG, input_curr_index << VBUS_IN_CURR_LIM_SHIFT); if (ret) dev_err(di->dev, "%s write failed\n", __func__); /** * ab8500_charger_set_main_in_curr() - set main charger input current * @di: pointer to the ab8500_charger structure * @ich_in: input charger current, in mA * * Set main charger input current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, int ich_in) { return ab8500_charger_set_current(di, ich_in, AB8500_MCH_IPT_CURLVL_REG); } return ret; /** * ab8500_charger_set_output_curr() - set charger output current * @di: pointer to the ab8500_charger structure * @ich_out: output charger current, in mA * * Set charger output current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_output_curr(struct ab8500_charger *di, int ich_out) { return ab8500_charger_set_current(di, ich_out, AB8500_CH_OPT_CRNTLVL_REG); } /** Loading Loading @@ -1074,7 +1176,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, volt_index = ab8500_voltage_to_regval(vset); curr_index = ab8500_current_to_regval(iset); input_curr_index = ab8500_current_to_regval( di->bat->chg_params->ac_curr_max); di->bm->chg_params->ac_curr_max); if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " Loading @@ -1090,23 +1192,24 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, return ret; } /* MainChInputCurr: current that can be drawn from the charger*/ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_MCH_IPT_CURLVL_REG, input_curr_index << MAIN_CH_INPUT_CURR_SHIFT); ret = ab8500_charger_set_main_in_curr(di, di->bm->chg_params->ac_curr_max); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s Failed to set MainChInputCurr\n", __func__); return ret; } /* ChOutputCurentLevel: protected output current */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, iset); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } /* Check if VBAT overshoot control should be enabled */ if (!di->bat->enable_overshoot) if (!di->bm->enable_overshoot) overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; /* Enable Main Charger */ Loading Loading @@ -1158,12 +1261,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, return ret; } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1); ret = ab8500_charger_set_output_curr(di, 0); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } } else { Loading Loading @@ -1266,14 +1368,15 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return ret; } /* ChOutputCurentLevel: protected output current */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, ich_out); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } /* Check if VBAT overshoot control should be enabled */ if (!di->bat->enable_overshoot) if (!di->bm->enable_overshoot) overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; /* Enable USB Charger */ Loading Loading @@ -1366,7 +1469,6 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, int ich_out) { int ret; int curr_index; struct ab8500_charger *di; if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS) Loading @@ -1376,18 +1478,11 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, else return -ENXIO; curr_index = ab8500_current_to_regval(ich_out); if (curr_index < 0) { dev_err(di->dev, "Charger current too high, " "charging not started\n"); return -ENXIO; } ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); ret = ab8500_charger_set_output_curr(di, ich_out); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", __func__); return ret; } Loading Loading @@ -2359,8 +2454,8 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_BACKUP_CHG_REG, di->bat->bkup_bat_v | di->bat->bkup_bat_i); di->bm->bkup_bat_v | di->bm->bkup_bat_i); if (ret) { dev_err(di->dev, "failed to setup backup battery charging\n"); goto out; Loading Loading @@ -2541,6 +2636,7 @@ static char *supply_interface[] = { static int ab8500_charger_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct abx500_bm_data *plat = pdev->dev.platform_data; struct ab8500_charger *di; int irq, i, charger_status, ret = 0; Loading @@ -2549,24 +2645,22 @@ static int ab8500_charger_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); return -ENOMEM; } di->bat = pdev->mfd_cell->platform_data; if (!di->bat) { if (!plat) { dev_err(&pdev->dev, "no battery management data supplied\n"); return -EINVAL; } di->bm = plat; if (np) { ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); dev_err(&pdev->dev, "failed to get battery information\n"); return ret; } di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); } else { dev_err(&pdev->dev, "missing dt node for ab8500_charger\n"); return -EINVAL; } } else { dev_info(&pdev->dev, "falling back to legacy platform data\n"); } else di->autopower_cfg = false; } /* get parent data */ di->dev = &pdev->dev; Loading