From nobody Tue Dec 2 02:29:43 2025 Received: from relay11.grserver.gr (relay11.grserver.gr [78.46.171.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 79A063093BA; Wed, 19 Nov 2025 17:45:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.46.171.57 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763574330; cv=none; b=pYO7yA7gZnpnJDT0ctxtcFsRVOsaMF+6iOU8iosxuTJrV3dItYJrXvTmzXGRx02BPfzLW6/jP5IlES7ackKtEqb409FHQIp0cTKqGq1e8JhI01xG47r4ENRj7ak5GdbhOXWosleD8PpILsEcISEAkdlQlSpheBOpeM1y6sTYBfk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763574330; c=relaxed/simple; bh=oveUdTlU06E6CfvUlT4/eBuZDkg69NYh/+i2jLkxuzI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JYEV2gSCoftb/VTrH006knifvnoWPq4mi/ZEJ/f0gJqVI02ex9JeaLHwyx4by7kpLvhCAz8+vkNrb8zArHM/KObBL/FRNNdY4d0vOkW33ngjNdB39f2HvR2sJbEaumpXopjGuvlkU/hgO/XdknlUqrECmaX1tP/DDylLsZwEqW4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=pass (2048-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=kR+gpE1z; arc=none smtp.client-ip=78.46.171.57 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="kR+gpE1z" Received: from relay11 (localhost.localdomain [127.0.0.1]) by relay11.grserver.gr (Proxmox) with ESMTP id C41DDC48D5; Wed, 19 Nov 2025 19:45:22 +0200 (EET) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay11.grserver.gr (Proxmox) with ESMTPS id 2FE5EBC90C; Wed, 19 Nov 2025 19:45:22 +0200 (EET) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:8d8a:5967:d692:ea4e]) by linux3247.grserver.gr (Postfix) with ESMTPSA id 3CD6C200E79; Wed, 19 Nov 2025 19:45:21 +0200 (EET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1763574321; bh=ayJ9MI5xF2/3yfcpAUOzsna2Ew6U+Ri/vAfa5QrLIHE=; h=From:To:Subject; b=kR+gpE1z1gNrrc1LwQxN0VdrapQiu4Gn3zIv/4H90oTNzKproAGlH+Y03O48c6w4L KW3XfK2pzpI03lp5tMEp8/DdUmLaAMenadUymJzTos0MBsG9cHFLNHF3EbI1Vn6R6O Q3eF67kXtI5QeJ3k63HIIL84HYgE8SlY2tRHElUQZ695Bjw/1f7yV5dy81NiG49fd2 eek2R0qOWcvzNthtpzFTOu1OfZtgNT3v3nw7I3ZErmya5TLW1/xpEa9x7Q1AGbiJHW B1bsTtVWxvyuvuCIW64LozW1q3HvynBHcIPMvwgHWTPHwC1KIKUW9PG4eCXSa7iBAR TiEVwxnx0GbEQ== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:8d8a:5967:d692:ea4e) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis , Armin Wolf Subject: [PATCH v6 3/6] platform/x86: ayaneo-ec: Add charge control support Date: Wed, 19 Nov 2025 18:45:02 +0100 Message-ID: <20251119174505.597218-4-lkml@antheas.dev> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251119174505.597218-1-lkml@antheas.dev> References: <20251119174505.597218-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <176357432178.2086468.16958912960422603405@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Antheas Kapenekakis --- 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 e19850bd2609..b049c55057b7 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -320,6 +320,7 @@ config AYANEO_EC tristate "Ayaneo EC platform control" depends on DMI 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 86d4eed49f42..69901ac335eb 100644 --- a/drivers/platform/x86/ayaneo-ec.c +++ b/drivers/platform/x86/ayaneo-ec.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include =20 #define AYANEO_PWM_ENABLE_REG 0x4A #define AYANEO_PWM_REG 0x4B @@ -23,17 +25,27 @@ =20 #define AYANEO_FAN_REG 0x76 =20 +#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; }; =20 struct ayaneo_ec_platform_data { struct platform_device *pdev; struct ayaneo_ec_quirk *quirks; + struct acpi_battery_hook battery_hook; }; =20 static const struct ayaneo_ec_quirk quirk_ayaneo3 =3D { .has_fan_control =3D true, + .has_charge_control =3D true, }; =20 static const struct dmi_system_id dmi_table[] =3D { @@ -164,11 +176,102 @@ static const struct hwmon_chip_info ayaneo_ec_chip_i= nfo =3D { .info =3D ayaneo_ec_sensors, }; =20 +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 =3D ec_read(AYANEO_CHARGE_REG, &tmp); + if (ret) + return ret; + + if (tmp =3D=3D AYANEO_CHARGE_VAL_INHIBIT) + val->intval =3D POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + else + val->intval =3D 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 =3D AYANEO_CHARGE_VAL_AUTO; + break; + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: + raw_val =3D 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[] =3D { + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, +}; + +static const struct power_supply_ext ayaneo_psy_ext =3D { + .name =3D "ayaneo-charge-control", + .properties =3D ayaneo_psy_ext_props, + .num_properties =3D ARRAY_SIZE(ayaneo_psy_ext_props), + .charge_behaviours =3D EC_CHARGE_CONTROL_BEHAVIOURS, + .get_property =3D ayaneo_psy_ext_get_prop, + .set_property =3D ayaneo_psy_ext_set_prop, + .property_is_writeable =3D 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 =3D + 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; =20 dmi_entry =3D dmi_first_match(dmi_table); if (!dmi_entry) @@ -189,6 +292,15 @@ static int ayaneo_ec_probe(struct platform_device *pde= v) return PTR_ERR(hwdev); } =20 + if (data->quirks->has_charge_control) { + data->battery_hook.add_battery =3D ayaneo_add_battery; + data->battery_hook.remove_battery =3D ayaneo_remove_battery; + data->battery_hook.name =3D "Ayaneo Battery"; + ret =3D devm_battery_hook_register(&pdev->dev, &data->battery_hook); + if (ret) + return ret; + } + return 0; } =20 --=20 2.52.0