From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f195.google.com (mail-pf1-f195.google.com [209.85.210.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E4932DA742 for ; Tue, 30 Dec 2025 00:33:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.195 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767054820; cv=none; b=dQTPIXHNj+EZcNlRpwhDs6YfTUnfhQL30XmbA1n9hTA/XNUypIukvFO6iuV5a9c13M1G2o5/S9eQ1T4iEhIaMoh4Dq3Egwu/nTJme83PQ2hBS2/fYGz74U3JOd5+XVBqx+YaZG10dtTYEd30nO0U87kyHohpSasIymCFI9KTbu8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767054820; c=relaxed/simple; bh=oWgzFPh6Xk63phUVjE1VPLOjLHvlEa4NlrrigjDqrDE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cz45dERemXMrh4/G1ayElj+Zazo0d2sD68GkomYOi1SBmYrC1spHXVf00XZzgybIntDIN83/Y3NbhMC5SDNm670JMqo3lXr5JbGNS65mY+6wEub7lnDR4PwbbEgHX/FRrB+YeYNPGJXt1fVFfcUXDVAeKdmYvR347R/tlVOa9Fk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=evvtKJky; arc=none smtp.client-ip=209.85.210.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="evvtKJky" Received: by mail-pf1-f195.google.com with SMTP id d2e1a72fcca58-7f1243792f2so6352374b3a.1 for ; Mon, 29 Dec 2025 16:33:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767054816; x=1767659616; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=h8GT9Ha1jA/0OeYqmx0KDJpRc2kzNe9zv0KeqP7AQN8=; b=evvtKJkyPsnen2UpmTKuZR2VvrD8hXZSxbMbd+7TY9SWlelLbDuo4fx9ToOpCYSFWB PeaaAITRKa/mvNOIkAkZU79IbVqXqoGzqsoSe4XiQUZ1fU5dzzSebCGC89WD16OjZuU2 KUoH2wMEUnTKf+32c1gP9zvshWY451ymNIaOBojeyxPeBc1spz+48uLSknzomuUbaBiK D/mFoD0/LHrNnLSoDvpbmFNfMOI7XCx4O2BL/WnwaeabjzsfF6bvxIcbSwiMTE8JRGRK LYl7NAqO0Y4TdW2kRnQW5s2lnuH0Jes23YhWRqtNCSbymL48jqhoVfurcYiU7bkUwQIZ a7EQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767054816; x=1767659616; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=h8GT9Ha1jA/0OeYqmx0KDJpRc2kzNe9zv0KeqP7AQN8=; b=vkCNc1IFn7KuBUMgG2sho9J+7HWQqwBvhGLTxqrH8C+mcvxLh6B1JsR2ZJaRBeS5Ry AZTp2siDzOEarOTuBi7cDDgSd6oVAP6cN9yENvcga+IiYFlOt6XmPRJ66ycrIjowfFsL 1rU3/TTjT/twWPTsgz5R8kwOk3Y/QLepGVbtHXY+pWchPs/r2D2faREnFPdc2BmIlNFF /MvNVDMDrHk2NayL29qIveVbfyWFqqH9r3xta8G0vadbTwhfBTCpz87kGcv+ArJPE0BP 4h4R8Thnp8VkPeOoA6nyUIKijkbIzStdkZKE/FdzLMRfoYEi9kRZ2QwFPokj1rOAbWXW N2Wg== X-Gm-Message-State: AOJu0YwXOESFe1iyvrmXrlKolPPSmx6ilkSRbRiwkIDeAbw6LhY2j3f4 OQThN/EpC3/6hSgE35T9VHVTZM58EzPqBTHlrZQ92hPd3i6/KmDnPd6x X-Gm-Gg: AY/fxX7okEZDme7Y4wjSOE2Rf0zMRhn2xm0C65zgUBeTE4bU/5SJUAxZfKkCClJILp8 eelHUjxHo6F+4V0153lNjZgU5ehWi+XksFRPK6X1FyAB4t3nNJpEb1Rxa3luh2HACxDXGYquL3c QAGCC3b0sqsZqJUKEp6E4Keo2wYTsg4lWpNYGgUzgIIwpUqK6Vzh24u7B9lg8B//W1oATxMNQ6u pg4/USA+oAkOv4do8pnOxBBZSm04uuzmKI+fvB5gbV1A94aKc4BTnvLG+WkHeZTZDSp97FcKR+T 2nTKN796hbDDhA/zWEVenHtibLRZNx60Wd8zH3decP2hNBoNNjHYddRzs1DQ+bE17iDhhmxMT74 6ath28oX3YCiRCzkw9NFRLcktxuo798anb+s/7r0ThXIYwqYSnUn2DLcX40jRzfwcpKS1RjQqWj T8a2y8JhQBklmIUJAmnsvaMUi5hmxW/5VE X-Google-Smtp-Source: AGHT+IHYb88URjQs672V28Syx/JIuf5lE0zhX1nasVzffgjk5A/E2i1g8LowgnvI1JU0x6zqLRL3DA== X-Received: by 2002:a05:6a00:438d:b0:7e8:43f5:bd5a with SMTP id d2e1a72fcca58-7ff67852a95mr28023491b3a.70.1767054815436; Mon, 29 Dec 2025 16:33:35 -0800 (PST) Received: from MRSPARKLE.localdomain ([150.228.155.85]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e8947a1sm30241562b3a.67.2025.12.29.16.33.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 16:33:35 -0800 (PST) From: Jonathan Brophy To: lee Jones , Pavel Machek , Andriy Shevencho , Jonathan Brophy , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Radoslav Tsvetkov Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v4 5/7] leds: Add driver documentation for leds-group-virtualcolor Date: Tue, 30 Dec 2025 13:32:42 +1300 Message-ID: <20251230003250.1197744-6-professorjonny98@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251230003250.1197744-1-professorjonny98@gmail.com> References: <20251230003250.1197744-1-professorjonny98@gmail.com> Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=y Content-Transfer-Encoding: 8bit From: Jonathan Brophy Add comprehensive driver documentation covering: Architecture: - Winner-takes-all arbitration model - Priority-based selection with sequence number tie-breaking - Deterministic channel ordering by LED_COLOR_ID - Locking hierarchy to prevent deadlocks Features: - Two operating modes (multicolor and standard) - Gamma correction support - Update batching for reduced bus traffic - Comprehensive debugfs interface (when CONFIG_DEBUG_FS enabled) Configuration: - Device tree binding examples (RGB, RGBW, fixed-color) - Module parameters for tuning - Sysfs interface usage examples - Performance optimization guidelines Troubleshooting: - Common issues and solutions - Debug logging instructions - Known limitations The documentation includes practical examples for channel ordering verification, priority arbitration scenarios, and debugfs monitoring. Signed-off-by: Jonathan Brophy --- .../leds/leds-group-virtualcolor.rst | 641 ++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 Documentation/leds/leds-group-virtualcolor.rst diff --git a/Documentation/leds/leds-group-virtualcolor.rst b/Documentation/leds/leds-group-virtualcolor.rst new file mode 100644 index 000000000000..a885fc614840 --- /dev/null +++ b/Documentation/leds/leds-group-virtualcolor.rst @@ -0,0 +1,641 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================================== +Virtual Grouped LED Driver with Multicolor ABI +===================================================== + +:Author: Jonathan Brophy +:Version: 4 + +Overview +======== + +The ``leds-group-virtualcolor`` driver provides virtual LED devices that +arbitrate control over shared physical LEDs based on priority. Multiple +virtual LEDs can reference the same physical LEDs, with winner-takes-all +arbitration determining which virtual LED controls the hardware. + +This enables complex lighting scenarios where different subsystems (e.g., +notifications, indicators, effects) can request LED control without explicit +coordination. The driver handles arbitration automatically using a +priority-based system with sequence number tiebreaking. + +Key Features +============ + +* **Winner-takes-all arbitration**: Only ONE virtual LED controls hardware at any time +* **Priority-based selection**: Higher priority virtual LEDs win control +* **Sequence-based tiebreaking**: Most recent update wins among equal priorities +* **Multicolor ABI support**: Standard Linux multicolor LED interface +* **Deterministic channel ordering**: Channels sorted by LED_COLOR_ID value +* **Two operating modes**: + + - Multicolor mode (dynamic color mixing with intensity control) + - Standard mode (fixed color multipliers, brightness-only control) + +* **Gamma correction**: Optional perceptual brightness correction +* **Update batching**: Debounces rapid changes to reduce bus traffic +* **Comprehensive debugfs**: Runtime statistics and diagnostics (when CONFIG_DEBUG_FS enabled) +* **Power management**: Suspend/resume with state preservation + +Hardware Support +================ + +The driver works with any physical LED devices that expose the standard +``led_classdev`` interface. Physical LEDs are referenced via device tree +phandles and can be: + +* GPIO LEDs (gpio-leds compatible) +* PWM LEDs (pwm-leds compatible) +* I2C-connected LED controllers +* SPI-connected LED controllers +* Any device using the Linux LED subsystem + +Architecture +============ + +Winner-Takes-All Arbitration +----------------------------- + +The driver uses a winner-takes-all arbitration model: + +1. Only virtual LEDs with brightness > 0 participate in arbitration +2. The virtual LED with the highest priority wins +3. If priorities are equal, the most recently updated virtual LED wins (sequence number) +4. The winner controls **ALL** physical LEDs +5. Physical LEDs not used by the winner are turned off + +Each virtual LED has: + +* **Priority** (0 to INT_MAX): Higher values win arbitration +* **Sequence number**: Atomic counter incremented on brightness changes +* **Channel configuration**: Maps physical LEDs to color channels + +Channel Ordering +---------------- + +Physical LEDs are automatically grouped into channels by their color property. +**Channels are ordered by ascending LED_COLOR_ID value** (0, 1, 2, 3, ...). + +This ordering is deterministic and can be verified at runtime via the +``multi_index`` sysfs attribute. + +Example color ID values: + +* LED_COLOR_ID_WHITE = 0 +* LED_COLOR_ID_RED = 1 +* LED_COLOR_ID_GREEN = 2 +* LED_COLOR_ID_BLUE = 3 +* LED_COLOR_ID_AMBER = 4 +* LED_COLOR_ID_VIOLET = 5 + +For a virtual LED with ``leds = <&white>, <&red>, <&green>, <&blue>``: + +* Channel order: [0]=white (ID 0), [1]=red (ID 1), [2]=green (ID 2), [3]=blue (ID 3) +* multi_index reports: "0 1 2 3" +* multi_intensity order: white red green blue + +For a virtual LED with ``leds = <&red>, <&green>, <&blue>`` (no white): + +* Channel order: [0]=red (ID 1), [1]=green (ID 2), [2]=blue (ID 3) +* multi_index reports: "1 2 3" +* multi_intensity order: red green blue + +Brightness Calculation +---------------------- + +Final physical LED brightness is calculated as:: + + channel_value = intensity * multiplier / 255 (in multicolor mode) + multiplier (in standard mode) + + scaled_value = channel_value * vled_brightness / vled_max_brightness + + final_brightness = gamma_table[scaled_value] (if gamma enabled) + scaled_value (if gamma disabled) + +Locking Hierarchy +----------------- + +To prevent deadlocks, locks must be acquired in this order: + +1. ``vcolor_controller.lock`` (per-controller, protects arbitration state) +2. ``global_owner_rwsem`` (global, protects physical LED ownership) +3. ``virtual_led.lock`` (per-vLED, protects channel data) + +Virtual LED locks are never held during arbitration. The driver copies +channel state under lock, then releases before processing. + +Device Tree Bindings +==================== + +Controller Node +--------------- + +``compatible`` + Must be "leds-group-virtualcolor" + +``#address-cells`` + Must be 1 + +``#size-cells`` + Must be 0 + +Child Node Properties (Virtual LEDs) +------------------------------------- + +Each child node represents one virtual LED. + +``reg`` + Unique index for this virtual LED (required) + +``color`` + LED_COLOR_ID value (typically LED_COLOR_ID_MULTI for multicolor LEDs) + +``function`` + LED function identifier (e.g., LED_FUNCTION_STATUS) + +``leds`` + Phandle array referencing physical LED devices (required). + Physical LEDs are grouped by their color property into channels. + Channel order is determined by ascending LED_COLOR_ID value. + +``priority`` + Integer priority value (0 to 2147483647). Higher values win + arbitration. Default: 0 + +``led-mode`` + Operating mode, either "multicolor" or "standard". + Default: "multicolor" + + * **multicolor**: Intensity can be changed via multi_intensity sysfs + * **standard**: Color fixed by multipliers, only brightness control available + +``mc-channel-multipliers`` + Array of u32 values (0-255), one per color channel. Optional. + Must be ordered to match the channel order (sorted by color ID). + Default: 255 for all channels + + * In multicolor mode: Scales intensity values + * In standard mode: Defines fixed color mix (required) + +``linux,default-trigger`` + Default LED trigger (e.g., "heartbeat", "none") + +Example Device Tree +------------------- + +Basic RGB LED with Priority +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: dts + + #include + + virtualcolor { + compatible = "leds-group-virtualcolor"; + #address-cells = <1>; + #size-cells = <0>; + + notification_led: virtual-led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_STATUS; + priority = <100>; + led-mode = "multicolor"; + leds = <&red_led>, <&green_led>, <&blue_led>; + /* Channels: [0]=red (ID 1), [1]=green (ID 2), [2]=blue (ID 3) */ + }; + + ambient_led: virtual-led@1 { + reg = <1>; + color = ; + function = LED_FUNCTION_STATUS; + priority = <10>; + led-mode = "multicolor"; + leds = <&red_led>, <&green_led>, <&blue_led>; + }; + }; + +RGBW LED with White Channel +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: dts + + virtualcolor { + compatible = "leds-group-virtualcolor"; + #address-cells = <1>; + #size-cells = <0>; + + status_led: virtual-led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_STATUS; + priority = <100>; + led-mode = "multicolor"; + leds = <&red_led>, <&green_led>, <&blue_led>, <&white_led>; + /* Channels: [0]=white (ID 0), [1]=red, [2]=green, [3]=blue */ + /* Note: White comes FIRST because LED_COLOR_ID_WHITE = 0 */ + }; + }; + +Standard Mode with Fixed Color +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: dts + + virtualcolor { + compatible = "leds-group-virtualcolor"; + #address-cells = <1>; + #size-sizes = <0>; + + warm_white: virtual-led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_STATUS; + priority = <50>; + led-mode = "standard"; + leds = <&red_led>, <&green_led>, <&blue_led>; + mc-channel-multipliers = <255 180 100>; + /* Channels: [0]=red:255, [1]=green:180, [2]=blue:100 */ + /* Creates warm white: full red, 70% green, 40% blue */ + }; + }; + +Sysfs Interface +=============== + +Each virtual LED creates a standard LED class device at:: + + /sys/class/leds/: