Re: [RFC power_supply 2/2] platform/chrome: Add Peak Shift and Adv Batt Charging for Wilco EC

From: Nick Crews
Date: Tue Mar 05 2019 - 12:11:55 EST


Friendly bump to make sure this doesn't slip down peoples' inboxes.
Any comments would be appreciated :)

-Nick
On Fri, Feb 22, 2019 at 4:10 PM Nick Crews <ncrews@xxxxxxxxxxxx> wrote:
>
> This is an example driver that uses the proposed Peak Shift and
> Adv Batt Charging support in the main power supply subsystem.
>
> At this point, there is no actual communication with the EC,
> the point of this is to show the interface that usespace would see,
> and to show the use case for the added properties to the power
> supply susbsystem. To see the location of where the properties
> would appear in userspace, see the Documentation file.
>
> Signed-off-by: Nick Crews <ncrews@xxxxxxxxxxxx>
> ---
> .../ABI/testing/sysfs-class-power-wilco | 81 +++++++
> drivers/platform/chrome/wilco_ec/Kconfig | 14 ++
> drivers/platform/chrome/wilco_ec/Makefile | 2 +
> .../platform/chrome/wilco_ec/advanced_power.c | 199 ++++++++++++++++++
> drivers/platform/chrome/wilco_ec/core.c | 14 ++
> include/linux/platform_data/wilco-ec.h | 2 +
> 6 files changed, 312 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-class-power-wilco
> create mode 100644 drivers/platform/chrome/wilco_ec/advanced_power.c
>
> diff --git a/Documentation/ABI/testing/sysfs-class-power-wilco b/Documentation/ABI/testing/sysfs-class-power-wilco
> new file mode 100644
> index 000000000000..5c96b28aa597
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-power-wilco
> @@ -0,0 +1,81 @@
> +What: /sys/class/power_supply/wilco_adv_power/peak_shift_sched_<day of week>
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + For each weekday a start and end time to run in Peak Shift mode
> + can be set. During these times the system will run from the
> + battery even if the AC is attached as long as the battery stays
> + above the threshold specified. After the end time specified the
> + system will run from AC if attached but will not charge the
> + battery. The system will again function normally using AC and
> + recharging the battery after the specified Charge Start time.
> +
> + The input buffer must have the format "start_hr start_min end_hr
> + end_min charge_start_hr charge_start_min" The hour fields must
> + be in the range [0-23], and the minutes must be one of (0, 15,
> + 30, 45). The string must be parseable by sscanf() using the
> + format string "%d %d %d %d %d %d". An example valid input is
> + "6 15 009 45 23 0", which corresponds to 6:15, 9:45, and 23:00
> +
> + The output buffer will be filled with the format "start_hr
> + start_min end_hr end_min charge_start_hr charge_start_min" The
> + hour fields will be in the range [0-23], and the minutes will be
> + one of (0, 15, 30, 45). Each number will be zero padded to two
> + characters. An example output is "06 15 09 45 23 00", which
> + corresponds to 6:15, 9:45, and 23:00
> +
> +What: /sys/class/power_supply/wilco_adv_power/peak_shift_enable
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Enable/disable the peakshift power management policy.
> +
> + Input should be parseable by kstrtou8().
> + Output will be either "0\n" or "1\n".
> +
> +What: /sys/class/power_supply/wilco_adv_power/peak_shift_batt_threshold
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Read/write the battery percentage threshold for which the
> + peakshift policy is used. The valid range is [15, 50].
> +
> + Input should be parseable to range [15,50] by kstrtou8().
> + Output will be two-digit ascii number in range [15, 50].
> +
> +What: /sys/class/power_supply/wilco_adv_power/adv_batt_charging_sched_<day of week>
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Advanced Charging Mode allows the user to maximize the battery
> + health. In Advanced Charging Mode the system will use standard
> + charging algorithm and other techniques during non-work hours to
> + maximize battery health. During work hours, an express charge is
> + used. This express charge allows the battery to be charged
> + faster; therefore, the battery is at full charge sooner. For
> + each day the time in which the system will be most heavily used
> + is specified by the start time and the duration.
> +
> + The input buffer must have the format "start_hr start_min
> + duration_hr duration_min" The hour fields must be in the range
> + [0-23], and the minutes must be one of (0, 15, 30, 45). The
> + string must be parseable by sscanf() using the format string
> + "%d %d %d %d %d %d". An example valid input is "0006 15 23 45",
> + which corresponds to a start time of 6:15 and a duration of
> + 23:45.
> +
> + The output buffer will be filled with the format "start_hr
> + start_min duration_hr duration_min" The hour fields will be in
> + the range [0-23], and the minutes will be one of (0, 15, 30,
> + 45). Each number will be zero padded to two characters. An
> + example output is "06 15 23 45", which corresponds to a start
> + time of 6:15 and a duration of 23:45
> +
> +What: /sys/class/power_supply/wilco_adv_power/adv_batt_charging_enable
> ++Date: January 2019
> ++KernelVersion: 4.19
> ++Description:
> + Enable/disable the Advanced Battery Charging policy.
> +
> + Input should be parseable by kstrtou8().
> + Output will be either "0\n" or "1\n".
> diff --git a/drivers/platform/chrome/wilco_ec/Kconfig b/drivers/platform/chrome/wilco_ec/Kconfig
> index 4a119ced4d0c..0e172076b14e 100644
> --- a/drivers/platform/chrome/wilco_ec/Kconfig
> +++ b/drivers/platform/chrome/wilco_ec/Kconfig
> @@ -18,3 +18,17 @@ config WILCO_EC_DEBUGFS
> manipulation and allow for testing arbitrary commands. This
> interface is intended for debug only and will not be present
> on production devices.
> +
> +config WILCO_EC_ADV_POWER
> + tristate "Enable Peak Shift and Adv Batt Charging power policies"
> + depends on WILCO_EC
> + help
> + If you say Y here, you get support to control two power policies
> + managed by the EC:
> +
> + Peak Shift is power saving policy that minimizes AC usage during
> + the peak usage times during the day.
> +
> + In Advanced Charging Mode the system will use standard
> + charging algorithms and other techniques during non-work
> + hours to maximize battery health.
> diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile
> index 063e7fb4ea17..b7e8df5d3806 100644
> --- a/drivers/platform/chrome/wilco_ec/Makefile
> +++ b/drivers/platform/chrome/wilco_ec/Makefile
> @@ -4,3 +4,5 @@ wilco_ec-objs := core.o mailbox.o
> obj-$(CONFIG_WILCO_EC) += wilco_ec.o
> wilco_ec_debugfs-objs := debugfs.o
> obj-$(CONFIG_WILCO_EC_DEBUGFS) += wilco_ec_debugfs.o
> +wilco_ec_adv_power-objs := advanced_power.o
> +obj-$(CONFIG_WILCO_EC_ADV_POWER) += wilco_ec_adv_power.o
> diff --git a/drivers/platform/chrome/wilco_ec/advanced_power.c b/drivers/platform/chrome/wilco_ec/advanced_power.c
> new file mode 100644
> index 000000000000..d53c8d60f523
> --- /dev/null
> +++ b/drivers/platform/chrome/wilco_ec/advanced_power.c
> @@ -0,0 +1,199 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Peak Shift and Advanced Battery Charging Power Policies
> + *
> + * Copyright 2018 Google LLC
> + *
> + * Peak Shift is power saving policy that minimizes AC usage during the
> + * peak usage times during the day. For each weekday a start and end time
> + * to run in Peak Shift mode can be set. During these times the system will
> + * run from the battery even if the AC is attached as long as the battery
> + * stays above the threshold specified. After the end time specified the
> + * system will run from AC if attached but will not charge the battery. The
> + * system will again function normally using AC and recharging the battery
> + * after the specified Charge Start time.
> + *
> + * Advanced Charging Mode allows the user to maximize the battery health.
> + * In Advanced Charging Mode the system will use standard charging
> + * algorithm and other techniques during non-work hours to maximize battery
> + * health. During work hours, an express charge is used. This express
> + * charge allows the battery to be charged faster; therefore, the battery
> + * is at full charge sooner. For each day the time in which the system will
> + * be most heavily used is specified by the start time and the duration.
> +
> + */
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/module.h>
> +#include <linux/platform_data/wilco-ec.h>
> +
> +#define DRV_NAME "wilco_adv_power"
> +
> +static enum power_supply_property wilco_adv_power_props[] = {
> + POWER_SUPPLY_PROP_PEAK_SHIFT_ENABLE,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_BATT_THRESHOLD,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SUNDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_MONDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_TUESDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_WEDNESDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_THURSDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_FRIDAY,
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SATURDAY,
> +
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_ENABLE,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SUNDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_MONDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_TUESDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_WEDNESDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_THURSDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_FRIDAY,
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SATURDAY,
> +};
> +
> +struct wilco_adv_power_data {
> + struct wilco_ec_device *ec;
> + struct power_supply *psy;
> +};
> +
> +static int wilco_adv_power_get_property(struct power_supply *psy,
> + enum power_supply_property psp,
> + union power_supply_propval *val)
> +{
> + // struct wilco_adv_power_data *data = power_supply_get_drvdata(psy);
> + // This is a stub, really will use mailbox() on data->ec...
> + int ret = 0;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_ENABLE:
> + val->intval = 1;
> + break;
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_BATT_THRESHOLD:
> + val->intval = 42;
> + break;
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SUNDAY ...
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SATURDAY:
> + val->psval.start_hours = 23;
> + val->psval.start_minutes = 0;
> + val->psval.end_hours = 75;
> + val->psval.end_minutes = 1;
> + val->psval.charge_start_hours = 0;
> + val->psval.charge_start_minutes = 59;
> + break;
> + case POWER_SUPPLY_PROP_ADV_BATT_CHARGING_ENABLE:
> + val->intval = 0;
> + break;
> + case POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SUNDAY ...
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SATURDAY:
> + val->abcval.start_hours = 67;
> + val->abcval.start_minutes = 13;
> + val->abcval.duration_hours = 0;
> + val->abcval.duration_minutes = 88;
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int wilco_adv_power_set_property(struct power_supply *psy,
> + enum power_supply_property psp,
> + const union power_supply_propval *val)
> +{
> + // struct wilco_adv_power_data *data = power_supply_get_drvdata(psy);
> + // This is a stub, really will use mailbox() on data->ec...
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_ENABLE:
> + dev_err(&psy->dev, "peak_shift_enable=%d", val->intval);
> + break;
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_BATT_THRESHOLD:
> + dev_err(&psy->dev, "peak_shift_batt_thresh=%d", val->intval);
> + break;
> + case POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SUNDAY ...
> + POWER_SUPPLY_PROP_PEAK_SHIFT_SCHED_SATURDAY:
> + dev_err(&psy->dev, "peak_shift_sched_%d=%d %d %d %d %d %d", psp,
> + val->psval.start_hours,
> + val->psval.start_minutes,
> + val->psval.end_hours,
> + val->psval.end_minutes,
> + val->psval.charge_start_hours,
> + val->psval.charge_start_minutes);
> + break;
> + case POWER_SUPPLY_PROP_ADV_BATT_CHARGING_ENABLE:
> + dev_err(&psy->dev, "adv_batt_charging_enable=%d", val->intval);
> + break;
> + case POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SUNDAY ...
> + POWER_SUPPLY_PROP_ADV_BATT_CHARGING_SCHED_SATURDAY:
> + dev_err(&psy->dev, "adv_batt_charging_sched_%d=%d %d %d %d", psp,
> + val->abcval.start_hours,
> + val->abcval.start_minutes,
> + val->abcval.duration_hours,
> + val->abcval.duration_minutes);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static inline int wilco_adv_power_property_is_writeable(struct power_supply *psy,
> + enum power_supply_property psp)
> +{
> + return 1;
> +}
> +
> +static const struct power_supply_desc wps_desc = {
> + .properties = wilco_adv_power_props,
> + .num_properties = ARRAY_SIZE(wilco_adv_power_props),
> + .get_property = wilco_adv_power_get_property,
> + .set_property = wilco_adv_power_set_property,
> + .property_is_writeable = wilco_adv_power_property_is_writeable,
> + .name = DRV_NAME,
> + .type = POWER_SUPPLY_TYPE_MAINS,
> +};
> +
> +static int wilco_adv_power_probe(struct platform_device *pdev)
> +{
> + struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
> + struct power_supply_config psy_cfg = {};
> + struct wilco_adv_power_data *data;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (data == NULL)
> + return -ENOMEM;
> +
> + data->ec = ec;
> + psy_cfg.drv_data = data;
> + platform_set_drvdata(pdev, data);
> +
> + data->psy = power_supply_register(&pdev->dev, &wps_desc, &psy_cfg);
> + if (IS_ERR(data->psy))
> + return PTR_ERR(data->psy);
> +
> + return 0;
> +}
> +
> +static int wilco_adv_power_remove(struct platform_device *pdev)
> +{
> + struct wilco_adv_power_data *data = platform_get_drvdata(pdev);
> +
> + power_supply_unregister(data->psy);
> + return 0;
> +}
> +
> +static struct platform_driver wilco_adv_power_driver = {
> + .probe = wilco_adv_power_probe,
> + .remove = wilco_adv_power_remove,
> + .driver = {
> + .name = DRV_NAME
> + }
> +};
> +module_platform_driver(wilco_adv_power_driver);
> +
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_AUTHOR("Nick Crews <ncrews@xxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Wilco Peak Shift and Advanced Battery Charging driver");
> diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
> index 05e1e2be1c91..8f53214cbb1e 100644
> --- a/drivers/platform/chrome/wilco_ec/core.c
> +++ b/drivers/platform/chrome/wilco_ec/core.c
> @@ -89,8 +89,21 @@ static int wilco_ec_probe(struct platform_device *pdev)
> goto unregister_debugfs;
> }
>
> + /* Register child device that will be found by the peak shift driver. */
> + ec->adv_power_pdev = platform_device_register_data(dev,
> + "wilco_adv_power",
> + PLATFORM_DEVID_AUTO,
> + NULL, 0);
> + if (IS_ERR(ec->adv_power_pdev)) {
> + dev_err(dev, "Failed to create adv power platform device\n");
> + ret = PTR_ERR(ec->adv_power_pdev);
> + goto unregister_rtc;
> + }
> +
> return 0;
>
> +unregister_rtc:
> + platform_device_unregister(ec->rtc_pdev);
> unregister_debugfs:
> if (ec->debugfs_pdev)
> platform_device_unregister(ec->debugfs_pdev);
> @@ -102,6 +115,7 @@ static int wilco_ec_remove(struct platform_device *pdev)
> {
> struct wilco_ec_device *ec = platform_get_drvdata(pdev);
>
> + platform_device_unregister(ec->adv_power_pdev);
> platform_device_unregister(ec->rtc_pdev);
> if (ec->debugfs_pdev)
> platform_device_unregister(ec->debugfs_pdev);
> diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h
> index 446473a46b88..84e9aacd3759 100644
> --- a/include/linux/platform_data/wilco-ec.h
> +++ b/include/linux/platform_data/wilco-ec.h
> @@ -36,6 +36,7 @@
> * @data_size: Size of the data buffer used for EC communication.
> * @debugfs_pdev: The child platform_device used by the debugfs sub-driver.
> * @rtc_pdev: The child platform_device used by the RTC sub-driver.
> + * @adv_power_pdev: Child platform_device used by the advanced power sub-driver.
> */
> struct wilco_ec_device {
> struct device *dev;
> @@ -47,6 +48,7 @@ struct wilco_ec_device {
> size_t data_size;
> struct platform_device *debugfs_pdev;
> struct platform_device *rtc_pdev;
> + struct platform_device *adv_power_pdev;
> };
>
> /**
> --
> 2.20.1
>