[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <d719d78f-5466-4d3f-a43c-dfd4c2c0190a@gmx.de>
Date: Tue, 4 Nov 2025 21:00:07 +0100
From: Armin Wolf <W_Armin@....de>
To: Antheas Kapenekakis <lkml@...heas.dev>
Cc: platform-driver-x86@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-hwmon@...r.kernel.org, Hans de Goede <hansg@...nel.org>,
Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>,
Derek John Clark <derekjohn.clark@...il.com>,
Joaquín Ignacio Aramendía <samsagax@...il.com>,
Jean Delvare <jdelvare@...e.com>, Guenter Roeck <linux@...ck-us.net>
Subject: Re: [PATCH v3 3/6] platform/x86: ayaneo-ec: Add charge control
support
Am 02.11.25 um 19:37 schrieb Antheas Kapenekakis:
> On Sun, 2 Nov 2025 at 19:26, Armin Wolf <W_Armin@....de> wrote:
>> Am 31.10.25 um 17:36 schrieb Antheas Kapenekakis:
>>
>>> Ayaneo devices support charge inhibition via the EC. This inhibition
>>> only works while the device is powered on, and resets between restarts.
>>> However, it is maintained across suspend/resume cycles.
>>>
>>> The EC does not support charge threshold control. Instead, userspace
>>> software on Windows manually toggles charge inhibition depending on
>>> battery level.
>>>
>>> Reviewed-by: Armin Wolf <W_Armin@....de>
>>> Signed-off-by: Antheas Kapenekakis <lkml@...heas.dev>
>>> ---
>>> drivers/platform/x86/Kconfig | 1 +
>>> drivers/platform/x86/ayaneo-ec.c | 112 +++++++++++++++++++++++++++++++
>>> 2 files changed, 113 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>>> index b3beaff4b03a..a45449ae83f8 100644
>>> --- a/drivers/platform/x86/Kconfig
>>> +++ b/drivers/platform/x86/Kconfig
>>> @@ -319,6 +319,7 @@ config ASUS_TF103C_DOCK
>>> config AYANEO_EC
>>> tristate "Ayaneo EC platform control"
>>> depends on ACPI_EC
>>> + depends on ACPI_BATTERY
>>> depends on HWMON
>>> help
>>> Enables support for the platform EC of Ayaneo devices. This
>>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
>>> index 108a23458a4f..697bb053a7d6 100644
>>> --- a/drivers/platform/x86/ayaneo-ec.c
>>> +++ b/drivers/platform/x86/ayaneo-ec.c
>>> @@ -15,6 +15,8 @@
>>> #include <linux/kernel.h>
>>> #include <linux/module.h>
>>> #include <linux/platform_device.h>
>>> +#include <linux/power_supply.h>
>>> +#include <acpi/battery.h>
>>>
>>> #define AYANEO_PWM_ENABLE_REG 0x4A
>>> #define AYANEO_PWM_REG 0x4B
>>> @@ -23,17 +25,27 @@
>>>
>>> #define AYANEO_FAN_REG 0x76
>>>
>>> +#define EC_CHARGE_CONTROL_BEHAVIOURS \
>>> + (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
>>> + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
>> I think POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE would be more suitable here.
> Charge inhibition works during sleep.
I must have suffered from a misunderstanding then. In this case:
Reviewed-by: Armin Wolf <W_Armin@....de>
>> Other than that:
>> Reviewed-by: Armin Wolf <W_Armin@....de>
>>
>>> +#define AYANEO_CHARGE_REG 0x1e
>>> +#define AYANEO_CHARGE_VAL_AUTO 0xaa
>>> +#define AYANEO_CHARGE_VAL_INHIBIT 0x55
>>> +
>>> struct ayaneo_ec_quirk {
>>> bool has_fan_control;
>>> + bool has_charge_control;
>>> };
>>>
>>> struct ayaneo_ec_platform_data {
>>> struct platform_device *pdev;
>>> struct ayaneo_ec_quirk *quirks;
>>> + struct acpi_battery_hook battery_hook;
>>> };
>>>
>>> static const struct ayaneo_ec_quirk quirk_ayaneo3 = {
>>> .has_fan_control = true,
>>> + .has_charge_control = true,
>>> };
>>>
>>> static const struct dmi_system_id dmi_table[] = {
>>> @@ -164,11 +176,102 @@ static const struct hwmon_chip_info ayaneo_ec_chip_info = {
>>> .info = ayaneo_ec_sensors,
>>> };
>>>
>>> +static int ayaneo_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)
>>> +{
>>> + int ret;
>>> + u8 tmp;
>>> +
>>> + switch (psp) {
>>> + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
>>> + ret = ec_read(AYANEO_CHARGE_REG, &tmp);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (tmp == AYANEO_CHARGE_VAL_INHIBIT)
>>> + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
>>> + else
>>> + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
>>> + return 0;
>>> + default:
>>> + return -EINVAL;
>>> + }
>>> +}
>>> +
>>> +static int ayaneo_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)
>>> +{
>>> + u8 raw_val;
>>> +
>>> + switch (psp) {
>>> + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
>>> + switch (val->intval) {
>>> + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
>>> + raw_val = AYANEO_CHARGE_VAL_AUTO;
>>> + break;
>>> + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
>>> + raw_val = AYANEO_CHARGE_VAL_INHIBIT;
>>> + break;
>>> + default:
>>> + return -EINVAL;
>>> + }
>>> + return ec_write(AYANEO_CHARGE_REG, raw_val);
>>> + default:
>>> + return -EINVAL;
>>> + }
>>> +}
>>> +
>>> +static int ayaneo_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 ayaneo_psy_ext_props[] = {
>>> + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
>>> +};
>>> +
>>> +static const struct power_supply_ext ayaneo_psy_ext = {
>>> + .name = "ayaneo-charge-control",
>>> + .properties = ayaneo_psy_ext_props,
>>> + .num_properties = ARRAY_SIZE(ayaneo_psy_ext_props),
>>> + .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
>>> + .get_property = ayaneo_psy_ext_get_prop,
>>> + .set_property = ayaneo_psy_ext_set_prop,
>>> + .property_is_writeable = ayaneo_psy_prop_is_writeable,
>>> +};
>>> +
>>> +static int ayaneo_add_battery(struct power_supply *battery,
>>> + struct acpi_battery_hook *hook)
>>> +{
>>> + struct ayaneo_ec_platform_data *data =
>>> + container_of(hook, struct ayaneo_ec_platform_data, battery_hook);
>>> +
>>> + return power_supply_register_extension(battery, &ayaneo_psy_ext,
>>> + &data->pdev->dev, NULL);
>>> +}
>>> +
>>> +static int ayaneo_remove_battery(struct power_supply *battery,
>>> + struct acpi_battery_hook *hook)
>>> +{
>>> + power_supply_unregister_extension(battery, &ayaneo_psy_ext);
>>> + return 0;
>>> +}
>>> +
>>> static int ayaneo_ec_probe(struct platform_device *pdev)
>>> {
>>> const struct dmi_system_id *dmi_entry;
>>> struct ayaneo_ec_platform_data *data;
>>> struct device *hwdev;
>>> + int ret;
>>>
>>> dmi_entry = dmi_first_match(dmi_table);
>>> if (!dmi_entry)
>>> @@ -189,6 +292,15 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
>>> return PTR_ERR(hwdev);
>>> }
>>>
>>> + if (data->quirks->has_charge_control) {
>>> + data->battery_hook.add_battery = ayaneo_add_battery;
>>> + data->battery_hook.remove_battery = ayaneo_remove_battery;
>>> + data->battery_hook.name = "Ayaneo Battery";
>>> + ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> return 0;
>>> }
>>>
Powered by blists - more mailing lists