Skip to content

Commit

Permalink
power: supply: rn5t618: Add input current limit
Browse files Browse the repository at this point in the history
Adds properties for setting the maximum current to USB, ADP and Battery
supplies. USB and ADP limits are reset to OTP values upon replugging.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
  • Loading branch information
Andreas Kemnade authored and Sebastian Reichel committed Jun 3, 2021
1 parent 7d76367 commit 20a3c8b
Showing 1 changed file with 188 additions and 0 deletions.
188 changes: 188 additions & 0 deletions drivers/power/supply/rn5t618_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@

#define FG_ENABLE 1

/*
* Formula seems accurate for battery current, but for USB current around 70mA
* per step was seen on Kobo Clara HD but all sources show the same formula
* also fur USB current. To avoid accidentially unwanted high currents we stick
* to that formula
*/
#define TO_CUR_REG(x) ((x) / 100000 - 1)
#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
#define CHG_MIN_CUR 100000
#define CHG_MAX_CUR 1800000
#define ADP_MAX_CUR 2500000
#define USB_MAX_CUR 1400000


struct rn5t618_power_info {
struct rn5t618 *rn5t618;
struct platform_device *pdev;
Expand All @@ -61,12 +75,16 @@ static enum power_supply_usb_type rn5t618_usb_types[] = {
};

static enum power_supply_property rn5t618_usb_props[] = {
/* input current limit is not very accurate */
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_ONLINE,
};

static enum power_supply_property rn5t618_adp_props[] = {
/* input current limit is not very accurate */
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
};
Expand All @@ -82,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
};
Expand Down Expand Up @@ -271,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
return 0;
}

static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
const union power_supply_propval *val)
{
if (val->intval < CHG_MIN_CUR)
return -EINVAL;

if (val->intval >= CHG_MAX_CUR)
return -EINVAL;

return regmap_update_bits(info->rn5t618->regmap,
RN5T618_CHGISET,
0x1F, TO_CUR_REG(val->intval));
}

static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
unsigned int regval;
int ret;

ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
&regval);
if (ret < 0)
return ret;

val->intval = FROM_CUR_REG(regval);

return 0;
}

static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
Expand Down Expand Up @@ -336,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
ret = rn5t618_battery_get_current_limit(info, val);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = rn5t618_battery_charge_full(info, val);
break;
Expand All @@ -349,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
return ret;
}

static int rn5t618_battery_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);

switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return rn5t618_battery_set_current_limit(info, val);
default:
return -EINVAL;
}
}

static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return true;
default:
return false;
}
}

static int rn5t618_adp_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate;
unsigned int regval;
bool online;
int ret;

Expand All @@ -377,6 +455,14 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;

break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(info->rn5t618->regmap,
RN5T618_REGISET1, &regval);
if (ret < 0)
return ret;

val->intval = FROM_CUR_REG(regval);
break;
default:
return -EINVAL;
Expand All @@ -385,6 +471,45 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
return 0;
}

static int rn5t618_adp_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
int ret;

switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (val->intval > ADP_MAX_CUR)
return -EINVAL;

if (val->intval < CHG_MIN_CUR)
return -EINVAL;

ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
TO_CUR_REG(val->intval));
if (ret < 0)
return ret;

break;
default:
return -EINVAL;
}

return 0;
}

static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
return false;
}
}

static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
Expand Down Expand Up @@ -418,6 +543,7 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate;
unsigned int regval;
bool online;
int ret;

Expand Down Expand Up @@ -446,19 +572,77 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
return -ENODATA;

return rc5t619_usb_get_type(info, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
&regval);
if (ret < 0)
return ret;

val->intval = 0;
if (regval & 2) {
ret = regmap_read(info->rn5t618->regmap,
RN5T618_REGISET2,
&regval);
if (ret < 0)
return ret;

val->intval = FROM_CUR_REG(regval);
}
break;
default:
return -EINVAL;
}

return 0;
}

static int rn5t618_usb_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
int ret;

switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (val->intval > USB_MAX_CUR)
return -EINVAL;

if (val->intval < CHG_MIN_CUR)
return -EINVAL;

ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
0xE0 | TO_CUR_REG(val->intval));
if (ret < 0)
return ret;

break;
default:
return -EINVAL;
}

return 0;
}

static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
return false;
}
}

static const struct power_supply_desc rn5t618_battery_desc = {
.name = "rn5t618-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = rn5t618_battery_props,
.num_properties = ARRAY_SIZE(rn5t618_battery_props),
.get_property = rn5t618_battery_get_property,
.set_property = rn5t618_battery_set_property,
.property_is_writeable = rn5t618_battery_property_is_writeable,
};

static const struct power_supply_desc rn5t618_adp_desc = {
Expand All @@ -467,6 +651,8 @@ static const struct power_supply_desc rn5t618_adp_desc = {
.properties = rn5t618_adp_props,
.num_properties = ARRAY_SIZE(rn5t618_adp_props),
.get_property = rn5t618_adp_get_property,
.set_property = rn5t618_adp_set_property,
.property_is_writeable = rn5t618_adp_property_is_writeable,
};

static const struct power_supply_desc rn5t618_usb_desc = {
Expand All @@ -477,6 +663,8 @@ static const struct power_supply_desc rn5t618_usb_desc = {
.properties = rn5t618_usb_props,
.num_properties = ARRAY_SIZE(rn5t618_usb_props),
.get_property = rn5t618_usb_get_property,
.set_property = rn5t618_usb_set_property,
.property_is_writeable = rn5t618_usb_property_is_writeable,
};

static irqreturn_t rn5t618_charger_irq(int irq, void *data)
Expand Down

0 comments on commit 20a3c8b

Please sign in to comment.