Commit 92f7d909 authored by Matti Vaittinen's avatar Matti Vaittinen Committed by Sebastian Reichel
Browse files

power: supply: bd70528: use linear ranges



Change the bd70528 to use common linear_range code instead of
implementing a copy of it in this driver.

Signed-off-by: default avatarMatti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent bf584e4d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -706,6 +706,7 @@ config CHARGER_UCS1002
config CHARGER_BD70528
	tristate "ROHM bd70528 charger driver"
	depends on MFD_ROHM_BD70528
	select LINEAR_RANGES
	default n
	help
	 Say Y here to enable support for getting battery status
+55 −89
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/linear_range.h>

#define CHG_STAT_SUSPEND	0x0
#define CHG_STAT_TRICKLE	0x1
@@ -335,38 +336,37 @@ static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val)
	return 0;
}

struct bd70528_linear_range {
	int min;
	int step;
	int vals;
	int low_sel;
};

static const struct bd70528_linear_range current_limit_ranges[] = {
static const struct linear_range current_limit_ranges[] = {
	{
		.min = 5,
		.step = 1,
		.vals = 36,
		.low_sel = 0,
		.min_sel = 0,
		.max_sel = 0x22,
	},
	{
		.min = 40,
		.step = 5,
		.vals = 5,
		.low_sel = 0x23,
		.min_sel = 0x23,
		.max_sel = 0x26,
	},
	{
		.min = 60,
		.step = 20,
		.vals = 8,
		.low_sel = 0x27,
		.min_sel = 0x27,
		.max_sel = 0x2d,
	},
	{
		.min = 200,
		.step = 50,
		.vals = 7,
		.low_sel = 0x2e,
	}
		.min_sel = 0x2e,
		.max_sel = 0x34,
	},
	{
		.min = 500,
		.step = 0,
		.min_sel = 0x35,
		.max_sel = 0x3f,
	},
};

/*
@@ -374,18 +374,18 @@ static const struct bd70528_linear_range current_limit_ranges[] = {
 * voltage for low temperatures. The driver currently only reads
 * the charge current at room temperature. We do set both though.
 */
static const struct bd70528_linear_range warm_charge_curr[] = {
static const struct linear_range warm_charge_curr[] = {
	{
		.min = 10,
		.step = 10,
		.vals = 20,
		.low_sel = 0,
		.min_sel = 0,
		.max_sel = 0x12,
	},
	{
		.min = 200,
		.step = 25,
		.vals = 13,
		.low_sel = 0x13,
		.min_sel = 0x13,
		.max_sel = 0x1f,
	},
};

@@ -398,56 +398,6 @@ static const struct bd70528_linear_range warm_charge_curr[] = {
#define MAX_WARM_CHG_CURR_SEL 0x1f
#define MIN_CHG_CURR_SEL 0x0

static int find_value_for_selector_low(const struct bd70528_linear_range *r,
				       int selectors, unsigned int sel,
				       unsigned int *val)
{
	int i;

	for (i = 0; i < selectors; i++) {
		if (r[i].low_sel <= sel && r[i].low_sel + r[i].vals >= sel) {
			*val = r[i].min + (sel - r[i].low_sel) * r[i].step;
			return 0;
		}
	}
	return -EINVAL;
}

/*
 * For BD70528 voltage/current limits we happily accept any value which
 * belongs the range. We could check if value matching the selector is
 * desired by computing the range min + (sel - sel_low) * range step - but
 * I guess it is enough if we use voltage/current which is closest (below)
 * the requested?
 */
static int find_selector_for_value_low(const struct bd70528_linear_range *r,
				       int selectors, unsigned int val,
				       unsigned int *sel, bool *found)
{
	int i;
	int ret = -EINVAL;

	*found = false;
	for (i = 0; i < selectors; i++) {
		if (r[i].min <= val) {
			if (r[i].min + r[i].step * r[i].vals >= val) {
				*found = true;
				*sel = r[i].low_sel + (val - r[i].min) /
				       r[i].step;
				ret = 0;
				break;
			}
			/*
			 * If the range max is smaller than requested
			 * we can set the max supported value from range
			 */
			*sel = r[i].low_sel + r[i].vals;
			ret = 0;
		}
	}
	return ret;
}

static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)
{
	unsigned int sel;
@@ -463,9 +413,9 @@ static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)

	sel &= BD70528_MASK_CHG_CHG_CURR;

	ret = find_value_for_selector_low(&warm_charge_curr[0],
					  ARRAY_SIZE(warm_charge_curr), sel,
					  ma);
	ret = linear_range_get_value_array(&warm_charge_curr[0],
					   ARRAY_SIZE(warm_charge_curr),
					   sel, ma);
	if (ret) {
		dev_err(bdpsy->dev,
			"Unknown charge current value 0x%x\n",
@@ -491,10 +441,9 @@ static int get_current_limit(struct bd70528_psy *bdpsy, int *ma)

	sel &= BD70528_MASK_CHG_DCIN_ILIM;

	ret = find_value_for_selector_low(&current_limit_ranges[0],
					  ARRAY_SIZE(current_limit_ranges), sel,
					  ma);

	ret = linear_range_get_value_array(&current_limit_ranges[0],
					   ARRAY_SIZE(current_limit_ranges),
					   sel, ma);
	if (ret) {
		/* Unspecified values mean 500 mA */
		*ma = 500;
@@ -588,15 +537,28 @@ static int set_charge_current(struct bd70528_psy *bdpsy, int ma)
		goto set;
	}

	ret = find_selector_for_value_low(&warm_charge_curr[0],
					  ARRAY_SIZE(warm_charge_curr), ma,
					  &reg, &found);
/*
 * For BD70528 voltage/current limits we happily accept any value which
 * belongs the range. We could check if value matching the selector is
 * desired by computing the range min + (sel - sel_low) * range step - but
 * I guess it is enough if we use voltage/current which is closest (below)
 * the requested?
 */

	ret = linear_range_get_selector_low_array(warm_charge_curr,
						  ARRAY_SIZE(warm_charge_curr),
						  ma, &reg, &found);
	if (ret) {
		dev_err(bdpsy->dev,
			 "Unsupported charge current %u mA\n", ma);
		reg = MIN_CHG_CURR_SEL;
		goto set;
	}
	if (!found) {
		/* There was a gap in supported values and we hit it */
		/*
		 * There was a gap in supported values and we hit it.
		 * Yet a smaller value was found so we use it.
		 */
		dev_warn(bdpsy->dev,
			 "Unsupported charge current %u mA\n", ma);
	}
@@ -648,17 +610,21 @@ static int set_current_limit(struct bd70528_psy *bdpsy, int ma)
		goto set;
	}

	ret = find_selector_for_value_low(&current_limit_ranges[0],
					  ARRAY_SIZE(current_limit_ranges), ma,
					  &reg, &found);
	ret = linear_range_get_selector_low_array(current_limit_ranges,
					ARRAY_SIZE(current_limit_ranges),
					ma, &reg, &found);
	if (ret) {
		dev_err(bdpsy->dev, "Unsupported current limit %umA\n", ma);
		reg = MIN_CURR_LIMIT_SEL;
		goto set;
	}
	if (!found) {
		/* There was a gap in supported values and we hit it ?*/
		dev_warn(bdpsy->dev, "Unsupported current limit %umA\n",
			 ma);
		/*
		 * There was a gap in supported values and we hit it.
		 * We found a smaller value from ranges and use it.
		 * Warn user though.
		 */
		dev_warn(bdpsy->dev, "Unsupported current limit %umA\n", ma);
	}

set: