From nobody Sat Oct 4 03:17:21 2025 Received: from relay12.grserver.gr (relay12.grserver.gr [88.99.38.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C71B4242D72; Wed, 20 Aug 2025 16:16:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=88.99.38.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706594; cv=none; b=hNxOq7QjSfJv/OcL1YY/9wMj6Kee2UNA9hsr+E2XdfIp04Njz+T6z0GlWWHimxALtcHTUmgz1LvgwlqUHtgrx63f1SvIXZPY0jMhMX1Ery7I0R4286tMdYEymOsNz+R5znT/vIqZtVgYkz/cHONEl7GT6PGdjf2xjBwQou6Ux0A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706594; c=relaxed/simple; bh=cTLPsHBn531ojToU3+KN2htdYGLw8ZmtzCz0FHCb8js=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pwefPn86hMwsm67WDvCXUPDidvl4CJnS4YLfpyEIYTevMtlVSZRa8MhnaNnuBCwCVHoHEq+Sg25gJYV8hQvJedEMmx9EhIpP2u4zj5DUYdh3M3xtoj9C6KcYljF3YTvNbTXE9l7ZCUkLJeKrHUuZIFC9Ct1MtzyLO8kxN6NLgGo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=QvwvBfuF; arc=none smtp.client-ip=88.99.38.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="QvwvBfuF" Received: from relay12 (localhost [127.0.0.1]) by relay12.grserver.gr (Proxmox) with ESMTP id C54DFBDD12; Wed, 20 Aug 2025 19:06:32 +0300 (EEST) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay12.grserver.gr (Proxmox) with ESMTPS id E4AA6BDCB0; Wed, 20 Aug 2025 19:06:31 +0300 (EEST) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:7200:c86a:8976:4786]) by linux3247.grserver.gr (Postfix) with ESMTPSA id 040F3205624; Wed, 20 Aug 2025 19:06:30 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1755705991; bh=vQOykRQ/Qv/YWm2j41fZECGX/uzOVIyRStBZkJSOI2Q=; h=From:To:Subject; b=QvwvBfuFt6OIjGx9jIbXcic5icr7Ds0DXriEfkOAbjMjGdV0Mw5BxgLygxqs6shUv TLrgWBls/8FeOEgq47ic8s4n3ihhpoT6C+ZzN33kvZt8lK+Dir+Vma8Kj5RRHumuUq psMWr8dwypAqiaAm2JzvvVqlvwuWykK04D3tIEBkEcsZdfMjovRrSvVQNkOZh4nQ9J oCIvxPkcNfRWOLMo7jr8dVO079fRXFEJ+9n7qx4W7Qqh4NSqHKAa5ZbjkaydNfzjwH JKoV3stq1w9N/7+/Qjwx4kjEvmlo4o9xQbLjjFbUNUA4xCi/7mWOThbcAORtDU/POS N31EknXntkPWQ== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:7200:c86a:8976:4786) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis Subject: [PATCH v1 1/5] platform/x86: ayaneo-ec: Add Ayaneo Embedded Controller platform driver Date: Wed, 20 Aug 2025 18:06:24 +0200 Message-ID: <20250820160628.99678-2-lkml@antheas.dev> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250820160628.99678-1-lkml@antheas.dev> References: <20250820160628.99678-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <175570599153.2162638.11994229128294182856@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" 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 --- 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 daf520a13bdf..7afa7b8a3494 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4130,6 +4130,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 =20 +AYANEO PLATFORM EC DRIVER +M: Antheas Kapenekakis +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/ayaneo-ec.c + AZ6007 DVB DRIVER M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6d238e120dce..6d4a33791cc1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -304,6 +304,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. =20 +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 a0c5848513e3..f310e1233974 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -38,6 +38,9 @@ obj-$(CONFIG_ASUS_TF103C_DOCK) +=3D asus-tf103c-dock.o obj-$(CONFIG_EEEPC_LAPTOP) +=3D eeepc-laptop.o obj-$(CONFIG_EEEPC_WMI) +=3D eeepc-wmi.o =20 +# Ayaneo +obj-$(CONFIG_AYANEO_EC) +=3D ayaneo-ec.o + # Cisco/Meraki obj-$(CONFIG_MERAKI_MX100) +=3D meraki-mx100.o =20 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. Han= dles + * hwmon (fan speed, fan control), battery charge limits, and magic module + * control (connected modules, controller disconnection). + * + * Copyright (C) 2025 Antheas Kapenekakis + */ + +#include +#include +#include +#include +#include + +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 =3D { +}; + +static const struct dmi_system_id dmi_table[] =3D { + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"), + }, + .driver_data =3D (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 =3D dmi_first_match(dmi_table); + if (!dmi_entry) + return -ENODEV; + + data =3D devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->pdev =3D pdev; + data->quirks =3D dmi_entry->driver_data; + platform_set_drvdata(pdev, data); + + return 0; +} + +static struct platform_driver ayaneo_platform_driver =3D { + .driver =3D { + .name =3D "ayaneo-ec", + }, + .probe =3D ayaneo_ec_probe, +}; + +static struct platform_device *ayaneo_platform_device; + +static int __init ayaneo_ec_init(void) +{ + ayaneo_platform_device =3D + 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 "); +MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features"); +MODULE_LICENSE("GPL"); --=20 2.50.1 From nobody Sat Oct 4 03:17:21 2025 Received: from relay10.grserver.gr (relay10.grserver.gr [37.27.248.198]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8B8636CE15; Wed, 20 Aug 2025 16:14:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=37.27.248.198 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706463; cv=none; b=aIhypOkOonBalRwvyx6uFi+2mmDlqn+d/2O2s0VxdFSshqgnLcgAZZ156ryHsvckH4+MIFjPwS63+lYwwgKkOycCEdAJVXL+CSG7MJAd0p8NTTY67ye22wej5I5pRddO1Nn+kFtrQfcoSKxbI5ZSHzbsgJuOqDAkwu6lubSwkag= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706463; c=relaxed/simple; bh=jlw6eb/npySk95Pgm3mazx5MZCLoghLMeP5mbM9vroU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fTLsWFHFGSy8iemoZQA+7Oa7WZLvBwZANztg9jNseWrJPolZSQr6bw/tTmF5r4+bzWQGOQdkz3IZg3s4NbetBRSBi6+7crWGO1HnNPSo2LwshomKu/p1nTluOA9tIfIKq60HN4AS6n7z1N8Du6uvQmy32VvagGyncPFN/bDRQDg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=Mpk7NkW9; arc=none smtp.client-ip=37.27.248.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="Mpk7NkW9" Received: from relay10 (localhost.localdomain [127.0.0.1]) by relay10.grserver.gr (Proxmox) with ESMTP id 7CC02467ED; Wed, 20 Aug 2025 19:06:33 +0300 (EEST) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay10.grserver.gr (Proxmox) with ESMTPS id D2CD24236A; Wed, 20 Aug 2025 19:06:32 +0300 (EEST) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:7200:c86a:8976:4786]) by linux3247.grserver.gr (Postfix) with ESMTPSA id D9C0720638D; Wed, 20 Aug 2025 19:06:31 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1755705992; bh=hsSk4r8iuluSzpP/KO4eAbRVqzRjXz2ofuhwVybQrZ0=; h=From:To:Subject; b=Mpk7NkW9B/PNBSibUr15GBw4/xUxh+rZoX+GujnXMDZhP2AzDc4YNBGVHe4bqjCY/ dGHZWmWR+bgiciazPu7fzVwA7VqHJ6FG8gooe8/Z5zhYA5EZxmMvWnJu8BIJvgy6UV bqvjuS6aJsZ/Lm/0tDYbEvmepROKDk98yaVVFPlNCBFpL5WWiijw+XeQt1D24y1rDe 22P4gjFQdKT/ASX5slk+tEG8lGJWMYEgQRGsrSv1HIqY7ayi3khsw4d5bHNisjS4Ou V/DT5X57vv64cocz10LULBvEMwtTcBFIemhkj8VA1e0sRdL0D9MZ4KurPXiM74NK7N UAFbPES3pEGhw== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:7200:c86a:8976:4786) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis Subject: [PATCH v1 2/5] platform/x86: ayaneo-ec: Add hwmon support Date: Wed, 20 Aug 2025 18:06:25 +0200 Message-ID: <20250820160628.99678-3-lkml@antheas.dev> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250820160628.99678-1-lkml@antheas.dev> References: <20250820160628.99678-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <175570599240.2162693.14366500508778981372@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" 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 --- drivers/platform/x86/Kconfig | 2 + drivers/platform/x86/ayaneo-ec.c | 132 +++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6d4a33791cc1..0a7ca2c78456 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -307,6 +307,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..8b1902706b81 100644 --- a/drivers/platform/x86/ayaneo-ec.c +++ b/drivers/platform/x86/ayaneo-ec.c @@ -7,13 +7,23 @@ * Copyright (C) 2025 Antheas Kapenekakis */ =20 +#include #include +#include #include #include #include #include =20 +#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; }; =20 struct ayaneo_ec_platform_data { @@ -22,6 +32,7 @@ struct ayaneo_ec_platform_data { }; =20 static const struct ayaneo_ec_quirk ayaneo3 =3D { + .has_fan_control =3D true, }; =20 static const struct dmi_system_id dmi_table[] =3D { @@ -35,10 +46,124 @@ static const struct dmi_system_id dmi_table[] =3D { {}, }; =20 +/* 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 =3D ec_read(AYANEO_FAN_REG, &tmp); + if (ret) + return ret; + *val =3D tmp << 8; + ret =3D ec_read(AYANEO_FAN_REG + 1, &tmp); + if (ret) + return ret; + *val +=3D tmp; + return 0; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret =3D ec_read(AYANEO_PWM_REG, &tmp); + if (ret) + return ret; + *val =3D (255 * tmp) / 100; + if (*val < 0 || *val > 255) + return -EINVAL; + return 0; + case hwmon_pwm_enable: + ret =3D ec_read(AYANEO_PWM_ENABLE_REG, &tmp); + if (ret) + return ret; + if (tmp =3D=3D AYANEO_PWM_MODE_MANUAL) + *val =3D 1; + else + *val =3D 2; + return 0; + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types typ= e, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + if (val =3D=3D 1) + return ec_write(AYANEO_PWM_ENABLE_REG, + AYANEO_PWM_MODE_MANUAL); + else if (val =3D=3D 2) + return ec_write(AYANEO_PWM_ENABLE_REG, + AYANEO_PWM_MODE_AUTO); + else + 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 =3D { + .is_visible =3D ayaneo_ec_hwmon_is_visible, + .read =3D ayaneo_ec_read, + .write =3D ayaneo_ec_write, +}; + +static const struct hwmon_channel_info *const ayaneo_ec_sensors[] =3D { + 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 =3D { + .ops =3D &ayaneo_ec_hwmon_ops, + .info =3D 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; =20 dmi_entry =3D dmi_first_match(dmi_table); if (!dmi_entry) @@ -52,6 +177,13 @@ static int ayaneo_ec_probe(struct platform_device *pdev) data->quirks =3D dmi_entry->driver_data; platform_set_drvdata(pdev, data); =20 + if (data->quirks->has_fan_control) { + hwdev =3D 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; } =20 --=20 2.50.1 From nobody Sat Oct 4 03:17:21 2025 Received: from relay11.grserver.gr (relay11.grserver.gr [78.46.171.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0F3023909F; Wed, 20 Aug 2025 16:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.46.171.57 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706004; cv=none; b=T6q12Sa117jIQ9NVknXQv/X42w3MQx3OSjA6sk+/9JuR/ZdBj6eXtYtv5/fyqlbFiNcQJPMCvJPCHO2yDnPbC9ruA69LxZdNhNo2ECFqTGiBZ0tBKNhcvhB1xsgBXDPCfm3v45YGx4MT+7JH+423TThIIZg6SHNNmuCtJqL+iaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706004; c=relaxed/simple; bh=zb2g+r3cJ7UMel+RtIvaiOlpRn9I9h6P+DbCMImmBLk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=It+DKqj91KiGyZiuJnWZc0CUGYZf+dudwP5wT6a/KMcsPzrJeJ665DbRdvSjcmlbMc48Awm8L6s/WFXRQXVTc/M+ZjNUd8bnA8pMNd9epvolJ6QC7k0yTrDy/ZvmbPRqnQq7bzLEj/iy+I/WCBksz1Kr4EpDiePSnOGrk9fJFyg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=K2SnrFQK; arc=none smtp.client-ip=78.46.171.57 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="K2SnrFQK" Received: from relay11 (localhost.localdomain [127.0.0.1]) by relay11.grserver.gr (Proxmox) with ESMTP id 04241C5C82; Wed, 20 Aug 2025 19:06:34 +0300 (EEST) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay11.grserver.gr (Proxmox) with ESMTPS id 7D7E9C5C7D; Wed, 20 Aug 2025 19:06:33 +0300 (EEST) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:7200:c86a:8976:4786]) by linux3247.grserver.gr (Postfix) with ESMTPSA id A1FD41FD4AC; Wed, 20 Aug 2025 19:06:32 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1755705993; bh=5lPVm50we/HBZRgiKKoeroZQYLufvKOV3QNKU3+SIrs=; h=From:To:Subject; b=K2SnrFQKeQg/ITN0jYvs9AgSJ7Aog2B3TvIujGtIu7kMFf4a+vuReUAfMm0TDqJmd tbkzIH3sEUEF7n4YmMxiZLSjghc1MReEphsMrpNHQHys/3GDYHZJX8E5b45ALHIYUZ zzM6sFzdBKFzZnXFepM+8woH0yZviuqYPaLCLbSTqE/JXUXJxI4xds8mUnFDZUlq0t /U5RPrSZDEdxDWVY1DHiQD047Vt9w/tN+ky6u9Uc4KLb8X9VwhhStV5ywXntyEqleh D78uWdtQ+QmQP1eZLxDIEeB92DMzY/pbZJDec6wObZXeB2wlS1tIxklixuyvfhl+oi DIrlYbtE2a5rQ== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:7200:c86a:8976:4786) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis Subject: [PATCH v1 3/5] platform/x86: ayaneo-ec: Add charge control support Date: Wed, 20 Aug 2025 18:06:26 +0200 Message-ID: <20250820160628.99678-4-lkml@antheas.dev> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250820160628.99678-1-lkml@antheas.dev> References: <20250820160628.99678-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <175570599317.2162733.2479809423753195306@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" Ayaneo devices support charge inhibition via the EC. This inhibition only works while the device is powered on, and resets between restarts. However, it is maintained across suspend/resume cycles. The EC does not support charge threshold control. Instead, userspace software on Windows manually toggles charge inhibition depending on battery level. Signed-off-by: Antheas Kapenekakis --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/ayaneo-ec.c | 111 +++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0a7ca2c78456..c871a722e5ef 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -308,6 +308,7 @@ config AYANEO_EC tristate "Ayaneo EC platform control" depends on X86 depends on ACPI_EC + depends on ACPI_BATTERY depends on HWMON help Enables support for the platform EC of Ayaneo devices. This diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo= -ec.c index 8b1902706b81..a4bdc6ae7af7 100644 --- a/drivers/platform/x86/ayaneo-ec.c +++ b/drivers/platform/x86/ayaneo-ec.c @@ -14,6 +14,7 @@ #include #include #include +#include =20 #define AYANEO_PWM_ENABLE_REG 0x4A #define AYANEO_PWM_REG 0x4B @@ -22,17 +23,27 @@ =20 #define AYANEO_FAN_REG 0x76 =20 +#define EC_CHARGE_CONTROL_BEHAVIOURS \ + (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \ + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) +#define AYANEO_CHARGE_REG 0x1e +#define AYANEO_CHARGE_VAL_AUTO 0xaa +#define AYANEO_CHARGE_VAL_INHIBIT 0x55 + struct ayaneo_ec_quirk { bool has_fan_control; + bool has_charge_control; }; =20 struct ayaneo_ec_platform_data { struct platform_device *pdev; struct ayaneo_ec_quirk *quirks; + struct acpi_battery_hook battery_hook; }; =20 static const struct ayaneo_ec_quirk ayaneo3 =3D { .has_fan_control =3D true, + .has_charge_control =3D true, }; =20 static const struct dmi_system_id dmi_table[] =3D { @@ -159,11 +170,102 @@ static const struct hwmon_chip_info ayaneo_ec_chip_i= nfo =3D { .info =3D ayaneo_ec_sensors, }; =20 +static int ayaneo_psy_ext_get_prop(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret; + u8 tmp; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + ret =3D ec_read(AYANEO_CHARGE_REG, &tmp); + if (ret) + return ret; + + if (tmp =3D=3D AYANEO_CHARGE_VAL_INHIBIT) + val->intval =3D POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + else + val->intval =3D POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; + return 0; + default: + return -EINVAL; + } +} + +static int ayaneo_psy_ext_set_prop(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + u8 raw_val; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + switch (val->intval) { + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: + raw_val =3D AYANEO_CHARGE_VAL_AUTO; + break; + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: + raw_val =3D AYANEO_CHARGE_VAL_INHIBIT; + break; + default: + return -EINVAL; + } + return ec_write(AYANEO_CHARGE_REG, raw_val); + default: + return -EINVAL; + } +} + +static int ayaneo_psy_prop_is_writeable(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp) +{ + return true; +} + +static const enum power_supply_property ayaneo_psy_ext_props[] =3D { + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, +}; + +static const struct power_supply_ext ayaneo_psy_ext =3D { + .name =3D "ayaneo-charge-control", + .properties =3D ayaneo_psy_ext_props, + .num_properties =3D ARRAY_SIZE(ayaneo_psy_ext_props), + .charge_behaviours =3D EC_CHARGE_CONTROL_BEHAVIOURS, + .get_property =3D ayaneo_psy_ext_get_prop, + .set_property =3D ayaneo_psy_ext_set_prop, + .property_is_writeable =3D ayaneo_psy_prop_is_writeable, +}; + +static int ayaneo_add_battery(struct power_supply *battery, + struct acpi_battery_hook *hook) +{ + struct ayaneo_ec_platform_data *data =3D + container_of(hook, struct ayaneo_ec_platform_data, battery_hook); + + return power_supply_register_extension(battery, &ayaneo_psy_ext, + &data->pdev->dev, NULL); +} + +static int ayaneo_remove_battery(struct power_supply *battery, + struct acpi_battery_hook *hook) +{ + power_supply_unregister_extension(battery, &ayaneo_psy_ext); + return 0; +} + static int ayaneo_ec_probe(struct platform_device *pdev) { const struct dmi_system_id *dmi_entry; struct ayaneo_ec_platform_data *data; struct device *hwdev; + int ret; =20 dmi_entry =3D dmi_first_match(dmi_table); if (!dmi_entry) @@ -184,6 +286,15 @@ static int ayaneo_ec_probe(struct platform_device *pde= v) return PTR_ERR(hwdev); } =20 + if (data->quirks->has_charge_control) { + data->battery_hook.add_battery =3D ayaneo_add_battery; + data->battery_hook.remove_battery =3D ayaneo_remove_battery; + data->battery_hook.name =3D "Ayaneo Battery"; + ret =3D devm_battery_hook_register(&pdev->dev, &data->battery_hook); + if (ret) + return ret; + } + return 0; } =20 --=20 2.50.1 From nobody Sat Oct 4 03:17:21 2025 Received: from relay11.grserver.gr (relay11.grserver.gr [78.46.171.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C7AB158538; Wed, 20 Aug 2025 16:06:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.46.171.57 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706006; cv=none; b=LtYXjIZSGOMCs41/5BqbaqPXMNgwLc+MoqpX8Vy1xGcEuaV9ItYBLAiB1C0U/qFFmDgJStYgzlNdZejYXfscrHiY0yEvbhIHbC0g9gn440e5GfnPfQyxM7fmGjY0GfmI1cX1Yv+HHIC5n0LTNSamsFz9+r3NH6ob9V+Jq4j2tGo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706006; c=relaxed/simple; bh=SCLob1P7lf6sUZckuXPDUNBl/7tApROfvewivZSn0Po=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IHfEyFhqxzOmmycBuzymQRo9VSijGj+a8AYXEQiIi7Q4PuH7OY58oey6c9fhaRQrI1F9srSUtNJrkNaOe9+3H6LWgOINsG1f4Ewf5Zk//ojfRA5IBiTwaF/uBj8iSQibRqYaueoclWbsNjuR4BhT1IIOOcNl1v57w+EtMYjou98= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=VlZW8vY5; arc=none smtp.client-ip=78.46.171.57 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="VlZW8vY5" Received: from relay11 (localhost.localdomain [127.0.0.1]) by relay11.grserver.gr (Proxmox) with ESMTP id 2B044C5C89; Wed, 20 Aug 2025 19:06:35 +0300 (EEST) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay11.grserver.gr (Proxmox) with ESMTPS id 61D6FC5C7D; Wed, 20 Aug 2025 19:06:34 +0300 (EEST) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:7200:c86a:8976:4786]) by linux3247.grserver.gr (Postfix) with ESMTPSA id 7FA781FD027; Wed, 20 Aug 2025 19:06:33 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1755705994; bh=G/j1d5xYuzUU2coLnA/7L2dZMxo90xR3kuo3XTxCbC0=; h=From:To:Subject; b=VlZW8vY5fyjOxsTFQ1s8R0AAlqv2amR8qR5tT4n7pWRJ2heN7SfnLpp0FBgwgwF3S aInLAdk32FS2wlTrwLUxC5zKIvZVSCcZBxe9sh1FHP7o4oSaYFdW+z1tPpwuA97PvR 2hSIBTHVUrXjCuGIzG8y8oYte6kFQ6CrEL/G9HEL+uH+PqikPHJNAR8eSvDnDOG/KU Y7RPxRESEe+E5Wd0tHoK18IJ8mHU93KQjPjGCJDhWZjzm2BeBu435QaT4eNNNVlM8i rmieh1Bdcc87fPeqAC9H3pg/lbRhJY/za5Ix8HGWQHGCcmqeVyiHRDhzSKzuZ7p+8d upp/UbwlZxbzg== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:7200:c86a:8976:4786) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis Subject: [PATCH v1 4/5] platform/x86: ayaneo-ec: Add controller power and modules attributes Date: Wed, 20 Aug 2025 18:06:27 +0200 Message-ID: <20250820160628.99678-5-lkml@antheas.dev> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250820160628.99678-1-lkml@antheas.dev> References: <20250820160628.99678-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <175570599406.2162779.6203520223486516210@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" 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 firmware 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 'on'/'off'). 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 --- drivers/platform/x86/ayaneo-ec.c | 235 ++++++++++++++++++++++++++++++- 1 file changed, 234 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo= -ec.c index a4bdc6ae7af7..eb7f9ae03b4f 100644 --- a/drivers/platform/x86/ayaneo-ec.c +++ b/drivers/platform/x86/ayaneo-ec.c @@ -16,6 +16,10 @@ #include #include =20 +#include "firmware_attributes_class.h" + +#define DRIVER_NAME "ayaneo-ec" + #define AYANEO_PWM_ENABLE_REG 0x4A #define AYANEO_PWM_REG 0x4B #define AYANEO_PWM_MODE_AUTO 0x00 @@ -30,20 +34,60 @@ #define AYANEO_CHARGE_VAL_AUTO 0xaa #define AYANEO_CHARGE_VAL_INHIBIT 0x55 =20 +#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) + +enum ayaneo_fw_attr_id { + AYANEO_ATTR_CONTROLLER_MODULES, + AYANEO_ATTR_CONTROLLER_POWER, +}; + +static const char *const ayaneo_fw_attr_name[] =3D { + [AYANEO_ATTR_CONTROLLER_MODULES] =3D "controller_modules", + [AYANEO_ATTR_CONTROLLER_POWER] =3D "controller_power", +}; + +static const char *const ayaneo_fw_attr_desc[] =3D { + [AYANEO_ATTR_CONTROLLER_MODULES] =3D + "Which controller Magic Modules are connected (none, left, right, both)", + [AYANEO_ATTR_CONTROLLER_POWER] =3D "Controller power state (on, off)", +}; + +#define AYANEO_ATTR_ENUM_MAX_ATTRS 7 +#define AYANEO_ATTR_LANGUAGE_CODE "en_US.UTF-8" + struct ayaneo_ec_quirk { bool has_fan_control; bool has_charge_control; + bool has_magic_modules; + bool has_controller_power; }; =20 struct ayaneo_ec_platform_data { struct platform_device *pdev; struct ayaneo_ec_quirk *quirks; struct acpi_battery_hook battery_hook; + struct device *fw_attrs_dev; + struct kset *fw_attrs_kset; +}; + +struct ayaneo_fw_attr { + struct ayaneo_ec_platform_data *data; + enum ayaneo_fw_attr_id fw_attr_id; + struct attribute_group attr_group; + struct kobj_attribute display_name; + struct kobj_attribute current_value; }; =20 static const struct ayaneo_ec_quirk ayaneo3 =3D { .has_fan_control =3D true, .has_charge_control =3D true, + .has_magic_modules =3D true, + .has_controller_power =3D true, }; =20 static const struct dmi_system_id dmi_table[] =3D { @@ -260,6 +304,159 @@ static int ayaneo_remove_battery(struct power_supply = *battery, return 0; } =20 +static void ayaneo_kset_unregister(void *data) +{ + struct kset *kset =3D data; + + kset_unregister(kset); +} + +static void ayaneo_fw_attrs_dev_unregister(void *data) +{ + struct device *fw_attrs_dev =3D data; + + device_unregister(fw_attrs_dev); +} + +static ssize_t display_name_language_code_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", AYANEO_ATTR_LANGUAGE_CODE); +} + +static struct kobj_attribute fw_attr_display_name_language_code =3D + __ATTR_RO(display_name_language_code); + +static ssize_t display_name_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct ayaneo_fw_attr *fw_attr =3D + container_of(attr, struct ayaneo_fw_attr, display_name); + + return sysfs_emit(buf, "%s\n", ayaneo_fw_attr_desc[fw_attr->fw_attr_id]); +} + +static ssize_t current_value_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct ayaneo_fw_attr *fw_attr =3D + container_of(attr, struct ayaneo_fw_attr, current_value); + bool left, right; + char *out; + int ret; + u8 tmp; + + switch (fw_attr->fw_attr_id) { + case AYANEO_ATTR_CONTROLLER_MODULES: + ret =3D ec_read(AYANEO_MODULE_REG, &tmp); + if (ret) + return ret; + left =3D !(tmp & AYANEO_MODULE_LEFT); + right =3D !(tmp & AYANEO_MODULE_RIGHT); + + if (left && right) + out =3D "both"; + else if (left) + out =3D "left"; + else if (right) + out =3D "right"; + else + out =3D "none"; + + return sysfs_emit(buf, "%s\n", out); + case AYANEO_ATTR_CONTROLLER_POWER: + ret =3D ec_read(AYANEO_POWER_REG, &tmp); + if (ret) + return ret; + + if (tmp =3D=3D AYANEO_POWER_OFF) + out =3D "off"; + else + out =3D "on"; + + return sysfs_emit(buf, "%s\n", out); + } + return -EINVAL; +} + +static ssize_t current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + struct ayaneo_fw_attr *fw_attr =3D + container_of(attr, struct ayaneo_fw_attr, current_value); + int ret; + + switch (fw_attr->fw_attr_id) { + case AYANEO_ATTR_CONTROLLER_POWER: + if (sysfs_streq(buf, "on")) + ret =3D ec_write(AYANEO_POWER_REG, AYANEO_POWER_ON); + else if (sysfs_streq(buf, "off")) + ret =3D ec_write(AYANEO_POWER_REG, AYANEO_POWER_OFF); + if (ret) + return ret; + return count; + case AYANEO_ATTR_CONTROLLER_MODULES: + return -EINVAL; + } + return -EINVAL; +} + +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "string\n"); +} + +static struct kobj_attribute fw_attr_type_string =3D { + .attr =3D { .name =3D "type", .mode =3D 0444 }, + .show =3D type_show, +}; + +static int ayaneo_fw_attr_init(struct ayaneo_ec_platform_data *data, + const enum ayaneo_fw_attr_id fw_attr_id, + bool read_only) +{ + struct ayaneo_fw_attr *fw_attr; + struct attribute **attrs; + int idx =3D 0; + + fw_attr =3D devm_kzalloc(&data->pdev->dev, sizeof(*fw_attr), GFP_KERNEL); + if (!fw_attr) + return -ENOMEM; + + attrs =3D devm_kcalloc(&data->pdev->dev, AYANEO_ATTR_ENUM_MAX_ATTRS + 1, + sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + fw_attr->data =3D data; + fw_attr->fw_attr_id =3D fw_attr_id; + fw_attr->attr_group.name =3D ayaneo_fw_attr_name[fw_attr_id]; + fw_attr->attr_group.attrs =3D attrs; + + attrs[idx++] =3D &fw_attr_type_string.attr; + attrs[idx++] =3D &fw_attr_display_name_language_code.attr; + + sysfs_attr_init(&fw_attr->display_name.attr); + fw_attr->display_name.attr.name =3D "display_name"; + fw_attr->display_name.attr.mode =3D 0444; + fw_attr->display_name.show =3D display_name_show; + attrs[idx++] =3D &fw_attr->display_name.attr; + + sysfs_attr_init(&fw_attr->current_value.attr); + fw_attr->current_value.attr.name =3D "current_value"; + fw_attr->current_value.attr.mode =3D read_only ? 0444 : 0644; + fw_attr->current_value.show =3D current_value_show; + fw_attr->current_value.store =3D current_value_store; + attrs[idx++] =3D &fw_attr->current_value.attr; + + attrs[idx] =3D NULL; + return sysfs_create_group(&data->fw_attrs_kset->kobj, + &fw_attr->attr_group); +} + static int ayaneo_ec_probe(struct platform_device *pdev) { const struct dmi_system_id *dmi_entry; @@ -295,12 +492,48 @@ static int ayaneo_ec_probe(struct platform_device *pd= ev) return ret; } =20 + if (data->quirks->has_magic_modules || data->quirks->has_controller_power= ) { + data->fw_attrs_dev =3D device_create(&firmware_attributes_class, NULL, + MKDEV(0, 0), NULL, "%s", + DRIVER_NAME); + if (IS_ERR(data->fw_attrs_dev)) + return PTR_ERR(data->fw_attrs_dev); + + ret =3D devm_add_action_or_reset(&data->pdev->dev, + ayaneo_fw_attrs_dev_unregister, + data->fw_attrs_dev); + if (ret) + return ret; + + data->fw_attrs_kset =3D kset_create_and_add("attributes", NULL, + &data->fw_attrs_dev->kobj); + if (!data->fw_attrs_kset) + return -ENOMEM; + + ret =3D devm_add_action_or_reset(&data->pdev->dev, ayaneo_kset_unregiste= r, + data->fw_attrs_kset); + + if (data->quirks->has_magic_modules) { + ret =3D ayaneo_fw_attr_init( + data, AYANEO_ATTR_CONTROLLER_MODULES, true); + if (ret) + return ret; + } + + if (data->quirks->has_controller_power) { + ret =3D ayaneo_fw_attr_init( + data, AYANEO_ATTR_CONTROLLER_POWER, false); + if (ret) + return ret; + } + } + return 0; } =20 static struct platform_driver ayaneo_platform_driver =3D { .driver =3D { - .name =3D "ayaneo-ec", + .name =3D DRIVER_NAME, }, .probe =3D ayaneo_ec_probe, }; --=20 2.50.1 From nobody Sat Oct 4 03:17:21 2025 Received: from relay11.grserver.gr (relay11.grserver.gr [78.46.171.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC917322552; Wed, 20 Aug 2025 16:06:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.46.171.57 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706005; cv=none; b=jEh4eT4UW6GVfN+3YZtBHJ0v+PdCD3WeTRY+FZOMm4ATIP8Je/eaOM2ii0HQpeU1uk5l6pn+QW3Nd9IUFO0K3z2Vcb3et2N+iMqKYRgeOGJSVW/PqmDCL0K0w5AhIeIh+ZbC/n3BEssKiujVI9Y8h5lgIAbSM7KG9f+x2PMHe6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755706005; c=relaxed/simple; bh=OyjLUoxtggp5d0+RZpYLfQvewHpf4cKCUFH27ITNgXU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=asIyOL2AUk1hJ/RB88g15cSoSAe3Hz0gMBii+MjsD/LMF58MOwTf04/D0bqqAUyVtxlqPKR6ZwaxLlcJsBUw5jnNHZzwJJ1GO3oePH3byG/AafrrnWZQyPUwoXuiOE+/NWcYrsGQuzkp5ZmsxKkBV57HvrHF17qNEJgXP5MMdHs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev; spf=pass smtp.mailfrom=antheas.dev; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b=llRstwbm; arc=none smtp.client-ip=78.46.171.57 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=antheas.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=antheas.dev Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=antheas.dev header.i=@antheas.dev header.b="llRstwbm" Received: from relay11 (localhost.localdomain [127.0.0.1]) by relay11.grserver.gr (Proxmox) with ESMTP id DB58BC5C8C; Wed, 20 Aug 2025 19:06:35 +0300 (EEST) Received: from linux3247.grserver.gr (linux3247.grserver.gr [213.158.90.240]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by relay11.grserver.gr (Proxmox) with ESMTPS id 21AF9C5C88; Wed, 20 Aug 2025 19:06:35 +0300 (EEST) Received: from antheas-z13 (unknown [IPv6:2a05:f6c2:511b:0:7200:c86a:8976:4786]) by linux3247.grserver.gr (Postfix) with ESMTPSA id 53EDA205624; Wed, 20 Aug 2025 19:06:34 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=antheas.dev; s=default; t=1755705994; bh=aDYXMKRx6Z5R2mtYbT8/3FxTRnPKyI8a7RykQdzlWVQ=; h=From:To:Subject; b=llRstwbmO0UkCV3zSsUGx+ZjPn/TRdd+IZcrbpKDDqim9sTMRqnZrtADkp3Rn1Fg7 2w5OyEsMozm5G1O61Zwyj9EL7/NZJwjVcr3LupWIdFTVPyjGWBjg6HkyhqwV90ikMi gAOl6VEmw3Hscj71TSnEwUuPvkY3/c1R3woyxUgv7j9BEOVJY2wdHWKG8tuXK8p9iW AC4jRmuGQrmObguie5YHj+zushLNwCTNcLm6n9lXbAQ7Dnz8uQND/u+wKquvn+/cU1 Z6tHhFhPjg4gE4CXxK6mxkhG5c8C97hExEsWxP66xLIaSpKd2aOOXPg6EvvOFbH+EZ HlPhUV93YMZUQ== Authentication-Results: linux3247.grserver.gr; spf=pass (sender IP is 2a05:f6c2:511b:0:7200:c86a:8976:4786) smtp.mailfrom=lkml@antheas.dev smtp.helo=antheas-z13 Received-SPF: pass (linux3247.grserver.gr: connection is authenticated) From: Antheas Kapenekakis To: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Derek John Clark , =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= , Jean Delvare , Guenter Roeck , Antheas Kapenekakis Subject: [PATCH v1 5/5] platform/x86: ayaneo-ec: Move Ayaneo devices from oxpec to ayaneo-ec Date: Wed, 20 Aug 2025 18:06:28 +0200 Message-ID: <20250820160628.99678-6-lkml@antheas.dev> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250820160628.99678-1-lkml@antheas.dev> References: <20250820160628.99678-1-lkml@antheas.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-PPP-Message-ID: <175570599483.2162826.3848553097643706063@linux3247.grserver.gr> X-PPP-Vhost: antheas.dev X-Virus-Scanned: clamav-milter 1.4.3 at linux3247.grserver.gr X-Virus-Status: Clean Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Antheas Kapenekakis Tested-by: Derek J. Clark --- drivers/platform/x86/Kconfig | 4 +- drivers/platform/x86/ayaneo-ec.c | 66 ++++++++++++++++++ drivers/platform/x86/oxpec.c | 115 +------------------------------ 3 files changed, 68 insertions(+), 117 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c871a722e5ef..06b53b0a3818 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1031,9 +1031,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. =20 source "drivers/platform/x86/tuxedo/Kconfig" =20 diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo= -ec.c index eb7f9ae03b4f..d70fd0bd620e 100644 --- a/drivers/platform/x86/ayaneo-ec.c +++ b/drivers/platform/x86/ayaneo-ec.c @@ -83,6 +83,15 @@ struct ayaneo_fw_attr { struct kobj_attribute current_value; }; =20 +static const struct ayaneo_ec_quirk quirk_fan =3D { + .has_fan_control =3D true, +}; + +static const struct ayaneo_ec_quirk quirk_charge_limit =3D { + .has_fan_control =3D true, + .has_charge_control =3D true, +}; + static const struct ayaneo_ec_quirk ayaneo3 =3D { .has_fan_control =3D true, .has_charge_control =3D true, @@ -91,6 +100,63 @@ static const struct ayaneo_ec_quirk ayaneo3 =3D { }; =20 static const struct dmi_system_id dmi_table[] =3D { + + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), + }, + .driver_data =3D (void *)&quirk_fan, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "FLIP"), + }, + .driver_data =3D (void *)&quirk_fan, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "GEEK"), + }, + .driver_data =3D (void *)&quirk_fan, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), + }, + .driver_data =3D (void *)&quirk_charge_limit, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), + }, + .driver_data =3D (void *)&quirk_charge_limit, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), + }, + .driver_data =3D (void *)&quirk_charge_limit, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), + }, + .driver_data =3D (void *)&quirk_charge_limit, + }, + { + .matches =3D { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), + }, + .driver_data =3D (void *)&quirk_charge_limit, + }, { .matches =3D { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c index eb076bb4099b..2074650f5ba0 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) =20 enum oxp_board { aok_zoe_a1 =3D 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, @@ -124,62 +114,6 @@ static const struct dmi_system_id dmi_table[] =3D { }, .driver_data =3D (void *)aok_zoe_a1, }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), - }, - .driver_data =3D (void *)aya_neo_2, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), - }, - .driver_data =3D (void *)aya_neo_air, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), - }, - .driver_data =3D (void *)aya_neo_air_1s, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), - }, - .driver_data =3D (void *)aya_neo_air_plus_mendo, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), - }, - .driver_data =3D (void *)aya_neo_air_pro, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "FLIP"), - }, - .driver_data =3D (void *)aya_neo_flip, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "GEEK"), - }, - .driver_data =3D (void *)aya_neo_geek, - }, - { - .matches =3D { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), - }, - .driver_data =3D (void *)aya_neo_kun, - }, { .matches =3D { DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"), @@ -658,13 +592,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: @@ -685,14 +612,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: @@ -713,14 +632,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: @@ -760,14 +671,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: @@ -796,14 +699,6 @@ static int oxp_pwm_input_write(long val) /* scale to range [0-184] */ val =3D (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] */ @@ -840,14 +735,6 @@ static int oxp_pwm_input_read(long *val) /* scale from range [0-184] */ *val =3D (*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 =3D read_from_ec(OXP_SENSOR_PWM_REG, 1, val); --=20 2.50.1