[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <5423a653-01ac-95d2-fa52-31d849df65ef@linux.intel.com>
Date: Thu, 24 Apr 2025 16:48:41 +0300 (EEST)
From: Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>
To: Antheas Kapenekakis <lkml@...heas.dev>
cc: platform-driver-x86@...r.kernel.org, linux-hwmon@...r.kernel.org,
linux-doc@...r.kernel.org, linux-pm@...r.kernel.org,
Guenter Roeck <linux@...ck-us.net>, Jean Delvare <jdelvare@...e.com>,
Jonathan Corbet <corbet@....net>,
Joaquin Ignacio Aramendia <samsagax@...il.com>,
Derek J Clark <derekjohn.clark@...il.com>,
Kevin Greenberg <kdgreenberg234@...tonmail.com>,
Joshua Tam <csinaction@...me>, Parth Menon <parthasarathymenon@...il.com>,
Eileen <eileen@...-netbook.com>, LKML <linux-kernel@...r.kernel.org>,
sre@...nel.org, linux@...ssschuh.net, Hans de Goede <hdegoede@...hat.com>,
mario.limonciello@....com
Subject: Re: [PATCH v9 14/15] platform/x86: oxpec: Add charge threshold and
behaviour to OneXPlayer
On Thu, 17 Apr 2025, Antheas Kapenekakis wrote:
> With the X1 (AMD), OneXPlayer added a charge limit and charge inhibit
> feature to their devices. Charge limit allows for choosing an arbitrary
> battery charge setpoint in percentages. Charge ihibit allows to instruct
> the device to stop charging either when it is awake or always.
>
> This feature was then extended for the F1Pro as well. OneXPlayer also
> released BIOS updates for the X1 Mini, X1 (Intel), and F1 devices that
> add support for this feature. Therefore, enable it for all F1 and
> X1 devices.
>
> Reviewed-by: Thomas Weißschuh <linux@...ssschuh.net>
> Reviewed-by: Derek J. Clark <derekjohn.clark@...il.com>
> Signed-off-by: Antheas Kapenekakis <lkml@...heas.dev>
> ---
> drivers/platform/x86/Kconfig | 1 +
> drivers/platform/x86/oxpec.c | 155 ++++++++++++++++++++++++++++++++++-
> 2 files changed, 155 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 739740c4bb535..6c9e64a03aaef 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -1204,6 +1204,7 @@ config SEL3350_PLATFORM
> config OXP_EC
> tristate "OneXPlayer EC platform control"
> depends on ACPI_EC
> + depends on ACPI_BATTERY
> depends on HWMON
> depends on X86
> help
> diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
> index f0b9fff704de2..ce20bf70027df 100644
> --- a/drivers/platform/x86/oxpec.c
> +++ b/drivers/platform/x86/oxpec.c
> @@ -24,6 +24,7 @@
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/processor.h>
> +#include <acpi/battery.h>
>
> /* Handle ACPI lock mechanism */
> static u32 oxp_mutex;
> @@ -60,6 +61,7 @@ enum oxp_board {
> };
>
> static enum oxp_board board;
> +static struct device *oxp_dev;
>
> /* Fan reading and PWM */
> #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
> @@ -93,6 +95,23 @@ static enum oxp_board board;
> #define OXP_X1_TURBO_LED_OFF 0x01
> #define OXP_X1_TURBO_LED_ON 0x02
>
> +/* Battery extension settings */
> +#define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
> + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \
Please change the endings to:
...) | <tabs>\
> + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE))
> +
> +#define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */
> +#define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */
Please use tabs for aligning the values (there were a few other defines
in the earlier patches with spaces too). (I know the earlier ones used
space but they don't seem to be in the same group so lets just move to
tabs with new stuff, optionally, you can add a patch to change also the
pre-existing ones to use space).
> +
> +#define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01
> +/*
> + * X1 Mask is 0x0A, OneXFly F1Pro is just 0x02
> + * but the extra bit on the X1 does nothing.
Reflow to fill 80 chars.
> + */
> +#define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02
> +#define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \
> + OXP_X1_CHARGE_INHIBIT_MASK_OFF)
Align to (.
--
i.
> +
> static const struct dmi_system_id dmi_table[] = {
> {
> .matches = {
> @@ -507,6 +526,129 @@ static ssize_t tt_led_show(struct device *dev,
>
> static DEVICE_ATTR_RW(tt_led);
>
> +/* Callbacks for charge behaviour attributes */
> +static bool oxp_psy_ext_supported(void)
> +{
> + switch (board) {
> + case oxp_x1:
> + case oxp_fly:
> + return true;
> + default:
> + break;
> + }
> + return false;
> +}
> +
> +static int oxp_psy_ext_get_prop(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *data,
> + enum power_supply_property psp,
> + union power_supply_propval *val)
> +{
> + long raw_val;
> + int ret;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
> + ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val);
> + if (ret)
> + return ret;
> + if (raw_val < 0 || raw_val > 100)
> + return -EINVAL;
> + val->intval = raw_val;
> + return 0;
> + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
> + ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val);
> + if (ret)
> + return ret;
> + if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) ==
> + OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS)
> + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
> + else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) ==
> + OXP_X1_CHARGE_INHIBIT_MASK_AWAKE)
> + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE;
> + else
> + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
> + return 0;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int oxp_psy_ext_set_prop(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *data,
> + enum power_supply_property psp,
> + const union power_supply_propval *val)
> +{
> + long raw_val;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
> + if (val->intval > 100)
> + return -EINVAL;
> + return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval);
> + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
> + switch (val->intval) {
> + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
> + raw_val = 0;
> + break;
> + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE:
> + raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE;
> + break;
> + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
> + raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val);
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int oxp_psy_prop_is_writeable(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *data,
> + enum power_supply_property psp)
> +{
> + return true;
> +}
> +
> +static const enum power_supply_property oxp_psy_ext_props[] = {
> + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
> + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
> +};
> +
> +static const struct power_supply_ext oxp_psy_ext = {
> + .name = "oxp-charge-control",
> + .properties = oxp_psy_ext_props,
> + .num_properties = ARRAY_SIZE(oxp_psy_ext_props),
> + .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
> + .get_property = oxp_psy_ext_get_prop,
> + .set_property = oxp_psy_ext_set_prop,
> + .property_is_writeable = oxp_psy_prop_is_writeable,
> +};
> +
> +static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
> +{
> + return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL);
> +}
> +
> +static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
> +{
> + power_supply_unregister_extension(battery, &oxp_psy_ext);
> + return 0;
> +}
> +
> +static struct acpi_battery_hook battery_hook = {
> + .add_battery = oxp_add_battery,
> + .remove_battery = oxp_remove_battery,
> + .name = "OneXPlayer Battery",
> +};
> +
> /* PWM enable/disable functions */
> static int oxp_pwm_enable(void)
> {
> @@ -847,11 +989,22 @@ static int oxp_platform_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> struct device *hwdev;
> + int ret;
>
> + oxp_dev = dev;
> hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL,
> &oxp_ec_chip_info, NULL);
>
> - return PTR_ERR_OR_ZERO(hwdev);
> + if (IS_ERR(hwdev))
> + return PTR_ERR(hwdev);
> +
> + if (oxp_psy_ext_supported()) {
> + ret = devm_battery_hook_register(dev, &battery_hook);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> }
>
> static struct platform_driver oxp_platform_driver = {
>
Powered by blists - more mailing lists