From nobody Tue Dec 2 00:46:26 2025 Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) (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 CE8D819E7D1 for ; Sun, 23 Nov 2025 19:11:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925063; cv=none; b=krIS+Eey4qdgmBQF5KdAq7DhpB6ffajxFUlpTuT7F/lrWTJqapTLhxIkyhd9KMuq6WSA9NBFXHtScFhrUAWMvft9iRXHs9cTDCe4KZoTiYWIR8/gZet1MnlQQc5SNmNseaxeZYQN9Q0KHPdxPl7NV69j1tkeouNBl4og3hdfWsE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925063; c=relaxed/simple; bh=W+d111LR+xNx3RKW8XANYn1tFwiI7uSiriuB+9Vemgc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sG1bUrIyDGQdRSsa7kwy0RJNGGTLzi6N743T5tRiGibYu73igFvKC61YyQDnHJK8aQiMm4KUt2fdN/sImxTQWw6KijfQE72uIA8qTx0PoPGhFpl5XJBGmhzlE71U81PnWFEOdkNl3r7LDIDfLKwtFC/2QNyf2ifg22m2RDzoxuQ= 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=K7oJ8stR; arc=none smtp.client-ip=209.85.214.182 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="K7oJ8stR" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-299d40b0845so59637095ad.3 for ; Sun, 23 Nov 2025 11:11:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763925061; x=1764529861; 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=snR5Ie8ioOVLlQgQYszHxBdrNEYSsK+md57vZ0OA05A=; b=K7oJ8stRncxOmLzI0RIpJe1ptAsj/UNjCZzu04s0VyghasLPCgymeC9j2bAuwV3V7I jRrieF/EZls2wnGFRIic0npOzQcSTjxC+QAY+T+dl4vXEWkqgQJVmi+uhlRymVQmfCCi HYlVpJ58sTit5JATAnKf0oOXP4lzuANEiE/1DdF4W318thlNJm4oEWRdycMnHdw8+an1 q7C9zvAgbeuZFLWztYh3yCpQbMRG5Cg/2PsdgQm6PMQ1YyEpyjlZTSyXKlc7yQhkQhl5 Wj2jmwCZ5mxi/Bi7qWkuMuDG19hGgYUeiI8qAMuNbAK6d19dW7xNZ62+Hfpbtzhzj/0q Q9Ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763925061; x=1764529861; 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=snR5Ie8ioOVLlQgQYszHxBdrNEYSsK+md57vZ0OA05A=; b=hx6N0Xh+E2830KLoEpf4SVu1JknJ56EDJiC/xOt0TWPnmLPEmDLzabDCYI4GAeLe8U eZ/XB6HtY9orDeWTVAMOA2oeZjpqPnZqkC1imZnz/QtJfqZZN7p3CzK9GWetNg3lNDtP p8tE9THlFPTm01CPRzxtQu6Xy08IBIfm+q/TQkP5Eb+6y4DaI7RSdDaONXi+PbMsdi5M GyBOI97wKxj8OnjIycCfK+fh5bHh6cNOKi5P33hccCPrM9WqizVaWo4Fl+Mm6nxkREsC gDGR6bStPDwEwWbcCiXCsa2jBFDNfWCOBdaj5BfIPkf5gJSywH3yVyjFlj7CK7CThw5R XaCg== X-Forwarded-Encrypted: i=1; AJvYcCWZk4cMJ3XXvp6/PFmIltQZ4rNIbmAemhS5mOnZxmGWQNd0hhrQkcdrKvT2/OfWO55QA0M6f4cLtuu46eM=@vger.kernel.org X-Gm-Message-State: AOJu0YzpTmb2ukztObWgMDLERdYumMrpi0CHqNK+1d4kMHd2kWC4Kdgn 4HbmkwoiRcADIUS3t6+Eo9aHvyEQEJRfyFKFizc7va0S1ciswrthJGcK X-Gm-Gg: ASbGncvp77tS3d6xwXg0U9GLxqK1Id/A6Oith+5695yaZeZPY3cMUmhmVdiH7YEk0jS KHfGa1W8ck/zgPFmggcOv7amf11Lx5OoK4lqODqDUJO1xN/v1/pSZ7ublm7oOtmPk0Q/GO7vC0i BWXcJn0jnNrpNhRTHMuvdphyD/eqPzIRKwTZvVbD7njtcYDPG/cvHrtAk+WqddWPLEgKdLR9C3x 6mlrJRL7/YOEhKKFKvfi3AXP8+jaH+IA1svbl97kGJvxsqxPzLOVeme4rrHpM1wdMiA9vfsK0jq i2WG6XL5jBvgCPtp/dG8IS+GY49G9DiJJK1hTitGWw2yDKAZPSNUuZGqhumOqClFMFXw/M3iHbB 4MtBIL78f09wJjTGWA9xSuTOJ+ZDTbn/UplJFS8B+ovjRYWoz3vYBkKmC2oZR/nKwhUhRUQvIZ6 Bruv5XbQOED1jvExdNRuwGpw== X-Google-Smtp-Source: AGHT+IF0RXexou+mQLUqo3Kt/PJPWss92seMrQ3+jlkSL30o1VIH5TwjhSWy6HXLhbOc2rDL5Zr0QQ== X-Received: by 2002:a17:903:2346:b0:29b:5c65:4531 with SMTP id d9443c01a7336-29b6bf806c7mr108223425ad.59.1763925061145; Sun, 23 Nov 2025 11:11:01 -0800 (PST) Received: from DESKTOP-P76LG1N.lan ([42.116.199.188]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29b5b13e720sm109542655ad.42.2025.11.23.11.10.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Nov 2025 11:11:00 -0800 (PST) From: Nam Tran To: lee@kernel.org Cc: pavel@kernel.org, gregkh@linuxfoundation.org, rdunlap@infradead.org, christophe.jaillet@wanadoo.fr, krzk+dt@kernel.org, robh@kernel.org, conor+dt@kernel.org, corbet@lwn.net, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-doc@vger.kernel.org, Nam Tran Subject: [PATCH v18 1/3] dt-bindings: leds: add TI/National Semiconductor LP5812 LED Driver Date: Mon, 24 Nov 2025 02:10:40 +0700 Message-Id: <20251123191042.116917-2-trannamatk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251123191042.116917-1-trannamatk@gmail.com> References: <20251123191042.116917-1-trannamatk@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The LP5812 is a 4x3 RGB LED driver with an autonomous animation engine and time-cross-multiplexing (TCM) support for up to 12 LEDs or 4 RGB LEDs. It supports both analog (256 levels) and PWM (8-bit) dimming, including exponential PWM for smooth brightness control. Signed-off-by: Nam Tran --- .../devicetree/bindings/leds/ti,lp5812.yaml | 251 ++++++++++++++++++ MAINTAINERS | 6 + 2 files changed, 257 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/ti,lp5812.yaml diff --git a/Documentation/devicetree/bindings/leds/ti,lp5812.yaml b/Docume= ntation/devicetree/bindings/leds/ti,lp5812.yaml new file mode 100644 index 000000000000..ea9d6ae92344 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/ti,lp5812.yaml @@ -0,0 +1,251 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/ti,lp5812.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI LP5812 4x3 Matrix RGB LED Driver with Autonomous Control + +maintainers: + - Nam Tran + +description: | + The LP5812 is a 4x3 matrix RGB LED driver with I2C interface + and autonomous animation engine control. + For more product information please see the link below: + https://www.ti.com/product/LP5812#tech-docs + +properties: + compatible: + const: ti,lp5812 + + reg: + maxItems: 1 + + ti,scan-mode: + description: | + Selects the LED scan mode of the LP5812. The device supports + three modes: + - Direct-drive mode (by default if 'ti,scan-mode' is omitted) + drives up to 4 LEDs directly by internal current sinks (LED0-LED3). + - TCM-drive mode ("tcm::") drives up to 12 LEDs + (4 RGB) using 1-4 scan multiplexing. The specifies the number + of scans (1-4), and defines the scan order of the outpu= ts. + - Mix-drive mode ("mix:::") combines + direct-drive and TCM-drive outputs. The specifies the number + of scans, selects the direct-drive outputs, and + defines the scan order. + $ref: /schemas/types.yaml#/definitions/string + pattern: '^(tcm|mix):[1-4](:[0-3]){1,4}$' + + vcc-supply: + description: Regulator providing power to the 'VCC' pin. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-3]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 3 + + required: + - reg + - label + + "^multi-led@[4-7]$": + type: object + $ref: leds-class-multicolor.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 4 + maximum: 7 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[4-9a-f]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 4 + maximum: 15 + + required: + - reg + + required: + - reg + - label + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + led-controller@1b { + #address-cells =3D <1>; + #size-cells =3D <0>; + compatible =3D "ti,lp5812"; + reg =3D <0x1b>; + ti,scan-mode =3D "tcm:4:0:1:2:3"; + vcc-supply =3D <&vdd_3v3_reg>; + + led@0 { + reg =3D <0x0>; + label =3D "LED0"; + led-max-microamp =3D <25500>; + }; + + led@1 { + reg =3D <0x1>; + label =3D "LED1"; + led-max-microamp =3D <25500>; + }; + + led@2 { + reg =3D <0x2>; + label =3D "LED2"; + led-max-microamp =3D <25500>; + }; + + led@3 { + reg =3D <0x3>; + label =3D "LED3"; + led-max-microamp =3D <25500>; + }; + + multi-led@4 { + #address-cells =3D <1>; + #size-cells =3D <0>; + reg =3D <0x4>; + color =3D ; + label =3D "LED_A"; + + led@4 { + reg =3D <0x4>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@5 { + reg =3D <0x5>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@6 { + reg =3D <0x6>; + color =3D ; + led-max-microamp =3D <25500>; + }; + }; + + multi-led@5 { + #address-cells =3D <1>; + #size-cells =3D <0>; + reg =3D <0x5>; + color =3D ; + label =3D "LED_B"; + + led@7 { + reg =3D <0x7>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@8 { + reg =3D <0x8>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@9 { + reg =3D <0x9>; + color =3D ; + led-max-microamp =3D <25500>; + }; + }; + + multi-led@6 { + #address-cells =3D <1>; + #size-cells =3D <0>; + reg =3D <0x6>; + color =3D ; + label =3D "LED_C"; + + led@a { + reg =3D <0xa>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@b { + reg =3D <0xb>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@c { + reg =3D <0xc>; + color =3D ; + led-max-microamp =3D <25500>; + }; + }; + + multi-led@7 { + #address-cells =3D <1>; + #size-cells =3D <0>; + reg =3D <0x7>; + color =3D ; + label =3D "LED_D"; + + led@d { + reg =3D <0xd>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@e { + reg =3D <0xe>; + color =3D ; + led-max-microamp =3D <25500>; + }; + + led@f { + reg =3D <0xf>; + color =3D ; + led-max-microamp =3D <25500>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 6df89b14b521..22da152c3c87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25448,6 +25448,12 @@ S: Supported F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml F: drivers/iio/dac/ti-dac7612.c =20 +TEXAS INSTRUMENTS' LP5812 RGB LED DRIVER +M: Nam Tran +L: linux-leds@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/leds/ti,lp5812.yaml + TEXAS INSTRUMENTS' LB8864 LED BACKLIGHT DRIVER M: Alexander Sverdlin L: linux-leds@vger.kernel.org --=20 2.25.1 From nobody Tue Dec 2 00:46:26 2025 Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) (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 D539121D585 for ; Sun, 23 Nov 2025 19:11:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925072; cv=none; b=pdNeS4HhG0sSGaiprjtfVX6uEb/ntKtxxXYybgJJMN78QfM4CxKubT2PM3FLEDabJVZ0B5nmrJLsGP+PJ2rzA2CEYu7/MGEgK4sYfqA4VpHBdmBmLKw6alaYwQCUQ8MBqRUjYllZqlG+YnNalhq1Joo/db6PxuIwZ32AtmTgDd8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925072; c=relaxed/simple; bh=O18plpShV+fchMUltKYvzGY56U0ZJBnotTRON8MyPm0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=WlFaCtfaGjhnj1CXnIGfwKn+XoJUzNrr6VnNOflo4JwCtgDlzPWZ/6s0gdZ78QiJA5GlM/dxfTWMm1nZVh9isF+DSy8Au76K/3v/cVrS+f5s0NLez2hOM7zxg3AP3NSbd+2geXW0ZxFw42ZvJF3269Wuf+NB6o55BskGqDb6ch4= 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=YcS4NAY7; arc=none smtp.client-ip=209.85.214.175 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="YcS4NAY7" Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-298145fe27eso58398355ad.1 for ; Sun, 23 Nov 2025 11:11:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763925067; x=1764529867; 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=cyY8yfoYlTTD3ZiROTexVERYQH2FovLAoeHxnuHoIL4=; b=YcS4NAY7kWUneQlvkTqVw9RmRdiBmVWiwfffEE0gQbg+4Vx4WSskEaXyknMnJDvmyy uWcEO2V78/QUeeepMoGBVoZX5SdnBhu/o3rllhjzi7KML5KXsSwtBzJQ9841KFwQuy+6 0oVUcsS0tGX0CXLE4DntzK/U8dNycLQ4M8jtUIFG9TEmNwfVLk8dTWHSU8ryguPAZ3Fu PS+uuOdaAYoSGjd8HAWKxzsoeOatGBpAM8cIJtu9875iIVZLDwMWMGTlGz69t4xAXuKc ocl+U3AmLokJZLHR9twRjQSYhBdI5Y2nsWAELtaf0WJiRF/AW2Hfg668VRdQ+yOWv5Op tNVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763925067; x=1764529867; 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=cyY8yfoYlTTD3ZiROTexVERYQH2FovLAoeHxnuHoIL4=; b=Ea5m9leyEMH73ikAY9muaHByh/r+ewYK2aEDEnk44LRMgRwT1PBuVOlz2iJhZlAk3N TG1U0ZmeJkYo9AH+GZrqijrl+R38CmRbmQZ2DZvAldR/h/+9j4TF63A/cDQZlvoFhEkP q3QN3nzedjNXNQbtAifH9hhrP7O2YM00ltbydCGsVTQxm4hFZuDgohBc2P4Dvhn5q7Je Wl+ouKYfAUDPU14BWZNxArmf+TnZ03ZQreUKu73mCnsP33QjZ2Qak6m9h3l6IsyCAXic D2tki+WSVmrdsocWbTJNjR67C3r41/bJ69X+gCSkCB802c131TPMYRVEzdUa9zpcsc4A b3cA== X-Forwarded-Encrypted: i=1; AJvYcCUwdWFMmf4UdXvPaV8m3hZrHSrEVKD9phYVdxwoopownPo/sq6CxCeza2sPEjhWMyTgIfRjDnRC+DvG2T0=@vger.kernel.org X-Gm-Message-State: AOJu0YwdsUYnQa8JC0VZ/2+jHTISuDvnC0nKi+IO/ylJjCSCC8SnHcTX RGlsxAIfgjyP+KsC04mkslgWiXxGHooEGgAMlM8UMuBoLxhVM02CHECX X-Gm-Gg: ASbGnctLsvA26eykn1p57WYeJ2sfmZD1Ynrra3/JX7u7utW7hgRookcHT5rJBrQF5MU BYCkerktP4AA1F0rPIYROxU7qOm9DuQMkrV9TMpdoDSy+NZw3RV/8AW0FRcyjBKrqJ42RIw1Uxu CHWJBDuxJd0X/1zlMhzHCdlr1fLhl4R2NSpG/tJbcpYu2JBfJJ8W1X4hQhp4MXLVAhig+VWCIX3 OleYDkwpQt9yPV3wTIA1A7pcSysvQBJomsCngbXY2ZVf0ylxFHV8QQZ/lxDCvKKpctl8edKfHQA idWRmVvNepgNrVprhFPyb3j9QS/c5Q1wG/NXTYxRQapvWhJQzQQct5ysz0k/nm9QW1kHo0aBBvV Qp03Ul1mHPbOJnqOkV3KgyxnEI5canWiweihqO2VbisdSbvUep/U6pfmjC2IstVqwsZ3amYmW4a HEIT/b/1kErVyKESli+YPCTg== X-Google-Smtp-Source: AGHT+IEdn990VS6mIQgE7tE5DSzyxK+qGQZSd+broKw5osyU92CnIjEPsGRx3SdB01/BLY7WtxSiZg== X-Received: by 2002:a17:903:2985:b0:298:1830:6ada with SMTP id d9443c01a7336-29b6bf19c83mr111145565ad.30.1763925066725; Sun, 23 Nov 2025 11:11:06 -0800 (PST) Received: from DESKTOP-P76LG1N.lan ([42.116.199.188]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29b5b13e720sm109542655ad.42.2025.11.23.11.11.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Nov 2025 11:11:05 -0800 (PST) From: Nam Tran To: lee@kernel.org Cc: pavel@kernel.org, gregkh@linuxfoundation.org, rdunlap@infradead.org, christophe.jaillet@wanadoo.fr, krzk+dt@kernel.org, robh@kernel.org, conor+dt@kernel.org, corbet@lwn.net, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-doc@vger.kernel.org, Nam Tran Subject: [PATCH v18 2/3] leds: add basic support for TI/National Semiconductor LP5812 LED Driver Date: Mon, 24 Nov 2025 02:10:41 +0700 Message-Id: <20251123191042.116917-3-trannamatk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251123191042.116917-1-trannamatk@gmail.com> References: <20251123191042.116917-1-trannamatk@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="utf-8" Content-Transfer-Encoding: quoted-printable The LP5812 is a 4x3 matrix RGB LED driver with an autonomous animation engine and time-cross-multiplexing (TCM) support for up to 12 LEDs or 4 RGB LEDs. Each LED can be configured through the related registers to realize vivid and fancy lighting effects. This patch adds minimal driver support for the LP5812, implementing only the essential functionality: I2C communication with the device, LED registration, brightness control in manual mode, and basic sysfs interfaces for LED configuration and fault monitoring. This patch adds minimal driver support for the LP5812, implementing only the essential functionality: I2C communication with the device, LED registration, brightness control in manual mode, and basic sysfs interfaces for LED configuration and fault monitoring. Signed-off-by: Nam Tran --- MAINTAINERS | 4 + drivers/leds/rgb/Kconfig | 13 + drivers/leds/rgb/Makefile | 1 + drivers/leds/rgb/leds-lp5812.c | 646 +++++++++++++++++++++++++++++++++ drivers/leds/rgb/leds-lp5812.h | 172 +++++++++ 5 files changed, 836 insertions(+) create mode 100644 drivers/leds/rgb/leds-lp5812.c create mode 100644 drivers/leds/rgb/leds-lp5812.h diff --git a/MAINTAINERS b/MAINTAINERS index 22da152c3c87..9a7ae1794328 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25453,6 +25453,10 @@ M: Nam Tran L: linux-leds@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/leds/ti,lp5812.yaml +F: drivers/leds/rgb/Kconfig +F: drivers/leds/rgb/Makefile +F: drivers/leds/rgb/leds-lp5812.c +F: drivers/leds/rgb/leds-lp5812.h =20 TEXAS INSTRUMENTS' LB8864 LED BACKLIGHT DRIVER M: Alexander Sverdlin diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig index 222d943d826a..28ef4c487367 100644 --- a/drivers/leds/rgb/Kconfig +++ b/drivers/leds/rgb/Kconfig @@ -26,6 +26,19 @@ config LEDS_KTD202X To compile this driver as a module, choose M here: the module will be called leds-ktd202x. =20 +config LEDS_LP5812 + tristate "LED support for Texas Instruments LP5812" + depends on I2C + help + If you say Y here you get support for TI LP5812 LED driver. + The LP5812 is a 4x3 matrix RGB LED driver with autonomous + animation engine control. + + To compile this driver as a module, choose M here: the + module will be called leds-lp5812. + + If unsure, say N. + config LEDS_NCP5623 tristate "LED support for NCP5623" depends on I2C diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile index a501fd27f179..be45991f63f5 100644 --- a/drivers/leds/rgb/Makefile +++ b/drivers/leds/rgb/Makefile @@ -2,6 +2,7 @@ =20 obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) +=3D leds-group-multicolor.o obj-$(CONFIG_LEDS_KTD202X) +=3D leds-ktd202x.o +obj-$(CONFIG_LEDS_LP5812) +=3D leds-lp5812.o obj-$(CONFIG_LEDS_NCP5623) +=3D leds-ncp5623.o obj-$(CONFIG_LEDS_PWM_MULTICOLOR) +=3D leds-pwm-multicolor.o obj-$(CONFIG_LEDS_QCOM_LPG) +=3D leds-qcom-lpg.o diff --git a/drivers/leds/rgb/leds-lp5812.c b/drivers/leds/rgb/leds-lp5812.c new file mode 100644 index 000000000000..21515d97913e --- /dev/null +++ b/drivers/leds/rgb/leds-lp5812.c @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LP5812 LED driver + * + * Copyright (C) 2025 Texas Instruments + * + * Author: Jared Zhou + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leds-lp5812.h" + +static const struct lp5812_mode_mapping chip_mode_map[] =3D { + {"direct_mode", 0, 0, 0, 0, 0, 0}, + {"tcm:1:0", 1, 0, 0, 0, 0, 0}, + {"tcm:1:1", 1, 1, 0, 0, 0, 0}, + {"tcm:1:2", 1, 2, 0, 0, 0, 0}, + {"tcm:1:3", 1, 3, 0, 0, 0, 0}, + {"tcm:2:0:1", 2, 0, 1, 0, 0, 0}, + {"tcm:2:0:2", 2, 0, 2, 0, 0, 0}, + {"tcm:2:0:3", 2, 0, 3, 0, 0, 0}, + {"tcm:2:1:2", 2, 1, 2, 0, 0, 0}, + {"tcm:2:1:3", 2, 1, 3, 0, 0, 0}, + {"tcm:2:2:3", 2, 2, 3, 0, 0, 0}, + {"tcm:3:0:1:2", 3, 0, 1, 2, 0, 0}, + {"tcm:3:0:1:3", 3, 0, 1, 3, 0, 0}, + {"tcm:3:0:2:3", 3, 0, 2, 3, 0, 0}, + {"tcm:4:0:1:2:3", 4, 0, 1, 2, 3, 0}, + {"mix:1:0:1", 5, 1, 0, 0, 0, 0}, + {"mix:1:0:2", 5, 2, 0, 0, 0, 0}, + {"mix:1:0:3", 5, 3, 0, 0, 0, 0}, + {"mix:1:1:0", 5, 0, 0, 0, 0, 1}, + {"mix:1:1:2", 5, 2, 0, 0, 0, 1}, + {"mix:1:1:3", 5, 3, 0, 0, 0, 1}, + {"mix:1:2:0", 5, 0, 0, 0, 0, 2}, + {"mix:1:2:1", 5, 1, 0, 0, 0, 2}, + {"mix:1:2:3", 5, 3, 0, 0, 0, 2}, + {"mix:1:3:0", 5, 0, 0, 0, 0, 3}, + {"mix:1:3:1", 5, 1, 0, 0, 0, 3}, + {"mix:1:3:2", 5, 2, 0, 0, 0, 3}, + {"mix:2:0:1:2", 6, 1, 2, 0, 0, 0}, + {"mix:2:0:1:3", 6, 1, 3, 0, 0, 0}, + {"mix:2:0:2:3", 6, 2, 3, 0, 0, 0}, + {"mix:2:1:0:2", 6, 0, 2, 0, 0, 1}, + {"mix:2:1:0:3", 6, 0, 3, 0, 0, 1}, + {"mix:2:1:2:3", 6, 2, 3, 0, 0, 1}, + {"mix:2:2:0:1", 6, 0, 1, 0, 0, 2}, + {"mix:2:2:0:3", 6, 0, 3, 0, 0, 2}, + {"mix:2:2:1:3", 6, 1, 3, 0, 0, 2}, + {"mix:2:3:0:1", 6, 0, 1, 0, 0, 3}, + {"mix:2:3:0:2", 6, 0, 2, 0, 0, 3}, + {"mix:2:3:1:2", 6, 1, 2, 0, 0, 3}, + {"mix:3:0:1:2:3", 7, 1, 2, 3, 0, 0}, + {"mix:3:1:0:2:3", 7, 0, 2, 3, 0, 1}, + {"mix:3:2:0:1:3", 7, 0, 1, 3, 0, 2}, + {"mix:3:3:0:1:2", 7, 0, 1, 2, 0, 3} +}; + +static int lp5812_write(struct lp5812_chip *chip, u16 reg, u8 val) +{ + struct device *dev =3D &chip->client->dev; + struct i2c_msg msg; + u8 buf[LP5812_DATA_LENGTH]; + u8 reg_addr_bit8_9; + int ret; + + /* Extract register address bits 9 and 8 for Address Byte 1 */ + reg_addr_bit8_9 =3D (reg >> LP5812_REG_ADDR_HIGH_SHIFT) & LP5812_REG_ADDR= _BIT_8_9_MASK; + + /* Prepare payload: Address Byte 2 (bits [7:0]) and value to write */ + buf[LP5812_DATA_BYTE_0_IDX] =3D (u8)(reg & LP5812_REG_ADDR_LOW_MASK); + buf[LP5812_DATA_BYTE_1_IDX] =3D val; + + /* Construct I2C message for a write operation */ + msg.addr =3D (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bi= t8_9; + msg.flags =3D 0; + msg.len =3D sizeof(buf); + msg.buf =3D buf; + + ret =3D i2c_transfer(chip->client->adapter, &msg, 1); + if (ret =3D=3D 1) + return 0; + + dev_err(dev, "I2C write error, ret=3D%d\n", ret); + return ret < 0 ? ret : -EIO; +} + +static int lp5812_read(struct lp5812_chip *chip, u16 reg, u8 *val) +{ + struct device *dev =3D &chip->client->dev; + struct i2c_msg msgs[LP5812_READ_MSG_LENGTH]; + u8 ret_val; + u8 reg_addr_bit8_9; + u8 converted_reg; + int ret; + + /* Extract register address bits 9 and 8 for Address Byte 1 */ + reg_addr_bit8_9 =3D (reg >> LP5812_REG_ADDR_HIGH_SHIFT) & LP5812_REG_ADDR= _BIT_8_9_MASK; + + /* Lower 8 bits go in Address Byte 2 */ + converted_reg =3D (u8)(reg & LP5812_REG_ADDR_LOW_MASK); + + /* Prepare I2C write message to set register address */ + msgs[LP5812_MSG_0_IDX].addr =3D + (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bit8_9; + msgs[LP5812_MSG_0_IDX].flags =3D 0; + msgs[LP5812_MSG_0_IDX].len =3D 1; + msgs[LP5812_MSG_0_IDX].buf =3D &converted_reg; + + /* Prepare I2C read message to retrieve register value */ + msgs[LP5812_MSG_1_IDX].addr =3D + (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bit8_9; + msgs[LP5812_MSG_1_IDX].flags =3D I2C_M_RD; + msgs[LP5812_MSG_1_IDX].len =3D 1; + msgs[LP5812_MSG_1_IDX].buf =3D &ret_val; + + ret =3D i2c_transfer(chip->client->adapter, msgs, LP5812_READ_MSG_LENGTH); + if (ret =3D=3D LP5812_READ_MSG_LENGTH) { + *val =3D ret_val; + return 0; + } + + dev_err(dev, "I2C read error, ret=3D%d\n", ret); + *val =3D 0; + return ret < 0 ? ret : -EIO; +} + +static int lp5812_read_tsd_config_status(struct lp5812_chip *chip, u8 *reg= _val) +{ + return lp5812_read(chip, LP5812_TSD_CONFIG_STATUS, reg_val); +} + +static int lp5812_update_regs_config(struct lp5812_chip *chip) +{ + u8 reg_val; + int ret; + + ret =3D lp5812_write(chip, LP5812_CMD_UPDATE, LP5812_UPDATE_CMD_VAL); + if (ret) + return ret; + + ret =3D lp5812_read_tsd_config_status(chip, ®_val); + if (ret) + return ret; + + return reg_val & LP5812_CFG_ERR_STATUS_MASK; +} + +static ssize_t parse_drive_mode(struct lp5812_chip *chip, const char *str) +{ + int i; + + chip->u_drive_mode.s_drive_mode.mix_sel_led_0 =3D false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_1 =3D false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_2 =3D false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_3 =3D false; + + if (sysfs_streq(str, LP5812_MODE_DIRECT_NAME)) { + chip->u_drive_mode.s_drive_mode.led_mode =3D LP5812_MODE_DIRECT_VALUE; + return 0; + } + + for (i =3D 0; i < ARRAY_SIZE(chip_mode_map); i++) { + if (!sysfs_streq(str, chip_mode_map[i].mode_name)) + continue; + + chip->u_drive_mode.s_drive_mode.led_mode =3D chip_mode_map[i].mode; + chip->u_scan_order.s_scan_order.scan_order_0 =3D chip_mode_map[i].scan_o= rder_0; + chip->u_scan_order.s_scan_order.scan_order_1 =3D chip_mode_map[i].scan_o= rder_1; + chip->u_scan_order.s_scan_order.scan_order_2 =3D chip_mode_map[i].scan_o= rder_2; + chip->u_scan_order.s_scan_order.scan_order_3 =3D chip_mode_map[i].scan_o= rder_3; + + switch (chip_mode_map[i].selection_led) { + case LP5812_MODE_MIX_SELECT_LED_0: + chip->u_drive_mode.s_drive_mode.mix_sel_led_0 =3D true; + break; + case LP5812_MODE_MIX_SELECT_LED_1: + chip->u_drive_mode.s_drive_mode.mix_sel_led_1 =3D true; + break; + case LP5812_MODE_MIX_SELECT_LED_2: + chip->u_drive_mode.s_drive_mode.mix_sel_led_2 =3D true; + break; + case LP5812_MODE_MIX_SELECT_LED_3: + chip->u_drive_mode.s_drive_mode.mix_sel_led_3 =3D true; + break; + default: + return -EINVAL; + } + + return 0; + } + + return -EINVAL; +} + +static int lp5812_set_drive_mode_scan_order(struct lp5812_chip *chip) +{ + u8 val; + int ret; + + val =3D chip->u_drive_mode.drive_mode_val; + ret =3D lp5812_write(chip, LP5812_DEV_CONFIG1, val); + if (ret) + return ret; + + val =3D chip->u_scan_order.scan_order_val; + ret =3D lp5812_write(chip, LP5812_DEV_CONFIG2, val); + + return ret; +} + +static int lp5812_set_led_mode(struct lp5812_chip *chip, int led_number, + enum control_mode mode) +{ + u8 reg_val; + u16 reg; + int ret; + + /* + * Select device configuration register. + * Reg3 for LED_0=E2=80=93LED_3, LED_A0=E2=80=93A2, LED_B0 + * Reg4 for LED_B1=E2=80=93B2, LED_C0=E2=80=93C2, LED_D0=E2=80=93D2 + */ + if (led_number < LP5812_NUMBER_LED_IN_REG) + reg =3D LP5812_DEV_CONFIG3; + else + reg =3D LP5812_DEV_CONFIG4; + + ret =3D lp5812_read(chip, reg, ®_val); + if (ret) + return ret; + + if (mode =3D=3D LP5812_MODE_MANUAL) + reg_val &=3D ~(LP5812_ENABLE << (led_number % LP5812_NUMBER_LED_IN_REG)); + else + reg_val |=3D (LP5812_ENABLE << (led_number % LP5812_NUMBER_LED_IN_REG)); + + ret =3D lp5812_write(chip, reg, reg_val); + if (ret) + return ret; + + ret =3D lp5812_update_regs_config(chip); + + return ret; +} + +static int lp5812_manual_dc_pwm_control(struct lp5812_chip *chip, int led_= number, + u8 val, enum dimming_type dimming_type) +{ + u16 led_base_reg; + int ret; + + if (dimming_type =3D=3D LP5812_DIMMING_ANALOG) + led_base_reg =3D LP5812_MANUAL_DC_BASE; + else + led_base_reg =3D LP5812_MANUAL_PWM_BASE; + + ret =3D lp5812_write(chip, led_base_reg + led_number, val); + + return ret; +} + +static int lp5812_multicolor_brightness(struct lp5812_led *led) +{ + struct lp5812_chip *chip =3D led->chip; + int ret, i; + + guard(mutex)(&chip->lock); + for (i =3D 0; i < led->mc_cdev.num_colors; i++) { + ret =3D lp5812_manual_dc_pwm_control(chip, led->mc_cdev.subled_info[i].c= hannel, + led->mc_cdev.subled_info[i].brightness, + LP5812_DIMMING_PWM); + if (ret) + return ret; + } + + return 0; +} + +static int lp5812_led_brightness(struct lp5812_led *led) +{ + struct lp5812_chip *chip =3D led->chip; + struct lp5812_led_config *led_cfg; + int ret; + + led_cfg =3D &chip->led_config[led->chan_nr]; + + guard(mutex)(&chip->lock); + ret =3D lp5812_manual_dc_pwm_control(chip, led_cfg->led_id[0], + led->brightness, LP5812_DIMMING_PWM); + + return ret; +} + +static int lp5812_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct lp5812_led *led =3D container_of(cdev, struct lp5812_led, cdev); + + led->brightness =3D (u8)brightness; + + return lp5812_led_brightness(led); +} + +static int lp5812_set_mc_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *mc_dev =3D lcdev_to_mccdev(cdev); + struct lp5812_led *led =3D container_of(mc_dev, struct lp5812_led, mc_cde= v); + + led_mc_calc_color_components(&led->mc_cdev, brightness); + + return lp5812_multicolor_brightness(led); +} + +static int lp5812_init_led(struct lp5812_led *led, struct lp5812_chip *chi= p, int chan) +{ + struct device *dev =3D &chip->client->dev; + struct mc_subled *mc_led_info; + struct led_classdev *led_cdev; + int i, ret; + + if (chip->led_config[chan].name) { + led->cdev.name =3D chip->led_config[chan].name; + } else { + led->cdev.name =3D devm_kasprintf(dev, GFP_KERNEL, "%s:channel%d", + chip->label ? : chip->client->name, chan); + if (!led->cdev.name) + return -ENOMEM; + } + + if (!chip->led_config[chan].is_sc_led) { + mc_led_info =3D devm_kcalloc(dev, chip->led_config[chan].num_colors, + sizeof(*mc_led_info), GFP_KERNEL); + if (!mc_led_info) + return -ENOMEM; + + led_cdev =3D &led->mc_cdev.led_cdev; + led_cdev->name =3D led->cdev.name; + led_cdev->brightness_set_blocking =3D lp5812_set_mc_brightness; + led->mc_cdev.num_colors =3D chip->led_config[chan].num_colors; + + for (i =3D 0; i < led->mc_cdev.num_colors; i++) { + mc_led_info[i].color_index =3D + chip->led_config[chan].color_id[i]; + mc_led_info[i].channel =3D + chip->led_config[chan].led_id[i]; + } + + led->mc_cdev.subled_info =3D mc_led_info; + } else { + led->cdev.brightness_set_blocking =3D lp5812_set_brightness; + } + + led->chan_nr =3D chan; + + if (chip->led_config[chan].is_sc_led) { + ret =3D devm_led_classdev_register(dev, &led->cdev); + if (ret =3D=3D 0) + led->cdev.dev->platform_data =3D led; + } else { + ret =3D devm_led_classdev_multicolor_register(dev, &led->mc_cdev); + if (ret =3D=3D 0) + led->mc_cdev.led_cdev.dev->platform_data =3D led; + } + + return ret; +} + +static int lp5812_register_leds(struct lp5812_led *leds, struct lp5812_chi= p *chip) +{ + struct lp5812_led *led; + int num_channels =3D chip->num_channels; + u8 reg_val; + u16 reg; + int ret, i, j; + + for (i =3D 0; i < num_channels; i++) { + led =3D &leds[i]; + ret =3D lp5812_init_led(led, chip, i); + if (ret) + goto err_init_led; + + led->chip =3D chip; + + for (j =3D 0; j < chip->led_config[i].num_colors; j++) { + ret =3D lp5812_write(chip, + LP5812_AUTO_DC_BASE + chip->led_config[i].led_id[j], + chip->led_config[i].max_current[j]); + if (ret) + goto err_init_led; + + ret =3D lp5812_manual_dc_pwm_control(chip, chip->led_config[i].led_id[j= ], + chip->led_config[i].max_current[j], + LP5812_DIMMING_ANALOG); + if (ret) + goto err_init_led; + + ret =3D lp5812_set_led_mode(chip, chip->led_config[i].led_id[j], + LP5812_MODE_MANUAL); + if (ret) + goto err_init_led; + + reg =3D (chip->led_config[i].led_id[j] < LP5812_NUMBER_LED_IN_REG) ? + LP5812_LED_EN_1 : LP5812_LED_EN_2; + + ret =3D lp5812_read(chip, reg, ®_val); + if (ret) + goto err_init_led; + + reg_val |=3D (LP5812_ENABLE << (chip->led_config[i].led_id[j] % + LP5812_NUMBER_LED_IN_REG)); + + ret =3D lp5812_write(chip, reg, reg_val); + if (ret) + goto err_init_led; + } + } + + return 0; + +err_init_led: + return ret; +} + +static int lp5812_init_device(struct lp5812_chip *chip) +{ + int ret; + + usleep_range(LP5812_WAIT_DEVICE_STABLE_MIN, LP5812_WAIT_DEVICE_STABLE_MAX= ); + + ret =3D lp5812_write(chip, LP5812_REG_ENABLE, LP5812_ENABLE); + if (ret) { + dev_err(&chip->client->dev, "failed to enable LP5812 device\n"); + return ret; + } + + ret =3D lp5812_write(chip, LP5812_DEV_CONFIG12, LP5812_LSD_LOD_START_UP); + if (ret) { + dev_err(&chip->client->dev, "failed to configure device safety threshold= s\n"); + return ret; + } + + ret =3D parse_drive_mode(chip, chip->scan_mode); + if (ret) + return ret; + + ret =3D lp5812_set_drive_mode_scan_order(chip); + if (ret) + return ret; + + ret =3D lp5812_update_regs_config(chip); + if (ret) { + dev_err(&chip->client->dev, "failed to apply configuration updates\n"); + return ret; + } + + return 0; +} + +static void lp5812_deinit_device(struct lp5812_chip *chip) +{ + lp5812_write(chip, LP5812_LED_EN_1, LP5812_DISABLE); + lp5812_write(chip, LP5812_LED_EN_2, LP5812_DISABLE); + lp5812_write(chip, LP5812_REG_ENABLE, LP5812_DISABLE); +} + +static int lp5812_parse_led_channel(struct device_node *np, + struct lp5812_led_config *cfg, + int color_number) +{ + int color_id, reg, ret; + u32 max_cur; + + ret =3D of_property_read_u32(np, "reg", ®); + if (ret) + return ret; + + cfg->led_id[color_number] =3D reg; + + ret =3D of_property_read_u32(np, "led-max-microamp", &max_cur); + if (ret) + max_cur =3D 0; + /* Convert microamps to driver units */ + cfg->max_current[color_number] =3D max_cur / 100; + + ret =3D of_property_read_u32(np, "color", &color_id); + if (ret) + color_id =3D 0; + cfg->color_id[color_number] =3D color_id; + + return 0; +} + +static int lp5812_parse_led(struct device_node *np, + struct lp5812_led_config *cfg, + int led_index) +{ + int num_colors, ret; + + ret =3D of_property_read_string(np, "label", &cfg[led_index].name); + if (ret) + return ret; + + ret =3D of_property_read_u32(np, "reg", &cfg[led_index].chan_nr); + if (ret) + return ret; + + num_colors =3D 0; + for_each_available_child_of_node_scoped(np, child) { + ret =3D lp5812_parse_led_channel(child, &cfg[led_index], num_colors); + if (ret) + return ret; + + num_colors++; + } + + if (num_colors =3D=3D 0) { + ret =3D lp5812_parse_led_channel(np, &cfg[led_index], 0); + if (ret) + return ret; + + num_colors =3D 1; + cfg[led_index].is_sc_led =3D true; + } else { + cfg[led_index].is_sc_led =3D false; + } + + cfg[led_index].num_colors =3D num_colors; + + return 0; +} + +static int lp5812_of_probe(struct device *dev, + struct device_node *np, + struct lp5812_chip *chip) +{ + struct lp5812_led_config *cfg; + int num_channels, i =3D 0, ret; + + num_channels =3D of_get_available_child_count(np); + if (num_channels =3D=3D 0) { + dev_err(dev, "no LED channels\n"); + return -EINVAL; + } + + cfg =3D devm_kcalloc(dev, num_channels, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + chip->led_config =3D &cfg[0]; + chip->num_channels =3D num_channels; + + for_each_available_child_of_node_scoped(np, child) { + ret =3D lp5812_parse_led(child, cfg, i); + if (ret) + return -EINVAL; + i++; + } + + ret =3D of_property_read_string(np, "ti,scan-mode", &chip->scan_mode); + if (ret) + chip->scan_mode =3D LP5812_MODE_DIRECT_NAME; + + of_property_read_string(np, "label", &chip->label); + + return 0; +} + +static int lp5812_probe(struct i2c_client *client) +{ + struct lp5812_chip *chip; + struct device_node *np =3D dev_of_node(&client->dev); + struct lp5812_led *leds; + int ret; + + if (!np) + return -EINVAL; + + chip =3D devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + ret =3D lp5812_of_probe(&client->dev, np, chip); + if (ret) + return ret; + + leds =3D devm_kcalloc(&client->dev, chip->num_channels, sizeof(*leds), GF= P_KERNEL); + if (!leds) + return -ENOMEM; + + chip->client =3D client; + mutex_init(&chip->lock); + i2c_set_clientdata(client, chip); + + ret =3D lp5812_init_device(chip); + if (ret) + return ret; + + ret =3D lp5812_register_leds(leds, chip); + if (ret) + goto err_out; + + return 0; + +err_out: + lp5812_deinit_device(chip); + return ret; +} + +static void lp5812_remove(struct i2c_client *client) +{ + struct lp5812_chip *chip =3D i2c_get_clientdata(client); + + lp5812_deinit_device(chip); +} + +static const struct of_device_id of_lp5812_match[] =3D { + { .compatible =3D "ti,lp5812" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_lp5812_match); + +static struct i2c_driver lp5812_driver =3D { + .driver =3D { + .name =3D "lp5812", + .of_match_table =3D of_lp5812_match, + }, + .probe =3D lp5812_probe, + .remove =3D lp5812_remove, +}; +module_i2c_driver(lp5812_driver); + +MODULE_DESCRIPTION("Texas Instruments LP5812 LED Driver"); +MODULE_AUTHOR("Jared Zhou "); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/rgb/leds-lp5812.h b/drivers/leds/rgb/leds-lp5812.h new file mode 100644 index 000000000000..d86af233d57d --- /dev/null +++ b/drivers/leds/rgb/leds-lp5812.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * LP5812 Driver Header + * + * Copyright (C) 2025 Texas Instruments + * + * Author: Jared Zhou + */ + +#ifndef _LP5812_H_ +#define _LP5812_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LP5812_REG_ENABLE 0x0000 +#define LP5812_REG_RESET 0x0023 +#define LP5812_DEV_CONFIG0 0x0001 +#define LP5812_DEV_CONFIG1 0x0002 +#define LP5812_DEV_CONFIG2 0x0003 +#define LP5812_DEV_CONFIG3 0x0004 +#define LP5812_DEV_CONFIG4 0x0005 +#define LP5812_DEV_CONFIG5 0x0006 +#define LP5812_DEV_CONFIG6 0x0007 +#define LP5812_DEV_CONFIG7 0x0008 +#define LP5812_DEV_CONFIG8 0x0009 +#define LP5812_DEV_CONFIG9 0x000A +#define LP5812_DEV_CONFIG10 0x000B +#define LP5812_DEV_CONFIG11 0x000c +#define LP5812_DEV_CONFIG12 0x000D +#define LP5812_CMD_UPDATE 0x0010 +#define LP5812_LED_EN_1 0x0020 +#define LP5812_LED_EN_2 0x0021 +#define LP5812_FAULT_CLEAR 0x0022 +#define LP5812_MANUAL_DC_BASE 0x0030 +#define LP5812_AUTO_DC_BASE 0x0050 +#define LP5812_MANUAL_PWM_BASE 0x0040 + +#define LP5812_TSD_CONFIG_STATUS 0x0300 +#define LP5812_LOD_STATUS 0x0301 +#define LP5812_LSD_STATUS 0x0303 + +#define LP5812_ENABLE 0x01 +#define LP5812_DISABLE 0x00 +#define FAULT_CLEAR_ALL 0x07 +#define TSD_CLEAR_VAL 0x04 +#define LSD_CLEAR_VAL 0x02 +#define LOD_CLEAR_VAL 0x01 +#define LP5812_RESET 0x66 +#define LP5812_DEV_CONFIG12_DEFAULT 0x08 + +#define LP5812_UPDATE_CMD_VAL 0x55 +#define LP5812_REG_ADDR_HIGH_SHIFT 8 +#define LP5812_REG_ADDR_BIT_8_9_MASK 0x03 +#define LP5812_REG_ADDR_LOW_MASK 0xFF +#define LP5812_CHIP_ADDR_SHIFT 2 +#define LP5812_DATA_LENGTH 2 +#define LP5812_DATA_BYTE_0_IDX 0 +#define LP5812_DATA_BYTE_1_IDX 1 + +#define LP5812_READ_MSG_LENGTH 2 +#define LP5812_MSG_0_IDX 0 +#define LP5812_MSG_1_IDX 1 +#define LP5812_CFG_ERR_STATUS_MASK 0x01 +#define LP5812_CFG_TSD_STATUS_SHIFT 1 +#define LP5812_CFG_TSD_STATUS_MASK 0x01 + +#define LP5812_FAULT_CLEAR_LOD 0 +#define LP5812_FAULT_CLEAR_LSD 1 +#define LP5812_FAULT_CLEAR_TSD 2 +#define LP5812_FAULT_CLEAR_ALL 3 +#define LP5812_NUMBER_LED_IN_REG 8 + +#define LP5812_WAIT_DEVICE_STABLE_MIN 1000 +#define LP5812_WAIT_DEVICE_STABLE_MAX 1100 + +#define LP5812_LSD_LOD_START_UP 0x0B +#define LP5812_MODE_NAME_MAX_LEN 20 +#define LP5812_MODE_DIRECT_NAME "direct_mode" +#define LP5812_MODE_DIRECT_VALUE 0 +#define LP5812_MODE_MIX_SELECT_LED_0 0 +#define LP5812_MODE_MIX_SELECT_LED_1 1 +#define LP5812_MODE_MIX_SELECT_LED_2 2 +#define LP5812_MODE_MIX_SELECT_LED_3 3 + +enum control_mode { + LP5812_MODE_MANUAL =3D 0, + LP5812_MODE_AUTONOMOUS +}; + +enum dimming_type { + LP5812_DIMMING_ANALOG, + LP5812_DIMMING_PWM +}; + +union u_scan_order { + struct { + u8 scan_order_0:2; + u8 scan_order_1:2; + u8 scan_order_2:2; + u8 scan_order_3:2; + } s_scan_order; + u8 scan_order_val; +}; + +union u_drive_mode { + struct { + u8 mix_sel_led_0:1; + u8 mix_sel_led_1:1; + u8 mix_sel_led_2:1; + u8 mix_sel_led_3:1; + u8 led_mode:3; + u8 pwm_fre:1; + } s_drive_mode; + u8 drive_mode_val; +}; + +struct lp5812_reg { + u16 addr; + union { + u8 val; + u8 mask; + u8 shift; + }; +}; + +struct lp5812_mode_mapping { + char mode_name[LP5812_MODE_NAME_MAX_LEN]; + u8 mode; + u8 scan_order_0; + u8 scan_order_1; + u8 scan_order_2; + u8 scan_order_3; + u8 selection_led; +}; + +struct lp5812_led_config { + bool is_sc_led; + const char *name; + u8 color_id[LED_COLOR_ID_MAX]; + u32 max_current[LED_COLOR_ID_MAX]; + int chan_nr; + int num_colors; + int led_id[LED_COLOR_ID_MAX]; +}; + +struct lp5812_chip { + u8 num_channels; + struct i2c_client *client; + struct mutex lock; /* Protects register access */ + struct lp5812_led_config *led_config; + const char *label; + const char *scan_mode; + union u_scan_order u_scan_order; + union u_drive_mode u_drive_mode; +}; + +struct lp5812_led { + u8 brightness; + int chan_nr; + struct led_classdev cdev; + struct led_classdev_mc mc_cdev; + struct lp5812_chip *chip; +}; + +#endif /*_LP5812_H_*/ --=20 2.25.1 From nobody Tue Dec 2 00:46:26 2025 Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) (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 3AD4923BD1A for ; Sun, 23 Nov 2025 19:11:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925075; cv=none; b=PHbp+yVwHGRIneDl7UZiULTKKONhzQhP74MxrasprOk1/HunRzs0L9yFn/4XV3TO98dPOoRHdX3MvzIYqa5z7fRFcAhJsf/vhxazWbBUiq3sCOCTrsggc0uuXvO05y07WTYT3wp+LIGxhKBQHGDISXRP4kZP8z/bSmfgQQM/UUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763925075; c=relaxed/simple; bh=LN6U1JVPb9+1eLo7g3FdtdqGnUAJDli/a5RS4lOyf10=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kAUf32ldIihuHD+rdPeyH9NUXnQf3uh7pxTUI57biGiVsYgzOT5mG3TG63e35H/0v5WeGzgZ6in90rHlgpsd4WEAM7tbE0KWtGgHsssOH09RyJ6lSEgKFHK+s5+iIl6d1MYjIed1lf4ebQjsB1fe78AWUx41E97jdz+G9UPB3SY= 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=iOMdDLE8; arc=none smtp.client-ip=209.85.214.177 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="iOMdDLE8" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-29558061c68so48918705ad.0 for ; Sun, 23 Nov 2025 11:11:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763925072; x=1764529872; 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=tmHa/LXJpUTjBGHVWC+hnuQBMTBsWIpO679JoMtrn84=; b=iOMdDLE8fAGVk7tfLpvay21h0WC/XTevAG/C4o2Du14TKamob8BiZP1EcortPLiQtE pG9d3iOmwS4pGgBzQr1QWkCAZRnT1+0PawgyIg5FA4dxE3FEorqmHk8pkvQnz7wEn8oa utSH2Vt2HChPdVu6R9FShXEzmoKNyf9QXoaCGyPmQS3iDKUnBPtjgy+pu9th/rQTnoUb scXsBxzTIMaUIRPm3k4stA2T3Loj8c3uZHFUZAyIE61Db8x0ZnZNL/Fmk9prkXcgI15N d5Srbt39IUpC/dLEhJlZVNxmjyHMNYgsv2SpJYgczzVqzGbkYzdAwfR5/4svLM5z+46N /n6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763925072; x=1764529872; 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=tmHa/LXJpUTjBGHVWC+hnuQBMTBsWIpO679JoMtrn84=; b=tH/LjeumTLM246CbdRQ8uu66q6dJ74+hkQI7rAABrqO9YSOYg2JVc2R0Ts0fVVT94d 3m4XFL/9M/nwJ2hSldBqEtxqcMGW4X5yUj7HdPkV1VuZgThcMdWJ5983+t51xBW7znTa HhMFffXAVVp/fGtRxqIM+50WkqNzE9wrN8xjg1Sbr4O4Pup9SwVGzrm1SHSGcD9B/2nz gUs4d4GMffF6Lgp5dMCj//oOIVCDOjQd5uy3RmHwVOTahsZ++8KbjNCLvqg6UbaOa+mq 7qmGJDvHN0csMOdgy3ERh1Ut7EmqOxkvlesiwxbOwTeeGKoDOR0fQCsUl7Ip3jCW1qHP hV5A== X-Forwarded-Encrypted: i=1; AJvYcCU7j2Kkd1hOqHGZhB6R+b7KJuq7uGDhiw0o9xhTYfg4xFDT2eu/lX2kSpj4lVKz83Pvg0N6o/s87IsVIJk=@vger.kernel.org X-Gm-Message-State: AOJu0YycAYbAMiqwjdBfSEKjrr+/d2lBcxPP5wWsRkbeZPU3MWfwWmfS BpL29QPwRnba8D3afIhBZKXnTwURGG7jay5PF7xbIHS7ZDCed1NySsiV X-Gm-Gg: ASbGncslMh3KHiP7zWtzOCAYvn9tAzb4xKEv3oYzKnIxz5TRGPUv3JMyKAGGXLLLdmQ XdF+oPQ0yMPVZ0/y7kKroaObI4WtgVijv3G04ePvMFgBclE3udCt0fGkSqzThGt8czjzZq23nlw Tu7b6nkUnMoSelaHryNiX88TtokUyKLpGgkOufiZoXar6LC0mPisKm33LmwhNqIOaSQ27X8AfPT uie3FE+hwfJVvi1Jiv2q7boKHizt6pRttErjST6ikdZIXIPt8nwqnFe3hUwdgIK574GjS9lswvf NAGmWO0fbXTGl+PDn0GitIqHilvvNb0epvHqrNrOf6x8zFsLmSjGb1/ejioiBYTvZsG4QE/ZbZe 3kyLcmp7TTY7OUtU0+GYvRmfIV9awDT+1BZa5bUGxIm1iL1eFZLeeX4IBY0XR6c6W9zeucJWnQG pSSzsaXkdwlVo8IG9XnVEDAg== X-Google-Smtp-Source: AGHT+IHPFoSxQZoigWdf+doSXm3n1IZ6Vj/SJ4gDleYOYUskKuzp0oVLKr/lcnHOJRJnx6TXf+8YNg== X-Received: by 2002:a17:903:38c4:b0:297:df17:54cd with SMTP id d9443c01a7336-29b6becd454mr118444255ad.27.1763925072582; Sun, 23 Nov 2025 11:11:12 -0800 (PST) Received: from DESKTOP-P76LG1N.lan ([42.116.199.188]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29b5b13e720sm109542655ad.42.2025.11.23.11.11.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Nov 2025 11:11:12 -0800 (PST) From: Nam Tran To: lee@kernel.org Cc: pavel@kernel.org, gregkh@linuxfoundation.org, rdunlap@infradead.org, christophe.jaillet@wanadoo.fr, krzk+dt@kernel.org, robh@kernel.org, conor+dt@kernel.org, corbet@lwn.net, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-doc@vger.kernel.org, Nam Tran Subject: [PATCH v18 3/3] docs: leds: Document TI LP5812 LED driver Date: Mon, 24 Nov 2025 02:10:42 +0700 Message-Id: <20251123191042.116917-4-trannamatk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251123191042.116917-1-trannamatk@gmail.com> References: <20251123191042.116917-1-trannamatk@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The driver provides sysfs interfaces to control and configure the LP5812 device and its LED channels. The documetation describes the chip's capabilities, sysfs interface, and usage examples. Signed-off-by: Nam Tran --- Documentation/leds/index.rst | 1 + Documentation/leds/leds-lp5812.rst | 50 ++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 52 insertions(+) create mode 100644 Documentation/leds/leds-lp5812.rst diff --git a/Documentation/leds/index.rst b/Documentation/leds/index.rst index 76fae171039c..bebf44004278 100644 --- a/Documentation/leds/index.rst +++ b/Documentation/leds/index.rst @@ -25,6 +25,7 @@ LEDs leds-lp5523 leds-lp5562 leds-lp55xx + leds-lp5812 leds-mlxcpld leds-mt6370-rgb leds-sc27xx diff --git a/Documentation/leds/leds-lp5812.rst b/Documentation/leds/leds-l= p5812.rst new file mode 100644 index 000000000000..4c22d9a79d14 --- /dev/null +++ b/Documentation/leds/leds-lp5812.rst @@ -0,0 +1,50 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Kernel driver for lp5812 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +* TI/National Semiconductor LP5812 LED Driver +* Datasheet: https://www.ti.com/product/LP5812#tech-docs + +Authors: Jared Zhou + +Description +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The LP5812 is a 4x3 matrix LED driver with support for both manual and +autonomous animation control. This driver provides sysfs interfaces to +control and configure the LP5812 device and its LED channels. + +Sysfs Interface +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver uses the standard multicolor LED class interfaces defined +in `Documentation/ABI/testing/sysfs-class-led-multicolor`. + +Each LP5812 LED output appears under ``/sys/class/leds/`` with its +assigned label (for example ``LED_A``). + +The following attributes are exposed: + - multi_intensity: Per-channel RGB intensity control. + - brightness: Standard brightness control (0-255) + +Autonomous Control Modes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The driver also supports autonomous control through pattern configuration +(e.g., direct, tcmscan, or mixscan modes) defined in the device tree. +When configured, the LP5812 can generate transitions and color effects +without CPU intervention. + +Refer to the device tree binding document for valid mode strings and +configuration examples. + +Example Usage +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +To control LED_A:: + # Set RGB intensity (R=3D50, G=3D50, B=3D50) + echo 50 50 50 > /sys/class/leds/LED_A/multi_intensity + # Set overall brightness to maximum + echo 255 > /sys/class/leds/LED_A/brightness diff --git a/MAINTAINERS b/MAINTAINERS index 9a7ae1794328..f696e2299a43 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25453,6 +25453,7 @@ M: Nam Tran L: linux-leds@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/leds/ti,lp5812.yaml +F: Documentation/leds/leds-lp5812.rst F: drivers/leds/rgb/Kconfig F: drivers/leds/rgb/Makefile F: drivers/leds/rgb/leds-lp5812.c --=20 2.25.1