Re: [PATCH v3] hwmon: (oxp-sensors) Add tt_toggle attribute on supported boards

From: Guenter Roeck
Date: Sat Jun 17 2023 - 13:16:57 EST


On Sun, Jun 11, 2023 at 11:33:20AM -0300, Joaquín Ignacio Aramendía wrote:
> OneXPlayer boards from the last generation (both for OneXPlayer and AOK
> ZOE brands) have a toggle in the EC to switch the "Turbo/Silent" button
> into a different keyboard event.
>
> Add a means to use that "Turbo button takeover" function and expose it
> to userspace in a custom sysfs `tt_toggle` attribute. It can be read to
> take the current state. Write 1|0 to activate the function. The specific
> keycode is dependent on the board but can be checked by running
> `evtest` utility.
>
> Newer BIOS on the OneXPlayer added this function aside from string changes.
> Add a board enum to differentiate it from the old OneXplayer Mini AMD BIOS.
>
> Currently known supported boards:
> - AOK ZOE A1
> - OneXPlayer Mini AMD (only newer BIOS version supported)
> - OneXPlayer Mini Pro
>
> Signed-off-by: Joaquín Ignacio Aramendía <samsagax@xxxxxxxxx>

Applied to hwmon-next.

Thanks,
Guenter

> ---
> v2 changes:
> - Attach the attribute to the platform device as per review
> - Make the attribute return status 0|1 instead of read value
>
> v3 changes:
> - Mention the attribute attached to the platform device on Documentation
> - Use boolean instead of base 10 int in tt_toggle_store()
> - Remove unnecesary status logic in tt_toggle_show() (use !!val instead)
> - Add missing breaks in probe()
> ---
> Documentation/hwmon/oxp-sensors.rst | 17 ++++
> drivers/hwmon/oxp-sensors.c | 134 +++++++++++++++++++++++++++-
> 2 files changed, 150 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst
> index 4ab442301415..0ca1f7728c34 100644
> --- a/Documentation/hwmon/oxp-sensors.rst
> +++ b/Documentation/hwmon/oxp-sensors.rst
> @@ -19,6 +19,11 @@ out the EC registers and values to write to since the EC layout and model is
> different. Aya Neo devices preceding the AIR may not be supportable as the EC
> model is different and do not appear to have manual control capabilities.
>
> +Some models have a toggle for changing the behaviour of the "Turbo/Silent"
> +button of the device. It will change the key event that it triggers with
> +a flip of the `tt_toggle` attribute. See below for boards that support this
> +function.
> +
> Supported devices
> -----------------
>
> @@ -33,6 +38,11 @@ Currently the driver supports the following handhelds:
> - OneXPlayer mini AMD
> - OneXPlayer mini AMD PRO
>
> +"Turbo/Silent" button behaviour toggle is only supported on:
> + - AOK ZOE A1
> + - OneXPlayer mini AMD (only with updated alpha BIOS)
> + - OneXPlayer mini AMD PRO
> +
> Sysfs entries
> -------------
>
> @@ -49,3 +59,10 @@ pwm1
> Read Write. Read this attribute to see current duty cycle in the range [0-255].
> When pwm1_enable is set to "1" (manual) write any value in the range [0-255]
> to set fan speed.
> +
> +tt_toggle
> + Read Write. Read this attribute to check the status of the turbo/silent
> + button behaviour function. Write "1" to activate the switch and "0" to
> + deactivate it. The specific keycodes and behaviour is specific to the device
> + both with this function on and off. This attribute is attached to the platform
> + driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle)
> diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c
> index 0ec7588610ad..be36d38f13d9 100644
> --- a/drivers/hwmon/oxp-sensors.c
> +++ b/drivers/hwmon/oxp-sensors.c
> @@ -47,15 +47,29 @@ enum oxp_board {
> aya_neo_air_pro,
> aya_neo_geek,
> oxp_mini_amd,
> + oxp_mini_amd_a07,
> oxp_mini_amd_pro,
> };
>
> static enum oxp_board board;
>
> +/* Fan reading and PWM */
> #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
> #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
> #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
>
> +/* Turbo button takeover function
> + * Older boards have different values and EC registers
> + * for the same function
> + */
> +#define OXP_OLD_TURBO_SWITCH_REG 0x1E
> +#define OXP_OLD_TURBO_TAKE_VAL 0x01
> +#define OXP_OLD_TURBO_RETURN_VAL 0x00
> +
> +#define OXP_TURBO_SWITCH_REG 0xF1
> +#define OXP_TURBO_TAKE_VAL 0x40
> +#define OXP_TURBO_RETURN_VAL 0x00
> +
> static const struct dmi_system_id dmi_table[] = {
> {
> .matches = {
> @@ -104,7 +118,7 @@ static const struct dmi_system_id dmi_table[] = {
> DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
> DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
> },
> - .driver_data = (void *)oxp_mini_amd,
> + .driver_data = (void *)oxp_mini_amd_a07,
> },
> {
> .matches = {
> @@ -156,6 +170,102 @@ static int write_to_ec(u8 reg, u8 value)
> return ret;
> }
>
> +/* Turbo button toggle functions */
> +static int tt_toggle_enable(void)
> +{
> + u8 reg;
> + u8 val;
> +
> + switch (board) {
> + case oxp_mini_amd_a07:
> + reg = OXP_OLD_TURBO_SWITCH_REG;
> + val = OXP_OLD_TURBO_TAKE_VAL;
> + break;
> + case oxp_mini_amd_pro:
> + case aok_zoe_a1:
> + reg = OXP_TURBO_SWITCH_REG;
> + val = OXP_TURBO_TAKE_VAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return write_to_ec(reg, val);
> +}
> +
> +static int tt_toggle_disable(void)
> +{
> + u8 reg;
> + u8 val;
> +
> + switch (board) {
> + case oxp_mini_amd_a07:
> + reg = OXP_OLD_TURBO_SWITCH_REG;
> + val = OXP_OLD_TURBO_RETURN_VAL;
> + break;
> + case oxp_mini_amd_pro:
> + case aok_zoe_a1:
> + reg = OXP_TURBO_SWITCH_REG;
> + val = OXP_TURBO_RETURN_VAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return write_to_ec(reg, val);
> +}
> +
> +/* Callbacks for turbo toggle attribute */
> +static ssize_t tt_toggle_store(struct device *dev,
> + struct device_attribute *attr, const char *buf,
> + size_t count)
> +{
> + int rval;
> + bool value;
> +
> + rval = kstrtobool(buf, &value);
> + if (rval)
> + return rval;
> +
> + if (value) {
> + rval = tt_toggle_enable();
> + if (rval)
> + return rval;
> + } else {
> + rval = tt_toggle_disable();
> + if (rval)
> + return rval;
> + }
> + return count;
> +}
> +
> +static ssize_t tt_toggle_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int retval;
> + u8 reg;
> + long val;
> +
> + switch (board) {
> + case oxp_mini_amd_a07:
> + reg = OXP_OLD_TURBO_SWITCH_REG;
> + break;
> + case oxp_mini_amd_pro:
> + case aok_zoe_a1:
> + reg = OXP_TURBO_SWITCH_REG;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + retval = read_from_ec(reg, 1, &val);
> + if (retval)
> + return retval;
> +
> + return sysfs_emit(buf, "%d\n", !!val);
> +}
> +
> +static DEVICE_ATTR_RW(tt_toggle);
> +
> +/* PWM enable/disable functions */
> static int oxp_pwm_enable(void)
> {
> return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01);
> @@ -206,6 +316,7 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
> case aya_neo_air_pro:
> case aya_neo_geek:
> case oxp_mini_amd:
> + case oxp_mini_amd_a07:
> *val = (*val * 255) / 100;
> break;
> case oxp_mini_amd_pro:
> @@ -247,6 +358,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
> case aya_neo_air_pro:
> case aya_neo_geek:
> case oxp_mini_amd:
> + case oxp_mini_amd_a07:
> val = (val * 100) / 255;
> break;
> case aok_zoe_a1:
> @@ -274,6 +386,13 @@ static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
> NULL,
> };
>
> +static struct attribute *oxp_ec_attrs[] = {
> + &dev_attr_tt_toggle.attr,
> + NULL
> +};
> +
> +ATTRIBUTE_GROUPS(oxp_ec);
> +
> static const struct hwmon_ops oxp_ec_hwmon_ops = {
> .is_visible = oxp_ec_hwmon_is_visible,
> .read = oxp_platform_read,
> @@ -291,6 +410,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
> const struct dmi_system_id *dmi_entry;
> struct device *dev = &pdev->dev;
> struct device *hwdev;
> + int ret;
>
> /*
> * Have to check for AMD processor here because DMI strings are the
> @@ -305,6 +425,18 @@ static int oxp_platform_probe(struct platform_device *pdev)
>
> board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
>
> + switch (board) {
> + case aok_zoe_a1:
> + case oxp_mini_amd_a07:
> + case oxp_mini_amd_pro:
> + ret = devm_device_add_groups(dev, oxp_ec_groups);
> + if (ret)
> + return ret;
> + break;
> + default:
> + break;
> + }
> +
> hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
> &oxp_ec_chip_info, NULL);
>