From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f195.google.com (mail-pl1-f195.google.com [209.85.214.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 E292D30101F for ; Tue, 30 Dec 2025 08:24:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.195 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767083063; cv=none; b=Rgzz6uaa+D3OodzNlVl2ZAMKSMfagsXjQo9WYicrfXQVLsj8HxVItDRfMOQjijpjC2DbPALDANszkD/R/WAmj2jXTGRcNv0+X9WVdXN2+znhNYvvbGN02agmaG4r9jUwvDfy+IOBsUkNlW51sie853BdTpljPTfPcgyaVQmes60= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767083063; c=relaxed/simple; bh=oWgzFPh6Xk63phUVjE1VPLOjLHvlEa4NlrrigjDqrDE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=H4VmriWwMRSy20uiGuvha52do4YcwYVESfYmRTrqxLol6tleLGQp0GPpzLiEv+I9uBTYeAJe1pxjIEGmOAtczJidQkWr23YhAJp1Uj5693CJEjfoAGFFkpOgPHkSA44koXama6gF3t2JFg0SDmzFKIkX4WloKLlYHF5cYSsaeSU= 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=Dzn9Sb+S; arc=none smtp.client-ip=209.85.214.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="Dzn9Sb+S" Received: by mail-pl1-f195.google.com with SMTP id d9443c01a7336-2a0c20ee83dso124606165ad.2 for ; Tue, 30 Dec 2025 00:24:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767083060; x=1767687860; 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=Dzn9Sb+St6XqiOEj31cJYDUGEqdduWkkN0Aqpl4yEuXInBfdyFEI05yMcs4E4puFPR UuS9Q4QPD7bhb5GQ6KU8KwBW2OUVZdX+wEYabdUScxQlCZYSL7dxCmt+dn9gorWmU2HY xSO4HEDsaQA9ZXNjReLHJdluo+lPMVaTplObZcFfxtyJon9tlMxBO7f80amYrFPZoDLa ozOvPXOiwKT4swAl+uHFr7yM2TyD7I2H6TIrnqoOcfU0GqXCdz5zZ0TlxG6CspB3Skr+ dB51vwfgSfw6hZH5GtKqCivVKruhd9nUX1+gzrH6YhXDWHvMHVh5xQO0Cta4SBrFcjXW aXvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767083060; x=1767687860; 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=VVDbTxAF+MVNi+dLnA4+44+EG4SwLB9H/j5Gj9Hr//Gt6D8zV2ZrPuQuQkFEW6h3no EON7pIRsgTxJMmeXsrPpLSBS4FBOZhW0u/Y5fzRxI2bUE3/C3SJ9LQMUWtZk6NIuG3kj bMFRBmNWHj4gd2HJ/j9MuWio71D8LQG6rt70XCjx0HHSfCDecwVrA2wBnpSKqBHZ5jUI fq4pNmxFH765tPalmU+hU25DXQN85qUFvigzMkjlIQX9nIRgY6cPJQzv14CyGWuc+ZfY bPaAWI04e3v+6lexQjT381YqEhzx6EvBX+UauwwC81y5Z90UIgZcslGSal4FwEnh0KxO 8REg== X-Forwarded-Encrypted: i=1; AJvYcCUlYCE5usK4HT3xpx0Dk/LzAysErYn0uowJaNZ6DxmMJRkBSXf6CuP4crbxxmRQ8DJV2l/Wq74/QXcnv24=@vger.kernel.org X-Gm-Message-State: AOJu0Yy2rTlskgYFbpxxTKtrm1hIhWFkf/xVMO3oaduuNGvrymxEb+7h tqsacu8FthBCVUj8e3NNRuUNRZEfiuCqqQ3Ie1MRkXMiCcLotMnfJuf4 X-Gm-Gg: AY/fxX6h5MZF4XX3eIx0UNGlB/aTBSHHSJ5TCqGCdquMx74Epogc+n3p82MEgodCAlh fxqmXNwIww2toV+rBo6UaE0Js0b5kywzUuHvBhGaGHjxHPF3issPTBiMtMDprO0eSeEo0PxhETJ dCFlt11q7m0tjBNJQtFOtp/4MV7QoETLIWj1NYGJEANTgAf4ZjtEmjDPY1ek3UsXJb/nP4O5Odo 1Ub7f4ULNME5FlXjjNGrYKySeLKr3TtmW6VXU3flH0UC1eh+LHwENHawyWBXiOYJrStAur3fvzY p5Jp4BZwXxHFeGFTue3jjiaMr9GPzGMKPgIGQs1O+7GkB4Ov4uDh82mTOyihSkyiA86qBWB64j7 cn3hKOrumfPPAU+xG8xnvT8izQn8ItP03Ea/KLv7uv+MGVLottOLgnjfir1YWoYZpr8qARH1CoC HPAa1VexTx5PUkFA//A2C3TbukpeMXIeU+ X-Google-Smtp-Source: AGHT+IHtCrAUeTD/uISslDzNozK0Y0TUYjuHImxHBxv7Ealh5CidI6dgpeLnUIIfYFsJVqOcq3FPVw== X-Received: by 2002:a17:902:e806:b0:290:cd9c:1229 with SMTP id d9443c01a7336-2a2f252489bmr327463445ad.19.1767083059924; Tue, 30 Dec 2025 00:24:19 -0800 (PST) Received: from MRSPARKLE.localdomain ([150.228.155.85]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3d76ceesm296667165ad.91.2025.12.30.00.24.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Dec 2025 00:24:19 -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 v5 5/7] leds: Add driver documentation for leds-group-virtualcolor Date: Tue, 30 Dec 2025 21:23:18 +1300 Message-ID: <20251230082336.3308403-6-professorjonny98@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251230082336.3308403-1-professorjonny98@gmail.com> References: <20251230082336.3308403-1-professorjonny98@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@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/: