From nobody Mon Jun 8 06:39:46 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E4D2330D25 for ; Fri, 5 Jun 2026 08:19:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780647558; cv=none; b=PdVpO+m0KqgNRd5RHkxylV+ctkosWFlelHh3WDIiBdj7i5lHt+kh5eq4RmxwJhAHoOqic6ir0ZXSkqmdIIho5IAQ2Uh0sn/4yR76EniOEer/n4zNtec+PU9p5AOAG8Dr9ScfYh2Sz7kB9gtJH7HCYXGHmOeblaAx3jSuaKIQ+zY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780647558; c=relaxed/simple; bh=pLBgdPnPL6CCcTZBAU1Nc0ZyiQ5sp8g36luZ6dHW9vs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=m2kf88nUEC1Zh2XXyM+HhWnD2ro9/R076lIVSqqsQjJErWEo9nIiA3J1UZxGOx/WXhO+KwGgpZDy9YIKKPN3+02G8f3nt7k/IWrKRTgMDAfla86TrW8/cL6Pt2OjKEZgOfeuyVx9lQqQGwmSe4bofS4FhAcCrpNnkGGHJfdpR2A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=oo/3CBd5; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=HK2Vt/AN; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="oo/3CBd5"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="HK2Vt/AN" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 65525bjS820570 for ; Fri, 5 Jun 2026 08:19:16 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:message-id :mime-version:subject:to; s=qcppdkim1; bh=rmlgNOg+uqMW5pF9FH3Wuf JOYU/bHWvIswBDiuAIugY=; b=oo/3CBd5z4Ps5iTalsZjKdUSj47McfMrHYf9JS Z/X+bKBkx5ad5RHrh0u54bwDiLrz83HTQjXnld3/JquFZAT5Cxx4hz9J63cRzF4j Mn8OFD9bzfDW+pV7+pIdvI83LpvG2wcba3oJ68PnokGsi/LVBcZQp/NDuRvoJaUr k1CJ5n4YtKzjF+KfTK7xdEmXImLcsI2II7NyfxaYeb2wom1FNzFZuU3nWepsxOpG BsaE8QzXDbc9EBzgima3tGJK6XfMCLa+THjByj3aiiikFwFWyCROsdP8Axsu1CkX PRiID6SXzFQCC8hVJg+o/toNs/gr7hIf4jPeHq4SmXvdnj7w== Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4ekncbh846-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 05 Jun 2026 08:19:16 +0000 (GMT) Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-304d8613efbso1532334eec.1 for ; Fri, 05 Jun 2026 01:19:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1780647556; x=1781252356; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=rmlgNOg+uqMW5pF9FH3WufJOYU/bHWvIswBDiuAIugY=; b=HK2Vt/ANHANkPWeYxWtTsKR4uPgzdnt6y89KrrqEyAod/JWQnjQoJRasyEpfWFS9kw jLXweg4MS+qP4tkJ06w7Kk1smvgA0FiUPq9xI0kdXG9ZQADTRx2bdIZz6iV7Gaym7IDl bbYjETwATinewsmUSvgoRGP1Bx26qzrfzXHONp8JYPq+4EfHbms4mw7maH3lIkx7vQP9 0YkRSH71LFdvRTViyOz1Qr34kpxQxGSSUmfZwt0yCwzPXNh97E+pTArLqClLtOwjn4vQ sKZPDLre+uKVGo1ly/rKiWBTfffjckkRzkZAQMgupYMTdsJAUvUrnGxIKctto7j3H7Au UmuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780647556; x=1781252356; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=rmlgNOg+uqMW5pF9FH3WufJOYU/bHWvIswBDiuAIugY=; b=ipS7G1kWHQZCCTzeSM6zvs54Bchr7zDh4/WS5irjtMDlHiizVKs4DqPIu1TcEoFOY4 +cfKxkgS00JW6PXc6CEqiFAsBLyrHMGueD1BWJGtVQM8wTBVG/ul6DlbczYffeYCvBZm Ipw9kWmlPFhOwrsTBR9knk0Fp11xc1UJxxskf9d0tnuxBVUdhPtVWY0hbhQHOf2H4+bU Uyour6OuoMxJiipKo4+OMGMyXMGQlm/f2K2pf2+XS4FFMZ3hNaZmaIUWaGTiE3bPXFD4 /x0ISYyGL1UN9CI263SbWCDWTatdYu047jouZfpC9FdgbUG+Si7ZYx/6eQKduySF9gbq nieg== X-Forwarded-Encrypted: i=1; AFNElJ/nnzoGb8F/rWd9Awhi+oR0cUe3o4Dg8jocdQbsLdPbcivlHIkimU4MVpcP8E6mW0DqovajOL+vCopE4E0=@vger.kernel.org X-Gm-Message-State: AOJu0YyBFYj5BvWkpcNESt4msUD+hHS23/J8qfu8WtTXYW5ovkALXD63 A3vBgXVPeRsNufTHhb9ngJwfg8D9E5xmIjbswnbxmxA0HQ+KVo04MumIoWVSMiuck3UzcPhv9kt debL/C9JvzHN0rWkWOn44MN8GooFHbEHR10u2y1Ymgebc0aePj+9P+sn4MFwUe/fd4fo= X-Gm-Gg: Acq92OHORyuQl+p9f9g0W6DYuVe9jOul13zCsuNCOGQkJ+TypOgyDNTCFmtUneK1Q60 bNXlAx7E9z8ZC1sTOv2T3EuXlI4tl/NAFGCt/iSgfmZVXyghbHmC8TSWL5BvV5owhgczAaB2gGo zWHKw/2TGq0+oAljmBzRcTqdFGGMEM2zeROwZ9AKihCV83IVzXZE7/Uj101k2XeCpae4Km8tk7T YccJ6YG27X3Lhh8xTBUwUVvbMIysuvEOwPrDCnEE+eOpQDTtJYG5fzi6vTREvFGZlTf6AkFBf9n yY0pFU0LwCtvfuFI8eGUHk2HLN/YBZ62ltbayegcEKMGmPwK4HVGCZcgbGEHlW0jux/NaWaGOLi ApmMHEZzlsm9KYUOAsRiJT3WpK9pUZlvQu0grx57c5m5jjBh9RDlnRmYjpvkgY5i/woU4kkbXeG So9kStPG7m X-Received: by 2002:a05:7301:5f11:b0:2e0:1f09:d924 with SMTP id 5a478bee46e88-3077b33045emr1104969eec.5.1780647555744; Fri, 05 Jun 2026 01:19:15 -0700 (PDT) X-Received: by 2002:a05:7301:5f11:b0:2e0:1f09:d924 with SMTP id 5a478bee46e88-3077b33045emr1104947eec.5.1780647555062; Fri, 05 Jun 2026 01:19:15 -0700 (PDT) Received: from hu-fenglinw-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3074df9bbd4sm6442528eec.30.2026.06.05.01.19.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Jun 2026 01:19:14 -0700 (PDT) From: Fenglin Wu Date: Fri, 05 Jun 2026 01:18:24 -0700 Subject: [PATCH] leds: rgb: leds-qcom-lpg: Fix LED color balancing in HW pattern mode 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 Message-Id: <20260605-lpg-rgb-color-balance-fix-v1-1-3233644a3385@oss.qualcomm.com> X-B4-Tracking: v=1; b=H4sIAE+GImoC/yXMQQqDMBCF4avIrDuQRg1tr1JcJHGMU0IiEy0F8 e6m7fJ78P4dCglTgUezg9CbC+dUcb004GebAiGP1aCVNsqoHuMSUIJDn2MWdDba5Akn/uBNd60 x3d26qYX6X4Tq/Gs/h7/L5l7k128QjuME2s1HCX0AAAA= X-Change-ID: 20260605-lpg-rgb-color-balance-fix-82436649abf3 To: linux-arm-msm@vger.kernel.org, Lee Jones , Pavel Machek , Bjorn Andersson , Marijn Suijten , Anjelique Melendez , Guru Das Srinagesh Cc: David Collins , Subbaraman Narayanamurthy , Kamal Wadhwa , kernel@oss.qualcomm.com, Pavel Machek , linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org, Fenglin Wu X-Mailer: b4 0.16-dev-17187 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780647554; l=10106; i=fenglin.wu@oss.qualcomm.com; s=20260324; h=from:subject:message-id; bh=pLBgdPnPL6CCcTZBAU1Nc0ZyiQ5sp8g36luZ6dHW9vs=; b=6Z0oVyd1xr8VCs3uZ1XqVFhvWm9oO8Sprf488QlI/8qIGPw8uMV5vtsjv702W9WvF37QM7z2X g5kLJluamlNDd4QFCuWe/IV5HFHmzRS5JC9KM3Kw3CFK9nLNrJf3Aky X-Developer-Key: i=fenglin.wu@oss.qualcomm.com; a=ed25519; pk=hJdt3E7o54lql+miD2GaxwF74cDyhgNwMbmFOZ46bRU= X-Authority-Analysis: v=2.4 cv=OauoyBTY c=1 sm=1 tr=0 ts=6a228684 cx=c_pps a=PfFC4Oe2JQzmKTvty2cRDw==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=FelO9ux0wxsA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_K5XuSEh1TEqbUxoQ0s3:22 a=EUspDBNiAAAA:8 a=q7j7SU0M432TpuN6ahQA:9 a=QEXdDO2ut3YA:10 a=6Ab_bkdmUrQuMsNx7PHu:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNjA1MDA3OSBTYWx0ZWRfX7ltAdHIQomvb tOKwiZVk9GwhuzB9Td+UeU+iUSAFVpAr/COg3WsQx97Gniz9eMEZy128mNm8uPP8hMYjTX/UkXF W2EV2vvbYv1vMsAsxgvHk59jVb7440+Ro1CTPI8eNaOaVr4w4Os6s6glNFLlDaCH4XdBW3NWX9a TcoLcIUS5c4Ruag+f0D1d+fuGncfmBhd5wUN8xnGnZdYrfeQQ6hygj6h7Uq37wAfe/C6KNjYXDL DuBiwqCVXhY9DiX5x0815ZcHdrt+ub5pNfYiJ2o8BMWWH/kLtnEUGkWCEBM8jb7nWpOe0G5Efmj hP0d/2guXPYqaHYJn2wHaB1OR1xkQVxSW3/qpcCLYtiK9ZG7GIADerImPNppenLOxKy15dqRfJ7 Kh8CX3rLFbpGC3r5DOaASRkC7yaVnnfqpIJwBIrjYXI27Ue1dbFXdEw48/rfpEOYFZclpFy2zEi OxMEHLDnPqKG/PCBbuQ== X-Proofpoint-GUID: scwJJxcX9SdC-2Nsqh7wjIvlnhQ7jK15 X-Proofpoint-ORIG-GUID: scwJJxcX9SdC-2Nsqh7wjIvlnhQ7jK15 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-06-05_01,2026-05-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 spamscore=0 priorityscore=1501 phishscore=0 impostorscore=0 malwarescore=0 suspectscore=0 bulkscore=0 lowpriorityscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2606050079 Currently, when the LED is configured as a RGB LED or a multi-color LED device, the same pattern is programmed for all LED channels regardless of the sub-led intensities when triggered by HW pattern. It results that the LED device is always working in a white-balanced mode regardless of the intensity settings. To fix this, scale the pattern data according to the sub-led intensity and program the HW pattern separately for each LPG channel. Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") Fixes: 6ab1f766a80a ("leds: rgb: leds-qcom-lpg: Add support for PPG through= single SDAM") Fixes: 5e9ff626861a ("leds: rgb: leds-qcom-lpg: Include support for PPG wit= h dedicated LUT SDAM") Assisted-by: Claude:claude-4-6-sonnet Signed-off-by: Fenglin Wu --- drivers/leds/rgb/leds-qcom-lpg.c | 174 +++++++++++++++++++++++++++++++----= ---- 1 file changed, 141 insertions(+), 33 deletions(-) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-= lpg.c index d7d6518de30f..ca84da563e09 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -148,6 +148,24 @@ struct lpg_channel { unsigned int pattern_hi_idx; }; =20 +/** + * struct lpg_pattern - The LPG pattern normalized from the LED pattern + * @data: The pattern data array (caller must kfree) + * @len: number of entries to write to the LUT + * @delta_t: common step duration in ms + * @lo_pause: low-pause duration in ms + * @hi_pause: high-pause duration in ms + * @ping_pong: true if the pattern support reverse + */ +struct lpg_pattern { + struct led_pattern *data; + unsigned int len; + unsigned int delta_t; + unsigned int lo_pause; + unsigned int hi_pause; + bool ping_pong; +}; + /** * struct lpg_led - logical LED object * @lpg: lpg context reference @@ -959,23 +977,23 @@ static int lpg_blink_mc_set(struct led_classdev *cdev, return ret; } =20 -static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pa= ttern, - u32 len, int repeat) +/** + * lpg_prepare_pattern() - validate and normalize a leds-trigger-pattern p= ayload + * + * Collapses the paired-entry format required by the trigger into a compact + * array, detects palindrome ping-pong, and extracts timing parameters. + * On success the caller owns prep->data and must kfree() it. + */ +static int lpg_prepare_pattern(struct lpg *lpg, struct led_pattern *led_pa= ttern, + u32 len, int repeat, struct lpg_pattern *prep) { - struct lpg_channel *chan; - struct lpg *lpg =3D led->lpg; struct led_pattern *pattern; unsigned int brightness_a; unsigned int brightness_b; - unsigned int hi_pause =3D 0; - unsigned int lo_pause =3D 0; unsigned int actual_len; unsigned int delta_t; - unsigned int lo_idx; - unsigned int hi_idx; unsigned int i; bool ping_pong =3D true; - int ret =3D -EINVAL; =20 /* Hardware only support oneshot or indefinite loops */ if (repeat !=3D -1 && repeat !=3D 1) @@ -1001,9 +1019,9 @@ static int lpg_pattern_set(struct lpg_led *led, struc= t led_pattern *led_pattern, =20 for (i =3D 0; i < len; i +=3D 2) { if (led_pattern[i].brightness !=3D led_pattern[i + 1].brightness) - goto out_free_pattern; + goto out_free; if (led_pattern[i + 1].delta_t !=3D 0) - goto out_free_pattern; + goto out_free; =20 pattern[i / 2].brightness =3D led_pattern[i].brightness; pattern[i / 2].delta_t =3D led_pattern[i].delta_t; @@ -1016,7 +1034,7 @@ static int lpg_pattern_set(struct lpg_led *led, struc= t led_pattern *led_pattern, * through the entire LUT, so prohibit this. */ if (len < 2) - goto out_free_pattern; + goto out_free; =20 /* * The LPG plays patterns with at a fixed pace, a "low pause" can be @@ -1073,13 +1091,13 @@ static int lpg_pattern_set(struct lpg_led *led, str= uct led_pattern *led_pattern, * specify hi pause. Reject other variations. */ if (i !=3D actual_len - 1) - goto out_free_pattern; + goto out_free; } } =20 /* LPG_RAMP_DURATION_REG is a 9bit */ if (delta_t >=3D BIT(9)) - goto out_free_pattern; + goto out_free; =20 /* * Find "low pause" and "high pause" in the pattern in the LUT case. @@ -1087,20 +1105,48 @@ static int lpg_pattern_set(struct lpg_led *led, str= uct led_pattern *led_pattern, * duration of all steps. */ if (lpg->lut_base || lpg->lut_sdam) { - lo_pause =3D pattern[0].delta_t; - hi_pause =3D pattern[actual_len - 1].delta_t; + prep->lo_pause =3D pattern[0].delta_t; + prep->hi_pause =3D pattern[actual_len - 1].delta_t; } else { if (delta_t !=3D pattern[0].delta_t || delta_t !=3D pattern[actual_len -= 1].delta_t) - goto out_free_pattern; + goto out_free; + prep->lo_pause =3D 0; + prep->hi_pause =3D 0; } =20 + prep->data =3D pattern; + prep->len =3D actual_len; + prep->delta_t =3D delta_t; + prep->ping_pong =3D ping_pong; + + return 0; + +out_free: + kfree(pattern); + return -EINVAL; +} + +static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pa= ttern, + u32 len, int repeat) +{ + struct lpg_channel *chan; + struct lpg *lpg =3D led->lpg; + struct lpg_pattern pattern; + unsigned int lo_idx; + unsigned int hi_idx; + unsigned int i; + int ret; + + ret =3D lpg_prepare_pattern(lpg, led_pattern, len, repeat, &pattern); + if (ret < 0) + return ret; =20 mutex_lock(&lpg->lock); =20 if (lpg->lut_base) - ret =3D lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx); + ret =3D lpg_lut_store(lpg, pattern.data, pattern.len, &lo_idx, &hi_idx); else - ret =3D lpg_lut_store_sdam(lpg, pattern, actual_len, &lo_idx, &hi_idx); + ret =3D lpg_lut_store_sdam(lpg, pattern.data, pattern.len, &lo_idx, &hi_= idx); =20 if (ret < 0) goto out_unlock; @@ -1108,12 +1154,12 @@ static int lpg_pattern_set(struct lpg_led *led, str= uct led_pattern *led_pattern, for (i =3D 0; i < led->num_channels; i++) { chan =3D led->channels[i]; =20 - chan->ramp_tick_ms =3D delta_t; - chan->ramp_ping_pong =3D ping_pong; + chan->ramp_tick_ms =3D pattern.delta_t; + chan->ramp_ping_pong =3D pattern.ping_pong; chan->ramp_oneshot =3D repeat !=3D -1; =20 - chan->ramp_lo_pause_ms =3D lo_pause; - chan->ramp_hi_pause_ms =3D hi_pause; + chan->ramp_lo_pause_ms =3D pattern.lo_pause; + chan->ramp_hi_pause_ms =3D pattern.hi_pause; =20 chan->pattern_lo_idx =3D lo_idx; chan->pattern_hi_idx =3D hi_idx; @@ -1121,8 +1167,7 @@ static int lpg_pattern_set(struct lpg_led *led, struc= t led_pattern *led_pattern, =20 out_unlock: mutex_unlock(&lpg->lock); -out_free_pattern: - kfree(pattern); + kfree(pattern.data); =20 return ret; } @@ -1144,23 +1189,88 @@ static int lpg_pattern_single_set(struct led_classd= ev *cdev, } =20 static int lpg_pattern_mc_set(struct led_classdev *cdev, - struct led_pattern *pattern, u32 len, + struct led_pattern *led_pattern, u32 len, int repeat) { struct led_classdev_mc *mc =3D lcdev_to_mccdev(cdev); struct lpg_led *led =3D container_of(mc, struct lpg_led, mcdev); + struct lpg *lpg =3D led->lpg; + struct lpg_channel *chan; + struct lpg_pattern pattern; + struct led_pattern *scaled; unsigned int triled_mask =3D 0; - int ret, i; + unsigned int lo_idx; + unsigned int hi_idx; + unsigned int scale; + unsigned int i, j; + int ret; + + ret =3D lpg_prepare_pattern(lpg, led_pattern, len, repeat, &pattern); + if (ret < 0) + return ret; + + /* Allocate buffer for the per-channel scaled pattern copy */ + scaled =3D kmalloc_array(pattern.len, sizeof(*scaled), GFP_KERNEL); + if (!scaled) { + ret =3D -ENOMEM; + goto out_free_prep; + } =20 for (i =3D 0; i < led->num_channels; i++) triled_mask |=3D led->channels[i]->triled_mask; - triled_set(led->lpg, triled_mask, 0); + triled_set(lpg, triled_mask, 0); + + led_mc_calc_color_components(mc, LED_FULL); + + /* + * Each channel gets its own LUT block scaled by subled_info[i].brightness + * so the pattern respects the configured colour balance. + */ + mutex_lock(&lpg->lock); + for (i =3D 0; i < led->num_channels; i++) { + chan =3D led->channels[i]; + scale =3D mc->subled_info[i].brightness; + + for (j =3D 0; j < pattern.len; j++) { + scaled[j].brightness =3D DIV_ROUND_CLOSEST( + (u32)pattern.data[j].brightness * scale, LED_FULL); + scaled[j].delta_t =3D pattern.data[j].delta_t; + } + + if (lpg->lut_base) + ret =3D lpg_lut_store(lpg, scaled, pattern.len, &lo_idx, &hi_idx); + else + ret =3D lpg_lut_store_sdam(lpg, scaled, pattern.len, &lo_idx, &hi_idx); + + if (ret < 0) { + /* Free LUT slots already allocated for previous channels */ + while (i-- > 0) { + chan =3D led->channels[i]; + lpg_lut_free(lpg, chan->pattern_lo_idx, chan->pattern_hi_idx); + chan->pattern_lo_idx =3D 0; + chan->pattern_hi_idx =3D 0; + } + goto out_unlock; + } + + chan->ramp_tick_ms =3D pattern.delta_t; + chan->ramp_ping_pong =3D pattern.ping_pong; + chan->ramp_oneshot =3D repeat !=3D -1; + chan->ramp_lo_pause_ms =3D pattern.lo_pause; + chan->ramp_hi_pause_ms =3D pattern.hi_pause; + chan->pattern_lo_idx =3D lo_idx; + chan->pattern_hi_idx =3D hi_idx; + } + +out_unlock: + mutex_unlock(&lpg->lock); + kfree(scaled); +out_free_prep: + kfree(pattern.data); =20 - ret =3D lpg_pattern_set(led, pattern, len, repeat); if (ret < 0) return ret; =20 - led_mc_calc_color_components(mc, LED_FULL); lpg_brightness_set(led, cdev, mc->subled_info); =20 return 0; @@ -1174,11 +1284,9 @@ static int lpg_pattern_clear(struct lpg_led *led) =20 mutex_lock(&lpg->lock); =20 - chan =3D led->channels[0]; - lpg_lut_free(lpg, chan->pattern_lo_idx, chan->pattern_hi_idx); - for (i =3D 0; i < led->num_channels; i++) { chan =3D led->channels[i]; + lpg_lut_free(lpg, chan->pattern_lo_idx, chan->pattern_hi_idx); lpg_sdam_configure_triggers(chan, 0); lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); chan->pattern_lo_idx =3D 0; --- base-commit: 1795fd2dbe84ef4d393b69a0b2a3b371f810bde5 change-id: 20260605-lpg-rgb-color-balance-fix-82436649abf3 Best regards, -- =20 Fenglin Wu