Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 240fbe23 authored by Anton Vorontsov's avatar Anton Vorontsov
Browse files
parents 2fbb520d 215cf5c9
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -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
	},
};

+1 −1
Original line number Diff line number Diff line
@@ -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
+254 −269
Original line number Diff line number Diff line
@@ -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;
}
+51 −45
Original line number Diff line number Diff line
@@ -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;
@@ -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 */
@@ -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 {
		/*
@@ -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
@@ -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 */
@@ -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);
@@ -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) {
@@ -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);
@@ -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) {
@@ -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;
@@ -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;
}

/**
@@ -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) {
@@ -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,
@@ -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);
@@ -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;
@@ -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 */
@@ -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;
@@ -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;
+158 −64
Original line number Diff line number Diff line
@@ -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,
@@ -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
@@ -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;
@@ -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, &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
@@ -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:
@@ -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);
}

/**
@@ -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, "
@@ -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 */
@@ -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 {
@@ -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 */
@@ -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)
@@ -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;
	}

@@ -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;
@@ -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;

@@ -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