The patches were generated from the RPi repo with the following command: git format-patch v6.6.34..rpi-6.1.y Some patches needed rebasing and, as usual, the applied and reverted, wireless drivers, Github workflows, READMEs and defconfigs patches were removed. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
		
			
				
	
	
		
			236 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 4d47bc80314f4997d377eaf921d9ea2510a1b696 Mon Sep 17 00:00:00 2001
 | 
						|
From: Phil Elwell <phil@raspberrypi.com>
 | 
						|
Date: Mon, 13 Jul 2020 10:33:19 +0100
 | 
						|
Subject: [PATCH 0235/1085] leds: Add the actpwr trigger
 | 
						|
 | 
						|
The actpwr trigger is a meta trigger that cycles between an inverted
 | 
						|
mmc0 and default-on. It is written in a way that could fairly easily
 | 
						|
be generalised to support alternative sets of source triggers.
 | 
						|
 | 
						|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
 | 
						|
---
 | 
						|
 drivers/leds/trigger/Kconfig          |  11 ++
 | 
						|
 drivers/leds/trigger/Makefile         |   1 +
 | 
						|
 drivers/leds/trigger/ledtrig-actpwr.c | 190 ++++++++++++++++++++++++++
 | 
						|
 3 files changed, 202 insertions(+)
 | 
						|
 create mode 100644 drivers/leds/trigger/ledtrig-actpwr.c
 | 
						|
 | 
						|
--- a/drivers/leds/trigger/Kconfig
 | 
						|
+++ b/drivers/leds/trigger/Kconfig
 | 
						|
@@ -162,4 +162,15 @@ config LEDS_TRIGGER_TTY
 | 
						|
 
 | 
						|
 	  When build as a module this driver will be called ledtrig-tty.
 | 
						|
 
 | 
						|
+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
 | 
						|
--- a/drivers/leds/trigger/Makefile
 | 
						|
+++ b/drivers/leds/trigger/Makefile
 | 
						|
@@ -17,3 +17,4 @@ obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= led
 | 
						|
 obj-$(CONFIG_LEDS_TRIGGER_PATTERN)	+= ledtrig-pattern.o
 | 
						|
 obj-$(CONFIG_LEDS_TRIGGER_AUDIO)	+= ledtrig-audio.o
 | 
						|
 obj-$(CONFIG_LEDS_TRIGGER_TTY)		+= ledtrig-tty.o
 | 
						|
+obj-$(CONFIG_LEDS_TRIGGER_ACTPWR)	+= ledtrig-actpwr.o
 | 
						|
--- /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)) {
 | 
						|
+		del_timer_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 <phil@raspberrypi.com>");
 | 
						|
+MODULE_DESCRIPTION("ACT/PWR LED trigger");
 | 
						|
+MODULE_LICENSE("GPL v2");
 |