-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
power_supply: wilco_ec: Add charging config driver
Add a driver to control the charging algorithm used on Wilco devices. See Documentation/ABI/testing/sysfs-class-power-wilco for the userspace interface and other info. Signed-off-by: Nick Crews <ncrews@chromium.org> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
- Loading branch information
Nick Crews
authored and
Sebastian Reichel
committed
Jul 4, 2019
1 parent
1e10694
commit 3f57fe2
Showing
4 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
What: /sys/class/power_supply/wilco-charger/charge_type | ||
Date: April 2019 | ||
KernelVersion: 5.2 | ||
Description: | ||
What charging algorithm to use: | ||
|
||
Standard: Fully charges battery at a standard rate. | ||
Adaptive: Battery settings adaptively optimized based on | ||
typical battery usage pattern. | ||
Fast: Battery charges over a shorter period. | ||
Trickle: Extends battery lifespan, intended for users who | ||
primarily use their Chromebook while connected to AC. | ||
Custom: A low and high threshold percentage is specified. | ||
Charging begins when level drops below | ||
charge_control_start_threshold, and ceases when | ||
level is above charge_control_end_threshold. | ||
|
||
What: /sys/class/power_supply/wilco-charger/charge_control_start_threshold | ||
Date: April 2019 | ||
KernelVersion: 5.2 | ||
Description: | ||
Used when charge_type="Custom", as described above. Measured in | ||
percentages. The valid range is [50, 95]. | ||
|
||
What: /sys/class/power_supply/wilco-charger/charge_control_end_threshold | ||
Date: April 2019 | ||
KernelVersion: 5.2 | ||
Description: | ||
Used when charge_type="Custom", as described above. Measured in | ||
percentages. The valid range is [55, 100]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Charging control driver for the Wilco EC | ||
* | ||
* Copyright 2019 Google LLC | ||
* | ||
* See Documentation/ABI/testing/sysfs-class-power and | ||
* Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface | ||
* and other info. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/platform_data/wilco-ec.h> | ||
#include <linux/power_supply.h> | ||
|
||
#define DRV_NAME "wilco-charger" | ||
|
||
/* Property IDs and related EC constants */ | ||
#define PID_CHARGE_MODE 0x0710 | ||
#define PID_CHARGE_LOWER_LIMIT 0x0711 | ||
#define PID_CHARGE_UPPER_LIMIT 0x0712 | ||
|
||
enum charge_mode { | ||
CHARGE_MODE_STD = 1, /* Used for Standard */ | ||
CHARGE_MODE_EXP = 2, /* Express Charge, used for Fast */ | ||
CHARGE_MODE_AC = 3, /* Mostly AC use, used for Trickle */ | ||
CHARGE_MODE_AUTO = 4, /* Used for Adaptive */ | ||
CHARGE_MODE_CUSTOM = 5, /* Used for Custom */ | ||
}; | ||
|
||
#define CHARGE_LOWER_LIMIT_MIN 50 | ||
#define CHARGE_LOWER_LIMIT_MAX 95 | ||
#define CHARGE_UPPER_LIMIT_MIN 55 | ||
#define CHARGE_UPPER_LIMIT_MAX 100 | ||
|
||
/* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */ | ||
static int psp_val_to_charge_mode(int psp_val) | ||
{ | ||
switch (psp_val) { | ||
case POWER_SUPPLY_CHARGE_TYPE_TRICKLE: | ||
return CHARGE_MODE_AC; | ||
case POWER_SUPPLY_CHARGE_TYPE_FAST: | ||
return CHARGE_MODE_EXP; | ||
case POWER_SUPPLY_CHARGE_TYPE_STANDARD: | ||
return CHARGE_MODE_STD; | ||
case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE: | ||
return CHARGE_MODE_AUTO; | ||
case POWER_SUPPLY_CHARGE_TYPE_CUSTOM: | ||
return CHARGE_MODE_CUSTOM; | ||
default: | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
/* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */ | ||
static int charge_mode_to_psp_val(enum charge_mode mode) | ||
{ | ||
switch (mode) { | ||
case CHARGE_MODE_AC: | ||
return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; | ||
case CHARGE_MODE_EXP: | ||
return POWER_SUPPLY_CHARGE_TYPE_FAST; | ||
case CHARGE_MODE_STD: | ||
return POWER_SUPPLY_CHARGE_TYPE_STANDARD; | ||
case CHARGE_MODE_AUTO: | ||
return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE; | ||
case CHARGE_MODE_CUSTOM: | ||
return POWER_SUPPLY_CHARGE_TYPE_CUSTOM; | ||
default: | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
static enum power_supply_property wilco_charge_props[] = { | ||
POWER_SUPPLY_PROP_CHARGE_TYPE, | ||
POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, | ||
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, | ||
}; | ||
|
||
static int wilco_charge_get_property(struct power_supply *psy, | ||
enum power_supply_property psp, | ||
union power_supply_propval *val) | ||
{ | ||
struct wilco_ec_device *ec = power_supply_get_drvdata(psy); | ||
u32 property_id; | ||
int ret; | ||
u8 raw; | ||
|
||
switch (psp) { | ||
case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
property_id = PID_CHARGE_MODE; | ||
break; | ||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: | ||
property_id = PID_CHARGE_LOWER_LIMIT; | ||
break; | ||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: | ||
property_id = PID_CHARGE_UPPER_LIMIT; | ||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
|
||
ret = wilco_ec_get_byte_property(ec, property_id, &raw); | ||
if (ret < 0) | ||
return ret; | ||
if (property_id == PID_CHARGE_MODE) { | ||
ret = charge_mode_to_psp_val(raw); | ||
if (ret < 0) | ||
return -EBADMSG; | ||
raw = ret; | ||
} | ||
val->intval = raw; | ||
|
||
return 0; | ||
} | ||
|
||
static int wilco_charge_set_property(struct power_supply *psy, | ||
enum power_supply_property psp, | ||
const union power_supply_propval *val) | ||
{ | ||
struct wilco_ec_device *ec = power_supply_get_drvdata(psy); | ||
int mode; | ||
|
||
switch (psp) { | ||
case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
mode = psp_val_to_charge_mode(val->intval); | ||
if (mode < 0) | ||
return -EINVAL; | ||
return wilco_ec_set_byte_property(ec, PID_CHARGE_MODE, mode); | ||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: | ||
if (val->intval < CHARGE_LOWER_LIMIT_MIN || | ||
val->intval > CHARGE_LOWER_LIMIT_MAX) | ||
return -EINVAL; | ||
return wilco_ec_set_byte_property(ec, PID_CHARGE_LOWER_LIMIT, | ||
val->intval); | ||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: | ||
if (val->intval < CHARGE_UPPER_LIMIT_MIN || | ||
val->intval > CHARGE_UPPER_LIMIT_MAX) | ||
return -EINVAL; | ||
return wilco_ec_set_byte_property(ec, PID_CHARGE_UPPER_LIMIT, | ||
val->intval); | ||
default: | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
static int wilco_charge_property_is_writeable(struct power_supply *psy, | ||
enum power_supply_property psp) | ||
{ | ||
return 1; | ||
} | ||
|
||
static const struct power_supply_desc wilco_ps_desc = { | ||
.properties = wilco_charge_props, | ||
.num_properties = ARRAY_SIZE(wilco_charge_props), | ||
.get_property = wilco_charge_get_property, | ||
.set_property = wilco_charge_set_property, | ||
.property_is_writeable = wilco_charge_property_is_writeable, | ||
.name = DRV_NAME, | ||
.type = POWER_SUPPLY_TYPE_MAINS, | ||
}; | ||
|
||
static int wilco_charge_probe(struct platform_device *pdev) | ||
{ | ||
struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
struct power_supply_config psy_cfg = {}; | ||
struct power_supply *psy; | ||
|
||
psy_cfg.drv_data = ec; | ||
psy = devm_power_supply_register(&pdev->dev, &wilco_ps_desc, &psy_cfg); | ||
|
||
return PTR_ERR_OR_ZERO(psy); | ||
} | ||
|
||
static struct platform_driver wilco_charge_driver = { | ||
.probe = wilco_charge_probe, | ||
.driver = { | ||
.name = DRV_NAME, | ||
} | ||
}; | ||
module_platform_driver(wilco_charge_driver); | ||
|
||
MODULE_ALIAS("platform:" DRV_NAME); | ||
MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); | ||
MODULE_LICENSE("GPL v2"); | ||
MODULE_DESCRIPTION("Wilco EC charge control driver"); |