]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
platform/x86: sel3350-platform: Retain LED state on load and unload
authorBrodie Abrew <brodie_abrew@selinc.com>
Thu, 7 May 2026 00:49:16 +0000 (17:49 -0700)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 11 May 2026 16:15:20 +0000 (19:15 +0300)
When the platform driver is loaded or unloaded, it overwrites the
existing LED states. This can cause a loss of early boot state when the
driver loads, and it can cause the ALARM contact to change state or
flicker.

Explicitly retain the existing LED state to prevent overwriting on
driver load and unload.

Tested-By: Robert Joslyn <robert.joslyn@redrectangle.org>
Reviewed-by: Robert Joslyn <robert.joslyn@redrectangle.org>
Signed-off-by: Brodie Abrew <brodie_abrew@selinc.com>
Link: https://patch.msgid.link/20260507004916.6710-1-brodie_abrew@selinc.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/sel3350-platform.c

index 02e2081e2333b1495035f43db50ad9ed7e1099c8..f3a31423563251f8331ecb71d0d9f23f8fcde57e 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/machine.h>
 #include <linux/leds.h>
 #define SEL_PS_B_DETECT "sel_ps_b_detect"
 #define SEL_PS_B_GOOD   "sel_ps_b_good"
 
+#define AUX_LED_GRN1        "sel_aux_led_grn1"
+#define AUX_LED_GRN2        "sel_aux_led_grn2"
+#define AUX_LED_GRN3        "sel_aux_led_grn3"
+#define AUX_LED_GRN4        "sel_aux_led_grn4"
+#define ALARM_STATE_USER    "sel_alarm_state_user"
+#define ENABLE_STATE_USER   "sel_enable_state_user"
+#define AUX_LED_RED1        "sel_aux_led_red1"
+#define AUX_LED_RED2        "sel_aux_led_red2"
+#define AUX_LED_RED3        "sel_aux_led_red3"
+#define AUX_LED_RED4        "sel_aux_led_red4"
+
+static const char *const sel3350_leds_gpio_names[] = {
+       AUX_LED_GRN1,
+       AUX_LED_GRN2,
+       AUX_LED_GRN3,
+       AUX_LED_GRN4,
+       ALARM_STATE_USER,
+       ENABLE_STATE_USER,
+       AUX_LED_RED1,
+       AUX_LED_RED2,
+       AUX_LED_RED3,
+       AUX_LED_RED4,
+};
+
 /* LEDs */
-static const struct gpio_led sel3350_leds[] = {
-       { .name = "sel:green:aux1" },
-       { .name = "sel:green:aux2" },
-       { .name = "sel:green:aux3" },
-       { .name = "sel:green:aux4" },
-       { .name = "sel:red:alarm" },
+static struct gpio_led sel3350_leds[] = {
+       { .name = "sel:green:aux1",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:green:aux2",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:green:aux3",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:green:aux4",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:red:alarm",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
        { .name = "sel:green:enabled",
-         .default_state = LEDS_GPIO_DEFSTATE_ON },
-       { .name = "sel:red:aux1" },
-       { .name = "sel:red:aux2" },
-       { .name = "sel:red:aux3" },
-       { .name = "sel:red:aux4" },
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:red:aux1",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:red:aux2",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:red:aux3",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
+       { .name = "sel:red:aux4",
+         .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+         .retain_state_suspended = 1,
+         .retain_state_shutdown = 1,
+       },
 };
 
 static const struct gpio_led_platform_data sel3350_leds_pdata = {
@@ -50,25 +115,6 @@ static const struct gpio_led_platform_data sel3350_leds_pdata = {
        .leds = sel3350_leds,
 };
 
-/* Map GPIOs to LEDs */
-static struct gpiod_lookup_table sel3350_leds_table = {
-       .dev_id = "leds-gpio",
-       .table = {
-               GPIO_LOOKUP_IDX(BXT_NW, 49, NULL, 0, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_NW, 50, NULL, 1, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_NW, 51, NULL, 2, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_NW, 52, NULL, 3, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_W,  20, NULL, 4, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_W,  21, NULL, 5, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_SW, 37, NULL, 6, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_SW, 38, NULL, 7, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_SW, 39, NULL, 8, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX(BXT_SW, 40, NULL, 9, GPIO_ACTIVE_HIGH),
-               {},
-       }
-};
-
-/* Map GPIOs to power supplies */
 static struct gpiod_lookup_table sel3350_gpios_table = {
        .dev_id = B2093_GPIO_ACPI_ID ":00",
        .table = {
@@ -76,6 +122,16 @@ static struct gpiod_lookup_table sel3350_gpios_table = {
                GPIO_LOOKUP(BXT_NW, 45, SEL_PS_A_GOOD,   GPIO_ACTIVE_LOW),
                GPIO_LOOKUP(BXT_NW, 46, SEL_PS_B_DETECT, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP(BXT_NW, 47, SEL_PS_B_GOOD,   GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP(BXT_NW, 49, AUX_LED_GRN1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_NW, 50, AUX_LED_GRN2, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_NW, 51, AUX_LED_GRN3, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_NW, 52, AUX_LED_GRN4, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_W,  20, ALARM_STATE_USER, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_W,  21, ENABLE_STATE_USER, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_SW, 37, AUX_LED_RED1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_SW, 38, AUX_LED_RED2, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_SW, 39, AUX_LED_RED3, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP(BXT_SW, 40, AUX_LED_RED4, GPIO_ACTIVE_HIGH),
                {},
        }
 };
@@ -149,6 +205,7 @@ struct sel3350_data {
 static int sel3350_probe(struct platform_device *pdev)
 {
        int rs;
+       int i;
        struct sel3350_data *sel3350;
        struct power_supply_config ps_cfg = {};
 
@@ -158,9 +215,19 @@ static int sel3350_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, sel3350);
 
-       gpiod_add_lookup_table(&sel3350_leds_table);
        gpiod_add_lookup_table(&sel3350_gpios_table);
 
+       for (i = 0; i < ARRAY_SIZE(sel3350_leds); ++i) {
+               sel3350_leds[i].gpiod = devm_gpiod_get(&pdev->dev,
+                                                      sel3350_leds_gpio_names[i],
+                                                      GPIOD_ASIS);
+               if (IS_ERR_OR_NULL(sel3350_leds[i].gpiod)) {
+                       rs = -EPROBE_DEFER;
+                       goto err_gpio_loop;
+               }
+               gpiod_set_consumer_name(sel3350_leds[i].gpiod, sel3350_leds[i].name);
+       }
+
        sel3350->leds_pdev = platform_device_register_data(
                        NULL,
                        "leds-gpio",
@@ -209,11 +276,15 @@ static int sel3350_probe(struct platform_device *pdev)
 
        return 0;
 
+err_gpio_loop:
+       while (i--)
+               devm_gpiod_put(&pdev->dev, sel3350_leds[i].gpiod);
+       goto err_platform;
+
 err_ps:
        platform_device_unregister(sel3350->leds_pdev);
 err_platform:
        gpiod_remove_lookup_table(&sel3350_gpios_table);
-       gpiod_remove_lookup_table(&sel3350_leds_table);
 
        return rs;
 }
@@ -224,7 +295,6 @@ static void sel3350_remove(struct platform_device *pdev)
 
        platform_device_unregister(sel3350->leds_pdev);
        gpiod_remove_lookup_table(&sel3350_gpios_table);
-       gpiod_remove_lookup_table(&sel3350_leds_table);
 }
 
 static const struct acpi_device_id sel3350_device_ids[] = {