diff mbox series

[v3,08/12] platform/x86: oxpec: Add turbo led support to X1 devices

Message ID 20250309112114.1177361-9-lkml@antheas.dev (mailing list archive)
State Handled Elsewhere
Headers show
Series hwmon: (oxpsensors) Add devices, features, fix ABI and move to platform/x86 | expand

Commit Message

Antheas Kapenekakis March 9, 2025, 11:21 a.m. UTC
The X1 and X1 mini lineups feature an LED nested within their turbo
button. When turbo takeover is not enabled, the turbo button allows
the device to switch from 18W to 25W TDP. When the device is in the
25W TDP mode, the LED is turned on.

However, when we engage turbo takeover, the turbo led remains on its
last state, which might be illuminated and cannot be currently
controlled. Therefore, add the register that controls it under sysfs,
to allow userspace to turn it off once engaging turbo takeover and
then control it as they wish.

2024 OneXPlayer devices, other than the X1s, do not have a turbo LED.
However, earlier models do, so this can be extended to them as well
when the register for it is found.

Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
 drivers/platform/x86/oxpec.c | 84 ++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

Comments

Derek John Clark March 10, 2025, 11:57 p.m. UTC | #1
On Sun, Mar 9, 2025 at 4:21 AM Antheas Kapenekakis <lkml@antheas.dev> wrote:
>
> The X1 and X1 mini lineups feature an LED nested within their turbo
> button. When turbo takeover is not enabled, the turbo button allows
> the device to switch from 18W to 25W TDP. When the device is in the
> 25W TDP mode, the LED is turned on.
>
> However, when we engage turbo takeover, the turbo led remains on its
> last state, which might be illuminated and cannot be currently
> controlled. Therefore, add the register that controls it under sysfs,
> to allow userspace to turn it off once engaging turbo takeover and
> then control it as they wish.
>
> 2024 OneXPlayer devices, other than the X1s, do not have a turbo LED.
> However, earlier models do, so this can be extended to them as well
> when the register for it is found.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
>  drivers/platform/x86/oxpec.c | 84 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
>
> diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
> index 9cb024325da5..eb7eafebbd37 100644
> --- a/drivers/platform/x86/oxpec.c
> +++ b/drivers/platform/x86/oxpec.c
> @@ -106,6 +106,12 @@ static enum oxp_board board;
>  #define OXP_X1_CHARGE_BYPASS_MASK_ALWAYS (OXP_X1_CHARGE_BYPASS_MASK_S0 | \
>         OXP_X1_CHARGE_BYPASS_MASK_S3S5)
>
> +/* X1 Turbo LED */
> +#define OXP_X1_TURBO_LED_REG           0x57
> +
> +#define OXP_X1_TURBO_LED_OFF           0x01
> +#define OXP_X1_TURBO_LED_ON            0x02
> +
>  static const struct dmi_system_id dmi_table[] = {
>         {
>                 .matches = {
> @@ -453,6 +459,73 @@ static ssize_t tt_toggle_show(struct device *dev,
>
>  static DEVICE_ATTR_RW(tt_toggle);
>
> +/* Callbacks for turbo toggle attribute */
> +static umode_t tt_led_is_visible(struct kobject *kobj,
> +                                   struct attribute *attr, int n)
> +{
> +       switch (board) {
> +       case oxp_x1:
> +               return attr->mode;
> +       default:
> +               break;
> +       }
> +       return 0;
> +}
> +
> +static ssize_t tt_led_store(struct device *dev,
> +                              struct device_attribute *attr, const char *buf,
> +                              size_t count)
> +{
> +       u8 reg, val;
> +       int rval;
> +       bool value;
> +

Reverse xmas tree.

> +       rval = kstrtobool(buf, &value);
> +       if (rval)
> +               return rval;
> +
> +       switch (board) {
> +       case oxp_x1:
> +               reg = OXP_X1_TURBO_LED_REG;
> +               val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       rval = write_to_ec(reg, val);
> +
> +       if (rval)
> +               return rval;
> +
> +       return count;
> +}
> +
> +static ssize_t tt_led_show(struct device *dev,
> +                             struct device_attribute *attr, char *buf)
> +{
> +       int retval;
> +       u8 reg;
> +       long enval;
> +       long val;
> +

Reverse xmas tree.

Cheers,
- Derek

> +       switch (board) {
> +       case oxp_x1:
> +               reg = OXP_X1_TURBO_LED_REG;
> +               enval = OXP_X1_TURBO_LED_ON;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       retval = read_from_ec(reg, 1, &val);
> +       if (retval)
> +               return retval;
> +
> +       return sysfs_emit(buf, "%d\n", val == enval);
> +}
> +
> +static DEVICE_ATTR_RW(tt_led);
> +
>  /* Callbacks for turbo toggle attribute */
>  static bool charge_behaviour_supported(void)
>  {
> @@ -898,8 +971,19 @@ static struct attribute_group oxp_tt_toggle_attribute_group = {
>         .attrs = oxp_tt_toggle_attrs,
>  };
>
> +static struct attribute *oxp_tt_led_attrs[] = {
> +       &dev_attr_tt_led.attr,
> +       NULL
> +};
> +
> +static struct attribute_group oxp_tt_led_attribute_group = {
> +       .is_visible = tt_led_is_visible,
> +       .attrs = oxp_tt_led_attrs,
> +};
> +
>  static const struct attribute_group *oxp_ec_groups[] = {
>         &oxp_tt_toggle_attribute_group,
> +       &oxp_tt_led_attribute_group,
>         NULL
>  };
>
> --
> 2.48.1
>
diff mbox series

Patch

diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
index 9cb024325da5..eb7eafebbd37 100644
--- a/drivers/platform/x86/oxpec.c
+++ b/drivers/platform/x86/oxpec.c
@@ -106,6 +106,12 @@  static enum oxp_board board;
 #define OXP_X1_CHARGE_BYPASS_MASK_ALWAYS (OXP_X1_CHARGE_BYPASS_MASK_S0 | \
 	OXP_X1_CHARGE_BYPASS_MASK_S3S5)
 
+/* X1 Turbo LED */
+#define OXP_X1_TURBO_LED_REG           0x57
+
+#define OXP_X1_TURBO_LED_OFF           0x01
+#define OXP_X1_TURBO_LED_ON            0x02
+
 static const struct dmi_system_id dmi_table[] = {
 	{
 		.matches = {
@@ -453,6 +459,73 @@  static ssize_t tt_toggle_show(struct device *dev,
 
 static DEVICE_ATTR_RW(tt_toggle);
 
+/* Callbacks for turbo toggle attribute */
+static umode_t tt_led_is_visible(struct kobject *kobj,
+				    struct attribute *attr, int n)
+{
+	switch (board) {
+	case oxp_x1:
+		return attr->mode;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static ssize_t tt_led_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	u8 reg, val;
+	int rval;
+	bool value;
+
+	rval = kstrtobool(buf, &value);
+	if (rval)
+		return rval;
+
+	switch (board) {
+	case oxp_x1:
+		reg = OXP_X1_TURBO_LED_REG;
+		val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF;
+		break;
+	default:
+		return -EINVAL;
+	}
+	rval = write_to_ec(reg, val);
+
+	if (rval)
+		return rval;
+
+	return count;
+}
+
+static ssize_t tt_led_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	int retval;
+	u8 reg;
+	long enval;
+	long val;
+
+	switch (board) {
+	case oxp_x1:
+		reg = OXP_X1_TURBO_LED_REG;
+		enval = OXP_X1_TURBO_LED_ON;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	retval = read_from_ec(reg, 1, &val);
+	if (retval)
+		return retval;
+
+	return sysfs_emit(buf, "%d\n", val == enval);
+}
+
+static DEVICE_ATTR_RW(tt_led);
+
 /* Callbacks for turbo toggle attribute */
 static bool charge_behaviour_supported(void)
 {
@@ -898,8 +971,19 @@  static struct attribute_group oxp_tt_toggle_attribute_group = {
 	.attrs = oxp_tt_toggle_attrs,
 };
 
+static struct attribute *oxp_tt_led_attrs[] = {
+	&dev_attr_tt_led.attr,
+	NULL
+};
+
+static struct attribute_group oxp_tt_led_attribute_group = {
+	.is_visible = tt_led_is_visible,
+	.attrs = oxp_tt_led_attrs,
+};
+
 static const struct attribute_group *oxp_ec_groups[] = {
 	&oxp_tt_toggle_attribute_group,
+	&oxp_tt_led_attribute_group,
 	NULL
 };