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

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
...@@ -706,6 +706,7 @@ config CHARGER_UCS1002 ...@@ -706,6 +706,7 @@ config CHARGER_UCS1002
config CHARGER_BD70528 config CHARGER_BD70528
tristate "ROHM bd70528 charger driver" tristate "ROHM bd70528 charger driver"
depends on MFD_ROHM_BD70528 depends on MFD_ROHM_BD70528
select LINEAR_RANGES
default n default n
help help
Say Y here to enable support for getting battery status Say Y here to enable support for getting battery status
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/linear_range.h>
#define CHG_STAT_SUSPEND 0x0 #define CHG_STAT_SUSPEND 0x0
#define CHG_STAT_TRICKLE 0x1 #define CHG_STAT_TRICKLE 0x1
...@@ -335,38 +336,37 @@ static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val) ...@@ -335,38 +336,37 @@ static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val)
return 0; return 0;
} }
struct bd70528_linear_range { static const struct linear_range current_limit_ranges[] = {
int min;
int step;
int vals;
int low_sel;
};
static const struct bd70528_linear_range current_limit_ranges[] = {
{ {
.min = 5, .min = 5,
.step = 1, .step = 1,
.vals = 36, .min_sel = 0,
.low_sel = 0, .max_sel = 0x22,
}, },
{ {
.min = 40, .min = 40,
.step = 5, .step = 5,
.vals = 5, .min_sel = 0x23,
.low_sel = 0x23, .max_sel = 0x26,
}, },
{ {
.min = 60, .min = 60,
.step = 20, .step = 20,
.vals = 8, .min_sel = 0x27,
.low_sel = 0x27, .max_sel = 0x2d,
}, },
{ {
.min = 200, .min = 200,
.step = 50, .step = 50,
.vals = 7, .min_sel = 0x2e,
.low_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[] = { ...@@ -374,18 +374,18 @@ static const struct bd70528_linear_range current_limit_ranges[] = {
* voltage for low temperatures. The driver currently only reads * voltage for low temperatures. The driver currently only reads
* the charge current at room temperature. We do set both though. * 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, .min = 10,
.step = 10, .step = 10,
.vals = 20, .min_sel = 0,
.low_sel = 0, .max_sel = 0x12,
}, },
{ {
.min = 200, .min = 200,
.step = 25, .step = 25,
.vals = 13, .min_sel = 0x13,
.low_sel = 0x13, .max_sel = 0x1f,
}, },
}; };
...@@ -398,56 +398,6 @@ static const struct bd70528_linear_range warm_charge_curr[] = { ...@@ -398,56 +398,6 @@ static const struct bd70528_linear_range warm_charge_curr[] = {
#define MAX_WARM_CHG_CURR_SEL 0x1f #define MAX_WARM_CHG_CURR_SEL 0x1f
#define MIN_CHG_CURR_SEL 0x0 #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) static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)
{ {
unsigned int sel; unsigned int sel;
...@@ -463,9 +413,9 @@ static int get_charge_current(struct bd70528_psy *bdpsy, int *ma) ...@@ -463,9 +413,9 @@ static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)
sel &= BD70528_MASK_CHG_CHG_CURR; sel &= BD70528_MASK_CHG_CHG_CURR;
ret = find_value_for_selector_low(&warm_charge_curr[0], ret = linear_range_get_value_array(&warm_charge_curr[0],
ARRAY_SIZE(warm_charge_curr), sel, ARRAY_SIZE(warm_charge_curr),
ma); sel, ma);
if (ret) { if (ret) {
dev_err(bdpsy->dev, dev_err(bdpsy->dev,
"Unknown charge current value 0x%x\n", "Unknown charge current value 0x%x\n",
...@@ -491,10 +441,9 @@ static int get_current_limit(struct bd70528_psy *bdpsy, int *ma) ...@@ -491,10 +441,9 @@ static int get_current_limit(struct bd70528_psy *bdpsy, int *ma)
sel &= BD70528_MASK_CHG_DCIN_ILIM; sel &= BD70528_MASK_CHG_DCIN_ILIM;
ret = find_value_for_selector_low(&current_limit_ranges[0], ret = linear_range_get_value_array(&current_limit_ranges[0],
ARRAY_SIZE(current_limit_ranges), sel, ARRAY_SIZE(current_limit_ranges),
ma); sel, ma);
if (ret) { if (ret) {
/* Unspecified values mean 500 mA */ /* Unspecified values mean 500 mA */
*ma = 500; *ma = 500;
...@@ -588,15 +537,28 @@ static int set_charge_current(struct bd70528_psy *bdpsy, int ma) ...@@ -588,15 +537,28 @@ static int set_charge_current(struct bd70528_psy *bdpsy, int ma)
goto set; goto set;
} }
ret = find_selector_for_value_low(&warm_charge_curr[0], /*
ARRAY_SIZE(warm_charge_curr), ma, * For BD70528 voltage/current limits we happily accept any value which
&reg, &found); * 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) { if (ret) {
dev_err(bdpsy->dev,
"Unsupported charge current %u mA\n", ma);
reg = MIN_CHG_CURR_SEL; reg = MIN_CHG_CURR_SEL;
goto set; goto set;
} }
if (!found) { 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, dev_warn(bdpsy->dev,
"Unsupported charge current %u mA\n", ma); "Unsupported charge current %u mA\n", ma);
} }
...@@ -648,17 +610,21 @@ static int set_current_limit(struct bd70528_psy *bdpsy, int ma) ...@@ -648,17 +610,21 @@ static int set_current_limit(struct bd70528_psy *bdpsy, int ma)
goto set; goto set;
} }
ret = find_selector_for_value_low(&current_limit_ranges[0], ret = linear_range_get_selector_low_array(current_limit_ranges,
ARRAY_SIZE(current_limit_ranges), ma, ARRAY_SIZE(current_limit_ranges),
&reg, &found); ma, &reg, &found);
if (ret) { if (ret) {
dev_err(bdpsy->dev, "Unsupported current limit %umA\n", ma);
reg = MIN_CURR_LIMIT_SEL; reg = MIN_CURR_LIMIT_SEL;
goto set; goto set;
} }
if (!found) { if (!found) {
/* There was a gap in supported values and we hit it ?*/ /*
dev_warn(bdpsy->dev, "Unsupported current limit %umA\n", * There was a gap in supported values and we hit it.
ma); * We found a smaller value from ranges and use it.
* Warn user though.
*/
dev_warn(bdpsy->dev, "Unsupported current limit %umA\n", ma);
} }
set: set:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment