From patchwork Wed Feb 12 14:30:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eddie James X-Patchwork-Id: 864985 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 BD09620458B for ; Wed, 12 Feb 2025 14:30:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370646; cv=none; b=mCdE44f3JZDcT566qGbGpym/0CPVqLKfhl6l0v+X855mkeIROr0m06EJSJ+Oj/n35IkMk+kE5Hi4n/O6Fk1lYP0UmoLw2OpcWz4YqepTOLI3oRZHkB+jvQShwVOJKXE8FVXpTQsn0T1V4Qh6aPke57TMfHMIVwIgxKlZWmofHfY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370646; c=relaxed/simple; bh=eaK7vrOvX+5NN1b0FTrh2LySm8QNKlDxTqVWLhuE2YY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=heuPtP6kL06sYVW9kHB0CM3v1117DDAb1ihfj958BTgO7KUoAWJUyDj0TYuIKHXqrdN65i6xuthpWHYvB8qKLomI14wfnGfNTy2fZgpVSiMP5lz3y38PBflAQMcoCN/GnZLBddHic3J+0FTq4SDMbfuVNwUsWPcfWptzpAeRBkA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=TiENYAKN; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="TiENYAKN" Received: from pps.filterd (m0356516.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 51CCKavf020594; Wed, 12 Feb 2025 14:30:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=Cc2asp5Hag0kDGNiF rn2Ta5kvAk+MUJ0mFl2fgTPo9Y=; b=TiENYAKNn1rYmKJqcm1gZXeooS9BYAWY/ ojouoDrdzmGQPvXgFt5cLYCDa6MgB5j0kCTomsmodb7OaJNi5PqEocAt22rxn/Po 7AIE0M5jCM9fgrdjzQbAdxDxlwNKG4xDvPerL+vIbO9XQpVhtgCq6UD+DbtQfyYa m5znSnp2KpojdNh2qsIqHA9kmESXV9+KGNuQ7xVR9Ijli3+YwxPsanq1OW9QnFQk 23GuMWldXmlKp/O47Ziv1yWnHoAwjaF88mE5ceKRpmujEa72lJXWaFlgzV4jhvqr B8blFHL8c2Cnb/rUJxE/xnF7DnnaBMAvwNOYKRrPIszet/01nrT2A== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6nw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from m0356516.ppops.net (m0356516.ppops.net [127.0.0.1]) by pps.reinject (8.18.0.8/8.18.0.8) with ESMTP id 51CEPJGP004568; Wed, 12 Feb 2025 14:30:40 GMT Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6np-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 51CCpTCv028236; Wed, 12 Feb 2025 14:30:40 GMT Received: from smtprelay02.dal12v.mail.ibm.com ([172.16.1.4]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 44phyyhe3q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay02.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 51CEUdSX30671406 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 12 Feb 2025 14:30:39 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 86F1B5805D; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 648F15806A; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from slate16.aus.stglabs.ibm.com (unknown [9.61.104.210]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) From: Eddie James To: linux-leds@vger.kernel.org Cc: eajames@linux.ibm.com, andy.shevchenko@gmail.com, lee@kernel.org, pavel@kernel.org Subject: [PATCH v8 1/4] leds: pca955x: Refactor with helper functions and renaming Date: Wed, 12 Feb 2025 08:30:35 -0600 Message-ID: <20250212143038.1416501-2-eajames@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250212143038.1416501-1-eajames@linux.ibm.com> References: <20250212143038.1416501-1-eajames@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: LTnCJaoAS-gReP6ComR29M3R4shvZv04 X-Proofpoint-GUID: gqI9_BFUDqPDrKCwdxUV39rBaoP9_vCg X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1057,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-02-12_04,2025-02-11_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 suspectscore=0 adultscore=0 impostorscore=0 phishscore=0 bulkscore=0 mlxlogscore=821 mlxscore=0 clxscore=1011 lowpriorityscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2501170000 definitions=main-2502120111 Add helper functions to clean up the code, and rename a few oddly named functions and variables. Signed-off-by: Eddie James Reviewed-by: Andy Shevchenko --- drivers/leds/leds-pca955x.c | 52 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 94a9f8a54b359..4a7111a24ab49 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -124,13 +124,15 @@ struct pca955x_led { struct fwnode_handle *fwnode; }; +#define led_to_pca955x(l) container_of(l, struct pca955x_led, led_cdev) + struct pca955x_platform_data { struct pca955x_led *leds; int num_leds; }; /* 8 bits per input register */ -static inline int pca95xx_num_input_regs(int bits) +static inline int pca955x_num_input_regs(int bits) { return (bits + 7) / 8; } @@ -145,6 +147,11 @@ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state) ((state & 0x3) << (led_num << 1)); } +static inline int pca955x_ledstate(u8 ls, int led_num) +{ + return (ls >> (led_num << 1)) & 0x3; +} + /* * Write to frequency prescaler register, used to program the * period of the PWM output. period = (PSCx + 1) / 38 @@ -152,7 +159,7 @@ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state) static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) { struct pca955x *pca955x = i2c_get_clientdata(client); - u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + (2 * n); + u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + (2 * n); int ret; ret = i2c_smbus_write_byte_data(client, cmd, val); @@ -172,7 +179,7 @@ static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) { struct pca955x *pca955x = i2c_get_clientdata(client); - u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); + u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); int ret; ret = i2c_smbus_write_byte_data(client, cmd, val); @@ -189,7 +196,7 @@ static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) { struct pca955x *pca955x = i2c_get_clientdata(client); - u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n; + u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 4 + n; int ret; ret = i2c_smbus_write_byte_data(client, cmd, val); @@ -206,7 +213,7 @@ static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val) { struct pca955x *pca955x = i2c_get_clientdata(client); - u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n; + u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 4 + n; int ret; ret = i2c_smbus_read_byte_data(client, cmd); @@ -222,7 +229,7 @@ static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val) static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val) { struct pca955x *pca955x = i2c_get_clientdata(client); - u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); + u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); int ret; ret = i2c_smbus_read_byte_data(client, cmd); @@ -237,9 +244,7 @@ static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val) static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) { - struct pca955x_led *pca955x_led = container_of(led_cdev, - struct pca955x_led, - led_cdev); + struct pca955x_led *pca955x_led = led_to_pca955x(led_cdev); struct pca955x *pca955x = pca955x_led->pca955x; u8 ls, pwm; int ret; @@ -248,8 +253,7 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) if (ret) return ret; - ls = (ls >> ((pca955x_led->led_num % 4) << 1)) & 0x3; - switch (ls) { + switch (pca955x_ledstate(ls, pca955x_led->led_num % 4)) { case PCA955X_LS_LED_ON: ret = LED_FULL; break; @@ -273,34 +277,28 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) static int pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct pca955x_led *pca955x_led; - struct pca955x *pca955x; + struct pca955x_led *pca955x_led = led_to_pca955x(led_cdev); + struct pca955x *pca955x = pca955x_led->pca955x; + int reg = pca955x_led->led_num / 4; + int bit = pca955x_led->led_num % 4; u8 ls; - int chip_ls; /* which LSx to use (0-3 potentially) */ - int ls_led; /* which set of bits within LSx to use (0-3) */ int ret; - pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev); - pca955x = pca955x_led->pca955x; - - chip_ls = pca955x_led->led_num / 4; - ls_led = pca955x_led->led_num % 4; - mutex_lock(&pca955x->lock); - ret = pca955x_read_ls(pca955x->client, chip_ls, &ls); + ret = pca955x_read_ls(pca955x->client, reg, &ls); if (ret) goto out; switch (value) { case LED_FULL: - ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON); + ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_ON); break; case LED_OFF: - ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF); + ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_OFF); break; case LED_HALF: - ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK0); + ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK0); break; default: /* @@ -313,11 +311,11 @@ static int pca955x_led_set(struct led_classdev *led_cdev, ret = pca955x_write_pwm(pca955x->client, 1, 255 - value); if (ret) goto out; - ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1); + ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK1); break; } - ret = pca955x_write_ls(pca955x->client, chip_ls, ls); + ret = pca955x_write_ls(pca955x->client, reg, ls); out: mutex_unlock(&pca955x->lock); From patchwork Wed Feb 12 14:30:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eddie James X-Patchwork-Id: 864984 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 B4A0B20A5F2 for ; Wed, 12 Feb 2025 14:30:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370647; cv=none; b=R4DD7rkr07/cdGnau7Pca1KdPFRyAgKzzikAYoD7ZILpdHAti+9qRHKdtg0zP2G2eIMOjBqe0PaSWXoTs0HE48QeHhowUTKUP8z3Hy7tYTcD4YKHpThp30GyGWJgwZsggcBuN61yMxPEn4MGSlWvLAv3G/1862UtwMXuxUH0CmY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370647; c=relaxed/simple; bh=9KGCHgjovlcK5XrnD5jnkmmToaXePww/iq4vlR4s49U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pQsYp2QlCCSEYCHLdGoKtCTNpNDvwgmLFdqcM8jest68s4JkgmEFPplJstxBPGgjlSqIqd4CPhUNn1wHrczhFHUZgUwgguMKVpsOyCVX72KMt78Yr+qb1Jc9uUShibFTHzsf20+iC/KzyWcZjxJb3t4RIct2FcnVBe94nWk8HWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=ZNFkPfuQ; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="ZNFkPfuQ" Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 51CD85XD013836; Wed, 12 Feb 2025 14:30:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=k80e+u6/Ql2NWACKD DC6QYoK4nwJH+jfVAEChXUCh+k=; b=ZNFkPfuQV8sPgaFimnYeco9NBZl5SxM4S Bom4wl6bsKuj3wg3doYHAuascYDP/9qODq7KHFaxWqlf01W2GlW4aw9D3DIQfBEf jUxzKyYaly5AzKa/K29hTvKU9+oU6JxYnWYRlIGxHKsvCU4VlFRYwOJE9NyJxnDt YiFDs+5fCbF/9K0lsNYE84fawZ+KxWxlV/hSDqyIKX71vLbzStndubt1cw9FudRG dbjyB3Wcd855ZnwqaIzSIq/39XQiBmNywia2L4GH3xGM4LR1vRZdA8/91xGN4rBS 9UW335C7OoAas/s+9u0wUXKuoJ9EBWt3H9W8eWsoEGaye3mFMdv1Q== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44rjfyuj3k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from m0353725.ppops.net (m0353725.ppops.net [127.0.0.1]) by pps.reinject (8.18.0.8/8.18.0.8) with ESMTP id 51CEIw4a014937; Wed, 12 Feb 2025 14:30:41 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44rjfyuj3e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 51CDK6tV016749; Wed, 12 Feb 2025 14:30:40 GMT Received: from smtprelay02.dal12v.mail.ibm.com ([172.16.1.4]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 44pk3k98b2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay02.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 51CEUd1A30671410 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 12 Feb 2025 14:30:39 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AE6555805D; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8D9C658065; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from slate16.aus.stglabs.ibm.com (unknown [9.61.104.210]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) From: Eddie James To: linux-leds@vger.kernel.org Cc: eajames@linux.ibm.com, andy.shevchenko@gmail.com, lee@kernel.org, pavel@kernel.org Subject: [PATCH v8 2/4] leds: pca955x: Use pointers to driver data rather than I2C client Date: Wed, 12 Feb 2025 08:30:36 -0600 Message-ID: <20250212143038.1416501-3-eajames@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250212143038.1416501-1-eajames@linux.ibm.com> References: <20250212143038.1416501-1-eajames@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 1uQvJmZbf5ufJpxebLTP43nqFVYFZjyb X-Proofpoint-ORIG-GUID: Uj7GVAnx4bo_RDOydWNgAv0cbw-hWG7z X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1057,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-02-12_04,2025-02-11_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 impostorscore=0 mlxscore=0 suspectscore=0 adultscore=0 clxscore=1011 mlxlogscore=766 lowpriorityscore=0 priorityscore=1501 phishscore=0 malwarescore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2501170000 definitions=main-2502120111 As a minor clean up item, pass the driver data pointer instead of the I2C client to the reader and writer helper functions. Now the PCA driver data doesn't have to be looked up again in the I2C client data Signed-off-by: Eddie James Reviewed-by: Andy Shevchenko --- drivers/leds/leds-pca955x.c | 61 ++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 4a7111a24ab49..4990f8aff6d16 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -156,16 +156,15 @@ static inline int pca955x_ledstate(u8 ls, int led_num) * Write to frequency prescaler register, used to program the * period of the PWM output. period = (PSCx + 1) / 38 */ -static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) +static int pca955x_write_psc(struct pca955x *pca955x, int n, u8 val) { - struct pca955x *pca955x = i2c_get_clientdata(client); u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + (2 * n); int ret; - ret = i2c_smbus_write_byte_data(client, cmd, val); + ret = i2c_smbus_write_byte_data(pca955x->client, cmd, val); if (ret < 0) - dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", - __func__, n, val, ret); + dev_err(&pca955x->client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", __func__, n, + val, ret); return ret; } @@ -176,16 +175,15 @@ static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) * * Duty cycle is (256 - PWMx) / 256 */ -static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) +static int pca955x_write_pwm(struct pca955x *pca955x, int n, u8 val) { - struct pca955x *pca955x = i2c_get_clientdata(client); u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); int ret; - ret = i2c_smbus_write_byte_data(client, cmd, val); + ret = i2c_smbus_write_byte_data(pca955x->client, cmd, val); if (ret < 0) - dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", - __func__, n, val, ret); + dev_err(&pca955x->client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", __func__, n, + val, ret); return ret; } @@ -193,16 +191,15 @@ static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) * Write to LED selector register, which determines the source that * drives the LED output. */ -static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) +static int pca955x_write_ls(struct pca955x *pca955x, int n, u8 val) { - struct pca955x *pca955x = i2c_get_clientdata(client); u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 4 + n; int ret; - ret = i2c_smbus_write_byte_data(client, cmd, val); + ret = i2c_smbus_write_byte_data(pca955x->client, cmd, val); if (ret < 0) - dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", - __func__, n, val, ret); + dev_err(&pca955x->client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", __func__, n, + val, ret); return ret; } @@ -210,32 +207,28 @@ static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) * Read the LED selector register, which determines the source that * drives the LED output. */ -static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val) +static int pca955x_read_ls(struct pca955x *pca955x, int n, u8 *val) { - struct pca955x *pca955x = i2c_get_clientdata(client); u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 4 + n; int ret; - ret = i2c_smbus_read_byte_data(client, cmd); + ret = i2c_smbus_read_byte_data(pca955x->client, cmd); if (ret < 0) { - dev_err(&client->dev, "%s: reg 0x%x, err %d\n", - __func__, n, ret); + dev_err(&pca955x->client->dev, "%s: reg 0x%x, err %d\n", __func__, n, ret); return ret; } *val = (u8)ret; return 0; } -static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val) +static int pca955x_read_pwm(struct pca955x *pca955x, int n, u8 *val) { - struct pca955x *pca955x = i2c_get_clientdata(client); u8 cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n); int ret; - ret = i2c_smbus_read_byte_data(client, cmd); + ret = i2c_smbus_read_byte_data(pca955x->client, cmd); if (ret < 0) { - dev_err(&client->dev, "%s: reg 0x%x, err %d\n", - __func__, n, ret); + dev_err(&pca955x->client->dev, "%s: reg 0x%x, err %d\n", __func__, n, ret); return ret; } *val = (u8)ret; @@ -249,7 +242,7 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) u8 ls, pwm; int ret; - ret = pca955x_read_ls(pca955x->client, pca955x_led->led_num / 4, &ls); + ret = pca955x_read_ls(pca955x, pca955x_led->led_num / 4, &ls); if (ret) return ret; @@ -264,7 +257,7 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) ret = LED_HALF; break; case PCA955X_LS_BLINK1: - ret = pca955x_read_pwm(pca955x->client, 1, &pwm); + ret = pca955x_read_pwm(pca955x, 1, &pwm); if (ret) return ret; ret = 255 - pwm; @@ -286,7 +279,7 @@ static int pca955x_led_set(struct led_classdev *led_cdev, mutex_lock(&pca955x->lock); - ret = pca955x_read_ls(pca955x->client, reg, &ls); + ret = pca955x_read_ls(pca955x, reg, &ls); if (ret) goto out; @@ -308,14 +301,14 @@ static int pca955x_led_set(struct led_classdev *led_cdev, * OFF, HALF, or FULL. But, this is probably better than * just turning off for all other values. */ - ret = pca955x_write_pwm(pca955x->client, 1, 255 - value); + ret = pca955x_write_pwm(pca955x, 1, 255 - value); if (ret) goto out; ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK1); break; } - ret = pca955x_write_ls(pca955x->client, reg, ls); + ret = pca955x_write_ls(pca955x, reg, ls); out: mutex_unlock(&pca955x->lock); @@ -579,22 +572,22 @@ static int pca955x_probe(struct i2c_client *client) } /* PWM0 is used for half brightness or 50% duty cycle */ - err = pca955x_write_pwm(client, 0, 255 - LED_HALF); + err = pca955x_write_pwm(pca955x, 0, 255 - LED_HALF); if (err) return err; if (!keep_pwm) { /* PWM1 is used for variable brightness, default to OFF */ - err = pca955x_write_pwm(client, 1, 0); + err = pca955x_write_pwm(pca955x, 1, 0); if (err) return err; } /* Set to fast frequency so we do not see flashing */ - err = pca955x_write_psc(client, 0, 0); + err = pca955x_write_psc(pca955x, 0, 0); if (err) return err; - err = pca955x_write_psc(client, 1, 0); + err = pca955x_write_psc(pca955x, 1, 0); if (err) return err; From patchwork Wed Feb 12 14:30:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eddie James X-Patchwork-Id: 864722 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 7933B2066E2 for ; Wed, 12 Feb 2025 14:30:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370647; cv=none; b=Z/g22J44EztzClQRX7CDNgfP1MsvlSpw1LUQUjvl1z3dDNSyQ2Hao1GYMub8oiZFjmLDBcEi9IIzeaAjFyUhFCIgIQdb3NiUzLy95oEJKjWHLwJrHy1Cc8E8QjixTre6i3SSPNVkiypNDyhqe8H54YbUTkJ+fOjXSwXXVn5mKWw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370647; c=relaxed/simple; bh=QQvooXI0tVQVA5T46yImYY8GI+9R0G36ovFEEqmR+MM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s7R3KjFvnMWxGAww8fXqNpiS97bcuizvQsp1KrsqK9fkAcH5kVDzEndTvJZ3WPnX7MY/mGVGpU6QeThmGMuOyBRcmfTTSQglvqqg9GFwiYk39ciDvSQW2K0yN2ITNgqmBg3oB9mHkwsRczzGR6cQTYl8hvZPkZRh74pMgMN7oCk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=TQLsbTbF; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="TQLsbTbF" Received: from pps.filterd (m0356516.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 51CAT094021320; Wed, 12 Feb 2025 14:30:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=kdbdrs8hWKIdppRKu for5ddAEudusp4cDLzfQcOtm6Y=; b=TQLsbTbFvfcUaQI3fF/LtSDAZ9oBIAgzR CgMz5sov2D3b0h1OhyhljV1ADXAn3nn5qW2xtnUlnTJPXI5hf2upfCVKy+c2T97T PbNhSIrOzvY4tUEcKHOet603yFpevbrufqAatUeaCxh7vso6c1+7k0dzyQMFFRoc K2MNRC121L0IwzbnVAK3I36rmqp+u5ITv+cr2biXXmZEGLquAJOgrOJY/Xt9i+VC II8WUlpIm64MxMspPLgeTHkHQCMgVsuVJGpuTp1X/48phxPLgCNQmUk8RWVqMGOz YxheldRh6JwJmOAjmwjzH08QG4C4Et7G4GAyXbovdTiHGUFYsndOA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6p2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from m0356516.ppops.net (m0356516.ppops.net [127.0.0.1]) by pps.reinject (8.18.0.8/8.18.0.8) with ESMTP id 51CEJmmc022120; Wed, 12 Feb 2025 14:30:40 GMT Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6nq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 51CDV1QZ012083; Wed, 12 Feb 2025 14:30:40 GMT Received: from smtprelay02.dal12v.mail.ibm.com ([172.16.1.4]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 44pktk120q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay02.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 51CEUd9D14615156 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 12 Feb 2025 14:30:40 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D605758065; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B502958068; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from slate16.aus.stglabs.ibm.com (unknown [9.61.104.210]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) From: Eddie James To: linux-leds@vger.kernel.org Cc: eajames@linux.ibm.com, andy.shevchenko@gmail.com, lee@kernel.org, pavel@kernel.org Subject: [PATCH v8 3/4] leds: pca955x: Optimize probe led selection Date: Wed, 12 Feb 2025 08:30:37 -0600 Message-ID: <20250212143038.1416501-4-eajames@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250212143038.1416501-1-eajames@linux.ibm.com> References: <20250212143038.1416501-1-eajames@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: r47-l7TSvlSkRS1y9gxDf5mWtVvooPzP X-Proofpoint-GUID: p8ZNk2AbylB7jMuYSzC2aXKx_t5AhTM1 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1057,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-02-12_04,2025-02-11_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 suspectscore=0 adultscore=0 impostorscore=0 phishscore=0 bulkscore=0 mlxlogscore=716 mlxscore=0 clxscore=1011 lowpriorityscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2501170000 definitions=main-2502120111 Previously, the probe function might do up to 32 reads and writes to the same 4 registers to program the led selection. Reduce this to a maximum of 5 operations by accumulating the changes to the led selection and comparing with the previous value to write the selection if different. Signed-off-by: Eddie James Reviewed-by: Andy Shevchenko --- Changes since v7: - Improve comment - Use post-increment drivers/leds/leds-pca955x.c | 38 +++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 4990f8aff6d16..eb268e6ee2a8b 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -446,7 +446,9 @@ static int pca955x_probe(struct i2c_client *client) struct led_classdev *led; struct led_init_data init_data; struct i2c_adapter *adapter; - int i, err; + int i, bit, err, nls, reg; + u8 ls1[4]; + u8 ls2[4]; struct pca955x_platform_data *pdata; bool set_default_label = false; bool keep_pwm = false; @@ -504,6 +506,17 @@ static int pca955x_probe(struct i2c_client *client) init_data.devname_mandatory = false; init_data.devicename = "pca955x"; + nls = pca955x_num_led_regs(chip->bits); + /* Use auto-increment feature to read all the LED selectors at once. */ + err = i2c_smbus_read_i2c_block_data(client, + 0x10 | (pca955x_num_input_regs(chip->bits) + 4), nls, + ls1); + if (err < 0) + return err; + + for (i = 0; i < nls; i++) + ls2[i] = ls1[i]; + for (i = 0; i < chip->bits; i++) { pca955x_led = &pca955x->leds[i]; pca955x_led->led_num = i; @@ -515,19 +528,16 @@ static int pca955x_probe(struct i2c_client *client) case PCA955X_TYPE_GPIO: break; case PCA955X_TYPE_LED: + bit = i % 4; + reg = i / 4; led = &pca955x_led->led_cdev; led->brightness_set_blocking = pca955x_led_set; led->brightness_get = pca955x_led_get; - if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF) { - err = pca955x_led_set(led, LED_OFF); - if (err) - return err; - } else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON) { - err = pca955x_led_set(led, LED_FULL); - if (err) - return err; - } + if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF) + ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_OFF); + else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON) + ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_ON); init_data.fwnode = pdata->leds[i].fwnode; @@ -571,6 +581,14 @@ static int pca955x_probe(struct i2c_client *client) } } + for (i = 0; i < nls; i++) { + if (ls1[i] != ls2[i]) { + err = pca955x_write_ls(pca955x, i, ls2[i]); + if (err) + return err; + } + } + /* PWM0 is used for half brightness or 50% duty cycle */ err = pca955x_write_pwm(pca955x, 0, 255 - LED_HALF); if (err) From patchwork Wed Feb 12 14:30:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eddie James X-Patchwork-Id: 864721 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 DBA6920458B for ; Wed, 12 Feb 2025 14:30:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370648; cv=none; b=TDKbUmeGNNEuUTk355tJyVHPOc2irikiz+65hv4je5yJ5D0lNS3JITpxB+Ubbf1Schaq9MXSF7jb3uqc00FJWrdMePQo0RSWUsQzl1cckXa4NegGEOBAlb3AOFRhMuSjoMNBJaD2f3hixRCg/4EQ3Gfv2ahZLjdpZgCbYFS12Eg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739370648; c=relaxed/simple; bh=cxcalY3SsRnbZucSuGbKEa0SK+pd7/YFMWyjhgof3eI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=si6tA1wWf+Dru3EBQcI4xJGlNcLfGlDNr1+nC7Uew4DL0TlJFUhwA3bbif5+ewOAOBFl2A9BTfzEFc0bF1fKLZ+ZoOseQsYr9Rp+BbNtdySk1IydCwH1S7coMCHUG0oinYlaBjNYphf/afjXdvnepdHfu1Ml9cZ7wruwO/Fu2I8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=pfbI3E5y; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="pfbI3E5y" Received: from pps.filterd (m0356516.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 51CDJpxH021340; Wed, 12 Feb 2025 14:30:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=2uRzeX5VocdCzQM1f 5vCnF78kTTf5802I4r+LuiOr5I=; b=pfbI3E5yaXm79dWmGdSIzvRGghU8Y+fWO v6Yo8o1q7R6hrm1/1NPMf4hi9FUxuYBXdAyrZKuXtywlAiux7dKSbSeRpj//4hmn QvNfo3u1usuQ2PnnPRnGQWirLbRZegmW36uar0EAFmwmaJEKNIK7oBWexBFYavRr 2BtdTsI248aGwvKcDVGcv6wZH1C3X9SX54Xc9FYn4MGinBY3qpd2RC9Qjutan+Rj bi/yQQqiuJiPfKQcKVUwWDFIc8pLp5OdeHW82sHjgkBj1Vyk4HLOgM2DQEQXdRn9 o6YgdoHXmFxFqZDymW67b44OZ9Iv5lgKMBNYOf0aQ22enolAZMVMg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6p5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from m0356516.ppops.net (m0356516.ppops.net [127.0.0.1]) by pps.reinject (8.18.0.8/8.18.0.8) with ESMTP id 51CEUeXE022827; Wed, 12 Feb 2025 14:30:41 GMT Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44r9cue6nt-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:41 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 51CDSLmZ011651; Wed, 12 Feb 2025 14:30:40 GMT Received: from smtprelay06.dal12v.mail.ibm.com ([172.16.1.8]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 44pktk120s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 12 Feb 2025 14:30:40 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay06.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 51CEUedF29164152 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 12 Feb 2025 14:30:40 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1105558056; Wed, 12 Feb 2025 14:30:40 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DCCCC58067; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) Received: from slate16.aus.stglabs.ibm.com (unknown [9.61.104.210]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Wed, 12 Feb 2025 14:30:39 +0000 (GMT) From: Eddie James To: linux-leds@vger.kernel.org Cc: eajames@linux.ibm.com, andy.shevchenko@gmail.com, lee@kernel.org, pavel@kernel.org Subject: [PATCH v8 4/4] leds: pca955x: Add HW blink support Date: Wed, 12 Feb 2025 08:30:38 -0600 Message-ID: <20250212143038.1416501-5-eajames@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250212143038.1416501-1-eajames@linux.ibm.com> References: <20250212143038.1416501-1-eajames@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: r0pU9VN-m3vwUi4tchQz6xrU-3iS6GlR X-Proofpoint-GUID: Gq04GaF9Btuh_WNWiXEMPWW15V9uPWqt X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1057,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-02-12_04,2025-02-11_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 suspectscore=0 adultscore=0 impostorscore=0 phishscore=0 bulkscore=0 mlxlogscore=999 mlxscore=0 clxscore=1015 lowpriorityscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2501170000 definitions=main-2502120111 Support blinking using the PCA955x chip. Use PWM0 for blinking instead of LED_HALF brightness. Since there is only one frequency and brightness register for any blinking LED, track the blink state of each LED and only support one HW blinking frequency. If another frequency is requested, fallback to software blinking. In addition, blinked LEDs can only use full brightness in order to maintain 50% duty cycle, which is required for the specified blink rate. Signed-off-by: Eddie James Reviewed-by: Andy Shevchenko --- Changes since v7: - Split declaration and assignment for lengthy function call - Use 'period' instead of 'p' - Add comments for psc/blink rate conversion functions drivers/leds/leds-pca955x.c | 224 +++++++++++++++++++++++++++--------- 1 file changed, 172 insertions(+), 52 deletions(-) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index eb268e6ee2a8b..156649e1e1c4f 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -62,6 +62,8 @@ #define PCA955X_GPIO_HIGH LED_OFF #define PCA955X_GPIO_LOW LED_FULL +#define PCA955X_BLINK_DEFAULT_MS 1000 + enum pca955x_type { pca9550, pca9551, @@ -74,6 +76,7 @@ struct pca955x_chipdef { int bits; u8 slv_addr; /* 7-bit slave address mask */ int slv_addr_shift; /* Number of bits to ignore */ + int blink_div; /* PSC divider */ }; static const struct pca955x_chipdef pca955x_chipdefs[] = { @@ -81,26 +84,31 @@ static const struct pca955x_chipdef pca955x_chipdefs[] = { .bits = 2, .slv_addr = /* 110000x */ 0x60, .slv_addr_shift = 1, + .blink_div = 44, }, [pca9551] = { .bits = 8, .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, + .blink_div = 38, }, [pca9552] = { .bits = 16, .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, + .blink_div = 44, }, [ibm_pca9552] = { .bits = 16, .slv_addr = /* 0110xxx */ 0x30, .slv_addr_shift = 3, + .blink_div = 44, }, [pca9553] = { .bits = 4, .slv_addr = /* 110001x */ 0x62, .slv_addr_shift = 1, + .blink_div = 44, }, }; @@ -109,7 +117,9 @@ struct pca955x { struct pca955x_led *leds; const struct pca955x_chipdef *chipdef; struct i2c_client *client; + unsigned long active_blink; unsigned long active_pins; + unsigned long blink_period; #ifdef CONFIG_LEDS_PCA955X_GPIO struct gpio_chip gpio; #endif @@ -154,7 +164,8 @@ static inline int pca955x_ledstate(u8 ls, int led_num) /* * Write to frequency prescaler register, used to program the - * period of the PWM output. period = (PSCx + 1) / 38 + * period of the PWM output. period = (PSCx + 1) / coeff + * Where for pca9551 chips coeff = 38 and for all other chips coeff = 44 */ static int pca955x_write_psc(struct pca955x *pca955x, int n, u8 val) { @@ -235,6 +246,21 @@ static int pca955x_read_pwm(struct pca955x *pca955x, int n, u8 *val) return 0; } +static int pca955x_read_psc(struct pca955x *pca955x, int n, u8 *val) +{ + int ret; + u8 cmd; + + cmd = pca955x_num_input_regs(pca955x->chipdef->bits) + (2 * n); + ret = i2c_smbus_read_byte_data(pca955x->client, cmd); + if (ret < 0) { + dev_err(&pca955x->client->dev, "%s: reg 0x%x, err %d\n", __func__, n, ret); + return ret; + } + *val = (u8)ret; + return 0; +} + static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) { struct pca955x_led *pca955x_led = led_to_pca955x(led_cdev); @@ -248,14 +274,12 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev) switch (pca955x_ledstate(ls, pca955x_led->led_num % 4)) { case PCA955X_LS_LED_ON: + case PCA955X_LS_BLINK0: ret = LED_FULL; break; case PCA955X_LS_LED_OFF: ret = LED_OFF; break; - case PCA955X_LS_BLINK0: - ret = LED_HALF; - break; case PCA955X_LS_BLINK1: ret = pca955x_read_pwm(pca955x, 1, &pwm); if (ret) @@ -283,29 +307,36 @@ static int pca955x_led_set(struct led_classdev *led_cdev, if (ret) goto out; - switch (value) { - case LED_FULL: - ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_ON); - break; - case LED_OFF: - ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_OFF); - break; - case LED_HALF: - ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK0); - break; - default: - /* - * Use PWM1 for all other values. This has the unwanted - * side effect of making all LEDs on the chip share the - * same brightness level if set to a value other than - * OFF, HALF, or FULL. But, this is probably better than - * just turning off for all other values. - */ - ret = pca955x_write_pwm(pca955x, 1, 255 - value); - if (ret) + if (test_bit(pca955x_led->led_num, &pca955x->active_blink)) { + if (value == LED_OFF) { + clear_bit(pca955x_led->led_num, &pca955x->active_blink); + ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_OFF); + } else { + /* No variable brightness for blinking LEDs */ goto out; - ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK1); - break; + } + } else { + switch (value) { + case LED_FULL: + ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_ON); + break; + case LED_OFF: + ls = pca955x_ledsel(ls, bit, PCA955X_LS_LED_OFF); + break; + default: + /* + * Use PWM1 for all other values. This has the unwanted + * side effect of making all LEDs on the chip share the + * same brightness level if set to a value other than + * OFF or FULL. But, this is probably better than just + * turning off for all other values. + */ + ret = pca955x_write_pwm(pca955x, 1, 255 - value); + if (ret) + goto out; + ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK1); + break; + } } ret = pca955x_write_ls(pca955x, reg, ls); @@ -316,6 +347,104 @@ static int pca955x_led_set(struct led_classdev *led_cdev, return ret; } +static u8 pca955x_period_to_psc(struct pca955x *pca955x, unsigned long period) +{ + /* psc register value = (blink period * coeff) - 1 */ + period *= pca955x->chipdef->blink_div; + period /= MSEC_PER_SEC; + period -= 1; + + return period; +} + +static unsigned long pca955x_psc_to_period(struct pca955x *pca955x, u8 psc) +{ + unsigned long period = psc; + + /* blink period = (psc register value + 1) / coeff */ + period += 1; + period *= MSEC_PER_SEC; + period /= pca955x->chipdef->blink_div; + + return period; +} + +static int pca955x_led_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct pca955x_led *pca955x_led = led_to_pca955x(led_cdev); + struct pca955x *pca955x = pca955x_led->pca955x; + unsigned long period = *delay_on + *delay_off; + int ret = 0; + + mutex_lock(&pca955x->lock); + + if (period) { + if (*delay_on != *delay_off) { + ret = -EINVAL; + goto out; + } + + if (period < pca955x_psc_to_period(pca955x, 0) || + period > pca955x_psc_to_period(pca955x, 0xff)) { + ret = -EINVAL; + goto out; + } + } else { + period = pca955x->active_blink ? pca955x->blink_period : + PCA955X_BLINK_DEFAULT_MS; + } + + if (!pca955x->active_blink || + pca955x->active_blink == BIT(pca955x_led->led_num) || + pca955x->blink_period == period) { + u8 psc = pca955x_period_to_psc(pca955x, period); + + if (!test_and_set_bit(pca955x_led->led_num, + &pca955x->active_blink)) { + u8 ls; + int reg = pca955x_led->led_num / 4; + int bit = pca955x_led->led_num % 4; + + ret = pca955x_read_ls(pca955x, reg, &ls); + if (ret) + goto out; + + ls = pca955x_ledsel(ls, bit, PCA955X_LS_BLINK0); + ret = pca955x_write_ls(pca955x, reg, ls); + if (ret) + goto out; + + /* + * Force 50% duty cycle to maintain the specified + * blink rate. + */ + ret = pca955x_write_pwm(pca955x, 0, 128); + if (ret) + goto out; + } + + if (pca955x->blink_period != period) { + pca955x->blink_period = period; + ret = pca955x_write_psc(pca955x, 0, psc); + if (ret) + goto out; + } + + period = pca955x_psc_to_period(pca955x, psc); + period /= 2; + *delay_on = period; + *delay_off = period; + } else { + ret = -EBUSY; + } + +out: + mutex_unlock(&pca955x->lock); + + return ret; +} + #ifdef CONFIG_LEDS_PCA955X_GPIO /* * Read the INPUT register, which contains the state of LEDs. @@ -450,8 +579,9 @@ static int pca955x_probe(struct i2c_client *client) u8 ls1[4]; u8 ls2[4]; struct pca955x_platform_data *pdata; + u8 psc0; + bool keep_psc0 = false; bool set_default_label = false; - bool keep_pwm = false; char default_label[8]; chip = i2c_get_match_data(client); @@ -502,6 +632,7 @@ static int pca955x_probe(struct i2c_client *client) mutex_init(&pca955x->lock); pca955x->client = client; pca955x->chipdef = chip; + pca955x->blink_period = PCA955X_BLINK_DEFAULT_MS; init_data.devname_mandatory = false; init_data.devicename = "pca955x"; @@ -533,11 +664,16 @@ static int pca955x_probe(struct i2c_client *client) led = &pca955x_led->led_cdev; led->brightness_set_blocking = pca955x_led_set; led->brightness_get = pca955x_led_get; + led->blink_set = pca955x_led_blink; if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF) ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_OFF); else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON) ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_ON); + else if (pca955x_ledstate(ls2[reg], bit) == PCA955X_LS_BLINK0) { + keep_psc0 = true; + set_bit(i, &pca955x->active_blink); + } init_data.fwnode = pdata->leds[i].fwnode; @@ -565,19 +701,6 @@ static int pca955x_probe(struct i2c_client *client) return err; set_bit(i, &pca955x->active_pins); - - /* - * For default-state == "keep", let the core update the - * brightness from the hardware, then check the - * brightness to see if it's using PWM1. If so, PWM1 - * should not be written below. - */ - if (pdata->leds[i].default_state == LEDS_DEFSTATE_KEEP) { - if (led->brightness != LED_FULL && - led->brightness != LED_OFF && - led->brightness != LED_HALF) - keep_pwm = true; - } } } @@ -589,22 +712,19 @@ static int pca955x_probe(struct i2c_client *client) } } - /* PWM0 is used for half brightness or 50% duty cycle */ - err = pca955x_write_pwm(pca955x, 0, 255 - LED_HALF); - if (err) - return err; - - if (!keep_pwm) { - /* PWM1 is used for variable brightness, default to OFF */ - err = pca955x_write_pwm(pca955x, 1, 0); - if (err) - return err; + if (keep_psc0) { + err = pca955x_read_psc(pca955x, 0, &psc0); + } else { + psc0 = pca955x_period_to_psc(pca955x, pca955x->blink_period); + err = pca955x_write_psc(pca955x, 0, psc0); } - /* Set to fast frequency so we do not see flashing */ - err = pca955x_write_psc(pca955x, 0, 0); if (err) return err; + + pca955x->blink_period = pca955x_psc_to_period(pca955x, psc0); + + /* Set PWM1 to fast frequency so we do not see flashing */ err = pca955x_write_psc(pca955x, 1, 0); if (err) return err;