From nobody Mon Oct 6 01:22:03 2025 Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93FFA143C61; Sat, 26 Jul 2025 20:40:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562450; cv=none; b=MHe/SiD6OSjUO2mondxZ1tLDxuBQ27fz33bJAbNSnJdPZ145XFwWF4UpWfHBAKLuhWvwZaA9I/cPxHavw3Y6dBPGVg0ZJY07rsiBYefwmGBmSgE5YBOlJbHYI17Ofsrd0yb8DOfUPahJkEWoFDuZsUdpnYPsQy8tloUcgh1Bpiw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562450; c=relaxed/simple; bh=9Eh5QdAtvnqZUlhE05dzTKKetcxsbQ3nPP2XCMkR95k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=am58mzL6ItBseZO2YA2kVUVMrxS8tf7us1lY/9CqmCM43iQQz5psomvAoFvDsAH0sKeu4efLSasUhuKsdcFCDrxretPy1lh/ofIncUMvPxInfJmbWYvbID6Hcpc3xweadG+21Rwf2dXvNctSnyj8tU+LWjymi/bPavW2lSobbX4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=UBBKEwpS; arc=none smtp.client-ip=209.85.216.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UBBKEwpS" Received: by mail-pj1-f41.google.com with SMTP id 98e67ed59e1d1-313a001d781so2642214a91.3; Sat, 26 Jul 2025 13:40:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753562448; x=1754167248; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NrIos3NPKROFxL6UszOMSCtv0bYW2mmxDnOrDUHYwT0=; b=UBBKEwpSpp8bGi4Syb7S5bMk4FZsQwgYGhCcQA1B0t74u8uYfeMqUb0WAYivnOX74d qpys6GZWIiEz0QLwzsHJXvVXr8sS36HbSLlbOHPpNJxYwKH+7RaaFEnuS7vQHdkMEdYn KJjCk0ZpLh2w7Z5xFZkKf8zYE9Iex9wqRcgt7D6/qytkDAVO36p7RjlOHZAWIeFqTep7 gRStlkP5VQbaqqn6jyrF/GxPL9LBs/iObwcFvxIjXmjJfnmvcl5IL+EGyCLX7y1Mx9Jy zrTPCyvcetz4KosEQk4fbZcGG1whpPPT7b0Ytqnh6Dw5f4f0TSMFe9XwLYh/51ut9Yoo ZNKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753562448; x=1754167248; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NrIos3NPKROFxL6UszOMSCtv0bYW2mmxDnOrDUHYwT0=; b=stpJC9doQmQmiHK4LalJqNL3rcSGMbXsnfHOkcpfEOsIglO4s+qGKJLfi0dK2zjCbc /LBmJd/sIsmmGimNj3HuyvscdkH0HX+k+J4iF/nGUIz02fUiafw6XYq5kGMVeQ4QSh3B FVzp5TZh3O3HdbgAJFNSsYetLwI8C8qzo4WbCNQxaLJm0589K3eSP29j5neQvSFx6+VV 45OaAv0c0Blultq8GJbmHeN8GIos5kRNbYAbBVT0PDmipQnCcWuMGGDcDKVR1ikvuMUE ULx8Npy8TfMro3EJSsQ7hoP+DSkM7WfBCh1vcT5fkubJiqZBiauoOS2BFVwAR0nPfdkm Kkgw== X-Forwarded-Encrypted: i=1; AJvYcCUdT14LDvHxa9hOh9RovdWLfIgfp0ZzGeHPRzMdNs/Au+mwahYuuS42jrIRksPXoYP9CeBCBVBgEMqe23Un@vger.kernel.org, AJvYcCVV3JK0/cSdxTKslS1B/TaL3qq6AUBTBllnC/d69mOCvj8zLdCMx/HJMXOJN+/lA9crnupNS6MfQnqNfx4=@vger.kernel.org, AJvYcCWfwMYirhqKMOuJj6SprnG0MgwijaDk7VAcKrS/s4NykoBjtNw2Vp9cNo8C5e0OrAvzO1PWikVmSgDDoPf9sx3nz3u6eQ==@vger.kernel.org, AJvYcCX9VPhnjik4DEcKpoq0I4oJ/wpiF/oOAWWZO890wuBDeYcabMQgWRdcqn79ng5htNgXitvNdeP47pY=@vger.kernel.org X-Gm-Message-State: AOJu0Yyly3eZU1+9hJQV+YAEc4t2bjftiJ2GXe56VzuCWSer3cZSuhQ8 JDd1VYxpRWj2r+IQdXIGJycvziRGdCX8dX2Whc30sx+y7KFdxgkwaxR3 X-Gm-Gg: ASbGncuaw3Js8QtryKp8DaiuBPnOIGLk655dQXCpknJzIsBDPnUx6dXTINF9pTMZeZ7 dPz7i+iDJiO+P0JhYSARyQ5TCTbadHyWi3x8VTSMYNlc3R1Wm4Ka1yo+VjwCBjy0AvtSKJ0iOCj PWTAYhMjnvTCvBb9mtAA+j1AWiZQTmhE/tfuM4U1wEZ/NcJxtUOAkNBEBUzBeFIYn4LaaaaWxu+ 9h1eTHkeJz+xldc2DOjLawO8Wu6n2DXJ55+ZY+CB1zrW2z+pVPebe+Qwn4RigEkFRINQ5agZ4M8 2M0fXOB+GknIuFjZZykGOJwL5up64lunNgv6GoebBFHxGmrKlvCfkO4lMNrAADPku92mpxnVhTm Wdz/9tRT6rqO7cwkRHLnG9Df11qhN6XOIHaAPJQCn1h3VAhSogvCXdC494RmrkYGTLIm4x/FtGm VDjA== X-Google-Smtp-Source: AGHT+IHv/yGf81T0mC2BYV0ujNgkcf+Fu8nFGSvznjj6qldwZKdJjyQY0xQqtdp93z0gqxzHh5CYlQ== X-Received: by 2002:a17:90b:4a86:b0:31c:36f5:d95 with SMTP id 98e67ed59e1d1-31e777386cemr9676966a91.2.1753562447569; Sat, 26 Jul 2025 13:40:47 -0700 (PDT) Received: from bliptop (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31e8ea37b21sm1905640a91.22.2025.07.26.13.40.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 26 Jul 2025 13:40:47 -0700 (PDT) From: "Derek J. Clark" To: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Hans de Goede Cc: Jean Delvare , Guenter Roeck , Alok Tiwari , David Box , "Derek J . Clark" , platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v3 1/4] platform/x86: (ayn-ec) Add PWM Fan HWMON Interface Date: Sat, 26 Jul 2025 13:40:38 -0700 Message-ID: <20250726204041.516440-2-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250726204041.516440-1-derekjohn.clark@gmail.com> References: <20250726204041.516440-1-derekjohn.clark@gmail.com> 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 Content-Type: text/plain; charset="utf-8" Adds platform driver for AYN Loki and Tectoy Zeenix lines of handheld devices. This patch implements a hwmon interface for EC provided manual PWM fan control and user defined fan curves. A global ACPI lock is used when reading or writing from the EC. There are 4 fan modes implemented in this patch. Modes 0-3 act in accordance with the standard hwmon logic where 0 is 100% fan speed, 1 is manual control, and 2 is automatic control. As the EC only provides 3 modes by default, mode 0 is implemented by setting the device to manual and then setting fan speed to 100% directly. In mode 1 the PWM duty cycle is set in sysfs with values [0-255], which are then scaled to the EC max of 128. Mode 4 is an automatic mode where the fan curve is user defined. There are 5 total set points and each set point takes a temperature in Celsius [0-100] and a PWM duty cycle [0-255]. When the CPU temperature reaches a given set point, the corresponding duty cycle is automatically set by the EC. Signed-off-by: Derek J. Clark space --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 12 + drivers/platform/x86/Makefile | 3 + drivers/platform/x86/ayn-ec.c | 520 ++++++++++++++++++++++++++++++++++ 4 files changed, 541 insertions(+) create mode 100644 drivers/platform/x86/ayn-ec.c diff --git a/MAINTAINERS b/MAINTAINERS index d61b004005fd..5b816883fe7d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4035,6 +4035,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 +AYN PLATFORM EC DRIVER +M: Derek J. Clark +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/ayn-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..4819bfcffb6b 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -304,6 +304,18 @@ 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 AYN_EC + tristate "AYN x86 devices EC platform control" + depends on ACPI + depends on HWMON + help + This is a driver for AYN and Tectoy x86 handheld devices. It provides + temperature monitoring, manual fan speed control, fan curve control, + and chassis RGB settings. + + If you have an x86 AYN or Tectoy handheld device say M here. The module + will be called ayn-platform. + 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..d32504b89365 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 +# Ayn +obj-$(CONFIG_AYN_EC) +=3D ayn-ec.o + # Cisco/Meraki obj-$(CONFIG_MERAKI_MX100) +=3D meraki-mx100.o =20 diff --git a/drivers/platform/x86/ayn-ec.c b/drivers/platform/x86/ayn-ec.c new file mode 100644 index 000000000000..8bd3ed1c69eb --- /dev/null +++ b/drivers/platform/x86/ayn-ec.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Platform driver for AYN x86 Handhelds. + * + * Implements multiple attributes provided by the EC. Fan reading and cont= rol, + * as well as temperature sensor readings are exposed via hwmon sysfs. EC = RGB + * control is exposed via an led-class-multicolor interface. + * + * Fan control is provided via a pwm interface in the range [0-255]. AYN u= se + * [0-128] as the range in the EC, the written value is scaled to accommod= ate. + * The EC also provides a configurable fan curve with five set points that + * associate a temperature in Celcius [0-100] with a fan speed [0-128]. The + * auto_point fan speeds are also scaled from the range [0-255]. Temperatu= re + * readings are scaled from degrees to millidegrees when read. + * + * RGB control is provided using 4 registers. One each for the colors red, + * green, and blue are [0-255]. There is also a effect register that takes + * switches between an EC controlled breathing that cycles through all col= ors + * and fades in/out, and manual, which enables setting a user defined colo= r. + * + * Copyright (C) 2025 Derek J. Clark + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Fan speed and PWM registers */ +#define AYN_SENSOR_PWM_FAN_ENABLE_REG 0x10 /* PWM operating mode */ +#define AYN_SENSOR_PWM_FAN_SET_REG 0x11 /* PWM duty cycle */ +#define AYN_SENSOR_PWM_FAN_SPEED_REG 0x20 /* Fan speed */ + +/* EC controlled fan curve registers */ +#define AYN_SENSOR_PWM_FAN_SPEED_1_REG 0x12 +#define AYN_SENSOR_PWM_FAN_SPEED_2_REG 0x14 +#define AYN_SENSOR_PWM_FAN_SPEED_3_REG 0x16 +#define AYN_SENSOR_PWM_FAN_SPEED_4_REG 0x18 +#define AYN_SENSOR_PWM_FAN_SPEED_5_REG 0x1A +#define AYN_SENSOR_PWM_FAN_TEMP_1_REG 0x13 +#define AYN_SENSOR_PWM_FAN_TEMP_2_REG 0x15 +#define AYN_SENSOR_PWM_FAN_TEMP_3_REG 0x17 +#define AYN_SENSOR_PWM_FAN_TEMP_4_REG 0x19 +#define AYN_SENSOR_PWM_FAN_TEMP_5_REG 0x1B + +/* AYN EC PWM Fan modes */ +#define AYN_PWM_FAN_MODE_MANUAL 0x00 +#define AYN_PWM_FAN_MODE_AUTO 0x01 +#define AYN_PWM_FAN_MODE_EC_CURVE 0x02 + +/* hwmon fan modes */ +#define HWMON_PWM_FAN_MODE_FULL 0x00 +#define HWMON_PWM_FAN_MODE_MANUAL 0x01 +#define HWMON_PWM_FAN_MODE_AUTO 0x02 +#define HWMON_PWM_FAN_MODE_EC_CURVE 0x03 + +/* Handle ACPI lock mechanism */ +#define ACPI_LOCK_DELAY_MS 500 + +int ayn_pwm_curve_registers[10] =3D { + AYN_SENSOR_PWM_FAN_SPEED_1_REG, + AYN_SENSOR_PWM_FAN_SPEED_2_REG, + AYN_SENSOR_PWM_FAN_SPEED_3_REG, + AYN_SENSOR_PWM_FAN_SPEED_4_REG, + AYN_SENSOR_PWM_FAN_SPEED_5_REG, + AYN_SENSOR_PWM_FAN_TEMP_1_REG, + AYN_SENSOR_PWM_FAN_TEMP_2_REG, + AYN_SENSOR_PWM_FAN_TEMP_3_REG, + AYN_SENSOR_PWM_FAN_TEMP_4_REG, + AYN_SENSOR_PWM_FAN_TEMP_5_REG, +}; + +struct ayn_device { + u32 ayn_lock; /* ACPI EC Lock */ +} drvdata; + +/* Handle ACPI lock mechanism */ +#define ACPI_LOCK_DELAY_MS 500 + +static bool lock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, + &drvdata.ayn_lock)); +} + +static bool unlock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_release_global_lock(drvdata.ayn_lock)); +} + +/** + * read_from_ec() - Reads a value from the embedded controller. + * + * @reg: The register to start the read from. + * @size: The number of sequential registers the data is contained in. + * @val: Pointer to return the data with. + * + * Return: 0, or an error. + */ +static int read_from_ec(u8 reg, int size, long *val) +{ + int ret, i; + u8 buf; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + *val =3D 0; + for (i =3D 0; i < size; i++) { + ret =3D ec_read(reg + i, &buf); + if (ret) + return ret; + *val <<=3D i * 8; + *val +=3D buf; + } + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return 0; +} + +/** + * write_to_ec() - Writes a value to the embedded controller. + * + * @reg: The register to write to. + * @val: Value to write + * + * Return: 0, or an error. + */ +static int write_to_ec(u8 reg, u8 val) +{ + int ret; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + pr_info("Writing EC value %d to register %u\n", val, reg); + ret =3D ec_write(reg, val); + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return ret; +} + +/** + * ayn_pwm_manual() - Enable manual control of the fan. + */ +static int ayn_pwm_manual(void) +{ + return write_to_ec(AYN_SENSOR_PWM_FAN_ENABLE_REG, 0x00); +} + +/** + * ayn_pwm_full() - Set fan to 100% speed. + */ +static int ayn_pwm_full(void) +{ + int ret; + + ret =3D write_to_ec(AYN_SENSOR_PWM_FAN_ENABLE_REG, 0x00); + if (ret) + return ret; + + return write_to_ec(AYN_SENSOR_PWM_FAN_SET_REG, 128); +} + +/** + * ayn_pwm_auto() - Enable automatic EC control of the fan. + */ +static int ayn_pwm_auto(void) +{ + return write_to_ec(AYN_SENSOR_PWM_FAN_ENABLE_REG, 0x01); +} + +/** + * ayn_pwm_ec_curve() - Enable manually setting the fan curve for automatic + * EC control of the fan. + */ +static int ayn_pwm_ec_curve(void) +{ + return write_to_ec(AYN_SENSOR_PWM_FAN_ENABLE_REG, 0x02); +} + +/** + * ayn_ec_hwmon_is_visible() - Determines RO or RW for hwmon attribute sys= fs. + * + * @drvdata: Unused void pointer to context data. + * @type: The hwmon_sensor_types type. + * @attr: The attribute to set RO/RW on. + * @channel: HWMON subsystem usage flags for the attribute. + * + * Return: Permission level. + */ +static umode_t ayn_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; + } +} + +/** + * ayn_pwm_fan_read() - Read from a hwmon pwm or fan attribute. + * + * @dev: parent device of the given attribute. + * @type: The hwmon_sensor_types type. + * @attr: The attribute to read from. + * @channel: HWMON subsystem usage flags for the attribute. + * @val: Pointer to return the read value from. + * + * Return: 0, or an error. + */ +static int ayn_pwm_fan_read(struct device *dev, enum hwmon_sensor_types ty= pe, + u32 attr, int channel, long *val) +{ + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + return read_from_ec(AYN_SENSOR_PWM_FAN_SPEED_REG, 2, + val); + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + ret =3D read_from_ec(AYN_SENSOR_PWM_FAN_ENABLE_REG, 1, + val); + if (ret) + return ret; + + /* EC uses 0 for manual, 1 for automatic, 2 for user + * fan curve. Reflect hwmon usage instead. + */ + if (*val =3D=3D 1) { + *val =3D 2; + return 0; + } + + if (*val =3D=3D 2) { + *val =3D 3; + return 0; + } + + /* Return 0 when fan at max, otherwise 1 for manual. */ + ret =3D read_from_ec(AYN_SENSOR_PWM_FAN_SET_REG, 1, val); + if (ret) + return ret; + + if (*val =3D=3D 128) + *val =3D 0; + else + *val =3D 1; + + return ret; + case hwmon_pwm_input: + ret =3D read_from_ec(AYN_SENSOR_PWM_FAN_SET_REG, 1, val); + if (ret) + return ret; + + *val =3D *val << 1; /* Max value is 128, scale to 255 */ + + return 0; + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +/** + * ayn_pwm_fan_write() - Write to a hwmon pwm attribute. + * + * @dev: parent device of the given attribute. + * @type: The hwmon_sensor_types type. + * @attr: The attribute to write to. + * @channel: HWMON subsystem usage flags for the attribute. + * @val: Value to write. + * + * Return: 0, or an error. + */ +static int ayn_pwm_fan_write(struct device *dev, enum hwmon_sensor_types t= ype, + u32 attr, int channel, long val) +{ + if (type !=3D hwmon_pwm) + return -EOPNOTSUPP; + switch (attr) { + case hwmon_pwm_enable: + switch (val) { + case HWMON_PWM_FAN_MODE_FULL: + return ayn_pwm_full(); + case HWMON_PWM_FAN_MODE_MANUAL: + return ayn_pwm_manual(); + case HWMON_PWM_FAN_MODE_AUTO: + return ayn_pwm_auto(); + case HWMON_PWM_FAN_MODE_EC_CURVE: + return ayn_pwm_ec_curve(); + default: + return -EINVAL; + } + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + + val =3D val >> 1; /* Max value is 128, scale from 255 */ + + return write_to_ec(AYN_SENSOR_PWM_FAN_SET_REG, val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *ayn_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_ops ayn_ec_hwmon_ops =3D { + .is_visible =3D ayn_ec_hwmon_is_visible, + .read =3D ayn_pwm_fan_read, + .write =3D ayn_pwm_fan_write, +}; + +static const struct hwmon_chip_info ayn_ec_chip_info =3D { + .ops =3D &ayn_ec_hwmon_ops, + .info =3D ayn_ec_sensors, +}; + +/** + * pwm_curve_store() - Write a fan curve speed or temperature value. + * + * @dev: The attribute's parent device. + * @attr: The attribute to read. + * @buf: Input value string from sysfs write. + * + * Return: Number of bytes read, or an error. + */ +static ssize_t pwm_curve_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int i =3D to_sensor_dev_attr(attr)->index; + int ret, val; + u8 reg; + + ret =3D kstrtoint(buf, 0, &val); + if (ret) + return ret; + + if (i < 5) { + if (val < 0 || val > 255) + return -EINVAL; + val =3D val >> 1; /* Max EC value is 128, scale from 255 */ + } else + if (val < 0 || val > 100) + return -EINVAL; + + reg =3D ayn_pwm_curve_registers[i]; + + ret =3D write_to_ec(reg, val); + if (ret) + return ret; + + return count; +} + +/** + * pwm_curve_show() - Read a fan curve speed or temperature value. + * + * @dev: The attribute's parent device. + * @attr: The attribute to read. + * @buf: Output buffer. + * + * Return: Number of bytes read, or an error. + */ +static ssize_t pwm_curve_show(struct device *dev, struct device_attribute = *attr, + char *buf) +{ + int i =3D to_sensor_dev_attr(attr)->index; + long val; + int ret; + u8 reg; + + reg =3D ayn_pwm_curve_registers[i]; + + ret =3D read_from_ec(reg, 1, &val); + if (ret) + return ret; + + if (i < 5) + val =3D val << 1; /* Max EC value is 128, scale to 255 */ + + return sysfs_emit(buf, "%ld\n", val); +} + +/* Fan curve attributes */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_pwm, pwm_curve, 0); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_pwm, pwm_curve, 1); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_pwm, pwm_curve, 2); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_pwm, pwm_curve, 3); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point5_pwm, pwm_curve, 4); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, pwm_curve, 5); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, pwm_curve, 6); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, pwm_curve, 7); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, pwm_curve, 8); +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point5_temp, pwm_curve, 9); + +static struct attribute *ayn_sensors_attrs[] =3D { + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(ayn_sensors); + +static int ayn_ec_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct device *hwdev; + + hwdev =3D devm_hwmon_device_register_with_info(dev, "aynec", NULL, + &ayn_ec_chip_info, + ayn_sensors_groups); + return PTR_ERR_OR_ZERO(hwdev); +} + +static struct platform_driver ayn_ec_driver =3D { + .driver =3D { + .name =3D "ayn-ec", + }, + .probe =3D ayn_ec_probe, +}; + +static struct platform_device *ayn_ec_device; + +static int __init ayn_ec_init(void) +{ + ayn_ec_device =3D platform_create_bundle(&ayn_ec_driver, ayn_ec_probe, + NULL, 0, NULL, 0); + + return PTR_ERR_OR_ZERO(ayn_ec_device); +} + +static void __exit ayn_ec_exit(void) +{ + platform_device_unregister(ayn_ec_device); + platform_driver_unregister(&ayn_ec_driver); +} + +static const struct dmi_system_id ayn_dmi_table[] =3D { + { + .ident =3D "AYN Loki Max", + .matches =3D { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ayn"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Loki Max"), + }, + }, + { + .ident =3D "AYN Loki MiniPro", + .matches =3D { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ayn"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Loki MiniPro"), + }, + }, + { + .ident =3D "AYN Loki Zero", + .matches =3D { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ayn"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Loki Zero"), + }, + }, + { + .ident =3D "Tectoy Zeenix Lite", + .matches =3D { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Tectoy"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Zeenix Lite"), + }, + }, + {}, +}; + +MODULE_DEVICE_TABLE(dmi, ayn_dmi_table); + +module_init(ayn_ec_init); +module_exit(ayn_ec_exit); + +MODULE_AUTHOR("Derek J. Clark "); +MODULE_DESCRIPTION("Platform driver that handles EC sensors of AYN x86 dev= ices"); +MODULE_LICENSE("GPL"); --=20 2.50.1 From nobody Mon Oct 6 01:22:03 2025 Received: from mail-pg1-f173.google.com (mail-pg1-f173.google.com [209.85.215.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 92B55288C16; Sat, 26 Jul 2025 20:40:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562451; cv=none; b=F23xzxTkJ/oM8wrG0a0LttNB+73x5YqW2IUlDmY2e2JmMZXFKfUfMCiy4j7sttj61ygU+yE8pbD9I+s2F2PaqhI8UPeGyS+vLhwdkqXWqhD7gdbn3jNXtqH+wvuGZmU7B4f+6q97TcqfKHTGrJCoElRXtFw5wOOHfzQ7PTycHNI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562451; c=relaxed/simple; bh=q8U3HbUWL3lV1u/BA5zoaez+fI3BJu2E54mbekDDKWI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NCAdjbi31g2ujhuVKvMiJWipbK8vtgZmxqIyGyZ9b9JHs5GgakJHowk2XcMA7sNoymL+GJiYtFjfNrvXaPlg/4v/2L27WWkmygb8Tdj9R9BcjniywTXHI+xVafDdp9V4dT3Z9GYmBIWTj618vp6uA++U98A5FpMNB9a389Kvlnk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GWR4ruCi; arc=none smtp.client-ip=209.85.215.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GWR4ruCi" Received: by mail-pg1-f173.google.com with SMTP id 41be03b00d2f7-b34ab678931so2576056a12.0; Sat, 26 Jul 2025 13:40:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753562449; x=1754167249; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iDyPibcHfFu9Yy643YaFIkeebd0KcluKqtCVtZQhMfU=; b=GWR4ruCigpTHy6fp/ynSh4QaWGAcfQXq8sKBypcHiAxXD8jQ/04WzwMRhI+F9UZWkg Y65wcdvxjtC68koW4ccy11PMwOsLKY5GUx/i2Td81e2hjVcZjbKN6r5uNZbmimwF+X99 AJmzfXkjSc3KrPCF7IyUByDXEn70u62ToGdfVeT03EDGCrF9E12gU4HYNa9of+RJs0mD d0EUxTng/hMiMGX1R2yd9hXzOoGolKplGJvQGmI4wvnjgEvy84iSx3QijnWXg4SRV8Uj 8TJx0fMAX3kS9VvWCBFop4vvtOw0/ZesA5NFfPUL5kmW9n1+4tjJodzvxY9I/LOW22qv itzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753562449; x=1754167249; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iDyPibcHfFu9Yy643YaFIkeebd0KcluKqtCVtZQhMfU=; b=nMt/OHDFZFtLJHMOwS4jYo4q5Uh45zTeT5NU6PzrWpC4O0z7X3Y+fzIZwzxh4/ZZb0 ezOb//5ne7lyZzSvpD3k3FYiPq80yW6VreV8PGvfQ2i/MhMjKL18KyN3Jasg03ULOfr/ BQgpCr7XlsrnkXBnNVT1dG+gHTcd3WdSASgpy16QBcN0b257zzjkoWgqaZVKrR7asDgk 9wMV3DxNAiO3Ji4LZxQc1CvWDNk7EE6mRJQYV90Ceehd3TzS1Kj7gJvgMoRoVfVPshXf 0lS33L/+FIiVJz1apItoFtTMxBTx+frISCS5D84L8W8BncL885l224Js2KcREZ9gfRe2 LSMg== X-Forwarded-Encrypted: i=1; AJvYcCVE2dofMmJikkz0aH2nxiVPviBRp1HZpJh3q1oHiUzZMJicW5IOzdinzkMAuA2Z2nmZRddldh7BnNU2ue8=@vger.kernel.org, AJvYcCXCVbd68o8nxNyHumdVB6iSq/voDzTH2TO5/wy5RPF5fiRcrluyFwCxw9GiAVFPPrtqNJ8deSt0ufM=@vger.kernel.org, AJvYcCXFkIdajbuK7xS2yiQFcxeygSMlHQ2RN1qOdDOYYhmDBoQ6QfQ3Bsi6EpqL7FDkpQEA7/lKqVUEpGbT34AF@vger.kernel.org, AJvYcCXefWKxpP0lHpkFsfTuwXY5aaJv81OAJBDUqbrse1DqHFYDwe74FjSslNSGeoak3A8vLVaf+HUDOLFyF3liRW/YZXoigg==@vger.kernel.org X-Gm-Message-State: AOJu0YwR7kltXKKat16C2ug1xzLxWubYb4gdYGJpL8sYLYzTcRmd0qfy CmQ7xPFjDfhZ6wUN8FvoV9NrHfB/9jW7LWYoH6evEhw3Dd8EpHIUgoyw X-Gm-Gg: ASbGncuMGCidxcCqU2/fh5qAK2kdFTrboE6ZObRN+IUyjEqWlkUTWmBsoJKQs1XtQd1 yjO9GxpcXPZcqutN1TBZhuC7QF7LhlyFx5jDTwk5TxogpA9TdFkVFc4FgXUvcKh7Xhm48RUX3au CrynW0NWczJgI05DYMFoGBOQOflA2nw9TBQnnhuJMrU7pNWGlJC1qupmDUKUjl+uJFzVoF9rALj lVxoOIhcSYDURRtSwMA9wf2bquXFOYJnWVwu/PhqfusqxO95FoPeycbeN+3I967khe4G0ONVPl7 l5nAObwuJyLbpLD+LS1+t/5NFmRfOmOQ+BKreB8M5hzp0WX4MWIMeY59cytWCObRFQqRBu+32aF 0VOIXQHEg2vHOvPE5AoCbgsrI/QFVYjPVhqP1syWSB4NEr6DNIdtRCwiLUNQ0fak1UPAcaz7IXr TJ5g== X-Google-Smtp-Source: AGHT+IEWydEjwUJsF744vx6ATJdAEZUQUMYwl3JG/2ocZxm7LtUz7J4UCB1DnPHs1dEoF1/u/F1GCA== X-Received: by 2002:a17:90b:518d:b0:31c:72d7:558b with SMTP id 98e67ed59e1d1-31e77a24bccmr9467658a91.32.1753562448843; Sat, 26 Jul 2025 13:40:48 -0700 (PDT) Received: from bliptop (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31e8ea37b21sm1905640a91.22.2025.07.26.13.40.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 26 Jul 2025 13:40:48 -0700 (PDT) From: "Derek J. Clark" To: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Hans de Goede Cc: Jean Delvare , Guenter Roeck , Alok Tiwari , David Box , "Derek J . Clark" , platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v3 2/4] platform/x86: (ayn-ec) Add Temperature Sensors Date: Sat, 26 Jul 2025 13:40:39 -0700 Message-ID: <20250726204041.516440-3-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250726204041.516440-1-derekjohn.clark@gmail.com> References: <20250726204041.516440-1-derekjohn.clark@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Adds temperature sensors to the ayn-ec hwmon interface. These read-only values include Battery, Motherboard, Charger IC, vCore, and CPU Core, as well as labels for each entry. The temperature values provided by the EC are whole numbers in degrees Celsius. As hwmon expects millidegrees, we scale the raw value up. `sensors` output after this patch is applied: aynec-isa-0000 Adapter: ISA adapter fan1: 1876 RPM Battery: +29.0=C2=B0C Motherboard: +30.0=C2=B0C Charger IC: +30.0=C2=B0C vCore: +36.0=C2=B0C CPU Core: +48.0=C2=B0C Signed-off-by: Derek J. Clark --- drivers/platform/x86/ayn-ec.c | 88 ++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/ayn-ec.c b/drivers/platform/x86/ayn-ec.c index 8bd3ed1c69eb..466cc33adcb0 100644 --- a/drivers/platform/x86/ayn-ec.c +++ b/drivers/platform/x86/ayn-ec.c @@ -61,6 +61,14 @@ #define HWMON_PWM_FAN_MODE_AUTO 0x02 #define HWMON_PWM_FAN_MODE_EC_CURVE 0x03 =20 +/* EC Temperature Sensors */ +#define AYN_SENSOR_BAT_TEMP_REG 0x04 /* Battery */ +#define AYN_SENSOR_CHARGE_TEMP_REG 0x07 /* Charger IC */ +#define AYN_SENSOR_MB_TEMP_REG 0x05 /* Motherboard */ +#define AYN_SENSOR_PROC_TEMP_REG 0x09 /* CPU Core */ +#define AYN_SENSOR_VCORE_TEMP_REG 0x08 /* vCore */ + + /* Handle ACPI lock mechanism */ #define ACPI_LOCK_DELAY_MS 500 =20 @@ -81,8 +89,19 @@ struct ayn_device { u32 ayn_lock; /* ACPI EC Lock */ } drvdata; =20 -/* Handle ACPI lock mechanism */ -#define ACPI_LOCK_DELAY_MS 500 +struct thermal_sensor { + char *name; + int reg; +}; + +static struct thermal_sensor thermal_sensors[] =3D { + { "Battery", AYN_SENSOR_BAT_TEMP_REG }, + { "Motherboard", AYN_SENSOR_MB_TEMP_REG }, + { "Charger IC", AYN_SENSOR_CHARGE_TEMP_REG }, + { "vCore", AYN_SENSOR_VCORE_TEMP_REG }, + { "CPU Core", AYN_SENSOR_PROC_TEMP_REG }, + {} +}; =20 static bool lock_global_acpi_lock(void) { @@ -428,6 +447,61 @@ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, pw= m_curve, 7); static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, pwm_curve, 8); static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point5_temp, pwm_curve, 9); =20 +/** + * thermal_sensor_show() - Read a thermal sensor attribute value. + * + * @dev: The attribute's parent device. + * @attr: The attribute to read. + * @buf: Buffer to write the result into. + * + * Return: Number of bytes read, or an error. + */ +static ssize_t thermal_sensor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + long ret, val; + int i; + + i =3D to_sensor_dev_attr(attr)->index; + + ret =3D read_from_ec(thermal_sensors[i].reg, 1, &val); + if (ret) + return ret; + + val =3D val * 1000L; + + return sysfs_emit(buf, "%ld\n", val); +} + +/** + * thermal_sensor_label_show() - Read a thermal sensor attribute label. + * + * @dev: The attribute's parent device. + * @attr: The attribute to read. + * @buf: Buffer to read to. + * + * Return: Number of bytes read, or an error. + */ +static ssize_t thermal_sensor_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i =3D to_sensor_dev_attr(attr)->index; + + return sysfs_emit(buf, "%s\n", thermal_sensors[i].name); +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, thermal_sensor, 0); +static SENSOR_DEVICE_ATTR_RO(temp2_input, thermal_sensor, 1); +static SENSOR_DEVICE_ATTR_RO(temp3_input, thermal_sensor, 2); +static SENSOR_DEVICE_ATTR_RO(temp4_input, thermal_sensor, 3); +static SENSOR_DEVICE_ATTR_RO(temp5_input, thermal_sensor, 4); +static SENSOR_DEVICE_ATTR_RO(temp1_label, thermal_sensor_label, 0); +static SENSOR_DEVICE_ATTR_RO(temp2_label, thermal_sensor_label, 1); +static SENSOR_DEVICE_ATTR_RO(temp3_label, thermal_sensor_label, 2); +static SENSOR_DEVICE_ATTR_RO(temp4_label, thermal_sensor_label, 3); +static SENSOR_DEVICE_ATTR_RO(temp5_label, thermal_sensor_label, 4); + static struct attribute *ayn_sensors_attrs[] =3D { &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, @@ -439,6 +513,16 @@ static struct attribute *ayn_sensors_attrs[] =3D { &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_label.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_label.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp5_label.dev_attr.attr, NULL, }; =20 --=20 2.50.1 From nobody Mon Oct 6 01:22:03 2025 Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3EE2C289802; Sat, 26 Jul 2025 20:40:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562453; cv=none; b=fROXjoNP2v4+GpMTAIXgWvpJb2I2D6ZRMK0CHSrxg+czklDljwdEM5smcnqdbF8w4IMyf8PGhjIX1yFMj9ehciNx4J+L+8DuoR/xNj7IqgWhV5TbV2jBCwZ+fl8662IlZOSv3nomxAF8roHvw7zga0nyb3xY8O35KZA0OiRIWV4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562453; c=relaxed/simple; bh=v1Htla8DdqHofygRD1HT9Xzu+Qm42ioKnabPdsoKMa4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WtNfIUm8Js2b4nnesflSPmLTnc1Vy6/Jr3335jrSulv391kuNQnr3k7AlRdPLxiXooyHkQlkCP47LO0tkQce50rQySEZFP1wDrxRI7v8fltqxxANiiX4HaLttaLCRkvhhnJmu4VcHh03BEmxNV1rdk10iM9ZFXYJvKAPhA2uTBU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZKXAlfBm; arc=none smtp.client-ip=209.85.216.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZKXAlfBm" Received: by mail-pj1-f41.google.com with SMTP id 98e67ed59e1d1-313a188174fso3382423a91.1; Sat, 26 Jul 2025 13:40:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753562450; x=1754167250; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Z9B+o1C+e4Ggr+NPOFbsgYgyM0Nxp9h9VhXkWaGTcOo=; b=ZKXAlfBmkjVv67ChyfMpMocyS1XJWguwPFkJ3sKZP+rEgeKaASdUi4Rie3SilsUIIJ RhZzP3W0ezYyvaXWpTaKKL/I4encQcfk6LhoNTZ8VR7/Lsf5y+6C3TjLdCIeY9KsttPK D8vLPcoaZlCLVpQ6UIQMAD+eT6um16JAnK7oyLsyj+kFuUhA3yP4KMVugJ5B8gyUyWta DAxy1GHMLik2+L2TWhy0khbPF4U1PSqbQmerFJtKoETAJB8UZgo0XaVKG/66dxhfIZwF ZRW2qYSZHra5hoxjjlaZIPIocEjFhhT/VSICmvJ9FHIEuaY0KENPvZ8uv1TbkEpqoNQR MmSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753562450; x=1754167250; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Z9B+o1C+e4Ggr+NPOFbsgYgyM0Nxp9h9VhXkWaGTcOo=; b=VSVC3MeItJLTev9epRRRdOx+bBbgr7F/hrSxr4xk54f9tZ5xM5mMsXV8DQN1B7qQMu aNmCMIHbTfh804ZuYygynrjQy9KcOt6hNkUH7oF4QQaOfKPYWtGGp1Fv0KWSkIb8Jthp f+tWdWjrSKHixYWSRWYM63bK6Q28Fel5wN8XSVohO0M5tVkBCzlAy4wGvzIl66w8BfM5 mvEbXxfrUPvWpanbYlDOgGwcCbZWMwggW8jRP96f+UILFtm8v5n1T9IGshHosKXzCXAi RlvOWousVzV+45IysjDIYvx/4Yuf7XuGZG9oHbLet5xhdnseh/D7cnGdtGnWdP4xmXzF l6Lw== X-Forwarded-Encrypted: i=1; AJvYcCUnM+WCG2K1Ie24AWDH+atieZvJx2pqAFu0DTdWtr2gttlqY27q2MVIlkIt7AiNInsWocTrzFubCnzzrfnq@vger.kernel.org, AJvYcCVbLzQ6WUhp42UAT1JdFQFOBJBH2ww7HxaxV29bRkmc3w0mJwga3pRahLvvskUCHVkzQtpCOKx5waI=@vger.kernel.org, AJvYcCWLVUZueDel2hA/gVEbyMhVhAAYkttvxV696wk2Vd8ScCPQsOjyNFrIpNqhED2NIj7UXZXEJw/UIpF7xaM=@vger.kernel.org, AJvYcCXUBF8MRBa3hQGC+2eauO+4I5mZbJ8ZECB9owYviVVzAd1/ToyUqoTVBIdPjnWHxYfJCYoe3uleYsUxJdb450OshFIeEQ==@vger.kernel.org X-Gm-Message-State: AOJu0YxwaCpjo/H3sYAIJPwuhCCL4E3pQwk1eU+5MZ1k6AOShnR1FIXS TvNPE+DxQ1zXShyfueuMT+5Kgxqg1ZzVU+iVhmdCDjqSb0hmWyg8xEJuZ9C9yQ== X-Gm-Gg: ASbGncv+fEUCh3JA6ysn8fg3u82znWeSkO0IOfevdqvXgjpPPGLQeKCZ/IzPtbNSwoz DEHVRX2U/NFUywi4n9L2Ul/2GfFnncgU1IC2blao4uXM+k1q9XL5tg3TgbUDMiCtYqs8wyksBUM hFxtdUWIaoCZncff9PMKnG+CYOr4Xnta4MQzbx7DLkQ/POkUYXUAovqBMbzj0tqxFQQeSnqmn+Z hetrnYX9eVYEdMO9S/6KKyJ2fA7YQxpP1GgUfvwFs6cKJ8NjkZ8HkpDg3KE6bMvMkLV+eyWdDLp Q7c7z0STZLCqKs29A57ZIdRBr5nrHymy8LRRDo55R2zW3eZOORJOvkeYSVGMEiVUMnV9Fd01x5M vofvxpbkRhhn1T2sZ6lFqM8wTHPj1sBn4/WEwmT8qV06IAkKrKopqDPyIvPMjZnGtv2erKvcG5f REzA== X-Google-Smtp-Source: AGHT+IHXW6NNkdTOWDwD1VOKEjtc2L+gA3ER179eOVlsSnxLqG34Nyt5i8ZSSuOVuJ062JcXrKwZNw== X-Received: by 2002:a17:90a:e7ce:b0:311:b5ac:6f7d with SMTP id 98e67ed59e1d1-31e765d1630mr9655839a91.6.1753562450090; Sat, 26 Jul 2025 13:40:50 -0700 (PDT) Received: from bliptop (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31e8ea37b21sm1905640a91.22.2025.07.26.13.40.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 26 Jul 2025 13:40:49 -0700 (PDT) From: "Derek J. Clark" To: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Hans de Goede Cc: Jean Delvare , Guenter Roeck , Alok Tiwari , David Box , "Derek J . Clark" , platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v3 3/4] platform/x86: (ayn-ec) Add RGB Interface Date: Sat, 26 Jul 2025 13:40:40 -0700 Message-ID: <20250726204041.516440-4-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250726204041.516440-1-derekjohn.clark@gmail.com> References: <20250726204041.516440-1-derekjohn.clark@gmail.com> 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 Content-Type: text/plain; charset="utf-8" Adds an EC controlled LED Multicolor Class Device for controlling the RGB rings around the joysticks. The EC provides a single register for each of the colors red, green, and blue, as well as a mode switching register. The EC accepts values [0-255] for all colors. There are two available effects: breathe, which is the default when the device is started, and monocolor. When resuming from sleep the user selected effect will be overwritten by the EC, so the driver retains the last setting and resets on resume. When setting a color, each color register is set before a final "write" code is sent to the device. The EC may briefly reflect the "write" code when writing, but quickly changes to the "monocolor" value once complete. The driver interprets both of these values as "monocolor" in _show to simplify the sysfs exposed to the user. Two custom attributes are added to the standard LED parent device: effect, a RW file descriptor used to set the effect, and effect_index, which enumerates the available valid options. Signed-off-by: Derek J. Clark --- drivers/platform/x86/Kconfig | 3 + drivers/platform/x86/ayn-ec.c | 285 ++++++++++++++++++++++++++++++++++ 2 files changed, 288 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4819bfcffb6b..85dfb88cca6f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -308,6 +308,9 @@ config AYN_EC tristate "AYN x86 devices EC platform control" depends on ACPI depends on HWMON + depends on NEW_LEDS + select LEDS_CLASS + select LEDS_CLASS_MULTICOLOR help This is a driver for AYN and Tectoy x86 handheld devices. It provides temperature monitoring, manual fan speed control, fan curve control, diff --git a/drivers/platform/x86/ayn-ec.c b/drivers/platform/x86/ayn-ec.c index 466cc33adcb0..25f748d7db18 100644 --- a/drivers/platform/x86/ayn-ec.c +++ b/drivers/platform/x86/ayn-ec.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,6 +70,16 @@ #define AYN_SENSOR_PROC_TEMP_REG 0x09 /* CPU Core */ #define AYN_SENSOR_VCORE_TEMP_REG 0x08 /* vCore */ =20 +/* EC Controlled RGB registers */ +#define AYN_LED_MC_RED_REG 0xB0 /* Range 0x00-0xFF */ +#define AYN_LED_MC_GREEN_REG 0xB1 /* Range 0x00-0xFF */ +#define AYN_LED_MC_BLUE_REG 0xB2 /* Range 0x00-0xFF */ +#define AYN_RGB_EFFECT_REG 0xB3 + +/* RGB effect modes */ +#define AYN_RGB_EFFECT_BREATHE 0x00 +#define AYN_RGB_EFFECT_MONOCOLOR 0x55 +#define AYN_RGB_EFFECT_WRITE 0xAA =20 /* Handle ACPI lock mechanism */ #define ACPI_LOCK_DELAY_MS 500 @@ -86,7 +98,9 @@ int ayn_pwm_curve_registers[10] =3D { }; =20 struct ayn_device { + struct led_classdev *led_cdev; u32 ayn_lock; /* ACPI EC Lock */ + u8 rgb_effect; } drvdata; =20 struct thermal_sensor { @@ -103,6 +117,33 @@ static struct thermal_sensor thermal_sensors[] =3D { {} }; =20 +#define DEVICE_ATTR_RW_NAMED(_name, _attrname) \ + struct device_attribute dev_attr_##_name =3D { \ + .attr =3D { .name =3D _attrname, .mode =3D 0644 }, \ + .show =3D _name##_show, \ + .store =3D _name##_store, \ + } + +#define DEVICE_ATTR_RO_NAMED(_name, _attrname) \ + struct device_attribute dev_attr_##_name =3D { \ + .attr =3D { .name =3D _attrname, .mode =3D 0444 }, \ + .show =3D _name##_show, \ + } + +/* Handle ACPI lock mechanism */ +#define ACPI_LOCK_DELAY_MS 500 + +/* RGB effect values */ +enum RGB_EFFECT_OPTION { + BREATHE, + MONOCOLOR, +}; + +static const char *const RGB_EFFECT_TEXT[] =3D { + [BREATHE] =3D "breathe", + [MONOCOLOR] =3D "monocolor", +}; + static bool lock_global_acpi_lock(void) { return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, @@ -528,10 +569,253 @@ static struct attribute *ayn_sensors_attrs[] =3D { =20 ATTRIBUTE_GROUPS(ayn_sensors); =20 +/** + * rgb_effect_write() - Set the RGB effect stored in drvdata.rgb_effect. + */ +static int rgb_effect_write(void) +{ + return write_to_ec(AYN_RGB_EFFECT_REG, drvdata.rgb_effect); +}; + +/** + * rgb_effect_read() - Read the RGB effect and store it in drvdata.rgb_eff= ect. + */ +static int rgb_effect_read(void) +{ + int ret; + long effect; + + ret =3D read_from_ec(AYN_RGB_EFFECT_REG, 1, &effect); + if (ret) + return ret; + + switch (effect) { + case AYN_RGB_EFFECT_WRITE: + case AYN_RGB_EFFECT_MONOCOLOR: + drvdata.rgb_effect =3D AYN_RGB_EFFECT_WRITE; + break; + default: + drvdata.rgb_effect =3D AYN_RGB_EFFECT_BREATHE; + } + + return 0; +} + +/** + * rgb_effect_store() - Store the given RGB effect and set it. + * + * @dev: parent device of the given attribute. + * @attr: The attribute to write to. + * @buf: Input value string from sysfs write. + * @count: The number of bytes written. + * + * Return: The number of bytes written, or an error. + */ +static ssize_t rgb_effect_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int ret; + + ret =3D sysfs_match_string(RGB_EFFECT_TEXT, buf); + if (ret < 0) + return ret; + + if (ret) + drvdata.rgb_effect =3D AYN_RGB_EFFECT_WRITE; + else + drvdata.rgb_effect =3D AYN_RGB_EFFECT_BREATHE; + + ret =3D rgb_effect_write(); + if (ret) + return ret; + + return count; +}; + +/** + * rgb_effect_show() - Read the current RGB effect. + * + * @dev: parent device of the given attribute. + * @attr: The attribute to read. + * @buf: Buffer to read to. + * + * Return: The number of bytes read, or an error. + */ +static ssize_t rgb_effect_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + + ret =3D rgb_effect_read(); + if (ret) + return ret; + + switch (drvdata.rgb_effect) { + case AYN_RGB_EFFECT_WRITE: + case AYN_RGB_EFFECT_MONOCOLOR: + i =3D MONOCOLOR; + break; + default: + i =3D BREATHE; + break; + } + + return sysfs_emit(buf, "%s\n", RGB_EFFECT_TEXT[i]); +}; + +static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect"); + +/** + * rgb_effect_show() - Display the RGB effects available. + * + * @dev: parent device of the given attribute. + * @attr: The attribute to read. + * @buf: Buffer to read to. + * + * Return: The number of bytes read, or an error. + */ +static ssize_t rgb_effect_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count =3D 0; + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(RGB_EFFECT_TEXT); i++) + count +=3D sysfs_emit_at(buf, count, "%s ", RGB_EFFECT_TEXT[i]); + + buf[count - 1] =3D '\n'; + + return count; +} + +static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index"); + +/** + * ayn_led_mc_brightness_set() - Write the brightness for the RGB LED. + * + * @led_cdev: Parent LED device for the led_classdev_mc. + * @brightness: Brightness value to write [0-255]. + */ +static void ayn_led_mc_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *led_cdev_mc =3D lcdev_to_mccdev(led_cdev); + struct mc_subled s_led; + int i, ret, val; + + switch (drvdata.rgb_effect) { + case AYN_RGB_EFFECT_WRITE: + case AYN_RGB_EFFECT_MONOCOLOR: + break; + case AYN_RGB_EFFECT_BREATHE: + return; + } + + led_cdev->brightness =3D brightness; + for (i =3D 0; i < led_cdev_mc->num_colors; i++) { + s_led =3D led_cdev_mc->subled_info[i]; + val =3D brightness * s_led.intensity / led_cdev->max_brightness; + ret =3D write_to_ec(s_led.channel, val); + if (ret) { + dev_err(led_cdev->dev, + "Error setting brightness: %d\n", ret); + return; + } + } + + /* Must write mode again to change to set color */ + write_to_ec(AYN_RGB_EFFECT_REG, AYN_RGB_EFFECT_WRITE); +}; + +/** + * ayn_led_mc_brightness_get() - Get the brightness for the RGB LED. + * + * @led_cdev: Parent LED device for the led_classdev_mc. + * + * Return: Current brightness. + */ +static enum led_brightness ayn_led_mc_brightness_get(struct led_classdev *= led_cdev) +{ + return led_cdev->brightness; +}; + +static struct attribute *ayn_led_mc_attrs[] =3D { + &dev_attr_rgb_effect.attr, + &dev_attr_rgb_effect_index.attr, + NULL, +}; + +static struct attribute_group ayn_led_mc_group =3D { + .attrs =3D ayn_led_mc_attrs, +}; + +struct mc_subled ayn_led_mc_subled_info[] =3D { + { + .color_index =3D LED_COLOR_ID_RED, + .brightness =3D 0, + .intensity =3D 0, + .channel =3D AYN_LED_MC_RED_REG, + }, + { + .color_index =3D LED_COLOR_ID_GREEN, + .brightness =3D 0, + .intensity =3D 0, + .channel =3D AYN_LED_MC_GREEN_REG, + }, + { + .color_index =3D LED_COLOR_ID_BLUE, + .brightness =3D 0, + .intensity =3D 0, + .channel =3D AYN_LED_MC_BLUE_REG, + }, +}; + +struct led_classdev_mc ayn_led_mc =3D { + .led_cdev =3D { + .name =3D "ayn:rgb:joystick_rings", + .brightness =3D 0, + .max_brightness =3D 255, + .brightness_set =3D ayn_led_mc_brightness_set, + .brightness_get =3D ayn_led_mc_brightness_get, + .color =3D LED_COLOR_ID_RGB, + }, + .num_colors =3D ARRAY_SIZE(ayn_led_mc_subled_info), + .subled_info =3D ayn_led_mc_subled_info, +}; + +static int ayn_ec_resume(struct platform_device *pdev) +{ + struct led_classdev *led_cdev =3D drvdata.led_cdev; + int ret; + + ret =3D rgb_effect_write(); + if (ret) + return ret; + + ayn_led_mc_brightness_set(led_cdev, led_cdev->brightness); + + return 0; +} + static int ayn_ec_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; struct device *hwdev; + int ret; + + ret =3D devm_led_classdev_multicolor_register(dev, &ayn_led_mc); + if (ret) + return ret; + + ret =3D devm_device_add_group(ayn_led_mc.led_cdev.dev, &ayn_led_mc_group); + if (ret) + return ret; + + drvdata.led_cdev =3D &ayn_led_mc.led_cdev; + ret =3D rgb_effect_read(); + if (ret) + return ret; =20 hwdev =3D devm_hwmon_device_register_with_info(dev, "aynec", NULL, &ayn_ec_chip_info, @@ -544,6 +828,7 @@ static struct platform_driver ayn_ec_driver =3D { .name =3D "ayn-ec", }, .probe =3D ayn_ec_probe, + .resume =3D ayn_ec_resume, }; =20 static struct platform_device *ayn_ec_device; --=20 2.50.1 From nobody Mon Oct 6 01:22:03 2025 Received: from mail-pg1-f170.google.com (mail-pg1-f170.google.com [209.85.215.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E79628A1F6; Sat, 26 Jul 2025 20:40:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562453; cv=none; b=V5kFmR0WeX0J0NaJNva12vD1GLTTvXGb4aMz80PhgJ8tIExSQW8Th5uRerxIX9wypB/FFFUDofrh0/D2oDImjPPZYYdIC9DVhPyVhHj2PssD+L0xOgNDUuu/0WMSItGkX8eyspCOS/Ud5lzR+owJqt0ox9pAuY9t1RmdecniW2M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753562453; c=relaxed/simple; bh=Up0KWTi39BtMHH0ZAqQexxhhMWXhXR7CZaMKH9IbFfY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JY/h6igW4jnt2DeqOwENHfqHbPsOZTNBmGVXRctRIEJuko8lzNQ5FNaREfwj9CTmbDBOZHU9iSdBrHcRlyoWEK2Ezq6orkP2v87nWpuPb9WJ/e8yLJGYi19JlS94E0yMiTK9VP2NLPK0ad+IWF/iTgpWH/AVo8/pY/lulrz5838= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lRoNUg4r; arc=none smtp.client-ip=209.85.215.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lRoNUg4r" Received: by mail-pg1-f170.google.com with SMTP id 41be03b00d2f7-b31d489a76dso3354315a12.1; Sat, 26 Jul 2025 13:40:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753562451; x=1754167251; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XxRXHDITuTEc5htofRaO84OQpguHqwXeLPIWvWejt0I=; b=lRoNUg4rM2amOk+/kZIjHNA3lBVHsbkWqTwuBvg0Ji4RTqnkN0mI8pvi+7Ec/MCEQy A1SgWlvVWnRZ7NEu8hoxkd40/JBXBsdmkB49l9rRJWxSSimt6FBQqdjqn0HhgZM+8yub wEnxDB9mP5/hHPlbMHZ4hWfe4mF1Zp6g896fPmyJxfnDtynTfojkH0L7lyWhXjwctYQo mbD4Qz/SQXLZxv4AwjKzPOL64xg20x+02lj4XNSFmtWZKwJJRI2uPJfyz1Y8uUwjmYIA YM/eJ4HtdthDmXpIfuLpNViZ1RAIl94a+Ug+uL8Lk8dicoKCiBw2qqXwO3zBP9Hp+ygz c4kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753562451; x=1754167251; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=XxRXHDITuTEc5htofRaO84OQpguHqwXeLPIWvWejt0I=; b=KlfAYrGfxvdPfXc7bLnaiX63Kg4ScBfccqCjCMzK5n8BCTa7RAi1KLDQJZM2KmY2/J SIBx7BzKRJ8fFRPh1PsOyPVNyoDKZz0qNbtxoBFMvgCvnxhe1yokUF6DtkmzX3l5PFv7 MGXnqvu2AI95Aha8SvxpZxaZUOtNWHqZA/Ya4uaZfWj6SKE6BgQ9DLjH2nK6QF5uU8IK ix3RyHCk6km4WTnjzHwLl5/y/QHOqPvGo5tYCS+AGND7YPQG9PTDMKNoIQffKzMkF5WU v6NKfhcSetSE6G0m5wZYNBd9xqM0t5fl3EGw6b0nbp3OlaYxGtXbNRkAuYaCJgLZnUgj 4QEw== X-Forwarded-Encrypted: i=1; AJvYcCVbftdyL4ic/mf+h+UndArti4pfbtt6heeHaHenb9V6moYpTM2VkrdlvMH8XuNVyfl4xudVwXAqa1lrXIBu@vger.kernel.org, AJvYcCWrvcL68ppUOO5CWFfgMy/MXxCna3htleO3fsZWcjdWsXWv2ul5WOhWRpcmUHyhL1TQLWVQVx14+fjdBUhCeZoLXilUHA==@vger.kernel.org, AJvYcCXQM84FU5oVZsWrAPWHB1s6KGXHt6HW4+1Ce76zWGLkIUdvwZjzOIt3oc0znv9fW7X3cEsnrSlEEk0=@vger.kernel.org, AJvYcCXYqnaEEgxoE8py9Dn1Lk/ok0g7SiSda1E7G3AdB4GwuykbB4TRHCBU54pkyRu0QB4/prwG1VE0/ayqB/I=@vger.kernel.org X-Gm-Message-State: AOJu0YzJCo5cWY6ZJ83qhWOYez3vyYLj+QabTSDaTFoZ5laUvvaMCpDZ M1Y2R3WAbbsCa+QNL/nAPEGHjAHbv/WlXFkdtmS8gPendx+Eo/cWmRob X-Gm-Gg: ASbGncvCs/0mLW+VbRR9A7MJd/E7QBQXobE+BGJTJZuwiIM6TSHEnQxvZlxv5hrbIi2 nAenXXuBN0mAHPkbe6GgZegiLlRUR40A2I0pQT2o7OJZGi76vomMJB/tL0/SiICH/FYmTSbawgW MfQa+coiu+Eey0+CMVIgrYw1E2lci6CY7ZEa/xJhxo5omBa8xAMVlsyg1TD60hy/wq+hV7WYAIg x/RcV0X/sctPSPMEh3EHiqGo+S/dpX86aKQBer9Efou0flSONsBWA6bYLjpTJoz27bXitM3X97T FiuKImf31E+m05IhGI8F/uKXvODTeXJPDC+F8x6Mu54rsQ+XZfZWpkKr9oxB6vBw/szrDCDYuFe RElfU7SZAxETiXU6RGAaVdgdKcKvYKCjQg54W38IMlVRLyzw0kh3isXcAKnCTNhBRsXPrOOr3cH 3XmDXqG0vwEhhP X-Google-Smtp-Source: AGHT+IGNZt6fbjyLeCK8wPdjfn9A479/Rzeyj75hewbRmiLLjMVu7D6q5V077Te4HEmqxqrYakPk4A== X-Received: by 2002:a05:6a20:2450:b0:220:10e5:825d with SMTP id adf61e73a8af0-23d7005260cmr10666498637.8.1753562451255; Sat, 26 Jul 2025 13:40:51 -0700 (PDT) Received: from bliptop (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31e8ea37b21sm1905640a91.22.2025.07.26.13.40.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 26 Jul 2025 13:40:51 -0700 (PDT) From: "Derek J. Clark" To: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Hans de Goede Cc: Jean Delvare , Guenter Roeck , Alok Tiwari , David Box , "Derek J . Clark" , platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v3 4/4] platform/x86: (ayn-ec) Add AYN EC Platform Documentation Date: Sat, 26 Jul 2025 13:40:41 -0700 Message-ID: <20250726204041.516440-5-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250726204041.516440-1-derekjohn.clark@gmail.com> References: <20250726204041.516440-1-derekjohn.clark@gmail.com> 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 Content-Type: text/plain; charset="utf-8" Adds ABI documentation for the ayn-ec platform driver Signed-off-by: Derek J. Clark --- .../ABI/testing/sysfs-platform-ayn-ec | 59 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 60 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-ayn-ec diff --git a/Documentation/ABI/testing/sysfs-platform-ayn-ec b/Documentatio= n/ABI/testing/sysfs-platform-ayn-ec new file mode 100644 index 000000000000..32cb6f7ca2fc --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-ayn-ec @@ -0,0 +1,59 @@ +What: /sys/class/hwmon/hwmon[0-9]/pwm1_enable +Date: July 2025 +KernelVersion: 6.17 +Contact: "Derek J. Clark" +Description: + This sets the PWM fan mode of operation. Valid values are [0-3]. + Values [0-2] conform with standard hwmon operating modes. Value 3 + enables user defined fan curve settings. + + Applies to AYN Loki and Tectoy Zeenix lines of handheld devices. + +What: /sys/class/hwmon/hwmon[0-9]/pwm1_auto_point[1-5]_pwm +Date: July 2025 +KernelVersion: 6.17 +Contact: "Derek J. Clark" +Description: + This sets the PWM fan duty cycle for the given index of the fan curve. + When the temperature reaches the corresponding pwm1_auto_point[1-5]_te= mp, + the EC will automatically increase the fan duty cycle to the given val= ue. + + Values are [0-255] + + Applies to AYN Loki and Tectoy Zeenix lines of handheld devices. + +What: /sys/class/hwmon/hwmon[0-9]/pwm1_auto_point[1-5]_temp +Date: July 2025 +KernelVersion: 6.17 +Contact: "Derek J. Clark" +Description: + This sets the activation temperature for the given index of the fan curv= e. + When the temperature reaches the given value, the EC will automatically + increase the fan duty cycle to the corresponding pwm1_auto_point[1-5]_= pwm + value. + + Values are [0-100] + + Applies to AYN Loki and Tectoy Zeenix lines of handheld devices. + +What: /sys/class/leds/ayn:rgb:joystick_rings/effect +Date: July 2025 +KernelVersion: 6.17 +Contact: "Derek J. Clark" +Description: + This controls the display effect of the RGB interface. + + Values are monocolor or breathe. + + Applies to AYN Loki and Tectoy Zeenix lines of handheld devices. + +What: /sys/class/leds/ayn:rgb:joystick_rings/effect_index +Date: July 2025 +KernelVersion: 6.17 +Contact: "Derek J. Clark" +Description: + This displays the available options for the effect attribute. + + Values are monocolor or breathe. + + Applies to AYN Loki and Tectoy Zeenix lines of handheld devices. diff --git a/MAINTAINERS b/MAINTAINERS index 5b816883fe7d..199bebbffa0d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4039,6 +4039,7 @@ AYN PLATFORM EC DRIVER M: Derek J. Clark L: platform-driver-x86@vger.kernel.org S: Maintained +F: Documentation/ABI/testing/sysfs-platform-ayn-ec F: drivers/platform/x86/ayn-ec.c =20 AZ6007 DVB DRIVER --=20 2.50.1