mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
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: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
parent
bf584e4dbd
commit
92f7d90972
2 changed files with 56 additions and 89 deletions
|
@ -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
|
||||
|
|
|
@ -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(¤t_limit_ranges[0],
|
||||
ARRAY_SIZE(current_limit_ranges), sel,
|
||||
ma);
|
||||
|
||||
ret = linear_range_get_value_array(¤t_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,
|
||||
®, &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, ®, &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(¤t_limit_ranges[0],
|
||||
ARRAY_SIZE(current_limit_ranges), ma,
|
||||
®, &found);
|
||||
ret = linear_range_get_selector_low_array(current_limit_ranges,
|
||||
ARRAY_SIZE(current_limit_ranges),
|
||||
ma, ®, &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:
|
||||
|
|
Loading…
Reference in a new issue