linux/drivers/platform/x86/intel/int3472/led.c
Marco Nenciarini 0ec7f158dc
platform/x86: int3472: Add support for GPIO type 0x02 (IR flood LED)
Add support for GPIO type 0x02, which controls an IR flood LED used
for face authentication on some laptops (e.g. Dell Pro Max 16 Premium).

Without this patch, the kernel logs "GPIO type 0x02 unknown; the sensor
may not work" and IR sensors paired with a flood LED cannot function.

The flood LED is registered through the LED subsystem like the existing
privacy LED, including a lookup entry to allow future consumer drivers
to find and control it via led_get().

To support multiple LEDs per INT3472 device, convert the single led
struct member to an array with a counter.

Signed-off-by: Marco Nenciarini <mnencia@kcore.it>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Link: https://patch.msgid.link/20260401203638.1601661-5-mnencia@kcore.it
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
2026-04-13 14:09:49 +03:00

64 lines
1.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Author: Hans de Goede <hdegoede@redhat.com> */
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
#include <linux/platform_data/x86/int3472.h>
static int int3472_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
{
struct int3472_led *led = container_of(led_cdev, struct int3472_led, classdev);
gpiod_set_value_cansleep(led->gpio, brightness);
return 0;
}
int skl_int3472_register_led(struct int3472_discrete_device *int3472, struct gpio_desc *gpio,
const char *con_id)
{
struct int3472_led *led;
char *p;
int ret;
if (int3472->n_leds >= INT3472_MAX_LEDS)
return -ENOSPC;
led = &int3472->leds[int3472->n_leds];
led->gpio = gpio;
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
snprintf(led->name, sizeof(led->name),
"%s::%s_led", acpi_dev_name(int3472->sensor), con_id);
p = strchr(led->name, ':');
if (p)
*p = '_';
led->classdev.name = led->name;
led->classdev.max_brightness = 1;
led->classdev.brightness_set_blocking = int3472_led_set;
ret = led_classdev_register(int3472->dev, &led->classdev);
if (ret)
return ret;
led->lookup.provider = led->name;
led->lookup.dev_id = int3472->sensor_name;
led->lookup.con_id = con_id;
led_add_lookup(&led->lookup);
int3472->n_leds++;
return 0;
}
void skl_int3472_unregister_leds(struct int3472_discrete_device *int3472)
{
for (unsigned int i = 0; i < int3472->n_leds; i++) {
struct int3472_led *led = &int3472->leds[i];
led_remove_lookup(&led->lookup);
led_classdev_unregister(&led->classdev);
gpiod_put(led->gpio);
}
}