diff options
Diffstat (limited to 'drivers/leds/trigger')
| -rw-r--r-- | drivers/leds/trigger/Kconfig | 18 | ||||
| -rw-r--r-- | drivers/leds/trigger/Makefile | 2 | ||||
| -rw-r--r-- | drivers/leds/trigger/ledtrig-actpwr.c | 190 | ||||
| -rw-r--r-- | drivers/leds/trigger/ledtrig-input.c | 55 |
4 files changed, 265 insertions, 0 deletions
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index c11282a74b5a..c48c1c3e9e11 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -113,6 +113,13 @@ config LEDS_TRIGGER_CAMERA This enables direct flash/torch on/off by the driver, kernel space. If unsure, say Y. +config LEDS_TRIGGER_INPUT + tristate "LED Input Trigger" + depends on LEDS_TRIGGERS + help + This allows the GPIOs assigned to be LEDs to be initialised to inputs. + If unsure, say Y. + config LEDS_TRIGGER_PANIC bool "LED Panic Trigger" help @@ -161,4 +168,15 @@ config LEDS_TRIGGER_INPUT_EVENTS When build as a module this driver will be called ledtrig-input-events. +config LEDS_TRIGGER_ACTPWR + tristate "ACT/PWR Input Trigger" + depends on LEDS_TRIGGERS + help + This trigger is intended for platforms that have one software- + controllable LED and no dedicated activity or power LEDs, hence the + need to make the one LED perform both functions. It cycles between + default-on and an inverted mmc0 every 500ms, guaranteeing that it is + on for at least half of the time. + If unsure, say N. + endif # LEDS_TRIGGERS diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 3b3628889f68..35a6b611a9a9 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -11,8 +11,10 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o +obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o obj-$(CONFIG_LEDS_TRIGGER_INPUT_EVENTS) += ledtrig-input-events.o +obj-$(CONFIG_LEDS_TRIGGER_ACTPWR) += ledtrig-actpwr.o diff --git a/drivers/leds/trigger/ledtrig-actpwr.c b/drivers/leds/trigger/ledtrig-actpwr.c new file mode 100644 index 000000000000..d0428f669bfb --- /dev/null +++ b/drivers/leds/trigger/ledtrig-actpwr.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Activity/power trigger + * + * Copyright (C) 2020 Raspberry Pi (Trading) Ltd. + * + * Based on Atsushi Nemoto's ledtrig-heartbeat.c, although there may be + * nothing left of the original now. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/leds.h> +#include "../leds.h" + +enum { + TRIG_ACT, + TRIG_PWR, + + TRIG_COUNT +}; + +struct actpwr_trig_src { + const char *name; + int interval; + bool invert; +}; + +struct actpwr_vled { + struct led_classdev cdev; + struct actpwr_trig_data *parent; + enum led_brightness value; + unsigned int interval; + bool invert; +}; + +struct actpwr_trig_data { + struct led_trigger trig; + struct actpwr_vled virt_leds[TRIG_COUNT]; + struct actpwr_vled *active; + struct timer_list timer; + int next_active; +}; + +static int actpwr_trig_activate(struct led_classdev *led_cdev); +static void actpwr_trig_deactivate(struct led_classdev *led_cdev); + +static const struct actpwr_trig_src actpwr_trig_sources[TRIG_COUNT] = { + [TRIG_ACT] = { "mmc0", 500, true }, + [TRIG_PWR] = { "default-on", 500, false }, +}; + +static struct actpwr_trig_data actpwr_data = { + { + .name = "actpwr", + .activate = actpwr_trig_activate, + .deactivate = actpwr_trig_deactivate, + } +}; + +static void actpwr_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled, + cdev); + struct actpwr_trig_data *trig = vled->parent; + + if (vled->invert) + value = !value; + vled->value = value; + + if (vled == trig->active) + led_trigger_event(&trig->trig, value); +} + +static int actpwr_brightness_set_blocking(struct led_classdev *led_cdev, + enum led_brightness value) +{ + actpwr_brightness_set(led_cdev, value); + return 0; +} + +static enum led_brightness actpwr_brightness_get(struct led_classdev *led_cdev) +{ + struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled, + cdev); + + return vled->value; +} + +static void actpwr_trig_cycle(struct timer_list *t) +{ + struct actpwr_trig_data *trig = &actpwr_data; + struct actpwr_vled *active; + + active = &trig->virt_leds[trig->next_active]; + trig->active = active; + trig->next_active = (trig->next_active + 1) % TRIG_COUNT; + + led_trigger_event(&trig->trig, active->value); + + mod_timer(&trig->timer, jiffies + msecs_to_jiffies(active->interval)); +} + +static int actpwr_trig_activate(struct led_classdev *led_cdev) +{ + struct actpwr_trig_data *trig = &actpwr_data; + + /* Start the timer if this is the first LED */ + if (!trig->active) + actpwr_trig_cycle(&trig->timer); + else + led_set_brightness_nosleep(led_cdev, trig->active->value); + + return 0; +} + +static void actpwr_trig_deactivate(struct led_classdev *led_cdev) +{ + struct actpwr_trig_data *trig = &actpwr_data; + + if (list_empty(&trig->trig.led_cdevs)) { + timer_delete_sync(&trig->timer); + trig->active = NULL; + } +} + +static int __init actpwr_trig_init(void) +{ + struct actpwr_trig_data *trig = &actpwr_data; + int ret = 0; + int i; + + timer_setup(&trig->timer, actpwr_trig_cycle, 0); + + /* Register one "LED" for each source trigger */ + for (i = 0; i < TRIG_COUNT; i++) + { + struct actpwr_vled *vled = &trig->virt_leds[i]; + struct led_classdev *cdev = &vled->cdev; + const struct actpwr_trig_src *src = &actpwr_trig_sources[i]; + + vled->parent = trig; + vled->interval = src->interval; + vled->invert = src->invert; + cdev->name = src->name; + cdev->brightness_set = actpwr_brightness_set; + cdev->brightness_set_blocking = actpwr_brightness_set_blocking; + cdev->brightness_get = actpwr_brightness_get; + cdev->default_trigger = src->name; + ret = led_classdev_register(NULL, cdev); + if (ret) + goto error_classdev; + } + + ret = led_trigger_register(&trig->trig); + if (ret) + goto error_classdev; + + return 0; + +error_classdev: + while (i > 0) + { + i--; + led_classdev_unregister(&trig->virt_leds[i].cdev); + } + + return ret; +} + +static void __exit actpwr_trig_exit(void) +{ + int i; + + led_trigger_unregister(&actpwr_data.trig); + for (i = 0; i < TRIG_COUNT; i++) + { + led_classdev_unregister(&actpwr_data.virt_leds[i].cdev); + } +} + +module_init(actpwr_trig_init); +module_exit(actpwr_trig_exit); + +MODULE_AUTHOR("Phil Elwell <[email protected]>"); +MODULE_DESCRIPTION("ACT/PWR LED trigger"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/trigger/ledtrig-input.c b/drivers/leds/trigger/ledtrig-input.c new file mode 100644 index 000000000000..8a974a355656 --- /dev/null +++ b/drivers/leds/trigger/ledtrig-input.c @@ -0,0 +1,55 @@ +/* + * Set LED GPIO to Input "Trigger" + * + * Copyright 2015 Phil Elwell <[email protected]> + * + * Based on Nick Forbes's ledtrig-default-on.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include "../leds.h" + +static int input_trig_activate(struct led_classdev *led_cdev) +{ + led_cdev->flags |= SET_GPIO_INPUT; + led_set_brightness(led_cdev, 0); + return 0; +} + +static void input_trig_deactivate(struct led_classdev *led_cdev) +{ + led_cdev->flags |= SET_GPIO_OUTPUT; + led_set_brightness(led_cdev, 0); +} + +static struct led_trigger input_led_trigger = { + .name = "input", + .activate = input_trig_activate, + .deactivate = input_trig_deactivate, +}; + +static int __init input_trig_init(void) +{ + return led_trigger_register(&input_led_trigger); +} + +static void __exit input_trig_exit(void) +{ + led_trigger_unregister(&input_led_trigger); +} + +module_init(input_trig_init); +module_exit(input_trig_exit); + +MODULE_AUTHOR("Phil Elwell <[email protected]>"); +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); |
