* [PATCH v2 1/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-15 9:04 ` Ilpo Järvinen
2025-10-26 22:25 ` Armin Wolf
2025-10-15 8:44 ` [PATCH v2 2/6] platform/x86: ayaneo-ec: Add hwmon support Antheas Kapenekakis
` (4 subsequent siblings)
5 siblings, 2 replies; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, Antheas Kapenekakis
Recent Ayaneo devices feature an ACPI mapped Embedded Controller (EC)
with standard addresses across models that provides access to fan
speed, fan control, battery charge limits, and controller power
controls. Introduce a new driver stub that will handle these driver
features.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
MAINTAINERS | 6 +++
drivers/platform/x86/Kconfig | 10 ++++
drivers/platform/x86/Makefile | 3 ++
drivers/platform/x86/ayaneo-ec.c | 89 ++++++++++++++++++++++++++++++++
4 files changed, 108 insertions(+)
create mode 100644 drivers/platform/x86/ayaneo-ec.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 46126ce2f968..8c4d0c26ca77 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4187,6 +4187,12 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
F: drivers/pwm/pwm-axi-pwmgen.c
+AYANEO PLATFORM EC DRIVER
+M: Antheas Kapenekakis <lkml@antheas.dev>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/ayaneo-ec.c
+
AZ6007 DVB DRIVER
M: Mauro Carvalho Chehab <mchehab@kernel.org>
L: linux-media@vger.kernel.org
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 46e62feeda3c..ff2678927696 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -316,6 +316,16 @@ config ASUS_TF103C_DOCK
If you have an Asus TF103C tablet say Y or M here, for a generic x86
distro config say M here.
+config AYANEO_EC
+ tristate "Ayaneo EC platform control"
+ depends on X86
+ help
+ Enables support for the platform EC of Ayaneo devices. This
+ includes fan control, fan speed, charge limit, magic
+ module detection, and controller power control.
+
+ If you have an Ayaneo device, say Y or M here.
+
config MERAKI_MX100
tristate "Cisco Meraki MX100 Platform Driver"
depends on GPIOLIB
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index c7db2a88c11a..274a685eb92d 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -39,6 +39,9 @@ obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
+# Ayaneo
+obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o
+
# Cisco/Meraki
obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
new file mode 100644
index 000000000000..90b86527ab0d
--- /dev/null
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles
+ * hwmon (fan speed, fan control), battery charge limits, and magic module
+ * control (connected modules, controller disconnection).
+ *
+ * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
+ */
+
+#include <linux/dmi.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct ayaneo_ec_quirk {
+};
+
+struct ayaneo_ec_platform_data {
+ struct platform_device *pdev;
+ struct ayaneo_ec_quirk *quirks;
+};
+
+static const struct ayaneo_ec_quirk ayaneo3 = {
+};
+
+static const struct dmi_system_id dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"),
+ },
+ .driver_data = (void *)&ayaneo3,
+ },
+ {},
+};
+
+static int ayaneo_ec_probe(struct platform_device *pdev)
+{
+ const struct dmi_system_id *dmi_entry;
+ struct ayaneo_ec_platform_data *data;
+
+ dmi_entry = dmi_first_match(dmi_table);
+ if (!dmi_entry)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->pdev = pdev;
+ data->quirks = dmi_entry->driver_data;
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static struct platform_driver ayaneo_platform_driver = {
+ .driver = {
+ .name = "ayaneo-ec",
+ },
+ .probe = ayaneo_ec_probe,
+};
+
+static struct platform_device *ayaneo_platform_device;
+
+static int __init ayaneo_ec_init(void)
+{
+ ayaneo_platform_device =
+ platform_create_bundle(&ayaneo_platform_driver,
+ ayaneo_ec_probe, NULL, 0, NULL, 0);
+
+ return PTR_ERR_OR_ZERO(ayaneo_platform_device);
+}
+
+static void __exit ayaneo_ec_exit(void)
+{
+ platform_device_unregister(ayaneo_platform_device);
+ platform_driver_unregister(&ayaneo_platform_driver);
+}
+
+MODULE_DEVICE_TABLE(dmi, dmi_table);
+
+module_init(ayaneo_ec_init);
+module_exit(ayaneo_ec_exit);
+
+MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>");
+MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features");
+MODULE_LICENSE("GPL");
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 1/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver
2025-10-15 8:44 ` [PATCH v2 1/6] " Antheas Kapenekakis
@ 2025-10-15 9:04 ` Ilpo Järvinen
2025-10-26 22:25 ` Armin Wolf
1 sibling, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:04 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> Recent Ayaneo devices feature an ACPI mapped Embedded Controller (EC)
> with standard addresses across models that provides access to fan
> speed, fan control, battery charge limits, and controller power
> controls. Introduce a new driver stub that will handle these driver
> features.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> MAINTAINERS | 6 +++
> drivers/platform/x86/Kconfig | 10 ++++
> drivers/platform/x86/Makefile | 3 ++
> drivers/platform/x86/ayaneo-ec.c | 89 ++++++++++++++++++++++++++++++++
> 4 files changed, 108 insertions(+)
> create mode 100644 drivers/platform/x86/ayaneo-ec.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 46126ce2f968..8c4d0c26ca77 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4187,6 +4187,12 @@ W: https://ez.analog.com/linux-software-drivers
> F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
> F: drivers/pwm/pwm-axi-pwmgen.c
>
> +AYANEO PLATFORM EC DRIVER
> +M: Antheas Kapenekakis <lkml@antheas.dev>
> +L: platform-driver-x86@vger.kernel.org
> +S: Maintained
> +F: drivers/platform/x86/ayaneo-ec.c
> +
> AZ6007 DVB DRIVER
> M: Mauro Carvalho Chehab <mchehab@kernel.org>
> L: linux-media@vger.kernel.org
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 46e62feeda3c..ff2678927696 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -316,6 +316,16 @@ config ASUS_TF103C_DOCK
> If you have an Asus TF103C tablet say Y or M here, for a generic x86
> distro config say M here.
>
> +config AYANEO_EC
> + tristate "Ayaneo EC platform control"
> + depends on X86
> + help
> + Enables support for the platform EC of Ayaneo devices. This
> + includes fan control, fan speed, charge limit, magic
> + module detection, and controller power control.
> +
> + If you have an Ayaneo device, say Y or M here.
> +
> config MERAKI_MX100
> tristate "Cisco Meraki MX100 Platform Driver"
> depends on GPIOLIB
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index c7db2a88c11a..274a685eb92d 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -39,6 +39,9 @@ obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
> obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
> obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
>
> +# Ayaneo
> +obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o
> +
> # Cisco/Meraki
> obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> new file mode 100644
> index 000000000000..90b86527ab0d
> --- /dev/null
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles
> + * hwmon (fan speed, fan control), battery charge limits, and magic module
> + * control (connected modules, controller disconnection).
> + *
> + * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
> + */
> +
> +#include <linux/dmi.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +struct ayaneo_ec_quirk {
> +};
> +
> +struct ayaneo_ec_platform_data {
> + struct platform_device *pdev;
> + struct ayaneo_ec_quirk *quirks;
> +};
> +
> +static const struct ayaneo_ec_quirk ayaneo3 = {
> +};
I suggest including quirks in the name.
> +
> +static const struct dmi_system_id dmi_table[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"),
> + },
> + .driver_data = (void *)&ayaneo3,
> + },
> + {},
> +};
> +
> +static int ayaneo_ec_probe(struct platform_device *pdev)
> +{
> + const struct dmi_system_id *dmi_entry;
> + struct ayaneo_ec_platform_data *data;
> +
> + dmi_entry = dmi_first_match(dmi_table);
> + if (!dmi_entry)
> + return -ENODEV;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->pdev = pdev;
> + data->quirks = dmi_entry->driver_data;
> + platform_set_drvdata(pdev, data);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ayaneo_platform_driver = {
> + .driver = {
> + .name = "ayaneo-ec",
> + },
> + .probe = ayaneo_ec_probe,
> +};
> +
> +static struct platform_device *ayaneo_platform_device;
> +
> +static int __init ayaneo_ec_init(void)
> +{
> + ayaneo_platform_device =
> + platform_create_bundle(&ayaneo_platform_driver,
> + ayaneo_ec_probe, NULL, 0, NULL, 0);
> +
> + return PTR_ERR_OR_ZERO(ayaneo_platform_device);
Please add include for this.
> +}
> +
> +static void __exit ayaneo_ec_exit(void)
> +{
> + platform_device_unregister(ayaneo_platform_device);
> + platform_driver_unregister(&ayaneo_platform_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(dmi, dmi_table);
> +
> +module_init(ayaneo_ec_init);
> +module_exit(ayaneo_ec_exit);
> +
> +MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>");
> +MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features");
> +MODULE_LICENSE("GPL");
>
--
i.
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 1/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver
2025-10-15 8:44 ` [PATCH v2 1/6] " Antheas Kapenekakis
2025-10-15 9:04 ` Ilpo Järvinen
@ 2025-10-26 22:25 ` Armin Wolf
1 sibling, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:25 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> Recent Ayaneo devices feature an ACPI mapped Embedded Controller (EC)
> with standard addresses across models that provides access to fan
> speed, fan control, battery charge limits, and controller power
> controls. Introduce a new driver stub that will handle these driver
> features.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> MAINTAINERS | 6 +++
> drivers/platform/x86/Kconfig | 10 ++++
> drivers/platform/x86/Makefile | 3 ++
> drivers/platform/x86/ayaneo-ec.c | 89 ++++++++++++++++++++++++++++++++
> 4 files changed, 108 insertions(+)
> create mode 100644 drivers/platform/x86/ayaneo-ec.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 46126ce2f968..8c4d0c26ca77 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4187,6 +4187,12 @@ W: https://ez.analog.com/linux-software-drivers
> F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
> F: drivers/pwm/pwm-axi-pwmgen.c
>
> +AYANEO PLATFORM EC DRIVER
> +M: Antheas Kapenekakis <lkml@antheas.dev>
> +L: platform-driver-x86@vger.kernel.org
> +S: Maintained
> +F: drivers/platform/x86/ayaneo-ec.c
> +
> AZ6007 DVB DRIVER
> M: Mauro Carvalho Chehab <mchehab@kernel.org>
> L: linux-media@vger.kernel.org
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 46e62feeda3c..ff2678927696 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -316,6 +316,16 @@ config ASUS_TF103C_DOCK
> If you have an Asus TF103C tablet say Y or M here, for a generic x86
> distro config say M here.
>
> +config AYANEO_EC
> + tristate "Ayaneo EC platform control"
> + depends on X86
Hi,
i think the "depends on X86" part is not necessary, all X86 platform drivers are
already only selectable on X86.
> + help
> + Enables support for the platform EC of Ayaneo devices. This
> + includes fan control, fan speed, charge limit, magic
> + module detection, and controller power control.
> +
> + If you have an Ayaneo device, say Y or M here.
> +
> config MERAKI_MX100
> tristate "Cisco Meraki MX100 Platform Driver"
> depends on GPIOLIB
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index c7db2a88c11a..274a685eb92d 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -39,6 +39,9 @@ obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
> obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
> obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
>
> +# Ayaneo
> +obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o
> +
> # Cisco/Meraki
> obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> new file mode 100644
> index 000000000000..90b86527ab0d
> --- /dev/null
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles
> + * hwmon (fan speed, fan control), battery charge limits, and magic module
> + * control (connected modules, controller disconnection).
> + *
> + * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
> + */
> +
> +#include <linux/dmi.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +struct ayaneo_ec_quirk {
> +};
> +
> +struct ayaneo_ec_platform_data {
> + struct platform_device *pdev;
> + struct ayaneo_ec_quirk *quirks;
> +};
> +
> +static const struct ayaneo_ec_quirk ayaneo3 = {
> +};
> +
> +static const struct dmi_system_id dmi_table[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"),
> + },
> + .driver_data = (void *)&ayaneo3,
> + },
> + {},
> +};
Missing MODULE_DEVICE_TABLE().
> +
> +static int ayaneo_ec_probe(struct platform_device *pdev)
> +{
> + const struct dmi_system_id *dmi_entry;
> + struct ayaneo_ec_platform_data *data;
> +
> + dmi_entry = dmi_first_match(dmi_table);
> + if (!dmi_entry)
> + return -ENODEV;
Why not doing this inside ayaneo_ec_init() ? This would also allow you
to mark the DMI table as __initconst. Please also mark ayaneo_ec_probe as
__init as well.
Thanks,
Armin Wolf
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->pdev = pdev;
> + data->quirks = dmi_entry->driver_data;
> + platform_set_drvdata(pdev, data);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ayaneo_platform_driver = {
> + .driver = {
> + .name = "ayaneo-ec",
> + },
> + .probe = ayaneo_ec_probe,
> +};
> +
> +static struct platform_device *ayaneo_platform_device;
> +
> +static int __init ayaneo_ec_init(void)
> +{
> + ayaneo_platform_device =
> + platform_create_bundle(&ayaneo_platform_driver,
> + ayaneo_ec_probe, NULL, 0, NULL, 0);
> +
> + return PTR_ERR_OR_ZERO(ayaneo_platform_device);
> +}
> +
> +static void __exit ayaneo_ec_exit(void)
> +{
> + platform_device_unregister(ayaneo_platform_device);
> + platform_driver_unregister(&ayaneo_platform_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(dmi, dmi_table);
> +
> +module_init(ayaneo_ec_init);
> +module_exit(ayaneo_ec_exit);
> +
> +MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>");
> +MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features");
> +MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 2/6] platform/x86: ayaneo-ec: Add hwmon support
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
2025-10-15 8:44 ` [PATCH v2 1/6] " Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-26 22:33 ` Armin Wolf
2025-10-15 8:44 ` [PATCH v2 3/6] platform/x86: ayaneo-ec: Add charge control support Antheas Kapenekakis
` (3 subsequent siblings)
5 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, Antheas Kapenekakis
Add hwmon single fan sensor reads and control for Ayaneo devices.
The register and method of access is the same for all devices.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/platform/x86/Kconfig | 2 +
drivers/platform/x86/ayaneo-ec.c | 134 +++++++++++++++++++++++++++++++
2 files changed, 136 insertions(+)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ff2678927696..f132a87fcee9 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -319,6 +319,8 @@ config ASUS_TF103C_DOCK
config AYANEO_EC
tristate "Ayaneo EC platform control"
depends on X86
+ depends on ACPI_EC
+ depends on HWMON
help
Enables support for the platform EC of Ayaneo devices. This
includes fan control, fan speed, charge limit, magic
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
index 90b86527ab0d..9884eed0cc84 100644
--- a/drivers/platform/x86/ayaneo-ec.c
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -7,13 +7,23 @@
* Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
*/
+#include <linux/acpi.h>
#include <linux/dmi.h>
+#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#define AYANEO_PWM_ENABLE_REG 0x4A
+#define AYANEO_PWM_REG 0x4B
+#define AYANEO_PWM_MODE_AUTO 0x00
+#define AYANEO_PWM_MODE_MANUAL 0x01
+
+#define AYANEO_FAN_REG 0x76
+
struct ayaneo_ec_quirk {
+ bool has_fan_control;
};
struct ayaneo_ec_platform_data {
@@ -22,6 +32,7 @@ struct ayaneo_ec_platform_data {
};
static const struct ayaneo_ec_quirk ayaneo3 = {
+ .has_fan_control = true,
};
static const struct dmi_system_id dmi_table[] = {
@@ -35,10 +46,126 @@ static const struct dmi_system_id dmi_table[] = {
{},
};
+/* Callbacks for hwmon interface */
+static umode_t ayaneo_ec_hwmon_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ switch (type) {
+ case hwmon_fan:
+ return 0444;
+ case hwmon_pwm:
+ return 0644;
+ default:
+ return 0;
+ }
+}
+
+static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ u8 tmp;
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ ret = ec_read(AYANEO_FAN_REG, &tmp);
+ if (ret)
+ return ret;
+ *val = tmp << 8;
+ ret = ec_read(AYANEO_FAN_REG + 1, &tmp);
+ if (ret)
+ return ret;
+ *val += tmp;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ ret = ec_read(AYANEO_PWM_REG, &tmp);
+ if (ret)
+ return ret;
+ *val = (255 * tmp) / 100;
+ if (*val < 0 || *val > 255)
+ return -EINVAL;
+ return 0;
+ case hwmon_pwm_enable:
+ ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
+ if (ret)
+ return ret;
+ if (tmp == AYANEO_PWM_MODE_MANUAL)
+ *val = 1;
+ else
+ *val = 2;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ switch (type) {
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_enable:
+ switch (val) {
+ case 1:
+ return ec_write(AYANEO_PWM_ENABLE_REG,
+ AYANEO_PWM_MODE_MANUAL);
+ case 2:
+ return ec_write(AYANEO_PWM_ENABLE_REG,
+ AYANEO_PWM_MODE_AUTO);
+ default:
+ return -EINVAL;
+ }
+ case hwmon_pwm_input:
+ if (val < 0 || val > 255)
+ return -EINVAL;
+ return ec_write(AYANEO_PWM_REG, (val * 100) / 255);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops ayaneo_ec_hwmon_ops = {
+ .is_visible = ayaneo_ec_hwmon_is_visible,
+ .read = ayaneo_ec_read,
+ .write = ayaneo_ec_write,
+};
+
+static const struct hwmon_channel_info *const ayaneo_ec_sensors[] = {
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
+ NULL,
+};
+
+static const struct hwmon_chip_info ayaneo_ec_chip_info = {
+ .ops = &ayaneo_ec_hwmon_ops,
+ .info = ayaneo_ec_sensors,
+};
+
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;
dmi_entry = dmi_first_match(dmi_table);
if (!dmi_entry)
@@ -52,6 +179,13 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
data->quirks = dmi_entry->driver_data;
platform_set_drvdata(pdev, data);
+ if (data->quirks->has_fan_control) {
+ hwdev = devm_hwmon_device_register_with_info(
+ &pdev->dev, "ayaneo_ec", NULL, &ayaneo_ec_chip_info, NULL);
+ if (IS_ERR(hwdev))
+ return PTR_ERR(hwdev);
+ }
+
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 2/6] platform/x86: ayaneo-ec: Add hwmon support
2025-10-15 8:44 ` [PATCH v2 2/6] platform/x86: ayaneo-ec: Add hwmon support Antheas Kapenekakis
@ 2025-10-26 22:33 ` Armin Wolf
0 siblings, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:33 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> Add hwmon single fan sensor reads and control for Ayaneo devices.
> The register and method of access is the same for all devices.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/Kconfig | 2 +
> drivers/platform/x86/ayaneo-ec.c | 134 +++++++++++++++++++++++++++++++
> 2 files changed, 136 insertions(+)
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index ff2678927696..f132a87fcee9 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -319,6 +319,8 @@ config ASUS_TF103C_DOCK
> config AYANEO_EC
> tristate "Ayaneo EC platform control"
> depends on X86
> + depends on ACPI_EC
> + depends on HWMON
> help
> Enables support for the platform EC of Ayaneo devices. This
> includes fan control, fan speed, charge limit, magic
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 90b86527ab0d..9884eed0cc84 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -7,13 +7,23 @@
> * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
> */
>
> +#include <linux/acpi.h>
> #include <linux/dmi.h>
> +#include <linux/hwmon.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
>
> +#define AYANEO_PWM_ENABLE_REG 0x4A
> +#define AYANEO_PWM_REG 0x4B
> +#define AYANEO_PWM_MODE_AUTO 0x00
> +#define AYANEO_PWM_MODE_MANUAL 0x01
> +
> +#define AYANEO_FAN_REG 0x76
> +
> struct ayaneo_ec_quirk {
> + bool has_fan_control;
> };
>
> struct ayaneo_ec_platform_data {
> @@ -22,6 +32,7 @@ struct ayaneo_ec_platform_data {
> };
>
> static const struct ayaneo_ec_quirk ayaneo3 = {
> + .has_fan_control = true,
> };
>
> static const struct dmi_system_id dmi_table[] = {
> @@ -35,10 +46,126 @@ static const struct dmi_system_id dmi_table[] = {
> {},
> };
>
> +/* Callbacks for hwmon interface */
> +static umode_t ayaneo_ec_hwmon_is_visible(const void *drvdata,
> + enum hwmon_sensor_types type, u32 attr,
> + int channel)
> +{
> + switch (type) {
> + case hwmon_fan:
> + return 0444;
> + case hwmon_pwm:
> + return 0644;
> + default:
> + return 0;
> + }
> +}
> +
> +static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type,
> + u32 attr, int channel, long *val)
> +{
> + u8 tmp;
> + int ret;
> +
> + switch (type) {
> + case hwmon_fan:
> + switch (attr) {
> + case hwmon_fan_input:
> + ret = ec_read(AYANEO_FAN_REG, &tmp);
> + if (ret)
> + return ret;
> + *val = tmp << 8;
> + ret = ec_read(AYANEO_FAN_REG + 1, &tmp);
> + if (ret)
> + return ret;
> + *val += tmp;
> + return 0;
> + default:
> + break;
> + }
> + break;
> + case hwmon_pwm:
> + switch (attr) {
> + case hwmon_pwm_input:
> + ret = ec_read(AYANEO_PWM_REG, &tmp);
> + if (ret)
> + return ret;
> + *val = (255 * tmp) / 100;
> + if (*val < 0 || *val > 255)
> + return -EINVAL;
I think it would make more sense to first check if tmp has a value between 0 and 100 and
then performing the calculation. Also please return -EIO instead of -EINVAL.
> + return 0;
> + case hwmon_pwm_enable:
> + ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
> + if (ret)
> + return ret;
> + if (tmp == AYANEO_PWM_MODE_MANUAL)
> + *val = 1;
> + else
> + *val = 2;
Please check for AYANEO_PWM_MODE_MANUAL as well and return -EIO if the EC
returned an unknown value.
> + return 0;
> + default:
> + break;
> + }
> + break;
> + default:
> + break;
> + }
> + return -EOPNOTSUPP;
> +}
> +
> +static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type,
> + u32 attr, int channel, long val)
> +{
> + switch (type) {
> + case hwmon_pwm:
> + switch (attr) {
> + case hwmon_pwm_enable:
> + switch (val) {
> + case 1:
> + return ec_write(AYANEO_PWM_ENABLE_REG,
> + AYANEO_PWM_MODE_MANUAL);
> + case 2:
> + return ec_write(AYANEO_PWM_ENABLE_REG,
> + AYANEO_PWM_MODE_AUTO);
> + default:
> + return -EINVAL;
> + }
> + case hwmon_pwm_input:
> + if (val < 0 || val > 255)
> + return -EINVAL;
> + return ec_write(AYANEO_PWM_REG, (val * 100) / 255);
> + default:
> + break;
> + }
> + break;
> + default:
> + break;
> + }
> + return -EOPNOTSUPP;
> +}
> +
> +static const struct hwmon_ops ayaneo_ec_hwmon_ops = {
> + .is_visible = ayaneo_ec_hwmon_is_visible,
> + .read = ayaneo_ec_read,
> + .write = ayaneo_ec_write,
> +};
> +
> +static const struct hwmon_channel_info *const ayaneo_ec_sensors[] = {
> + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
> + HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
> + NULL,
> +};
> +
> +static const struct hwmon_chip_info ayaneo_ec_chip_info = {
> + .ops = &ayaneo_ec_hwmon_ops,
> + .info = ayaneo_ec_sensors,
> +};
> +
> 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;
>
> dmi_entry = dmi_first_match(dmi_table);
> if (!dmi_entry)
> @@ -52,6 +179,13 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> data->quirks = dmi_entry->driver_data;
> platform_set_drvdata(pdev, data);
>
> + if (data->quirks->has_fan_control) {
> + hwdev = devm_hwmon_device_register_with_info(
> + &pdev->dev, "ayaneo_ec", NULL, &ayaneo_ec_chip_info, NULL);
Please run "./scripts/checkpatch.pl --strict" on this file and fix any issues.
Thanks,
Armin Wolf
> + if (IS_ERR(hwdev))
> + return PTR_ERR(hwdev);
> + }
> +
> return 0;
> }
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 3/6] platform/x86: ayaneo-ec: Add charge control support
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
2025-10-15 8:44 ` [PATCH v2 1/6] " Antheas Kapenekakis
2025-10-15 8:44 ` [PATCH v2 2/6] platform/x86: ayaneo-ec: Add hwmon support Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-26 22:35 ` Armin Wolf
2025-10-15 8:44 ` [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes Antheas Kapenekakis
` (2 subsequent siblings)
5 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, 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.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.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 f132a87fcee9..f5b2edc6bc67 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 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 9884eed0cc84..23c283f5eb61 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[] = {
@@ -161,11 +172,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)
@@ -186,6 +288,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;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 3/6] platform/x86: ayaneo-ec: Add charge control support
2025-10-15 8:44 ` [PATCH v2 3/6] platform/x86: ayaneo-ec: Add charge control support Antheas Kapenekakis
@ 2025-10-26 22:35 ` Armin Wolf
0 siblings, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:35 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 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.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.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 f132a87fcee9..f5b2edc6bc67 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 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 9884eed0cc84..23c283f5eb61 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>
You should also include <linux/power_supply.h>. With that being fixed:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
> #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[] = {
> @@ -161,11 +172,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)
> @@ -186,6 +288,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;
> }
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
` (2 preceding siblings ...)
2025-10-15 8:44 ` [PATCH v2 3/6] platform/x86: ayaneo-ec: Add charge control support Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-15 9:05 ` Ilpo Järvinen
2025-10-26 22:42 ` Armin Wolf
2025-10-15 8:44 ` [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec Antheas Kapenekakis
2025-10-15 8:44 ` [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook Antheas Kapenekakis
5 siblings, 2 replies; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, Antheas Kapenekakis
The Ayaneo 3 features hot-swappable controller modules. The ejection
and management is done through HID. However, after ejecting the modules,
the controller needs to be power cycled via the EC to re-initialize.
For this, the EC provides a variable that holds whether the left or
right modules are connected, and a power control register to turn
the controller on or off. After ejecting the modules, the controller
should be turned off. Then, after both modules are reinserted,
the controller may be powered on again to re-initialize.
This patch introduces two new sysfs attributes:
- `controller_modules`: a read-only attribute that indicates whether
the left and right modules are connected (none, left, right, both).
- `controller_power`: a read-write attribute that allows the user
to turn the controller on or off (with '1'/'0').
Therefore, after ejection is complete, userspace can power off the
controller, then wait until both modules have been reinserted
(`controller_modules` will return 'both') to turn on the controller.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
.../ABI/testing/sysfs-platform-ayaneo | 19 ++++
MAINTAINERS | 1 +
drivers/platform/x86/ayaneo-ec.c | 100 ++++++++++++++++++
3 files changed, 120 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-platform-ayaneo
diff --git a/Documentation/ABI/testing/sysfs-platform-ayaneo b/Documentation/ABI/testing/sysfs-platform-ayaneo
new file mode 100644
index 000000000000..1fa32ba60fd0
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-ayaneo
@@ -0,0 +1,19 @@
+What: /sys/devices/platform/<platform>/controller_power
+Date: Oct 2025
+KernelVersion: 6.9
+Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
+Description:
+ Current controller power state. Allows turning on and off
+ the controller power (e.g. for power savings). Write 1 to
+ turn on, 0 to turn off. File is readable and writable.
+
+What: /sys/devices/platform/<platform>/controller_modules
+Date: Oct 2025
+KernelVersion: 6.9
+Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
+Description:
+ Shows which controller modules are currently connected to
+ the device. Possible values are "left", "right" and "both".
+ File is read-only. The Windows software for this device
+ will only set controller power to 1 if both module sides
+ are connected (i.e. this file returns "both").
diff --git a/MAINTAINERS b/MAINTAINERS
index 8c4d0c26ca77..3dfa004555dd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4191,6 +4191,7 @@ AYANEO PLATFORM EC DRIVER
M: Antheas Kapenekakis <lkml@antheas.dev>
L: platform-driver-x86@vger.kernel.org
S: Maintained
+F: Documentation/ABI/testing/sysfs-platform-ayaneo
F: drivers/platform/x86/ayaneo-ec.c
AZ6007 DVB DRIVER
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
index 23c283f5eb61..363b61fc6e12 100644
--- a/drivers/platform/x86/ayaneo-ec.c
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -30,9 +30,17 @@
#define AYANEO_CHARGE_VAL_AUTO 0xaa
#define AYANEO_CHARGE_VAL_INHIBIT 0x55
+#define AYANEO_POWER_REG 0x2d
+#define AYANEO_POWER_OFF 0xfe
+#define AYANEO_POWER_ON 0xff
+#define AYANEO_MODULE_REG 0x2f
+#define AYANEO_MODULE_LEFT BIT(0)
+#define AYANEO_MODULE_RIGHT BIT(1)
+
struct ayaneo_ec_quirk {
bool has_fan_control;
bool has_charge_control;
+ bool has_magic_modules;
};
struct ayaneo_ec_platform_data {
@@ -44,6 +52,7 @@ struct ayaneo_ec_platform_data {
static const struct ayaneo_ec_quirk ayaneo3 = {
.has_fan_control = true,
.has_charge_control = true,
+ .has_magic_modules = true,
};
static const struct dmi_system_id dmi_table[] = {
@@ -262,6 +271,96 @@ static int ayaneo_remove_battery(struct power_supply *battery,
return 0;
}
+static ssize_t controller_power_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ bool value;
+ int ret;
+
+ ret = kstrtobool(buf, &value);
+ if (ret)
+ return ret;
+
+ ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t controller_power_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ u8 val;
+
+ ret = ec_read(AYANEO_POWER_REG, &val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
+}
+
+static DEVICE_ATTR_RW(controller_power);
+
+static ssize_t controller_modules_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ bool left, right;
+ char *out;
+ int ret;
+ u8 val;
+
+ ret = ec_read(AYANEO_MODULE_REG, &val);
+ if (ret)
+ return ret;
+
+ left = !(val & AYANEO_MODULE_LEFT);
+ right = !(val & AYANEO_MODULE_RIGHT);
+
+ if (left && right)
+ out = "both";
+ else if (left)
+ out = "left";
+ else if (right)
+ out = "right";
+ else
+ out = "none";
+
+ return sysfs_emit(buf, "%s\n", out);
+}
+
+static DEVICE_ATTR_RO(controller_modules);
+
+static struct attribute *aya_mm_attrs[] = {
+ &dev_attr_controller_power.attr,
+ &dev_attr_controller_modules.attr,
+ NULL
+};
+
+static umode_t aya_mm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+
+ if (data->quirks->has_magic_modules)
+ return attr->mode;
+ return 0;
+}
+
+static const struct attribute_group aya_mm_attribute_group = {
+ .is_visible = aya_mm_is_visible,
+ .attrs = aya_mm_attrs,
+};
+
+static const struct attribute_group *ayaneo_ec_groups[] = {
+ &aya_mm_attribute_group,
+ NULL
+};
+
static int ayaneo_ec_probe(struct platform_device *pdev)
{
const struct dmi_system_id *dmi_entry;
@@ -303,6 +402,7 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
static struct platform_driver ayaneo_platform_driver = {
.driver = {
.name = "ayaneo-ec",
+ .dev_groups = ayaneo_ec_groups,
},
.probe = ayaneo_ec_probe,
};
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes
2025-10-15 8:44 ` [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes Antheas Kapenekakis
@ 2025-10-15 9:05 ` Ilpo Järvinen
2025-10-15 9:08 ` Ilpo Järvinen
2025-10-26 22:42 ` Armin Wolf
1 sibling, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:05 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> The Ayaneo 3 features hot-swappable controller modules. The ejection
> and management is done through HID. However, after ejecting the modules,
> the controller needs to be power cycled via the EC to re-initialize.
>
> For this, the EC provides a variable that holds whether the left or
> right modules are connected, and a power control register to turn
> the controller on or off. After ejecting the modules, the controller
> should be turned off. Then, after both modules are reinserted,
> the controller may be powered on again to re-initialize.
>
> This patch introduces two new sysfs attributes:
> - `controller_modules`: a read-only attribute that indicates whether
> the left and right modules are connected (none, left, right, both).
> - `controller_power`: a read-write attribute that allows the user
> to turn the controller on or off (with '1'/'0').
>
> Therefore, after ejection is complete, userspace can power off the
> controller, then wait until both modules have been reinserted
> (`controller_modules` will return 'both') to turn on the controller.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> .../ABI/testing/sysfs-platform-ayaneo | 19 ++++
> MAINTAINERS | 1 +
> drivers/platform/x86/ayaneo-ec.c | 100 ++++++++++++++++++
> 3 files changed, 120 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-ayaneo
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-ayaneo b/Documentation/ABI/testing/sysfs-platform-ayaneo
> new file mode 100644
> index 000000000000..1fa32ba60fd0
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-ayaneo
> @@ -0,0 +1,19 @@
> +What: /sys/devices/platform/<platform>/controller_power
> +Date: Oct 2025
> +KernelVersion: 6.9
> +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> +Description:
> + Current controller power state. Allows turning on and off
> + the controller power (e.g. for power savings). Write 1 to
> + turn on, 0 to turn off. File is readable and writable.
> +
> +What: /sys/devices/platform/<platform>/controller_modules
> +Date: Oct 2025
> +KernelVersion: 6.9
> +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> +Description:
> + Shows which controller modules are currently connected to
> + the device. Possible values are "left", "right" and "both".
> + File is read-only. The Windows software for this device
> + will only set controller power to 1 if both module sides
> + are connected (i.e. this file returns "both").
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8c4d0c26ca77..3dfa004555dd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4191,6 +4191,7 @@ AYANEO PLATFORM EC DRIVER
> M: Antheas Kapenekakis <lkml@antheas.dev>
> L: platform-driver-x86@vger.kernel.org
> S: Maintained
> +F: Documentation/ABI/testing/sysfs-platform-ayaneo
> F: drivers/platform/x86/ayaneo-ec.c
>
> AZ6007 DVB DRIVER
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 23c283f5eb61..363b61fc6e12 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -30,9 +30,17 @@
> #define AYANEO_CHARGE_VAL_AUTO 0xaa
> #define AYANEO_CHARGE_VAL_INHIBIT 0x55
>
> +#define AYANEO_POWER_REG 0x2d
> +#define AYANEO_POWER_OFF 0xfe
> +#define AYANEO_POWER_ON 0xff
> +#define AYANEO_MODULE_REG 0x2f
> +#define AYANEO_MODULE_LEFT BIT(0)
> +#define AYANEO_MODULE_RIGHT BIT(1)
> +
> struct ayaneo_ec_quirk {
> bool has_fan_control;
> bool has_charge_control;
> + bool has_magic_modules;
> };
>
> struct ayaneo_ec_platform_data {
> @@ -44,6 +52,7 @@ struct ayaneo_ec_platform_data {
> static const struct ayaneo_ec_quirk ayaneo3 = {
> .has_fan_control = true,
> .has_charge_control = true,
> + .has_magic_modules = true,
> };
>
> static const struct dmi_system_id dmi_table[] = {
> @@ -262,6 +271,96 @@ static int ayaneo_remove_battery(struct power_supply *battery,
> return 0;
> }
>
> +static ssize_t controller_power_store(struct device *dev,
> + struct device_attribute *attr, const char *buf,
> + size_t count)
> +{
> + bool value;
> + int ret;
> +
> + ret = kstrtobool(buf, &value);
> + if (ret)
> + return ret;
> +
> + ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> +static ssize_t controller_power_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int ret;
> + u8 val;
> +
> + ret = ec_read(AYANEO_POWER_REG, &val);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
> +}
> +
> +static DEVICE_ATTR_RW(controller_power);
> +
> +static ssize_t controller_modules_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + bool left, right;
> + char *out;
> + int ret;
> + u8 val;
> +
> + ret = ec_read(AYANEO_MODULE_REG, &val);
> + if (ret)
> + return ret;
> +
> + left = !(val & AYANEO_MODULE_LEFT);
> + right = !(val & AYANEO_MODULE_RIGHT);
> +
> + if (left && right)
> + out = "both";
> + else if (left)
> + out = "left";
> + else if (right)
> + out = "right";
> + else
> + out = "none";
I suggest using switch/case for this so you don't need the internal
booleans at all.
BTW, I appreciate it very much this series is split per feature, it's so
much less daunting to start a review when I know I can actually finish
before the next interruption (and having to flush context from my
mind). :-)
--
i.
> +
> + return sysfs_emit(buf, "%s\n", out);
> +}
> +
> +static DEVICE_ATTR_RO(controller_modules);
> +
> +static struct attribute *aya_mm_attrs[] = {
> + &dev_attr_controller_power.attr,
> + &dev_attr_controller_modules.attr,
> + NULL
> +};
> +
> +static umode_t aya_mm_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> +
> + if (data->quirks->has_magic_modules)
> + return attr->mode;
> + return 0;
> +}
> +
> +static const struct attribute_group aya_mm_attribute_group = {
> + .is_visible = aya_mm_is_visible,
> + .attrs = aya_mm_attrs,
> +};
> +
> +static const struct attribute_group *ayaneo_ec_groups[] = {
> + &aya_mm_attribute_group,
> + NULL
> +};
> +
> static int ayaneo_ec_probe(struct platform_device *pdev)
> {
> const struct dmi_system_id *dmi_entry;
> @@ -303,6 +402,7 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> static struct platform_driver ayaneo_platform_driver = {
> .driver = {
> .name = "ayaneo-ec",
> + .dev_groups = ayaneo_ec_groups,
> },
> .probe = ayaneo_ec_probe,
> };
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes
2025-10-15 9:05 ` Ilpo Järvinen
@ 2025-10-15 9:08 ` Ilpo Järvinen
0 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:08 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
[-- Attachment #1: Type: text/plain, Size: 6195 bytes --]
On Wed, 15 Oct 2025, Ilpo Järvinen wrote:
> On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
>
> > The Ayaneo 3 features hot-swappable controller modules. The ejection
> > and management is done through HID. However, after ejecting the modules,
> > the controller needs to be power cycled via the EC to re-initialize.
> >
> > For this, the EC provides a variable that holds whether the left or
> > right modules are connected, and a power control register to turn
> > the controller on or off. After ejecting the modules, the controller
> > should be turned off. Then, after both modules are reinserted,
> > the controller may be powered on again to re-initialize.
> >
> > This patch introduces two new sysfs attributes:
> > - `controller_modules`: a read-only attribute that indicates whether
> > the left and right modules are connected (none, left, right, both).
> > - `controller_power`: a read-write attribute that allows the user
> > to turn the controller on or off (with '1'/'0').
> >
> > Therefore, after ejection is complete, userspace can power off the
> > controller, then wait until both modules have been reinserted
> > (`controller_modules` will return 'both') to turn on the controller.
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
> > .../ABI/testing/sysfs-platform-ayaneo | 19 ++++
> > MAINTAINERS | 1 +
> > drivers/platform/x86/ayaneo-ec.c | 100 ++++++++++++++++++
> > 3 files changed, 120 insertions(+)
> > create mode 100644 Documentation/ABI/testing/sysfs-platform-ayaneo
> >
> > diff --git a/Documentation/ABI/testing/sysfs-platform-ayaneo b/Documentation/ABI/testing/sysfs-platform-ayaneo
> > new file mode 100644
> > index 000000000000..1fa32ba60fd0
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-platform-ayaneo
> > @@ -0,0 +1,19 @@
> > +What: /sys/devices/platform/<platform>/controller_power
> > +Date: Oct 2025
> > +KernelVersion: 6.9
> > +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> > +Description:
> > + Current controller power state. Allows turning on and off
> > + the controller power (e.g. for power savings). Write 1 to
> > + turn on, 0 to turn off. File is readable and writable.
> > +
> > +What: /sys/devices/platform/<platform>/controller_modules
> > +Date: Oct 2025
> > +KernelVersion: 6.9
> > +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> > +Description:
> > + Shows which controller modules are currently connected to
> > + the device. Possible values are "left", "right" and "both".
> > + File is read-only. The Windows software for this device
> > + will only set controller power to 1 if both module sides
> > + are connected (i.e. this file returns "both").
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 8c4d0c26ca77..3dfa004555dd 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -4191,6 +4191,7 @@ AYANEO PLATFORM EC DRIVER
> > M: Antheas Kapenekakis <lkml@antheas.dev>
> > L: platform-driver-x86@vger.kernel.org
> > S: Maintained
> > +F: Documentation/ABI/testing/sysfs-platform-ayaneo
> > F: drivers/platform/x86/ayaneo-ec.c
> >
> > AZ6007 DVB DRIVER
> > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > index 23c283f5eb61..363b61fc6e12 100644
> > --- a/drivers/platform/x86/ayaneo-ec.c
> > +++ b/drivers/platform/x86/ayaneo-ec.c
> > @@ -30,9 +30,17 @@
> > #define AYANEO_CHARGE_VAL_AUTO 0xaa
> > #define AYANEO_CHARGE_VAL_INHIBIT 0x55
> >
> > +#define AYANEO_POWER_REG 0x2d
> > +#define AYANEO_POWER_OFF 0xfe
> > +#define AYANEO_POWER_ON 0xff
> > +#define AYANEO_MODULE_REG 0x2f
> > +#define AYANEO_MODULE_LEFT BIT(0)
> > +#define AYANEO_MODULE_RIGHT BIT(1)
Also, add include for BIT().
> > +
> > struct ayaneo_ec_quirk {
> > bool has_fan_control;
> > bool has_charge_control;
> > + bool has_magic_modules;
> > };
> >
> > struct ayaneo_ec_platform_data {
> > @@ -44,6 +52,7 @@ struct ayaneo_ec_platform_data {
> > static const struct ayaneo_ec_quirk ayaneo3 = {
> > .has_fan_control = true,
> > .has_charge_control = true,
> > + .has_magic_modules = true,
> > };
> >
> > static const struct dmi_system_id dmi_table[] = {
> > @@ -262,6 +271,96 @@ static int ayaneo_remove_battery(struct power_supply *battery,
> > return 0;
> > }
> >
> > +static ssize_t controller_power_store(struct device *dev,
> > + struct device_attribute *attr, const char *buf,
> > + size_t count)
> > +{
> > + bool value;
> > + int ret;
> > +
> > + ret = kstrtobool(buf, &value);
> > + if (ret)
> > + return ret;
> > +
> > + ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
> > + if (ret)
> > + return ret;
> > +
> > + return count;
> > +}
> > +
> > +static ssize_t controller_power_show(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + int ret;
> > + u8 val;
> > +
> > + ret = ec_read(AYANEO_POWER_REG, &val);
> > + if (ret)
> > + return ret;
> > +
> > + return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
Add include.
--
i.
> > +}
> > +
> > +static DEVICE_ATTR_RW(controller_power);
> > +
> > +static ssize_t controller_modules_show(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + bool left, right;
> > + char *out;
> > + int ret;
> > + u8 val;
> > +
> > + ret = ec_read(AYANEO_MODULE_REG, &val);
> > + if (ret)
> > + return ret;
> > +
> > + left = !(val & AYANEO_MODULE_LEFT);
> > + right = !(val & AYANEO_MODULE_RIGHT);
> > +
> > + if (left && right)
> > + out = "both";
> > + else if (left)
> > + out = "left";
> > + else if (right)
> > + out = "right";
> > + else
> > + out = "none";
>
> I suggest using switch/case for this so you don't need the internal
> booleans at all.
>
> BTW, I appreciate it very much this series is split per feature, it's so
> much less daunting to start a review when I know I can actually finish
> before the next interruption (and having to flush context from my
> mind). :-)
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes
2025-10-15 8:44 ` [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes Antheas Kapenekakis
2025-10-15 9:05 ` Ilpo Järvinen
@ 2025-10-26 22:42 ` Armin Wolf
1 sibling, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:42 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> The Ayaneo 3 features hot-swappable controller modules. The ejection
> and management is done through HID. However, after ejecting the modules,
> the controller needs to be power cycled via the EC to re-initialize.
>
> For this, the EC provides a variable that holds whether the left or
> right modules are connected, and a power control register to turn
> the controller on or off. After ejecting the modules, the controller
> should be turned off. Then, after both modules are reinserted,
> the controller may be powered on again to re-initialize.
>
> This patch introduces two new sysfs attributes:
> - `controller_modules`: a read-only attribute that indicates whether
> the left and right modules are connected (none, left, right, both).
> - `controller_power`: a read-write attribute that allows the user
> to turn the controller on or off (with '1'/'0').
>
> Therefore, after ejection is complete, userspace can power off the
> controller, then wait until both modules have been reinserted
> (`controller_modules` will return 'both') to turn on the controller.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> .../ABI/testing/sysfs-platform-ayaneo | 19 ++++
> MAINTAINERS | 1 +
> drivers/platform/x86/ayaneo-ec.c | 100 ++++++++++++++++++
> 3 files changed, 120 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-ayaneo
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-ayaneo b/Documentation/ABI/testing/sysfs-platform-ayaneo
> new file mode 100644
> index 000000000000..1fa32ba60fd0
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-ayaneo
Better use Documentation/ABI/testing/sysfs-platform-ayaneo-ec.
> @@ -0,0 +1,19 @@
> +What: /sys/devices/platform/<platform>/controller_power
Better use /sys/devices/platform/ayaneo-ec/controller_power.
> +Date: Oct 2025
> +KernelVersion: 6.9
Kernel version is outdated.
> +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> +Description:
> + Current controller power state. Allows turning on and off
> + the controller power (e.g. for power savings). Write 1 to
> + turn on, 0 to turn off. File is readable and writable.
> +
> +What: /sys/devices/platform/<platform>/controller_modules
See above.
> +Date: Oct 2025
> +KernelVersion: 6.9
See above.
With this being fixed:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> +Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
> +Description:
> + Shows which controller modules are currently connected to
> + the device. Possible values are "left", "right" and "both".
> + File is read-only. The Windows software for this device
> + will only set controller power to 1 if both module sides
> + are connected (i.e. this file returns "both").
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8c4d0c26ca77..3dfa004555dd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4191,6 +4191,7 @@ AYANEO PLATFORM EC DRIVER
> M: Antheas Kapenekakis <lkml@antheas.dev>
> L: platform-driver-x86@vger.kernel.org
> S: Maintained
> +F: Documentation/ABI/testing/sysfs-platform-ayaneo
> F: drivers/platform/x86/ayaneo-ec.c
>
> AZ6007 DVB DRIVER
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 23c283f5eb61..363b61fc6e12 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -30,9 +30,17 @@
> #define AYANEO_CHARGE_VAL_AUTO 0xaa
> #define AYANEO_CHARGE_VAL_INHIBIT 0x55
>
> +#define AYANEO_POWER_REG 0x2d
> +#define AYANEO_POWER_OFF 0xfe
> +#define AYANEO_POWER_ON 0xff
> +#define AYANEO_MODULE_REG 0x2f
> +#define AYANEO_MODULE_LEFT BIT(0)
> +#define AYANEO_MODULE_RIGHT BIT(1)
> +
> struct ayaneo_ec_quirk {
> bool has_fan_control;
> bool has_charge_control;
> + bool has_magic_modules;
> };
>
> struct ayaneo_ec_platform_data {
> @@ -44,6 +52,7 @@ struct ayaneo_ec_platform_data {
> static const struct ayaneo_ec_quirk ayaneo3 = {
> .has_fan_control = true,
> .has_charge_control = true,
> + .has_magic_modules = true,
> };
>
> static const struct dmi_system_id dmi_table[] = {
> @@ -262,6 +271,96 @@ static int ayaneo_remove_battery(struct power_supply *battery,
> return 0;
> }
>
> +static ssize_t controller_power_store(struct device *dev,
> + struct device_attribute *attr, const char *buf,
> + size_t count)
> +{
> + bool value;
> + int ret;
> +
> + ret = kstrtobool(buf, &value);
> + if (ret)
> + return ret;
> +
> + ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> +static ssize_t controller_power_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int ret;
> + u8 val;
> +
> + ret = ec_read(AYANEO_POWER_REG, &val);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
> +}
> +
> +static DEVICE_ATTR_RW(controller_power);
> +
> +static ssize_t controller_modules_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + bool left, right;
> + char *out;
> + int ret;
> + u8 val;
> +
> + ret = ec_read(AYANEO_MODULE_REG, &val);
> + if (ret)
> + return ret;
> +
> + left = !(val & AYANEO_MODULE_LEFT);
> + right = !(val & AYANEO_MODULE_RIGHT);
> +
> + if (left && right)
> + out = "both";
> + else if (left)
> + out = "left";
> + else if (right)
> + out = "right";
> + else
> + out = "none";
> +
> + return sysfs_emit(buf, "%s\n", out);
> +}
> +
> +static DEVICE_ATTR_RO(controller_modules);
> +
> +static struct attribute *aya_mm_attrs[] = {
> + &dev_attr_controller_power.attr,
> + &dev_attr_controller_modules.attr,
> + NULL
> +};
> +
> +static umode_t aya_mm_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> +
> + if (data->quirks->has_magic_modules)
> + return attr->mode;
> + return 0;
> +}
> +
> +static const struct attribute_group aya_mm_attribute_group = {
> + .is_visible = aya_mm_is_visible,
> + .attrs = aya_mm_attrs,
> +};
> +
> +static const struct attribute_group *ayaneo_ec_groups[] = {
> + &aya_mm_attribute_group,
> + NULL
> +};
> +
> static int ayaneo_ec_probe(struct platform_device *pdev)
> {
> const struct dmi_system_id *dmi_entry;
> @@ -303,6 +402,7 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> static struct platform_driver ayaneo_platform_driver = {
> .driver = {
> .name = "ayaneo-ec",
> + .dev_groups = ayaneo_ec_groups,
> },
> .probe = ayaneo_ec_probe,
> };
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
` (3 preceding siblings ...)
2025-10-15 8:44 ` [PATCH v2 4/6] platform/x86: ayaneo-ec: Add controller power and modules attributes Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-15 9:09 ` Ilpo Järvinen
2025-10-26 22:45 ` Armin Wolf
2025-10-15 8:44 ` [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook Antheas Kapenekakis
5 siblings, 2 replies; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, Antheas Kapenekakis
Currently, the oxpec driver contains Ayaneo devices. Move them to the
new ayaneo-ec driver, which is dedicated to them.
As this driver supports charge inhibition for Ayaneo, add support for it
for the AIR, AIR 1S, AB05-Medoncino, AIR Pro, and Kun, referenced from
the out-of-tree ayaneo-platform driver.
In addition, update the readmes of oxpec to reflect this change.
Link: https://github.com/ShadowBlip/ayaneo-platform
Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/platform/x86/Kconfig | 4 +-
drivers/platform/x86/ayaneo-ec.c | 65 +++++++++++++++++
drivers/platform/x86/oxpec.c | 115 +------------------------------
3 files changed, 67 insertions(+), 117 deletions(-)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f5b2edc6bc67..4d4be1634152 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1043,9 +1043,7 @@ config OXP_EC
help
Enables support for the platform EC of OneXPlayer and AOKZOE
handheld devices. This includes fan speed, fan controls, and
- disabling the default TDP behavior of the device. Due to legacy
- reasons, this driver also provides hwmon functionality to Ayaneo
- devices and the OrangePi Neo.
+ disabling the default TDP behavior of the device.
source "drivers/platform/x86/tuxedo/Kconfig"
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
index 363b61fc6e12..73e9dd39c703 100644
--- a/drivers/platform/x86/ayaneo-ec.c
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -49,6 +49,15 @@ struct ayaneo_ec_platform_data {
struct acpi_battery_hook battery_hook;
};
+static const struct ayaneo_ec_quirk quirk_fan = {
+ .has_fan_control = true,
+};
+
+static const struct ayaneo_ec_quirk quirk_charge_limit = {
+ .has_fan_control = true,
+ .has_charge_control = true,
+};
+
static const struct ayaneo_ec_quirk ayaneo3 = {
.has_fan_control = true,
.has_charge_control = true,
@@ -56,6 +65,62 @@ static const struct ayaneo_ec_quirk ayaneo3 = {
};
static const struct dmi_system_id dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
index 54377b282ff8..144a454103b9 100644
--- a/drivers/platform/x86/oxpec.c
+++ b/drivers/platform/x86/oxpec.c
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Platform driver for OneXPlayer and AOKZOE devices. For the time being,
- * it also exposes fan controls for AYANEO, and OrangePi Handhelds via
- * hwmon sysfs.
+ * Platform driver for OneXPlayer and AOKZOE devices.
*
* Fan control is provided via pwm interface in the range [0-255].
* Old AMD boards use [0-100] as range in the EC, the written value is
@@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void)
enum oxp_board {
aok_zoe_a1 = 1,
- aya_neo_2,
- aya_neo_air,
- aya_neo_air_1s,
- aya_neo_air_plus_mendo,
- aya_neo_air_pro,
- aya_neo_flip,
- aya_neo_geek,
- aya_neo_kun,
orange_pi_neo,
oxp_2,
oxp_fly,
@@ -131,62 +121,6 @@ static const struct dmi_system_id dmi_table[] = {
},
.driver_data = (void *)oxp_fly,
},
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
- },
- .driver_data = (void *)aya_neo_2,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
- },
- .driver_data = (void *)aya_neo_air,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
- },
- .driver_data = (void *)aya_neo_air_1s,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
- },
- .driver_data = (void *)aya_neo_air_plus_mendo,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
- },
- .driver_data = (void *)aya_neo_air_pro,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
- },
- .driver_data = (void *)aya_neo_flip,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
- },
- .driver_data = (void *)aya_neo_geek,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
- },
- .driver_data = (void *)aya_neo_kun,
- },
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
@@ -672,13 +606,6 @@ static int oxp_pwm_enable(void)
case orange_pi_neo:
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -699,14 +626,6 @@ static int oxp_pwm_disable(void)
case orange_pi_neo:
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val)
case orange_pi_neo:
return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val)
case oxp_g1_i:
return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_fly:
case oxp_mini_amd:
case oxp_mini_amd_a07:
@@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val)
/* scale to range [0-184] */
val = (val * 184) / 255;
return write_to_ec(OXP_SENSOR_PWM_REG, val);
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_mini_amd:
case oxp_mini_amd_a07:
/* scale to range [0-100] */
@@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val)
/* scale from range [0-184] */
*val = (*val * 255) / 184;
break;
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_mini_amd:
case oxp_mini_amd_a07:
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec
2025-10-15 8:44 ` [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec Antheas Kapenekakis
@ 2025-10-15 9:09 ` Ilpo Järvinen
2025-10-26 22:45 ` Armin Wolf
1 sibling, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:09 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
[-- Attachment #1: Type: text/plain, Size: 9231 bytes --]
On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> Currently, the oxpec driver contains Ayaneo devices. Move them to the
> new ayaneo-ec driver, which is dedicated to them.
>
> As this driver supports charge inhibition for Ayaneo, add support for it
> for the AIR, AIR 1S, AB05-Medoncino, AIR Pro, and Kun, referenced from
> the out-of-tree ayaneo-platform driver.
>
> In addition, update the readmes of oxpec to reflect this change.
>
> Link: https://github.com/ShadowBlip/ayaneo-platform
> Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/Kconfig | 4 +-
> drivers/platform/x86/ayaneo-ec.c | 65 +++++++++++++++++
> drivers/platform/x86/oxpec.c | 115 +------------------------------
> 3 files changed, 67 insertions(+), 117 deletions(-)
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index f5b2edc6bc67..4d4be1634152 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -1043,9 +1043,7 @@ config OXP_EC
> help
> Enables support for the platform EC of OneXPlayer and AOKZOE
> handheld devices. This includes fan speed, fan controls, and
> - disabling the default TDP behavior of the device. Due to legacy
> - reasons, this driver also provides hwmon functionality to Ayaneo
> - devices and the OrangePi Neo.
> + disabling the default TDP behavior of the device.
>
> source "drivers/platform/x86/tuxedo/Kconfig"
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 363b61fc6e12..73e9dd39c703 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -49,6 +49,15 @@ struct ayaneo_ec_platform_data {
> struct acpi_battery_hook battery_hook;
> };
>
> +static const struct ayaneo_ec_quirk quirk_fan = {
> + .has_fan_control = true,
> +};
> +
> +static const struct ayaneo_ec_quirk quirk_charge_limit = {
> + .has_fan_control = true,
> + .has_charge_control = true,
> +};
> +
> static const struct ayaneo_ec_quirk ayaneo3 = {
> .has_fan_control = true,
> .has_charge_control = true,
> @@ -56,6 +65,62 @@ static const struct ayaneo_ec_quirk ayaneo3 = {
> };
>
> static const struct dmi_system_id dmi_table[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> {
> .matches = {
> DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
> index 54377b282ff8..144a454103b9 100644
> --- a/drivers/platform/x86/oxpec.c
> +++ b/drivers/platform/x86/oxpec.c
> @@ -1,8 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0+
> /*
> - * Platform driver for OneXPlayer and AOKZOE devices. For the time being,
> - * it also exposes fan controls for AYANEO, and OrangePi Handhelds via
> - * hwmon sysfs.
> + * Platform driver for OneXPlayer and AOKZOE devices.
> *
> * Fan control is provided via pwm interface in the range [0-255].
> * Old AMD boards use [0-100] as range in the EC, the written value is
> @@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void)
>
> enum oxp_board {
> aok_zoe_a1 = 1,
> - aya_neo_2,
> - aya_neo_air,
> - aya_neo_air_1s,
> - aya_neo_air_plus_mendo,
> - aya_neo_air_pro,
> - aya_neo_flip,
> - aya_neo_geek,
> - aya_neo_kun,
> orange_pi_neo,
> oxp_2,
> oxp_fly,
> @@ -131,62 +121,6 @@ static const struct dmi_system_id dmi_table[] = {
> },
> .driver_data = (void *)oxp_fly,
> },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
> - },
> - .driver_data = (void *)aya_neo_2,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
> - },
> - .driver_data = (void *)aya_neo_air,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
> - },
> - .driver_data = (void *)aya_neo_air_1s,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
> - },
> - .driver_data = (void *)aya_neo_air_plus_mendo,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
> - },
> - .driver_data = (void *)aya_neo_air_pro,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
> - },
> - .driver_data = (void *)aya_neo_flip,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
> - },
> - .driver_data = (void *)aya_neo_geek,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
> - },
> - .driver_data = (void *)aya_neo_kun,
> - },
> {
> .matches = {
> DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
> @@ -672,13 +606,6 @@ static int oxp_pwm_enable(void)
> case orange_pi_neo:
> return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -699,14 +626,6 @@ static int oxp_pwm_disable(void)
> case orange_pi_neo:
> return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val)
> case orange_pi_neo:
> return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val)
> case oxp_g1_i:
> return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_fly:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> @@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val)
> /* scale to range [0-184] */
> val = (val * 184) / 255;
> return write_to_ec(OXP_SENSOR_PWM_REG, val);
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> /* scale to range [0-100] */
> @@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val)
> /* scale from range [0-184] */
> *val = (*val * 255) / 184;
> break;
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
--
i.
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec
2025-10-15 8:44 ` [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec Antheas Kapenekakis
2025-10-15 9:09 ` Ilpo Järvinen
@ 2025-10-26 22:45 ` Armin Wolf
1 sibling, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:45 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> Currently, the oxpec driver contains Ayaneo devices. Move them to the
> new ayaneo-ec driver, which is dedicated to them.
>
> As this driver supports charge inhibition for Ayaneo, add support for it
> for the AIR, AIR 1S, AB05-Medoncino, AIR Pro, and Kun, referenced from
> the out-of-tree ayaneo-platform driver.
>
> In addition, update the readmes of oxpec to reflect this change.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
> Link: https://github.com/ShadowBlip/ayaneo-platform
> Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/Kconfig | 4 +-
> drivers/platform/x86/ayaneo-ec.c | 65 +++++++++++++++++
> drivers/platform/x86/oxpec.c | 115 +------------------------------
> 3 files changed, 67 insertions(+), 117 deletions(-)
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index f5b2edc6bc67..4d4be1634152 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -1043,9 +1043,7 @@ config OXP_EC
> help
> Enables support for the platform EC of OneXPlayer and AOKZOE
> handheld devices. This includes fan speed, fan controls, and
> - disabling the default TDP behavior of the device. Due to legacy
> - reasons, this driver also provides hwmon functionality to Ayaneo
> - devices and the OrangePi Neo.
> + disabling the default TDP behavior of the device.
>
> source "drivers/platform/x86/tuxedo/Kconfig"
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 363b61fc6e12..73e9dd39c703 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -49,6 +49,15 @@ struct ayaneo_ec_platform_data {
> struct acpi_battery_hook battery_hook;
> };
>
> +static const struct ayaneo_ec_quirk quirk_fan = {
> + .has_fan_control = true,
> +};
> +
> +static const struct ayaneo_ec_quirk quirk_charge_limit = {
> + .has_fan_control = true,
> + .has_charge_control = true,
> +};
> +
> static const struct ayaneo_ec_quirk ayaneo3 = {
> .has_fan_control = true,
> .has_charge_control = true,
> @@ -56,6 +65,62 @@ static const struct ayaneo_ec_quirk ayaneo3 = {
> };
>
> static const struct dmi_system_id dmi_table[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
> + },
> + .driver_data = (void *)&quirk_fan,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> + DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
> + },
> + .driver_data = (void *)&quirk_charge_limit,
> + },
> {
> .matches = {
> DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
> index 54377b282ff8..144a454103b9 100644
> --- a/drivers/platform/x86/oxpec.c
> +++ b/drivers/platform/x86/oxpec.c
> @@ -1,8 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0+
> /*
> - * Platform driver for OneXPlayer and AOKZOE devices. For the time being,
> - * it also exposes fan controls for AYANEO, and OrangePi Handhelds via
> - * hwmon sysfs.
> + * Platform driver for OneXPlayer and AOKZOE devices.
> *
> * Fan control is provided via pwm interface in the range [0-255].
> * Old AMD boards use [0-100] as range in the EC, the written value is
> @@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void)
>
> enum oxp_board {
> aok_zoe_a1 = 1,
> - aya_neo_2,
> - aya_neo_air,
> - aya_neo_air_1s,
> - aya_neo_air_plus_mendo,
> - aya_neo_air_pro,
> - aya_neo_flip,
> - aya_neo_geek,
> - aya_neo_kun,
> orange_pi_neo,
> oxp_2,
> oxp_fly,
> @@ -131,62 +121,6 @@ static const struct dmi_system_id dmi_table[] = {
> },
> .driver_data = (void *)oxp_fly,
> },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
> - },
> - .driver_data = (void *)aya_neo_2,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
> - },
> - .driver_data = (void *)aya_neo_air,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
> - },
> - .driver_data = (void *)aya_neo_air_1s,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
> - },
> - .driver_data = (void *)aya_neo_air_plus_mendo,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
> - },
> - .driver_data = (void *)aya_neo_air_pro,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
> - },
> - .driver_data = (void *)aya_neo_flip,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
> - },
> - .driver_data = (void *)aya_neo_geek,
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
> - DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
> - },
> - .driver_data = (void *)aya_neo_kun,
> - },
> {
> .matches = {
> DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
> @@ -672,13 +606,6 @@ static int oxp_pwm_enable(void)
> case orange_pi_neo:
> return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -699,14 +626,6 @@ static int oxp_pwm_disable(void)
> case orange_pi_neo:
> return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val)
> case orange_pi_neo:
> return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_2:
> case oxp_fly:
> case oxp_mini_amd:
> @@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val)
> case oxp_g1_i:
> return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
> case aok_zoe_a1:
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_fly:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> @@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val)
> /* scale to range [0-184] */
> val = (val * 184) / 255;
> return write_to_ec(OXP_SENSOR_PWM_REG, val);
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> /* scale to range [0-100] */
> @@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val)
> /* scale from range [0-184] */
> *val = (*val * 255) / 184;
> break;
> - case aya_neo_2:
> - case aya_neo_air:
> - case aya_neo_air_1s:
> - case aya_neo_air_plus_mendo:
> - case aya_neo_air_pro:
> - case aya_neo_flip:
> - case aya_neo_geek:
> - case aya_neo_kun:
> case oxp_mini_amd:
> case oxp_mini_amd_a07:
> ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 8:44 [PATCH v2 0/6] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Antheas Kapenekakis
` (4 preceding siblings ...)
2025-10-15 8:44 ` [PATCH v2 5/6] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec Antheas Kapenekakis
@ 2025-10-15 8:44 ` Antheas Kapenekakis
2025-10-15 9:11 ` Ilpo Järvinen
` (2 more replies)
5 siblings, 3 replies; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 8:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck, Antheas Kapenekakis
The Ayaneo EC resets after hibernation, losing the charge control state.
Add a small PM hook to restore this state on hibernation resume.
The fan speed is also lost during hibernation, but since hibernation
failures are common with this class of devices, setting a low fan speed
when the userspace program controlling the fan will potentially not
take over could cause the device to overheat, so it is not restored.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
index 73e9dd39c703..8529f6f8dc69 100644
--- a/drivers/platform/x86/ayaneo-ec.c
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -37,6 +37,8 @@
#define AYANEO_MODULE_LEFT BIT(0)
#define AYANEO_MODULE_RIGHT BIT(1)
+#define AYANEO_CACHE_LEN 1
+
struct ayaneo_ec_quirk {
bool has_fan_control;
bool has_charge_control;
@@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
struct platform_device *pdev;
struct ayaneo_ec_quirk *quirks;
struct acpi_battery_hook battery_hook;
+
+ u8 cache[AYANEO_CACHE_LEN];
};
static const struct ayaneo_ec_quirk quirk_fan = {
@@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
return 0;
}
+static int ayaneo_freeze(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+ int ret, i = 0;
+
+ if (data->quirks->has_charge_control) {
+ ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
+ if (ret)
+ return ret;
+ i++;
+ }
+
+ return 0;
+}
+
+static int ayaneo_thaw(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+ int ret, i = 0;
+
+ if (data->quirks->has_charge_control) {
+ ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
+ if (ret)
+ return ret;
+ i++;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ayaneo_pm_ops = {
+ .freeze = ayaneo_freeze,
+ .thaw = ayaneo_thaw,
+};
+
static struct platform_driver ayaneo_platform_driver = {
.driver = {
.name = "ayaneo-ec",
.dev_groups = ayaneo_ec_groups,
+ .pm = &ayaneo_pm_ops,
},
.probe = ayaneo_ec_probe,
};
--
2.51.0
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 8:44 ` [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook Antheas Kapenekakis
@ 2025-10-15 9:11 ` Ilpo Järvinen
2025-10-15 9:16 ` Antheas Kapenekakis
2025-10-26 22:49 ` Armin Wolf
2025-10-28 20:26 ` Mario Limonciello
2 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:11 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> The Ayaneo EC resets after hibernation, losing the charge control state.
> Add a small PM hook to restore this state on hibernation resume.
>
> The fan speed is also lost during hibernation, but since hibernation
> failures are common with this class of devices, setting a low fan speed
> when the userspace program controlling the fan will potentially not
> take over could cause the device to overheat, so it is not restored.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 73e9dd39c703..8529f6f8dc69 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -37,6 +37,8 @@
> #define AYANEO_MODULE_LEFT BIT(0)
> #define AYANEO_MODULE_RIGHT BIT(1)
>
> +#define AYANEO_CACHE_LEN 1
> +
> struct ayaneo_ec_quirk {
> bool has_fan_control;
> bool has_charge_control;
> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> struct platform_device *pdev;
> struct ayaneo_ec_quirk *quirks;
> struct acpi_battery_hook battery_hook;
> +
> + u8 cache[AYANEO_CACHE_LEN];
> };
>
> static const struct ayaneo_ec_quirk quirk_fan = {
> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> return 0;
> }
>
> +static int ayaneo_freeze(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
What is this for?
> + }
> +
> + return 0;
> +}
> +
> +static int ayaneo_thaw(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
Same question here.
> + }
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops ayaneo_pm_ops = {
> + .freeze = ayaneo_freeze,
> + .thaw = ayaneo_thaw,
> +};
> +
> static struct platform_driver ayaneo_platform_driver = {
> .driver = {
> .name = "ayaneo-ec",
> .dev_groups = ayaneo_ec_groups,
> + .pm = &ayaneo_pm_ops,
> },
> .probe = ayaneo_ec_probe,
> };
>
--
i.
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 9:11 ` Ilpo Järvinen
@ 2025-10-15 9:16 ` Antheas Kapenekakis
2025-10-15 9:27 ` Ilpo Järvinen
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 9:16 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On Wed, 15 Oct 2025 at 11:11, Ilpo Järvinen
<ilpo.jarvinen@linux.intel.com> wrote:
>
> On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
>
> > The Ayaneo EC resets after hibernation, losing the charge control state.
> > Add a small PM hook to restore this state on hibernation resume.
> >
> > The fan speed is also lost during hibernation, but since hibernation
> > failures are common with this class of devices, setting a low fan speed
> > when the userspace program controlling the fan will potentially not
> > take over could cause the device to overheat, so it is not restored.
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
> > drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> > 1 file changed, 42 insertions(+)
> >
> > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > index 73e9dd39c703..8529f6f8dc69 100644
> > --- a/drivers/platform/x86/ayaneo-ec.c
> > +++ b/drivers/platform/x86/ayaneo-ec.c
> > @@ -37,6 +37,8 @@
> > #define AYANEO_MODULE_LEFT BIT(0)
> > #define AYANEO_MODULE_RIGHT BIT(1)
> >
> > +#define AYANEO_CACHE_LEN 1
> > +
> > struct ayaneo_ec_quirk {
> > bool has_fan_control;
> > bool has_charge_control;
> > @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> > struct platform_device *pdev;
> > struct ayaneo_ec_quirk *quirks;
> > struct acpi_battery_hook battery_hook;
> > +
> > + u8 cache[AYANEO_CACHE_LEN];
> > };
> >
> > static const struct ayaneo_ec_quirk quirk_fan = {
> > @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> > return 0;
> > }
> >
> > +static int ayaneo_freeze(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
>
> What is this for?
Adding additional registers to restore. Currently, there is only one
so it looks out of place.
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int ayaneo_thaw(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
>
> Same question here.
>
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dev_pm_ops ayaneo_pm_ops = {
> > + .freeze = ayaneo_freeze,
> > + .thaw = ayaneo_thaw,
> > +};
> > +
> > static struct platform_driver ayaneo_platform_driver = {
> > .driver = {
> > .name = "ayaneo-ec",
> > .dev_groups = ayaneo_ec_groups,
> > + .pm = &ayaneo_pm_ops,
> > },
> > .probe = ayaneo_ec_probe,
> > };
> >
>
> --
> i.
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 9:16 ` Antheas Kapenekakis
@ 2025-10-15 9:27 ` Ilpo Järvinen
2025-10-15 9:36 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-10-15 9:27 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
[-- Attachment #1: Type: text/plain, Size: 3887 bytes --]
On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> On Wed, 15 Oct 2025 at 11:11, Ilpo Järvinen
> <ilpo.jarvinen@linux.intel.com> wrote:
> >
> > On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> >
> > > The Ayaneo EC resets after hibernation, losing the charge control state.
> > > Add a small PM hook to restore this state on hibernation resume.
> > >
> > > The fan speed is also lost during hibernation, but since hibernation
> > > failures are common with this class of devices, setting a low fan speed
> > > when the userspace program controlling the fan will potentially not
> > > take over could cause the device to overheat, so it is not restored.
> > >
> > > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > > ---
> > > drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> > > 1 file changed, 42 insertions(+)
> > >
> > > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > > index 73e9dd39c703..8529f6f8dc69 100644
> > > --- a/drivers/platform/x86/ayaneo-ec.c
> > > +++ b/drivers/platform/x86/ayaneo-ec.c
> > > @@ -37,6 +37,8 @@
> > > #define AYANEO_MODULE_LEFT BIT(0)
> > > #define AYANEO_MODULE_RIGHT BIT(1)
> > >
> > > +#define AYANEO_CACHE_LEN 1
> > > +
> > > struct ayaneo_ec_quirk {
> > > bool has_fan_control;
> > > bool has_charge_control;
> > > @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> > > struct platform_device *pdev;
> > > struct ayaneo_ec_quirk *quirks;
> > > struct acpi_battery_hook battery_hook;
> > > +
> > > + u8 cache[AYANEO_CACHE_LEN];
> > > };
> > >
> > > static const struct ayaneo_ec_quirk quirk_fan = {
> > > @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> > > return 0;
> > > }
> > >
> > > +static int ayaneo_freeze(struct device *dev)
> > > +{
> > > + struct platform_device *pdev = to_platform_device(dev);
> > > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > > + int ret, i = 0;
> > > +
> > > + if (data->quirks->has_charge_control) {
> > > + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> > > + if (ret)
> > > + return ret;
> > > + i++;
> >
> > What is this for?
>
> Adding additional registers to restore. Currently, there is only one
> so it looks out of place.
When are patches for those additional registers going to be submitted?
If it's not like right around the corner, I'd prefer i be added only
at that time.
In any case, please mention in the changelog there's going to be more to
registers cache so it becomes justified why you're using an array for the
cache.
--
i.
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int ayaneo_thaw(struct device *dev)
> > > +{
> > > + struct platform_device *pdev = to_platform_device(dev);
> > > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > > + int ret, i = 0;
> > > +
> > > + if (data->quirks->has_charge_control) {
> > > + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> > > + if (ret)
> > > + return ret;
> > > + i++;
> >
> > Same question here.
> >
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static const struct dev_pm_ops ayaneo_pm_ops = {
> > > + .freeze = ayaneo_freeze,
> > > + .thaw = ayaneo_thaw,
> > > +};
> > > +
> > > static struct platform_driver ayaneo_platform_driver = {
> > > .driver = {
> > > .name = "ayaneo-ec",
> > > .dev_groups = ayaneo_ec_groups,
> > > + .pm = &ayaneo_pm_ops,
> > > },
> > > .probe = ayaneo_ec_probe,
> > > };
> > >
> >
> > --
> > i.
> >
> >
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 9:27 ` Ilpo Järvinen
@ 2025-10-15 9:36 ` Antheas Kapenekakis
0 siblings, 0 replies; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-15 9:36 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: platform-driver-x86, LKML, linux-hwmon, Hans de Goede,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On Wed, 15 Oct 2025 at 11:27, Ilpo Järvinen
<ilpo.jarvinen@linux.intel.com> wrote:
>
> On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
>
> > On Wed, 15 Oct 2025 at 11:11, Ilpo Järvinen
> > <ilpo.jarvinen@linux.intel.com> wrote:
> > >
> > > On Wed, 15 Oct 2025, Antheas Kapenekakis wrote:
> > >
> > > > The Ayaneo EC resets after hibernation, losing the charge control state.
> > > > Add a small PM hook to restore this state on hibernation resume.
> > > >
> > > > The fan speed is also lost during hibernation, but since hibernation
> > > > failures are common with this class of devices, setting a low fan speed
> > > > when the userspace program controlling the fan will potentially not
> > > > take over could cause the device to overheat, so it is not restored.
> > > >
> > > > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > > > ---
> > > > drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> > > > 1 file changed, 42 insertions(+)
> > > >
> > > > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > > > index 73e9dd39c703..8529f6f8dc69 100644
> > > > --- a/drivers/platform/x86/ayaneo-ec.c
> > > > +++ b/drivers/platform/x86/ayaneo-ec.c
> > > > @@ -37,6 +37,8 @@
> > > > #define AYANEO_MODULE_LEFT BIT(0)
> > > > #define AYANEO_MODULE_RIGHT BIT(1)
> > > >
> > > > +#define AYANEO_CACHE_LEN 1
> > > > +
> > > > struct ayaneo_ec_quirk {
> > > > bool has_fan_control;
> > > > bool has_charge_control;
> > > > @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> > > > struct platform_device *pdev;
> > > > struct ayaneo_ec_quirk *quirks;
> > > > struct acpi_battery_hook battery_hook;
> > > > +
> > > > + u8 cache[AYANEO_CACHE_LEN];
> > > > };
> > > >
> > > > static const struct ayaneo_ec_quirk quirk_fan = {
> > > > @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> > > > return 0;
> > > > }
> > > >
> > > > +static int ayaneo_freeze(struct device *dev)
> > > > +{
> > > > + struct platform_device *pdev = to_platform_device(dev);
> > > > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > > > + int ret, i = 0;
> > > > +
> > > > + if (data->quirks->has_charge_control) {
> > > > + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> > > > + if (ret)
> > > > + return ret;
> > > > + i++;
> > >
> > > What is this for?
> >
> > Adding additional registers to restore. Currently, there is only one
> > so it looks out of place.
>
> When are patches for those additional registers going to be submitted?
> If it's not like right around the corner, I'd prefer i be added only
> at that time.
I can move the increment to be inside the access to remove the extra
line. The idea was to minimize the diff when adding other registers.
As we test the driver more registers might get added, I cannot answer
that currently. I was also testing the controller power register, but
results were mixed.
> In any case, please mention in the changelog there's going to be more to
> registers cache so it becomes justified why you're using an array for the
> cache.
Ok.
Antheas
> --
> i.
>
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int ayaneo_thaw(struct device *dev)
> > > > +{
> > > > + struct platform_device *pdev = to_platform_device(dev);
> > > > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > > > + int ret, i = 0;
> > > > +
> > > > + if (data->quirks->has_charge_control) {
> > > > + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> > > > + if (ret)
> > > > + return ret;
> > > > + i++;
> > >
> > > Same question here.
> > >
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static const struct dev_pm_ops ayaneo_pm_ops = {
> > > > + .freeze = ayaneo_freeze,
> > > > + .thaw = ayaneo_thaw,
> > > > +};
> > > > +
> > > > static struct platform_driver ayaneo_platform_driver = {
> > > > .driver = {
> > > > .name = "ayaneo-ec",
> > > > .dev_groups = ayaneo_ec_groups,
> > > > + .pm = &ayaneo_pm_ops,
> > > > },
> > > > .probe = ayaneo_ec_probe,
> > > > };
> > > >
> > >
> > > --
> > > i.
> > >
> > >
> >
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 8:44 ` [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook Antheas Kapenekakis
2025-10-15 9:11 ` Ilpo Järvinen
@ 2025-10-26 22:49 ` Armin Wolf
2025-10-26 23:17 ` Antheas Kapenekakis
2025-10-28 20:26 ` Mario Limonciello
2 siblings, 1 reply; 36+ messages in thread
From: Armin Wolf @ 2025-10-26 22:49 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> The Ayaneo EC resets after hibernation, losing the charge control state.
> Add a small PM hook to restore this state on hibernation resume.
>
> The fan speed is also lost during hibernation, but since hibernation
> failures are common with this class of devices, setting a low fan speed
> when the userspace program controlling the fan will potentially not
> take over could cause the device to overheat, so it is not restored.
I am still not happy with potentially breaking fancontrol on this device.
Most users expect fancontrol to continue working after hibernation, so not
restoring the fan speed configuration seems risky to me. Would it be enough
to warn users about his inside the documentation?
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 73e9dd39c703..8529f6f8dc69 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -37,6 +37,8 @@
> #define AYANEO_MODULE_LEFT BIT(0)
> #define AYANEO_MODULE_RIGHT BIT(1)
>
> +#define AYANEO_CACHE_LEN 1
> +
> struct ayaneo_ec_quirk {
> bool has_fan_control;
> bool has_charge_control;
> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> struct platform_device *pdev;
> struct ayaneo_ec_quirk *quirks;
> struct acpi_battery_hook battery_hook;
> +
> + u8 cache[AYANEO_CACHE_LEN];
> };
>
> static const struct ayaneo_ec_quirk quirk_fan = {
> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> return 0;
> }
>
> +static int ayaneo_freeze(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
> + }
> +
> + return 0;
> +}
> +
> +static int ayaneo_thaw(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
> + }
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops ayaneo_pm_ops = {
> + .freeze = ayaneo_freeze,
> + .thaw = ayaneo_thaw,
> +};
> +
> static struct platform_driver ayaneo_platform_driver = {
> .driver = {
> .name = "ayaneo-ec",
> .dev_groups = ayaneo_ec_groups,
> + .pm = &ayaneo_pm_ops,
Please use pm_sleep_ptr() here.
Thanks,
Armin Wolf
> },
> .probe = ayaneo_ec_probe,
> };
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-26 22:49 ` Armin Wolf
@ 2025-10-26 23:17 ` Antheas Kapenekakis
2025-10-28 13:50 ` Armin Wolf
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-26 23:17 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
>
> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
>
> > The Ayaneo EC resets after hibernation, losing the charge control state.
> > Add a small PM hook to restore this state on hibernation resume.
> >
> > The fan speed is also lost during hibernation, but since hibernation
> > failures are common with this class of devices, setting a low fan speed
> > when the userspace program controlling the fan will potentially not
> > take over could cause the device to overheat, so it is not restored.
>
> I am still not happy with potentially breaking fancontrol on this device.
> Most users expect fancontrol to continue working after hibernation, so not
> restoring the fan speed configuration seems risky to me. Would it be enough
> to warn users about his inside the documentation?
This device features two modes of operation: a factory fan curve
managed by the EC and a fixed speed set via override of the EC.
The factory curve is tuned by the manufacturer to result in safe
operation in all conditions by monitoring the CPU temperature and is
not adjustable.
The fixed speed, on its own when set manually, is not use-able,
because this device has a fluctuating temperature based on workload.
So to meet the varying conditions, its speed would either have to be
set too high, leading to excess noise, or too low, potentially
overheating. Therefore, users of this interface control it via a
userspace program, e.g., hhd, coolercontrol, which allows creating a
custom fan curve based on measurements of temperature sensors.
When entering hibernation, the userspace program that controls the fan
speed is frozen, so the fan remains at its previous speed regardless
of temperature readings and there are no safety checks.
When resuming from hibernation, the EC takes over and monitors the
temperature, so it is safe until the userspace program is thawed. If
we introduce a resume hook, we take over from the EC before the
program is ready, introducing a gap where the device can potentially
overheat. If anything, the freeze hook should remove the fan speed
override instead, because suspend-then-hibernate is more of a
liability for overheating if hibernation hangs.
Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
AYN, MSI). Since the EC monitors the temperature there, it is fine to
restore the fan curve. Speaking of, I am having quite a few issues
with MSI Claws, so that series is a bit on the back burner, so I plan
to push these series first.
I will try to tend to this series in the next days. I wanted to push
the Asus stuff first though.
Antheas
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
> > drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> > 1 file changed, 42 insertions(+)
> >
> > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > index 73e9dd39c703..8529f6f8dc69 100644
> > --- a/drivers/platform/x86/ayaneo-ec.c
> > +++ b/drivers/platform/x86/ayaneo-ec.c
> > @@ -37,6 +37,8 @@
> > #define AYANEO_MODULE_LEFT BIT(0)
> > #define AYANEO_MODULE_RIGHT BIT(1)
> >
> > +#define AYANEO_CACHE_LEN 1
> > +
> > struct ayaneo_ec_quirk {
> > bool has_fan_control;
> > bool has_charge_control;
> > @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> > struct platform_device *pdev;
> > struct ayaneo_ec_quirk *quirks;
> > struct acpi_battery_hook battery_hook;
> > +
> > + u8 cache[AYANEO_CACHE_LEN];
> > };
> >
> > static const struct ayaneo_ec_quirk quirk_fan = {
> > @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> > return 0;
> > }
> >
> > +static int ayaneo_freeze(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int ayaneo_thaw(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dev_pm_ops ayaneo_pm_ops = {
> > + .freeze = ayaneo_freeze,
> > + .thaw = ayaneo_thaw,
> > +};
> > +
> > static struct platform_driver ayaneo_platform_driver = {
> > .driver = {
> > .name = "ayaneo-ec",
> > .dev_groups = ayaneo_ec_groups,
> > + .pm = &ayaneo_pm_ops,
>
> Please use pm_sleep_ptr() here.
>
> Thanks,
> Armin Wolf
>
> > },
> > .probe = ayaneo_ec_probe,
> > };
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-26 23:17 ` Antheas Kapenekakis
@ 2025-10-28 13:50 ` Armin Wolf
2025-10-28 15:20 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Armin Wolf @ 2025-10-28 13:50 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
Am 27.10.25 um 00:17 schrieb Antheas Kapenekakis:
> On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
>> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
>>
>>> The Ayaneo EC resets after hibernation, losing the charge control state.
>>> Add a small PM hook to restore this state on hibernation resume.
>>>
>>> The fan speed is also lost during hibernation, but since hibernation
>>> failures are common with this class of devices, setting a low fan speed
>>> when the userspace program controlling the fan will potentially not
>>> take over could cause the device to overheat, so it is not restored.
>> I am still not happy with potentially breaking fancontrol on this device.
>> Most users expect fancontrol to continue working after hibernation, so not
>> restoring the fan speed configuration seems risky to me. Would it be enough
>> to warn users about his inside the documentation?
> This device features two modes of operation: a factory fan curve
> managed by the EC and a fixed speed set via override of the EC.
>
> The factory curve is tuned by the manufacturer to result in safe
> operation in all conditions by monitoring the CPU temperature and is
> not adjustable.
>
> The fixed speed, on its own when set manually, is not use-able,
> because this device has a fluctuating temperature based on workload.
> So to meet the varying conditions, its speed would either have to be
> set too high, leading to excess noise, or too low, potentially
> overheating. Therefore, users of this interface control it via a
> userspace program, e.g., hhd, coolercontrol, which allows creating a
> custom fan curve based on measurements of temperature sensors.
>
> When entering hibernation, the userspace program that controls the fan
> speed is frozen, so the fan remains at its previous speed regardless
> of temperature readings and there are no safety checks.
>
> When resuming from hibernation, the EC takes over and monitors the
> temperature, so it is safe until the userspace program is thawed. If
> we introduce a resume hook, we take over from the EC before the
> program is ready, introducing a gap where the device can potentially
> overheat. If anything, the freeze hook should remove the fan speed
> override instead, because suspend-then-hibernate is more of a
> liability for overheating if hibernation hangs.
Understandable, how about introducing a module_param_unsafe() for enabling
write access to the fan settings? The fan settings would be read-only by default,
so no suspend handling would be necessary. Said suspend handling would only be
necessary when the user _explicitly_ requests write access to the fan settings.
What i am trying to say is that we should either expose a fully working feature
(fan control with suspend support) or none at all (fan speed monitoring only).
What do you thing about that?
Thanks,
Armin Wolf
>
> Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
> AYN, MSI). Since the EC monitors the temperature there, it is fine to
> restore the fan curve. Speaking of, I am having quite a few issues
> with MSI Claws, so that series is a bit on the back burner, so I plan
> to push these series first.
>
> I will try to tend to this series in the next days. I wanted to push
> the Asus stuff first though.
>
>
> Antheas
>
>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>> ---
>>> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
>>> 1 file changed, 42 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
>>> index 73e9dd39c703..8529f6f8dc69 100644
>>> --- a/drivers/platform/x86/ayaneo-ec.c
>>> +++ b/drivers/platform/x86/ayaneo-ec.c
>>> @@ -37,6 +37,8 @@
>>> #define AYANEO_MODULE_LEFT BIT(0)
>>> #define AYANEO_MODULE_RIGHT BIT(1)
>>>
>>> +#define AYANEO_CACHE_LEN 1
>>> +
>>> struct ayaneo_ec_quirk {
>>> bool has_fan_control;
>>> bool has_charge_control;
>>> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
>>> struct platform_device *pdev;
>>> struct ayaneo_ec_quirk *quirks;
>>> struct acpi_battery_hook battery_hook;
>>> +
>>> + u8 cache[AYANEO_CACHE_LEN];
>>> };
>>>
>>> static const struct ayaneo_ec_quirk quirk_fan = {
>>> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
>>> return 0;
>>> }
>>>
>>> +static int ayaneo_freeze(struct device *dev)
>>> +{
>>> + struct platform_device *pdev = to_platform_device(dev);
>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>> + int ret, i = 0;
>>> +
>>> + if (data->quirks->has_charge_control) {
>>> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
>>> + if (ret)
>>> + return ret;
>>> + i++;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int ayaneo_thaw(struct device *dev)
>>> +{
>>> + struct platform_device *pdev = to_platform_device(dev);
>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>> + int ret, i = 0;
>>> +
>>> + if (data->quirks->has_charge_control) {
>>> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
>>> + if (ret)
>>> + return ret;
>>> + i++;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const struct dev_pm_ops ayaneo_pm_ops = {
>>> + .freeze = ayaneo_freeze,
>>> + .thaw = ayaneo_thaw,
>>> +};
>>> +
>>> static struct platform_driver ayaneo_platform_driver = {
>>> .driver = {
>>> .name = "ayaneo-ec",
>>> .dev_groups = ayaneo_ec_groups,
>>> + .pm = &ayaneo_pm_ops,
>> Please use pm_sleep_ptr() here.
>>
>> Thanks,
>> Armin Wolf
>>
>>> },
>>> .probe = ayaneo_ec_probe,
>>> };
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 13:50 ` Armin Wolf
@ 2025-10-28 15:20 ` Antheas Kapenekakis
2025-10-28 15:25 ` Armin Wolf
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-28 15:20 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Tue, 28 Oct 2025 at 14:50, Armin Wolf <W_Armin@gmx.de> wrote:
>
> Am 27.10.25 um 00:17 schrieb Antheas Kapenekakis:
>
> > On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
> >> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> >>
> >>> The Ayaneo EC resets after hibernation, losing the charge control state.
> >>> Add a small PM hook to restore this state on hibernation resume.
> >>>
> >>> The fan speed is also lost during hibernation, but since hibernation
> >>> failures are common with this class of devices, setting a low fan speed
> >>> when the userspace program controlling the fan will potentially not
> >>> take over could cause the device to overheat, so it is not restored.
> >> I am still not happy with potentially breaking fancontrol on this device.
> >> Most users expect fancontrol to continue working after hibernation, so not
> >> restoring the fan speed configuration seems risky to me. Would it be enough
> >> to warn users about his inside the documentation?
> > This device features two modes of operation: a factory fan curve
> > managed by the EC and a fixed speed set via override of the EC.
> >
> > The factory curve is tuned by the manufacturer to result in safe
> > operation in all conditions by monitoring the CPU temperature and is
> > not adjustable.
> >
> > The fixed speed, on its own when set manually, is not use-able,
> > because this device has a fluctuating temperature based on workload.
> > So to meet the varying conditions, its speed would either have to be
> > set too high, leading to excess noise, or too low, potentially
> > overheating. Therefore, users of this interface control it via a
> > userspace program, e.g., hhd, coolercontrol, which allows creating a
> > custom fan curve based on measurements of temperature sensors.
> >
> > When entering hibernation, the userspace program that controls the fan
> > speed is frozen, so the fan remains at its previous speed regardless
> > of temperature readings and there are no safety checks.
> >
> > When resuming from hibernation, the EC takes over and monitors the
> > temperature, so it is safe until the userspace program is thawed. If
> > we introduce a resume hook, we take over from the EC before the
> > program is ready, introducing a gap where the device can potentially
> > overheat. If anything, the freeze hook should remove the fan speed
> > override instead, because suspend-then-hibernate is more of a
> > liability for overheating if hibernation hangs.
>
> Understandable, how about introducing a module_param_unsafe() for enabling
> write access to the fan settings? The fan settings would be read-only by default,
> so no suspend handling would be necessary. Said suspend handling would only be
> necessary when the user _explicitly_ requests write access to the fan settings.
>
> What i am trying to say is that we should either expose a fully working feature
> (fan control with suspend support) or none at all (fan speed monitoring only).
>
> What do you thing about that?
It is a safe parameter and it works during suspend. It has parity with
current hwmon drivers for other manufacturers.
Hibernation hooks for hwmon are unprecedented, in addition to
compromising the safety of the device. They _could_ be justified for
EC managed curves, since a minority of users might opt to set them via
systemd udev rules and the EC manages the temperature. But this is not
the case here.
Where does the need for these hooks stem from?
Antheas
> Thanks,
> Armin Wolf
>
> >
> > Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
> > AYN, MSI). Since the EC monitors the temperature there, it is fine to
> > restore the fan curve. Speaking of, I am having quite a few issues
> > with MSI Claws, so that series is a bit on the back burner, so I plan
> > to push these series first.
> >
> > I will try to tend to this series in the next days. I wanted to push
> > the Asus stuff first though.
> >
> >
> > Antheas
> >
> >>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>> ---
> >>> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> >>> 1 file changed, 42 insertions(+)
> >>>
> >>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> >>> index 73e9dd39c703..8529f6f8dc69 100644
> >>> --- a/drivers/platform/x86/ayaneo-ec.c
> >>> +++ b/drivers/platform/x86/ayaneo-ec.c
> >>> @@ -37,6 +37,8 @@
> >>> #define AYANEO_MODULE_LEFT BIT(0)
> >>> #define AYANEO_MODULE_RIGHT BIT(1)
> >>>
> >>> +#define AYANEO_CACHE_LEN 1
> >>> +
> >>> struct ayaneo_ec_quirk {
> >>> bool has_fan_control;
> >>> bool has_charge_control;
> >>> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> >>> struct platform_device *pdev;
> >>> struct ayaneo_ec_quirk *quirks;
> >>> struct acpi_battery_hook battery_hook;
> >>> +
> >>> + u8 cache[AYANEO_CACHE_LEN];
> >>> };
> >>>
> >>> static const struct ayaneo_ec_quirk quirk_fan = {
> >>> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> >>> return 0;
> >>> }
> >>>
> >>> +static int ayaneo_freeze(struct device *dev)
> >>> +{
> >>> + struct platform_device *pdev = to_platform_device(dev);
> >>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> >>> + int ret, i = 0;
> >>> +
> >>> + if (data->quirks->has_charge_control) {
> >>> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> >>> + if (ret)
> >>> + return ret;
> >>> + i++;
> >>> + }
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int ayaneo_thaw(struct device *dev)
> >>> +{
> >>> + struct platform_device *pdev = to_platform_device(dev);
> >>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> >>> + int ret, i = 0;
> >>> +
> >>> + if (data->quirks->has_charge_control) {
> >>> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> >>> + if (ret)
> >>> + return ret;
> >>> + i++;
> >>> + }
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static const struct dev_pm_ops ayaneo_pm_ops = {
> >>> + .freeze = ayaneo_freeze,
> >>> + .thaw = ayaneo_thaw,
> >>> +};
> >>> +
> >>> static struct platform_driver ayaneo_platform_driver = {
> >>> .driver = {
> >>> .name = "ayaneo-ec",
> >>> .dev_groups = ayaneo_ec_groups,
> >>> + .pm = &ayaneo_pm_ops,
> >> Please use pm_sleep_ptr() here.
> >>
> >> Thanks,
> >> Armin Wolf
> >>
> >>> },
> >>> .probe = ayaneo_ec_probe,
> >>> };
> >
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 15:20 ` Antheas Kapenekakis
@ 2025-10-28 15:25 ` Armin Wolf
2025-10-28 17:49 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Armin Wolf @ 2025-10-28 15:25 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
Am 28.10.25 um 16:20 schrieb Antheas Kapenekakis:
> On Tue, 28 Oct 2025 at 14:50, Armin Wolf <W_Armin@gmx.de> wrote:
>> Am 27.10.25 um 00:17 schrieb Antheas Kapenekakis:
>>
>>> On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
>>>> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
>>>>
>>>>> The Ayaneo EC resets after hibernation, losing the charge control state.
>>>>> Add a small PM hook to restore this state on hibernation resume.
>>>>>
>>>>> The fan speed is also lost during hibernation, but since hibernation
>>>>> failures are common with this class of devices, setting a low fan speed
>>>>> when the userspace program controlling the fan will potentially not
>>>>> take over could cause the device to overheat, so it is not restored.
>>>> I am still not happy with potentially breaking fancontrol on this device.
>>>> Most users expect fancontrol to continue working after hibernation, so not
>>>> restoring the fan speed configuration seems risky to me. Would it be enough
>>>> to warn users about his inside the documentation?
>>> This device features two modes of operation: a factory fan curve
>>> managed by the EC and a fixed speed set via override of the EC.
>>>
>>> The factory curve is tuned by the manufacturer to result in safe
>>> operation in all conditions by monitoring the CPU temperature and is
>>> not adjustable.
>>>
>>> The fixed speed, on its own when set manually, is not use-able,
>>> because this device has a fluctuating temperature based on workload.
>>> So to meet the varying conditions, its speed would either have to be
>>> set too high, leading to excess noise, or too low, potentially
>>> overheating. Therefore, users of this interface control it via a
>>> userspace program, e.g., hhd, coolercontrol, which allows creating a
>>> custom fan curve based on measurements of temperature sensors.
>>>
>>> When entering hibernation, the userspace program that controls the fan
>>> speed is frozen, so the fan remains at its previous speed regardless
>>> of temperature readings and there are no safety checks.
>>>
>>> When resuming from hibernation, the EC takes over and monitors the
>>> temperature, so it is safe until the userspace program is thawed. If
>>> we introduce a resume hook, we take over from the EC before the
>>> program is ready, introducing a gap where the device can potentially
>>> overheat. If anything, the freeze hook should remove the fan speed
>>> override instead, because suspend-then-hibernate is more of a
>>> liability for overheating if hibernation hangs.
>> Understandable, how about introducing a module_param_unsafe() for enabling
>> write access to the fan settings? The fan settings would be read-only by default,
>> so no suspend handling would be necessary. Said suspend handling would only be
>> necessary when the user _explicitly_ requests write access to the fan settings.
>>
>> What i am trying to say is that we should either expose a fully working feature
>> (fan control with suspend support) or none at all (fan speed monitoring only).
>>
>> What do you thing about that?
> It is a safe parameter and it works during suspend. It has parity with
> current hwmon drivers for other manufacturers.
>
> Hibernation hooks for hwmon are unprecedented, in addition to
> compromising the safety of the device. They _could_ be justified for
> EC managed curves, since a minority of users might opt to set them via
> systemd udev rules and the EC manages the temperature. But this is not
> the case here.
>
> Where does the need for these hooks stem from?
>
> Antheas
I agree that most hwmon drivers sadly do not restore the fan control settings during
resume from hibernation. This however is an error inside the drivers themself, as device
drivers are normally expected to restore such settings during resume. Without this the
fancontrol software will suddenly stop working after hibernation, something users do no
expect.
Copying the faulty behavior of existing drivers is not a good idea here.
Thanks,
Armin Wolf
>> Thanks,
>> Armin Wolf
>>
>>> Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
>>> AYN, MSI). Since the EC monitors the temperature there, it is fine to
>>> restore the fan curve. Speaking of, I am having quite a few issues
>>> with MSI Claws, so that series is a bit on the back burner, so I plan
>>> to push these series first.
>>>
>>> I will try to tend to this series in the next days. I wanted to push
>>> the Asus stuff first though.
>>>
>>>
>>> Antheas
>>>
>>>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>>>> ---
>>>>> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 42 insertions(+)
>>>>>
>>>>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
>>>>> index 73e9dd39c703..8529f6f8dc69 100644
>>>>> --- a/drivers/platform/x86/ayaneo-ec.c
>>>>> +++ b/drivers/platform/x86/ayaneo-ec.c
>>>>> @@ -37,6 +37,8 @@
>>>>> #define AYANEO_MODULE_LEFT BIT(0)
>>>>> #define AYANEO_MODULE_RIGHT BIT(1)
>>>>>
>>>>> +#define AYANEO_CACHE_LEN 1
>>>>> +
>>>>> struct ayaneo_ec_quirk {
>>>>> bool has_fan_control;
>>>>> bool has_charge_control;
>>>>> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
>>>>> struct platform_device *pdev;
>>>>> struct ayaneo_ec_quirk *quirks;
>>>>> struct acpi_battery_hook battery_hook;
>>>>> +
>>>>> + u8 cache[AYANEO_CACHE_LEN];
>>>>> };
>>>>>
>>>>> static const struct ayaneo_ec_quirk quirk_fan = {
>>>>> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
>>>>> return 0;
>>>>> }
>>>>>
>>>>> +static int ayaneo_freeze(struct device *dev)
>>>>> +{
>>>>> + struct platform_device *pdev = to_platform_device(dev);
>>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>>>> + int ret, i = 0;
>>>>> +
>>>>> + if (data->quirks->has_charge_control) {
>>>>> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> + i++;
>>>>> + }
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static int ayaneo_thaw(struct device *dev)
>>>>> +{
>>>>> + struct platform_device *pdev = to_platform_device(dev);
>>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>>>> + int ret, i = 0;
>>>>> +
>>>>> + if (data->quirks->has_charge_control) {
>>>>> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> + i++;
>>>>> + }
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static const struct dev_pm_ops ayaneo_pm_ops = {
>>>>> + .freeze = ayaneo_freeze,
>>>>> + .thaw = ayaneo_thaw,
>>>>> +};
>>>>> +
>>>>> static struct platform_driver ayaneo_platform_driver = {
>>>>> .driver = {
>>>>> .name = "ayaneo-ec",
>>>>> .dev_groups = ayaneo_ec_groups,
>>>>> + .pm = &ayaneo_pm_ops,
>>>> Please use pm_sleep_ptr() here.
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>> },
>>>>> .probe = ayaneo_ec_probe,
>>>>> };
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 15:25 ` Armin Wolf
@ 2025-10-28 17:49 ` Antheas Kapenekakis
2025-10-28 23:14 ` Armin Wolf
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-28 17:49 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Tue, 28 Oct 2025 at 16:26, Armin Wolf <W_Armin@gmx.de> wrote:
>
> Am 28.10.25 um 16:20 schrieb Antheas Kapenekakis:
>
> > On Tue, 28 Oct 2025 at 14:50, Armin Wolf <W_Armin@gmx.de> wrote:
> >> Am 27.10.25 um 00:17 schrieb Antheas Kapenekakis:
> >>
> >>> On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
> >>>> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
> >>>>
> >>>>> The Ayaneo EC resets after hibernation, losing the charge control state.
> >>>>> Add a small PM hook to restore this state on hibernation resume.
> >>>>>
> >>>>> The fan speed is also lost during hibernation, but since hibernation
> >>>>> failures are common with this class of devices, setting a low fan speed
> >>>>> when the userspace program controlling the fan will potentially not
> >>>>> take over could cause the device to overheat, so it is not restored.
> >>>> I am still not happy with potentially breaking fancontrol on this device.
> >>>> Most users expect fancontrol to continue working after hibernation, so not
> >>>> restoring the fan speed configuration seems risky to me. Would it be enough
> >>>> to warn users about his inside the documentation?
> >>> This device features two modes of operation: a factory fan curve
> >>> managed by the EC and a fixed speed set via override of the EC.
> >>>
> >>> The factory curve is tuned by the manufacturer to result in safe
> >>> operation in all conditions by monitoring the CPU temperature and is
> >>> not adjustable.
> >>>
> >>> The fixed speed, on its own when set manually, is not use-able,
> >>> because this device has a fluctuating temperature based on workload.
> >>> So to meet the varying conditions, its speed would either have to be
> >>> set too high, leading to excess noise, or too low, potentially
> >>> overheating. Therefore, users of this interface control it via a
> >>> userspace program, e.g., hhd, coolercontrol, which allows creating a
> >>> custom fan curve based on measurements of temperature sensors.
> >>>
> >>> When entering hibernation, the userspace program that controls the fan
> >>> speed is frozen, so the fan remains at its previous speed regardless
> >>> of temperature readings and there are no safety checks.
> >>>
> >>> When resuming from hibernation, the EC takes over and monitors the
> >>> temperature, so it is safe until the userspace program is thawed. If
> >>> we introduce a resume hook, we take over from the EC before the
> >>> program is ready, introducing a gap where the device can potentially
> >>> overheat. If anything, the freeze hook should remove the fan speed
> >>> override instead, because suspend-then-hibernate is more of a
> >>> liability for overheating if hibernation hangs.
> >> Understandable, how about introducing a module_param_unsafe() for enabling
> >> write access to the fan settings? The fan settings would be read-only by default,
> >> so no suspend handling would be necessary. Said suspend handling would only be
> >> necessary when the user _explicitly_ requests write access to the fan settings.
> >>
> >> What i am trying to say is that we should either expose a fully working feature
> >> (fan control with suspend support) or none at all (fan speed monitoring only).
> >>
> >> What do you thing about that?
> > It is a safe parameter and it works during suspend. It has parity with
> > current hwmon drivers for other manufacturers.
> >
> > Hibernation hooks for hwmon are unprecedented, in addition to
> > compromising the safety of the device. They _could_ be justified for
> > EC managed curves, since a minority of users might opt to set them via
> > systemd udev rules and the EC manages the temperature. But this is not
> > the case here.
> >
> > Where does the need for these hooks stem from?
> >
> > Antheas
>
> I agree that most hwmon drivers sadly do not restore the fan control settings during
> resume from hibernation. This however is an error inside the drivers themself, as device
> drivers are normally expected to restore such settings during resume. Without this the
> fancontrol software will suddenly stop working after hibernation, something users do no
> expect.
>
> Copying the faulty behavior of existing drivers is not a good idea here.
Well, unless you can solve the case of hibernation failing and what
happens to the fan speed I cannot sign off on it. These devices are
very expensive.
Controlling the fan is basic functionality, it cannot be marked or be
made an unsafe feature.
I am aware of the issue post hibernation, but thats easy to solve
through software, and as a maintainer of fan control software, which
also happens to be the main consumer of this module, I already have a
hook there. As it is needed by the other manufacturers as well.
Antheas
> Thanks,
> Armin Wolf
>
> >> Thanks,
> >> Armin Wolf
> >>
> >>> Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
> >>> AYN, MSI). Since the EC monitors the temperature there, it is fine to
> >>> restore the fan curve. Speaking of, I am having quite a few issues
> >>> with MSI Claws, so that series is a bit on the back burner, so I plan
> >>> to push these series first.
> >>>
> >>> I will try to tend to this series in the next days. I wanted to push
> >>> the Asus stuff first though.
> >>>
> >>>
> >>> Antheas
> >>>
> >>>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>>>> ---
> >>>>> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> >>>>> 1 file changed, 42 insertions(+)
> >>>>>
> >>>>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> >>>>> index 73e9dd39c703..8529f6f8dc69 100644
> >>>>> --- a/drivers/platform/x86/ayaneo-ec.c
> >>>>> +++ b/drivers/platform/x86/ayaneo-ec.c
> >>>>> @@ -37,6 +37,8 @@
> >>>>> #define AYANEO_MODULE_LEFT BIT(0)
> >>>>> #define AYANEO_MODULE_RIGHT BIT(1)
> >>>>>
> >>>>> +#define AYANEO_CACHE_LEN 1
> >>>>> +
> >>>>> struct ayaneo_ec_quirk {
> >>>>> bool has_fan_control;
> >>>>> bool has_charge_control;
> >>>>> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> >>>>> struct platform_device *pdev;
> >>>>> struct ayaneo_ec_quirk *quirks;
> >>>>> struct acpi_battery_hook battery_hook;
> >>>>> +
> >>>>> + u8 cache[AYANEO_CACHE_LEN];
> >>>>> };
> >>>>>
> >>>>> static const struct ayaneo_ec_quirk quirk_fan = {
> >>>>> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> >>>>> return 0;
> >>>>> }
> >>>>>
> >>>>> +static int ayaneo_freeze(struct device *dev)
> >>>>> +{
> >>>>> + struct platform_device *pdev = to_platform_device(dev);
> >>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> >>>>> + int ret, i = 0;
> >>>>> +
> >>>>> + if (data->quirks->has_charge_control) {
> >>>>> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> >>>>> + if (ret)
> >>>>> + return ret;
> >>>>> + i++;
> >>>>> + }
> >>>>> +
> >>>>> + return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static int ayaneo_thaw(struct device *dev)
> >>>>> +{
> >>>>> + struct platform_device *pdev = to_platform_device(dev);
> >>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> >>>>> + int ret, i = 0;
> >>>>> +
> >>>>> + if (data->quirks->has_charge_control) {
> >>>>> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> >>>>> + if (ret)
> >>>>> + return ret;
> >>>>> + i++;
> >>>>> + }
> >>>>> +
> >>>>> + return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static const struct dev_pm_ops ayaneo_pm_ops = {
> >>>>> + .freeze = ayaneo_freeze,
> >>>>> + .thaw = ayaneo_thaw,
> >>>>> +};
> >>>>> +
> >>>>> static struct platform_driver ayaneo_platform_driver = {
> >>>>> .driver = {
> >>>>> .name = "ayaneo-ec",
> >>>>> .dev_groups = ayaneo_ec_groups,
> >>>>> + .pm = &ayaneo_pm_ops,
> >>>> Please use pm_sleep_ptr() here.
> >>>>
> >>>> Thanks,
> >>>> Armin Wolf
> >>>>
> >>>>> },
> >>>>> .probe = ayaneo_ec_probe,
> >>>>> };
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 17:49 ` Antheas Kapenekakis
@ 2025-10-28 23:14 ` Armin Wolf
0 siblings, 0 replies; 36+ messages in thread
From: Armin Wolf @ 2025-10-28 23:14 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
Am 28.10.25 um 18:49 schrieb Antheas Kapenekakis:
> On Tue, 28 Oct 2025 at 16:26, Armin Wolf <W_Armin@gmx.de> wrote:
>> Am 28.10.25 um 16:20 schrieb Antheas Kapenekakis:
>>
>>> On Tue, 28 Oct 2025 at 14:50, Armin Wolf <W_Armin@gmx.de> wrote:
>>>> Am 27.10.25 um 00:17 schrieb Antheas Kapenekakis:
>>>>
>>>>> On Sun, 26 Oct 2025 at 23:50, Armin Wolf <W_Armin@gmx.de> wrote:
>>>>>> Am 15.10.25 um 10:44 schrieb Antheas Kapenekakis:
>>>>>>
>>>>>>> The Ayaneo EC resets after hibernation, losing the charge control state.
>>>>>>> Add a small PM hook to restore this state on hibernation resume.
>>>>>>>
>>>>>>> The fan speed is also lost during hibernation, but since hibernation
>>>>>>> failures are common with this class of devices, setting a low fan speed
>>>>>>> when the userspace program controlling the fan will potentially not
>>>>>>> take over could cause the device to overheat, so it is not restored.
>>>>>> I am still not happy with potentially breaking fancontrol on this device.
>>>>>> Most users expect fancontrol to continue working after hibernation, so not
>>>>>> restoring the fan speed configuration seems risky to me. Would it be enough
>>>>>> to warn users about his inside the documentation?
>>>>> This device features two modes of operation: a factory fan curve
>>>>> managed by the EC and a fixed speed set via override of the EC.
>>>>>
>>>>> The factory curve is tuned by the manufacturer to result in safe
>>>>> operation in all conditions by monitoring the CPU temperature and is
>>>>> not adjustable.
>>>>>
>>>>> The fixed speed, on its own when set manually, is not use-able,
>>>>> because this device has a fluctuating temperature based on workload.
>>>>> So to meet the varying conditions, its speed would either have to be
>>>>> set too high, leading to excess noise, or too low, potentially
>>>>> overheating. Therefore, users of this interface control it via a
>>>>> userspace program, e.g., hhd, coolercontrol, which allows creating a
>>>>> custom fan curve based on measurements of temperature sensors.
>>>>>
>>>>> When entering hibernation, the userspace program that controls the fan
>>>>> speed is frozen, so the fan remains at its previous speed regardless
>>>>> of temperature readings and there are no safety checks.
>>>>>
>>>>> When resuming from hibernation, the EC takes over and monitors the
>>>>> temperature, so it is safe until the userspace program is thawed. If
>>>>> we introduce a resume hook, we take over from the EC before the
>>>>> program is ready, introducing a gap where the device can potentially
>>>>> overheat. If anything, the freeze hook should remove the fan speed
>>>>> override instead, because suspend-then-hibernate is more of a
>>>>> liability for overheating if hibernation hangs.
>>>> Understandable, how about introducing a module_param_unsafe() for enabling
>>>> write access to the fan settings? The fan settings would be read-only by default,
>>>> so no suspend handling would be necessary. Said suspend handling would only be
>>>> necessary when the user _explicitly_ requests write access to the fan settings.
>>>>
>>>> What i am trying to say is that we should either expose a fully working feature
>>>> (fan control with suspend support) or none at all (fan speed monitoring only).
>>>>
>>>> What do you thing about that?
>>> It is a safe parameter and it works during suspend. It has parity with
>>> current hwmon drivers for other manufacturers.
>>>
>>> Hibernation hooks for hwmon are unprecedented, in addition to
>>> compromising the safety of the device. They _could_ be justified for
>>> EC managed curves, since a minority of users might opt to set them via
>>> systemd udev rules and the EC manages the temperature. But this is not
>>> the case here.
>>>
>>> Where does the need for these hooks stem from?
>>>
>>> Antheas
>> I agree that most hwmon drivers sadly do not restore the fan control settings during
>> resume from hibernation. This however is an error inside the drivers themself, as device
>> drivers are normally expected to restore such settings during resume. Without this the
>> fancontrol software will suddenly stop working after hibernation, something users do no
>> expect.
>>
>> Copying the faulty behavior of existing drivers is not a good idea here.
> Well, unless you can solve the case of hibernation failing and what
> happens to the fan speed I cannot sign off on it. These devices are
> very expensive.
>
> Controlling the fan is basic functionality, it cannot be marked or be
> made an unsafe feature.
>
> I am aware of the issue post hibernation, but thats easy to solve
> through software, and as a maintainer of fan control software, which
> also happens to be the main consumer of this module, I already have a
> hook there. As it is needed by the other manufacturers as well.
>
> Antheas
Alright, if Guenter is fine with this approach then i wont complain any longer.
However please document this non-standard behavior so people do not accidentally
"fix" it in the future.
Thank,
Armin Wolf
>> Thanks,
>> Armin Wolf
>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>> Other devices feature adjustable EC fan curves (e.g., Lenovo, Asus,
>>>>> AYN, MSI). Since the EC monitors the temperature there, it is fine to
>>>>> restore the fan curve. Speaking of, I am having quite a few issues
>>>>> with MSI Claws, so that series is a bit on the back burner, so I plan
>>>>> to push these series first.
>>>>>
>>>>> I will try to tend to this series in the next days. I wanted to push
>>>>> the Asus stuff first though.
>>>>>
>>>>>
>>>>> Antheas
>>>>>
>>>>>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>>>>>> ---
>>>>>>> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
>>>>>>> 1 file changed, 42 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
>>>>>>> index 73e9dd39c703..8529f6f8dc69 100644
>>>>>>> --- a/drivers/platform/x86/ayaneo-ec.c
>>>>>>> +++ b/drivers/platform/x86/ayaneo-ec.c
>>>>>>> @@ -37,6 +37,8 @@
>>>>>>> #define AYANEO_MODULE_LEFT BIT(0)
>>>>>>> #define AYANEO_MODULE_RIGHT BIT(1)
>>>>>>>
>>>>>>> +#define AYANEO_CACHE_LEN 1
>>>>>>> +
>>>>>>> struct ayaneo_ec_quirk {
>>>>>>> bool has_fan_control;
>>>>>>> bool has_charge_control;
>>>>>>> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
>>>>>>> struct platform_device *pdev;
>>>>>>> struct ayaneo_ec_quirk *quirks;
>>>>>>> struct acpi_battery_hook battery_hook;
>>>>>>> +
>>>>>>> + u8 cache[AYANEO_CACHE_LEN];
>>>>>>> };
>>>>>>>
>>>>>>> static const struct ayaneo_ec_quirk quirk_fan = {
>>>>>>> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
>>>>>>> return 0;
>>>>>>> }
>>>>>>>
>>>>>>> +static int ayaneo_freeze(struct device *dev)
>>>>>>> +{
>>>>>>> + struct platform_device *pdev = to_platform_device(dev);
>>>>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>>>>>> + int ret, i = 0;
>>>>>>> +
>>>>>>> + if (data->quirks->has_charge_control) {
>>>>>>> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
>>>>>>> + if (ret)
>>>>>>> + return ret;
>>>>>>> + i++;
>>>>>>> + }
>>>>>>> +
>>>>>>> + return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static int ayaneo_thaw(struct device *dev)
>>>>>>> +{
>>>>>>> + struct platform_device *pdev = to_platform_device(dev);
>>>>>>> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
>>>>>>> + int ret, i = 0;
>>>>>>> +
>>>>>>> + if (data->quirks->has_charge_control) {
>>>>>>> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
>>>>>>> + if (ret)
>>>>>>> + return ret;
>>>>>>> + i++;
>>>>>>> + }
>>>>>>> +
>>>>>>> + return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static const struct dev_pm_ops ayaneo_pm_ops = {
>>>>>>> + .freeze = ayaneo_freeze,
>>>>>>> + .thaw = ayaneo_thaw,
>>>>>>> +};
>>>>>>> +
>>>>>>> static struct platform_driver ayaneo_platform_driver = {
>>>>>>> .driver = {
>>>>>>> .name = "ayaneo-ec",
>>>>>>> .dev_groups = ayaneo_ec_groups,
>>>>>>> + .pm = &ayaneo_pm_ops,
>>>>>> Please use pm_sleep_ptr() here.
>>>>>>
>>>>>> Thanks,
>>>>>> Armin Wolf
>>>>>>
>>>>>>> },
>>>>>>> .probe = ayaneo_ec_probe,
>>>>>>> };
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-15 8:44 ` [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook Antheas Kapenekakis
2025-10-15 9:11 ` Ilpo Järvinen
2025-10-26 22:49 ` Armin Wolf
@ 2025-10-28 20:26 ` Mario Limonciello
2025-10-28 20:34 ` Antheas Kapenekakis
2 siblings, 1 reply; 36+ messages in thread
From: Mario Limonciello @ 2025-10-28 20:26 UTC (permalink / raw)
To: Antheas Kapenekakis, platform-driver-x86
Cc: linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare, Guenter Roeck
On 10/15/25 3:44 AM, Antheas Kapenekakis wrote:
> The Ayaneo EC resets after hibernation, losing the charge control state.
> Add a small PM hook to restore this state on hibernation resume.
>
> The fan speed is also lost during hibernation, but since hibernation
> failures are common with this class of devices, setting a low fan speed
> when the userspace program controlling the fan will potentially not
> take over could cause the device to overheat, so it is not restored.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> index 73e9dd39c703..8529f6f8dc69 100644
> --- a/drivers/platform/x86/ayaneo-ec.c
> +++ b/drivers/platform/x86/ayaneo-ec.c
> @@ -37,6 +37,8 @@
> #define AYANEO_MODULE_LEFT BIT(0)
> #define AYANEO_MODULE_RIGHT BIT(1)
>
> +#define AYANEO_CACHE_LEN 1
> +
> struct ayaneo_ec_quirk {
> bool has_fan_control;
> bool has_charge_control;
> @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> struct platform_device *pdev;
> struct ayaneo_ec_quirk *quirks;
> struct acpi_battery_hook battery_hook;
> +
> + u8 cache[AYANEO_CACHE_LEN];
> };
>
> static const struct ayaneo_ec_quirk quirk_fan = {
> @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> return 0;
> }
>
> +static int ayaneo_freeze(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
> + }
> +
> + return 0;
> +}
> +
> +static int ayaneo_thaw(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> + int ret, i = 0;
> +
> + if (data->quirks->has_charge_control) {
> + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> + if (ret)
> + return ret;
> + i++;
> + }
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops ayaneo_pm_ops = {
> + .freeze = ayaneo_freeze,
> + .thaw = ayaneo_thaw,
> +};
I think you're misinterpreting the PM callbacks purpose.
If you look at include/linux/pm.h you can see that thaw() is only used
on the way down (IE when creating the image or the case of errors).
If you want to restore the registers to what they were before a
hibernation you want to use the restore() or restore_early() callbacks.
> +
> static struct platform_driver ayaneo_platform_driver = {
> .driver = {
> .name = "ayaneo-ec",
> .dev_groups = ayaneo_ec_groups,
> + .pm = &ayaneo_pm_ops,
> },
> .probe = ayaneo_ec_probe,
> };
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 20:26 ` Mario Limonciello
@ 2025-10-28 20:34 ` Antheas Kapenekakis
2025-10-28 21:21 ` Mario Limonciello
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-28 20:34 UTC (permalink / raw)
To: Mario Limonciello
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Tue, 28 Oct 2025 at 21:26, Mario Limonciello <superm1@kernel.org> wrote:
>
> On 10/15/25 3:44 AM, Antheas Kapenekakis wrote:
> > The Ayaneo EC resets after hibernation, losing the charge control state.
> > Add a small PM hook to restore this state on hibernation resume.
> >
> > The fan speed is also lost during hibernation, but since hibernation
> > failures are common with this class of devices, setting a low fan speed
> > when the userspace program controlling the fan will potentially not
> > take over could cause the device to overheat, so it is not restored.
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
> > drivers/platform/x86/ayaneo-ec.c | 42 ++++++++++++++++++++++++++++++++
> > 1 file changed, 42 insertions(+)
> >
> > diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
> > index 73e9dd39c703..8529f6f8dc69 100644
> > --- a/drivers/platform/x86/ayaneo-ec.c
> > +++ b/drivers/platform/x86/ayaneo-ec.c
> > @@ -37,6 +37,8 @@
> > #define AYANEO_MODULE_LEFT BIT(0)
> > #define AYANEO_MODULE_RIGHT BIT(1)
> >
> > +#define AYANEO_CACHE_LEN 1
> > +
> > struct ayaneo_ec_quirk {
> > bool has_fan_control;
> > bool has_charge_control;
> > @@ -47,6 +49,8 @@ struct ayaneo_ec_platform_data {
> > struct platform_device *pdev;
> > struct ayaneo_ec_quirk *quirks;
> > struct acpi_battery_hook battery_hook;
> > +
> > + u8 cache[AYANEO_CACHE_LEN];
> > };
> >
> > static const struct ayaneo_ec_quirk quirk_fan = {
> > @@ -464,10 +468,48 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
> > return 0;
> > }
> >
> > +static int ayaneo_freeze(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_read(AYANEO_CHARGE_REG, &data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int ayaneo_thaw(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
> > + int ret, i = 0;
> > +
> > + if (data->quirks->has_charge_control) {
> > + ret = ec_write(AYANEO_CHARGE_REG, data->cache[i]);
> > + if (ret)
> > + return ret;
> > + i++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dev_pm_ops ayaneo_pm_ops = {
> > + .freeze = ayaneo_freeze,
> > + .thaw = ayaneo_thaw,
> > +};
>
> I think you're misinterpreting the PM callbacks purpose.
>
> If you look at include/linux/pm.h you can see that thaw() is only used
> on the way down (IE when creating the image or the case of errors).
>
> If you want to restore the registers to what they were before a
> hibernation you want to use the restore() or restore_early() callbacks.
Good catch, indeed restore is the correct resume hook. Thaw happens to
work because its part of the resume sequence.
> > +
> > static struct platform_driver ayaneo_platform_driver = {
> > .driver = {
> > .name = "ayaneo-ec",
> > .dev_groups = ayaneo_ec_groups,
> > + .pm = &ayaneo_pm_ops,
> > },
> > .probe = ayaneo_ec_probe,
> > };
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 20:34 ` Antheas Kapenekakis
@ 2025-10-28 21:21 ` Mario Limonciello
2025-10-28 21:39 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Mario Limonciello @ 2025-10-28 21:21 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
>>> The fan speed is also lost during hibernation, but since hibernation
>>> failures are common with this class of devices
Why are hibernation failures more common in this class of device than
anything else? The hibernation flow is nearly all done in Linux driver
code (with the exception of ACPI calls that move devices into D3 and out
of D0).
Perhaps you're seeing a manifestation of a general issue that we're
working on a solution for here:
https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
Or if you're on an older kernel and using hybrid sleep we had a generic
issue there as well which was fixed in 6.18-rc1.
Nonetheless; don't make policy decisions based upon kernel bugs. Fix
the kernel bugs.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 21:21 ` Mario Limonciello
@ 2025-10-28 21:39 ` Antheas Kapenekakis
2025-10-29 3:36 ` Mario Limonciello (AMD) (kernel.org)
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-28 21:39 UTC (permalink / raw)
To: Mario Limonciello
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Tue, 28 Oct 2025 at 22:21, Mario Limonciello <superm1@kernel.org> wrote:
>
> On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
> >>> The fan speed is also lost during hibernation, but since hibernation
> >>> failures are common with this class of devices
> Why are hibernation failures more common in this class of device than
> anything else? The hibernation flow is nearly all done in Linux driver
> code (with the exception of ACPI calls that move devices into D3 and out
> of D0).
I should correct myself here and say hibernation in general in Linux
leaves something to be desired.
Until secure boot supports hibernation, that will be the case because
not enough people use it.
I have had it break for multiple reasons, not incl. the ones below and
the ones we discussed last year where games are loaded.
For a few months I fixed some of the bugs but it is not sustainable.
> Perhaps you're seeing a manifestation of a general issue that we're
> working on a solution for here:
>
> https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
>
> https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
>
> https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
>
> Or if you're on an older kernel and using hybrid sleep we had a generic
> issue there as well which was fixed in 6.18-rc1.
>
> Nonetheless; don't make policy decisions based upon kernel bugs. Fix
> the kernel bugs.
My problem is I cannot in good conscience restore a fan speed before
the program responsible for it is guaranteed to thaw.
The best solution I can come up with would be in freeze save if manual
control is enabled, disable it, and then on resume set a flag that
makes the first write to fan speed also set pwm to manual.
This way suspend->hibernate flows, even if hibernation hangs when
creating the image, at least have proper fan control because they are
unattended, and resume hangs work similarly.
Antheas
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-28 21:39 ` Antheas Kapenekakis
@ 2025-10-29 3:36 ` Mario Limonciello (AMD) (kernel.org)
2025-10-29 8:48 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Mario Limonciello (AMD) (kernel.org) @ 2025-10-29 3:36 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On 10/28/2025 4:39 PM, Antheas Kapenekakis wrote:
> On Tue, 28 Oct 2025 at 22:21, Mario Limonciello <superm1@kernel.org> wrote:
>>
>> On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
>>>>> The fan speed is also lost during hibernation, but since hibernation
>>>>> failures are common with this class of devices
>> Why are hibernation failures more common in this class of device than
>> anything else? The hibernation flow is nearly all done in Linux driver
>> code (with the exception of ACPI calls that move devices into D3 and out
>> of D0).
>
> I should correct myself here and say hibernation in general in Linux
> leaves something to be desired.
>
> Until secure boot supports hibernation, that will be the case because
> not enough people use it.
The upstream kernel has no tie between UEFI secure boot and hibernation.
I think you're talking about some distro kernels that tie UEFI secure
boot to lockdown. Lockdown does currently prohibit hibernation.
>
> I have had it break for multiple reasons, not incl. the ones below and
> the ones we discussed last year where games are loaded.
>
> For a few months I fixed some of the bugs but it is not sustainable.
>
>> Perhaps you're seeing a manifestation of a general issue that we're
>> working on a solution for here:
>>
>> https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
>>
>> https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
>>
>> https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
>>
>> Or if you're on an older kernel and using hybrid sleep we had a generic
>> issue there as well which was fixed in 6.18-rc1.
>>
>> Nonetheless; don't make policy decisions based upon kernel bugs. Fix
>> the kernel bugs.
>
> My problem is I cannot in good conscience restore a fan speed before
> the program responsible for it is guaranteed to thaw.
>
> The best solution I can come up with would be in freeze save if manual
> control is enabled, disable it, and then on resume set a flag that
> makes the first write to fan speed also set pwm to manual.
>
> This way suspend->hibernate flows, even if hibernation hangs when
> creating the image, at least have proper fan control because they are
> unattended, and resume hangs work similarly.
>
> Antheas
>
This sounds like a workable approach for what I understand to be your
current design; but let me suggest some other ideas.
What happens if you're running something big and the OOM comes and
whacks the process? Now you don't have fan control running anymore.
So I see two options to improve things.
1) You can have userspace send a "heartbeat" to kernel space. This can
be as simple as a timestamp of reading a sysfs file. If userspace
doesn't read the file in X ms then you turn off manual control.
2) You move everything to a kthread. Userspace can read some input
options or maybe pick a few curve settings, but leave all the important
logic in that kthread.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-29 3:36 ` Mario Limonciello (AMD) (kernel.org)
@ 2025-10-29 8:48 ` Antheas Kapenekakis
2025-10-29 10:22 ` Guenter Roeck
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-29 8:48 UTC (permalink / raw)
To: Mario Limonciello (AMD) (kernel.org)
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare, Guenter Roeck
On Wed, 29 Oct 2025 at 04:36, Mario Limonciello (AMD) (kernel.org)
<superm1@kernel.org> wrote:
>
>
>
> On 10/28/2025 4:39 PM, Antheas Kapenekakis wrote:
> > On Tue, 28 Oct 2025 at 22:21, Mario Limonciello <superm1@kernel.org> wrote:
> >>
> >> On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
> >>>>> The fan speed is also lost during hibernation, but since hibernation
> >>>>> failures are common with this class of devices
> >> Why are hibernation failures more common in this class of device than
> >> anything else? The hibernation flow is nearly all done in Linux driver
> >> code (with the exception of ACPI calls that move devices into D3 and out
> >> of D0).
> >
> > I should correct myself here and say hibernation in general in Linux
> > leaves something to be desired.
> >
> > Until secure boot supports hibernation, that will be the case because
> > not enough people use it.
>
> The upstream kernel has no tie between UEFI secure boot and hibernation.
> I think you're talking about some distro kernels that tie UEFI secure
> boot to lockdown. Lockdown does currently prohibit hibernation.
>
> >
> > I have had it break for multiple reasons, not incl. the ones below and
> > the ones we discussed last year where games are loaded.
> >
> > For a few months I fixed some of the bugs but it is not sustainable.
> >
> >> Perhaps you're seeing a manifestation of a general issue that we're
> >> working on a solution for here:
> >>
> >> https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
> >>
> >> https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
> >>
> >> https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
> >>
> >> Or if you're on an older kernel and using hybrid sleep we had a generic
> >> issue there as well which was fixed in 6.18-rc1.
> >>
> >> Nonetheless; don't make policy decisions based upon kernel bugs. Fix
> >> the kernel bugs.
> >
> > My problem is I cannot in good conscience restore a fan speed before
> > the program responsible for it is guaranteed to thaw.
> >
> > The best solution I can come up with would be in freeze save if manual
> > control is enabled, disable it, and then on resume set a flag that
> > makes the first write to fan speed also set pwm to manual.
> >
> > This way suspend->hibernate flows, even if hibernation hangs when
> > creating the image, at least have proper fan control because they are
> > unattended, and resume hangs work similarly.
> >
> > Antheas
> >
>
> This sounds like a workable approach for what I understand to be your
> current design; but let me suggest some other ideas.
>
> What happens if you're running something big and the OOM comes and
> whacks the process? Now you don't have fan control running anymore.
>
> So I see two options to improve things.
>
> 1) You can have userspace send a "heartbeat" to kernel space. This can
> be as simple as a timestamp of reading a sysfs file. If userspace
> doesn't read the file in X ms then you turn off manual control.
The OOT scenario is something I have not handled yet specifically, or
have had happen.
Systemd will restart the service in the case of OOT after 5 seconds
and in the case of a crash there are multiple fallbacks to ensure the
custom curve turns off.
Most of the hibernation hangs that I have experienced happen before
journalctl turns on, so I assumed that it's before userspace
unfreezes. I am also not sure if restore() gets to run in those cases
or not.
Re: heart beat, read below.
> 2) You move everything to a kthread. Userspace can read some input
> options or maybe pick a few curve settings, but leave all the important
> logic in that kthread.
I think this is what Luke tried to do with the Zotac Zone. But in the
end, the kernel is limited to what calculations it can do, esp.
floating point and what it can access, so you end up with a worse
curve with limited extendability, and a driver specific ABI. And we
also risk duplicating all of this code on hwmon drivers and making it
harder to access.
I think part of this reason is why the platform side of the Zotac
stuff has not been upstreamed, even though the driver itself other
than that is pretty straightforward with an established ABI by now.
And it is also the reason we have not been able to add the module to
Bazzite, because 1) we cannot validate the new fan curve calculations
without a device and 2) they are worse that what we provide through
userspace (a polynomial ramp-up which embeds hysteresis to avoid
jittering, plus choice for both Edge and Tctl sensors).
In summary, I think there would great potential for a common set of
"hwmon" helpers that can use a temperature function and a speed set
function to handle a basic multi-point curve for basic, e.g., udev
use-cases. To that end, there could be a helper with a 5 second
timeout that turns off the custom speed. But it would be good for that
to be implemented globally, so it does not block device hw enablement.
As far as this driver is concerned, I will handle the hibernation case
with a lazy resume, per what I said in the previous email.
Antheas
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-29 8:48 ` Antheas Kapenekakis
@ 2025-10-29 10:22 ` Guenter Roeck
2025-10-29 10:49 ` Antheas Kapenekakis
0 siblings, 1 reply; 36+ messages in thread
From: Guenter Roeck @ 2025-10-29 10:22 UTC (permalink / raw)
To: Antheas Kapenekakis, Mario Limonciello (AMD) (kernel.org)
Cc: platform-driver-x86, linux-kernel, linux-hwmon, Hans de Goede,
Ilpo Järvinen, Derek John Clark,
Joaquín Ignacio Aramendía, Jean Delvare
On 10/29/25 01:48, Antheas Kapenekakis wrote:
> On Wed, 29 Oct 2025 at 04:36, Mario Limonciello (AMD) (kernel.org)
> <superm1@kernel.org> wrote:
>>
>>
>>
>> On 10/28/2025 4:39 PM, Antheas Kapenekakis wrote:
>>> On Tue, 28 Oct 2025 at 22:21, Mario Limonciello <superm1@kernel.org> wrote:
>>>>
>>>> On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
>>>>>>> The fan speed is also lost during hibernation, but since hibernation
>>>>>>> failures are common with this class of devices
>>>> Why are hibernation failures more common in this class of device than
>>>> anything else? The hibernation flow is nearly all done in Linux driver
>>>> code (with the exception of ACPI calls that move devices into D3 and out
>>>> of D0).
>>>
>>> I should correct myself here and say hibernation in general in Linux
>>> leaves something to be desired.
>>>
>>> Until secure boot supports hibernation, that will be the case because
>>> not enough people use it.
>>
>> The upstream kernel has no tie between UEFI secure boot and hibernation.
>> I think you're talking about some distro kernels that tie UEFI secure
>> boot to lockdown. Lockdown does currently prohibit hibernation.
>>
>>>
>>> I have had it break for multiple reasons, not incl. the ones below and
>>> the ones we discussed last year where games are loaded.
>>>
>>> For a few months I fixed some of the bugs but it is not sustainable.
>>>
>>>> Perhaps you're seeing a manifestation of a general issue that we're
>>>> working on a solution for here:
>>>>
>>>> https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
>>>>
>>>> https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
>>>>
>>>> https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
>>>>
>>>> Or if you're on an older kernel and using hybrid sleep we had a generic
>>>> issue there as well which was fixed in 6.18-rc1.
>>>>
>>>> Nonetheless; don't make policy decisions based upon kernel bugs. Fix
>>>> the kernel bugs.
>>>
>>> My problem is I cannot in good conscience restore a fan speed before
>>> the program responsible for it is guaranteed to thaw.
>>>
>>> The best solution I can come up with would be in freeze save if manual
>>> control is enabled, disable it, and then on resume set a flag that
>>> makes the first write to fan speed also set pwm to manual.
>>>
>>> This way suspend->hibernate flows, even if hibernation hangs when
>>> creating the image, at least have proper fan control because they are
>>> unattended, and resume hangs work similarly.
>>>
>>> Antheas
>>>
>>
>> This sounds like a workable approach for what I understand to be your
>> current design; but let me suggest some other ideas.
>>
>> What happens if you're running something big and the OOM comes and
>> whacks the process? Now you don't have fan control running anymore.
>>
>> So I see two options to improve things.
>>
>> 1) You can have userspace send a "heartbeat" to kernel space. This can
>> be as simple as a timestamp of reading a sysfs file. If userspace
>> doesn't read the file in X ms then you turn off manual control.
>
> The OOT scenario is something I have not handled yet specifically, or
> have had happen.
>
> Systemd will restart the service in the case of OOT after 5 seconds
> and in the case of a crash there are multiple fallbacks to ensure the
> custom curve turns off.
>
> Most of the hibernation hangs that I have experienced happen before
> journalctl turns on, so I assumed that it's before userspace
> unfreezes. I am also not sure if restore() gets to run in those cases
> or not.
>
> Re: heart beat, read below.
>
>> 2) You move everything to a kthread. Userspace can read some input
>> options or maybe pick a few curve settings, but leave all the important
>> logic in that kthread.
>
> I think this is what Luke tried to do with the Zotac Zone. But in the
> end, the kernel is limited to what calculations it can do, esp.
> floating point and what it can access, so you end up with a worse
> curve with limited extendability, and a driver specific ABI. And we
> also risk duplicating all of this code on hwmon drivers and making it
> harder to access.
>
> I think part of this reason is why the platform side of the Zotac
> stuff has not been upstreamed, even though the driver itself other
> than that is pretty straightforward with an established ABI by now.
> And it is also the reason we have not been able to add the module to
> Bazzite, because 1) we cannot validate the new fan curve calculations
> without a device and 2) they are worse that what we provide through
> userspace (a polynomial ramp-up which embeds hysteresis to avoid
> jittering, plus choice for both Edge and Tctl sensors).
>
> In summary, I think there would great potential for a common set of
> "hwmon" helpers that can use a temperature function and a speed set
> function to handle a basic multi-point curve for basic, e.g., udev
> use-cases. To that end, there could be a helper with a 5 second
> timeout that turns off the custom speed. But it would be good for that
> to be implemented globally, so it does not block device hw enablement.
>
Maybe I misunderstand. If so, apologies.
Thermal _control_ is what the thermal subsystem is for. hwmon is for
hardware monitoring, not control. You may do whatever you like
in platform drivers, including the duplication of termal subsystem
functionality, but please do not get hwmon involved. That includes
any kind of helpers to compute any kind of temperature curves.
Thanks,
Guenter
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-29 10:22 ` Guenter Roeck
@ 2025-10-29 10:49 ` Antheas Kapenekakis
2025-10-29 14:25 ` Guenter Roeck
0 siblings, 1 reply; 36+ messages in thread
From: Antheas Kapenekakis @ 2025-10-29 10:49 UTC (permalink / raw)
To: Guenter Roeck
Cc: Mario Limonciello (AMD) (kernel.org), platform-driver-x86,
linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare
On Wed, 29 Oct 2025 at 11:22, Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 10/29/25 01:48, Antheas Kapenekakis wrote:
> > On Wed, 29 Oct 2025 at 04:36, Mario Limonciello (AMD) (kernel.org)
> > <superm1@kernel.org> wrote:
> >>
> >>
> >>
> >> On 10/28/2025 4:39 PM, Antheas Kapenekakis wrote:
> >>> On Tue, 28 Oct 2025 at 22:21, Mario Limonciello <superm1@kernel.org> wrote:
> >>>>
> >>>> On 10/28/25 3:34 PM, Antheas Kapenekakis wrote:
> >>>>>>> The fan speed is also lost during hibernation, but since hibernation
> >>>>>>> failures are common with this class of devices
> >>>> Why are hibernation failures more common in this class of device than
> >>>> anything else? The hibernation flow is nearly all done in Linux driver
> >>>> code (with the exception of ACPI calls that move devices into D3 and out
> >>>> of D0).
> >>>
> >>> I should correct myself here and say hibernation in general in Linux
> >>> leaves something to be desired.
> >>>
> >>> Until secure boot supports hibernation, that will be the case because
> >>> not enough people use it.
> >>
> >> The upstream kernel has no tie between UEFI secure boot and hibernation.
> >> I think you're talking about some distro kernels that tie UEFI secure
> >> boot to lockdown. Lockdown does currently prohibit hibernation.
> >>
> >>>
> >>> I have had it break for multiple reasons, not incl. the ones below and
> >>> the ones we discussed last year where games are loaded.
> >>>
> >>> For a few months I fixed some of the bugs but it is not sustainable.
> >>>
> >>>> Perhaps you're seeing a manifestation of a general issue that we're
> >>>> working on a solution for here:
> >>>>
> >>>> https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/
> >>>>
> >>>> https://lore.kernel.org/linux-pm/20251026033115.436448-1-superm1@kernel.org/
> >>>>
> >>>> https://lore.kernel.org/linux-pm/5935682.DvuYhMxLoT@rafael.j.wysocki/T/#u
> >>>>
> >>>> Or if you're on an older kernel and using hybrid sleep we had a generic
> >>>> issue there as well which was fixed in 6.18-rc1.
> >>>>
> >>>> Nonetheless; don't make policy decisions based upon kernel bugs. Fix
> >>>> the kernel bugs.
> >>>
> >>> My problem is I cannot in good conscience restore a fan speed before
> >>> the program responsible for it is guaranteed to thaw.
> >>>
> >>> The best solution I can come up with would be in freeze save if manual
> >>> control is enabled, disable it, and then on resume set a flag that
> >>> makes the first write to fan speed also set pwm to manual.
> >>>
> >>> This way suspend->hibernate flows, even if hibernation hangs when
> >>> creating the image, at least have proper fan control because they are
> >>> unattended, and resume hangs work similarly.
> >>>
> >>> Antheas
> >>>
> >>
> >> This sounds like a workable approach for what I understand to be your
> >> current design; but let me suggest some other ideas.
> >>
> >> What happens if you're running something big and the OOM comes and
> >> whacks the process? Now you don't have fan control running anymore.
> >>
> >> So I see two options to improve things.
> >>
> >> 1) You can have userspace send a "heartbeat" to kernel space. This can
> >> be as simple as a timestamp of reading a sysfs file. If userspace
> >> doesn't read the file in X ms then you turn off manual control.
> >
> > The OOT scenario is something I have not handled yet specifically, or
> > have had happen.
> >
> > Systemd will restart the service in the case of OOT after 5 seconds
> > and in the case of a crash there are multiple fallbacks to ensure the
> > custom curve turns off.
> >
> > Most of the hibernation hangs that I have experienced happen before
> > journalctl turns on, so I assumed that it's before userspace
> > unfreezes. I am also not sure if restore() gets to run in those cases
> > or not.
> >
> > Re: heart beat, read below.
> >
> >> 2) You move everything to a kthread. Userspace can read some input
> >> options or maybe pick a few curve settings, but leave all the important
> >> logic in that kthread.
> >
> > I think this is what Luke tried to do with the Zotac Zone. But in the
> > end, the kernel is limited to what calculations it can do, esp.
> > floating point and what it can access, so you end up with a worse
> > curve with limited extendability, and a driver specific ABI. And we
> > also risk duplicating all of this code on hwmon drivers and making it
> > harder to access.
> >
> > I think part of this reason is why the platform side of the Zotac
> > stuff has not been upstreamed, even though the driver itself other
> > than that is pretty straightforward with an established ABI by now.
> > And it is also the reason we have not been able to add the module to
> > Bazzite, because 1) we cannot validate the new fan curve calculations
> > without a device and 2) they are worse that what we provide through
> > userspace (a polynomial ramp-up which embeds hysteresis to avoid
> > jittering, plus choice for both Edge and Tctl sensors).
> >
> > In summary, I think there would great potential for a common set of
> > "hwmon" helpers that can use a temperature function and a speed set
> > function to handle a basic multi-point curve for basic, e.g., udev
> > use-cases. To that end, there could be a helper with a 5 second
> > timeout that turns off the custom speed. But it would be good for that
> > to be implemented globally, so it does not block device hw enablement.
> >
>
> Maybe I misunderstand. If so, apologies.
>
> Thermal _control_ is what the thermal subsystem is for. hwmon is for
> hardware monitoring, not control. You may do whatever you like
> in platform drivers, including the duplication of termal subsystem
> functionality, but please do not get hwmon involved. That includes
> any kind of helpers to compute any kind of temperature curves.
I have no preference for which subsystem these helpers are placed if
implemented. But if thermal handlers are implemented they need to be
global. This includes timeouts for manual control and basic fan curves
(for which the ABI belongs to hwmon).
I cannot make manufacturer specific workarounds for X platform 6 point
curve because it was determined XYZ this and that, when the
manufacturer provides direct control.
Speaking of which, what is the policy for hwmon when it comes to
settings after hibernation. I am being asked to add a restore hook for
hwmon settings here, but other relevant drivers do not have it
(asuswmi, gpdfan, oxpec), is a new requirement for hwmon?
Antheas
> Thanks,
> Guenter
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 6/6] platform/x86: ayaneo-ec: Add suspend hook
2025-10-29 10:49 ` Antheas Kapenekakis
@ 2025-10-29 14:25 ` Guenter Roeck
0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2025-10-29 14:25 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: Mario Limonciello (AMD) (kernel.org), platform-driver-x86,
linux-kernel, linux-hwmon, Hans de Goede, Ilpo Järvinen,
Derek John Clark, Joaquín Ignacio Aramendía,
Jean Delvare
On 10/29/25 03:49, Antheas Kapenekakis wrote:
...
> Speaking of which, what is the policy for hwmon when it comes to
> settings after hibernation. I am being asked to add a restore hook for
> hwmon settings here, but other relevant drivers do not have it
> (asuswmi, gpdfan, oxpec), is a new requirement for hwmon?
>
Your driver is in platform/x86. I do not dictate or control requirements
in that subsystem. I only get involved at all if I catch a flagrant violation
of hwmon's API/ABI. I found that people implementing hwmon drivers outside
hwmon often do it to avoid maintainer scrutiny, and I am tired of arguing
with people claiming that they know the hwmon subsystem better than me.
For drivers/hwmon, there is no mandate to implement suspend/restore support,
but if implemented if _should_ be complete. I understand that this is not
always the case. I don't reject code because of it because it is sometimes
all but impossible to implement. My philosophy is that anyone interested
in a perfect implementation of suspend/restore support is invited to submit
patch(es) implementing it.
Long story short, there is no such requirement for hwmon drivers in
drivers/hwmon/, but I can not speak for requirement in drivers/platform/.
That is for the respective maintainers to determine and decide.
Guenter
^ permalink raw reply [flat|nested] 36+ messages in thread