[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <9cc4868f-98c3-4f5a-a252-a9d00bdc8d87@gmx.de>
Date: Fri, 5 Sep 2025 20:54:16 +0200
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 v1 3/5] platform/x86: ayaneo-ec: Add charge control
support
Am 22.08.25 um 23:04 schrieb Antheas Kapenekakis:
> On Fri, 22 Aug 2025 at 14:38, Armin Wolf <W_Armin@....de> wrote:
>> Am 20.08.25 um 18:06 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.
>> Does this include hibernation?
> No. S4/S5 reset the state. Can you give a reference for a regmap
> implementation? A hibernation hook would be a nice to have. Although I
> am not sure how I feel about restoring the fan speed after
> hibernation. It seems dangerous.
Take a look at this patch series: https://lore.kernel.org/platform-driver-x86/20250803210157.8185-1-W_Armin@gmx.de
Restoring the fan speed after hibernation should be OK as long as you also restore the other fan control settings.
This should be safe as long as you can test the driver on real hardware.
Thanks,
Armin Wolf
>> Thanks,
>> Armin Wolf
>>
>>> The EC does not support charge threshold control. Instead, userspace
>>> software on Windows manually toggles charge inhibition depending on
>>> battery level.
>>>
>>> Signed-off-by: Antheas Kapenekakis <lkml@...heas.dev>
>>> ---
>>> drivers/platform/x86/Kconfig | 1 +
>>> drivers/platform/x86/ayaneo-ec.c | 111 +++++++++++++++++++++++++++++++
>>> 2 files changed, 112 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>>> index 0a7ca2c78456..c871a722e5ef 100644
>>> --- a/drivers/platform/x86/Kconfig
>>> +++ b/drivers/platform/x86/Kconfig
>>> @@ -308,6 +308,7 @@ config AYANEO_EC
>>> tristate "Ayaneo EC platform control"
>>> depends on X86
>>> 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 8b1902706b81..a4bdc6ae7af7 100644
>>> --- a/drivers/platform/x86/ayaneo-ec.c
>>> +++ b/drivers/platform/x86/ayaneo-ec.c
>>> @@ -14,6 +14,7 @@
>>> #include <linux/kernel.h>
>>> #include <linux/module.h>
>>> #include <linux/platform_device.h>
>>> +#include <acpi/battery.h>
>>>
>>> #define AYANEO_PWM_ENABLE_REG 0x4A
>>> #define AYANEO_PWM_REG 0x4B
>>> @@ -22,17 +23,27 @@
>>>
>>> #define AYANEO_FAN_REG 0x76
>>>
>>> +#define EC_CHARGE_CONTROL_BEHAVIOURS \
>>> + (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
>>> + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
>>> +#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 ayaneo3 = {
>>> .has_fan_control = true,
>>> + .has_charge_control = true,
>>> };
>>>
>>> static const struct dmi_system_id dmi_table[] = {
>>> @@ -159,11 +170,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)
>>> @@ -184,6 +286,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