From nobody Sun Oct 5 21:57:24 2025 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (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 CF302288C34 for ; Tue, 29 Jul 2025 10:36:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785397; cv=none; b=lvFPNKqS1epeIShR83BqCvxEz6xG9zTYRoOKSvYUir4GOMxr+q7hcwE117v7h0s31ld5VrigKnCp7e/x1/6PPDu5cK8pJHi4ZWyJmLs+Q6bKGuTutIUP8Y37g6Y5x6LKF95F4MCnojuNRtBk5uRMqQs4WTDLMBW+mZl/QoTL4lo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785397; c=relaxed/simple; bh=kStrKArnSK1/UpquxNxJnujQbThqDJu1NL9oxLvTxtY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jCFR+3+M1CmGRVGV40km65ToQyjoI7mUuYkZieRodmGZJ2EZXLpyOqRhkRelNd7Qw4qld+//GIw4puQDuiGg9TKvNKDmERQmHr/eghxqERSHpHBwFbZ/EgGLp31JyrezJXtSho2KcbGXFt3E+iH8txu/3srjIal1blW++8gVJCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=U2KkoAh4; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="U2KkoAh4" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-3b77673fd78so2610739f8f.0 for ; Tue, 29 Jul 2025 03:36:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1753785392; x=1754390192; 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=N3/Mn3OWGfo9s2BHWZIuyQwZlVzznOtE4mN1WG8m4Kg=; b=U2KkoAh4HSnbG9f+3ZAzw7SpbD7zyeBc/JVAMu1kZeB01gOik6GcGXq2xa4V9KYcmC dCjlqvT42OQTZQTucHGL9RBhdU+SEWudGx5GJjpa8UeGb7TpNLd4PC6VwRw9BtItHICy bwkwa+jW+FJdXzvFhEf1VEAGvzK3frr7XL5RPW1Ymz173dtyQAk8S09Oft/YZCft1INN Ml/PKn3im0psAAtBCZG3YjgTZ6hnIOCrbBRVLPVr2qOjD6yOKXrWU0seKJvF0F6ZXsWI DQYN+kzEyH3PUV3YSOaNtj0abspIp8opB4x5lY2atwtIk/e4u+1qxdB2hdPTFUlZbLWb 9yOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753785392; x=1754390192; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=N3/Mn3OWGfo9s2BHWZIuyQwZlVzznOtE4mN1WG8m4Kg=; b=F/sSwkweWsNtLZEWmHh4weZZLIjeESWOKAVaXnhnwCYpxeVWTOORSnIH7RXFB3dtmP dCWbqKjrSNse5lakyPqEpb+B6rWf9L9Tbzls9uB/0Hd5BslBUOvrQtzdW3SLS+/rc5w1 SDmKh8IB7D+aVRNHbhcjSUCZB//BkxpgWgpcT5G+JIeuYE6evgrQI6ob21LG9Z1ts2B0 bG0XgMZcjuv7s2een000Q67XFAOJqPdKI9xf1OgtmWsttcHI1Gq7L4p093DJamckgJDB XUuv4WZt48PJgtvtp8ldXxcPtMdvZY6UFKvc0cZ+zjl9GWwj5gh0JYuOWD08eumI8F8Y ObiQ== X-Forwarded-Encrypted: i=1; AJvYcCVfFnRnFIZJM5Q+J0+1kF/c9o6xQddsHNmGqbUCjOsnf/p3cxGLw3Td8jepxKwCklJivohabzYMJuIh5n8=@vger.kernel.org X-Gm-Message-State: AOJu0YwzsRNBhZ8Bk3hRiH86R3PwYdKVGIqHMzGXKkyMdIyLFAq2+njZ UdgLg20LrpMddBQQTXZoDLVAeBN9Tn+BsQDrSbFRG/uMvIhkIrsUYBlWXEcQ6ORSWdo= X-Gm-Gg: ASbGnctJ3mLP9Ef9UCoP88v25OZESj9rNo3k9b/4j+cM/LFQ0Vzn6UDtvCerN9nz33x 7+op/B/AKAQfPuSiJhbBz+utM2W2PwXSOWtGYznwj87nPl8BRSiqZx9i7Ua7wi4kveydx8pvv+E NlI3TtpUK6nwsCY759kl/o0ZKCaXf6qc552eli6cy2LWilcMrPfMKL2qneoP4GItlFhrzxAGG4V WdonBAhWCfGg/G4/3Yhw9ZSEYzGkAK7wgc9lzyPM8fi6+fPCkoiyRuiXQ0KUj6CNQtEaRZjaonz sYaHWcwDvdxV9z8XRKWULHYFaPCZhJJA4ihFa2BDwAkV8FaoWR1J+bpL/mZYn0eOetS31wXdWKL VKzrouP2MS6HdaP81vVRmRuXNuz1koQ0wIHvHXc0VKlNIYpcpMGrMy9kRlqdNb/Hn X-Google-Smtp-Source: AGHT+IE866eWL+zj2Yu8ZEdG9Leib9gNx0Mwqy0baoDrZCSd8lBpM6cprNsV7mZpEagWPWAeeS1z3A== X-Received: by 2002:a05:6000:2502:b0:3b7:90db:aaba with SMTP id ffacd0b85a97d-3b790dbb162mr1187849f8f.24.1753785392003; Tue, 29 Jul 2025 03:36:32 -0700 (PDT) Received: from localhost (p200300f65f06ab0400000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f06:ab04::1b9]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-458705c4d91sm198068015e9.23.2025.07.29.03.36.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Jul 2025 03:36:31 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Jander , Clemens Gruber , linux-kernel@vger.kernel.org Subject: [PATCH 1/5] pwm: pca9685: Don't disable hardware in .free() Date: Tue, 29 Jul 2025 12:36:00 +0200 Message-ID: <1ee1a514aeb5f0effafa2d6ec91bc54130895cd9.1753784092.git.u.kleine-koenig@baylibre.com> X-Mailer: git-send-email 2.50.0 In-Reply-To: References: 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" X-Developer-Signature: v=1; a=openpgp-sha256; l=1008; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=kStrKArnSK1/UpquxNxJnujQbThqDJu1NL9oxLvTxtY=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoiKQSiW076lomyIjFfY6Xd+adPvN9z6QFCZGEX BJFLG5Zot6JATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaIikEgAKCRCPgPtYfRL+ TloaB/4mI91CeVM7rRzxDsC3YKZtJBVuRHvjeMIOPqWBPmjd/4YL4HqEed6Xqnspkb+6oMhsbAP 69wxv39m+Pv7CSIBI7xHlNuuudz/0DrWDM3eMQweXTwHUbQY/4W9DhMVk295gX1Yhd9IY5LVf0/ YECw4MyGSvS4V2gespyBcWJY28geG5y5Qukd86MyCPyuYnTEtT8RewWk5KiP7N7+5m8OvcT7rSO ZpNFf/9LcZ/SzChNlxmPJi1F74oRnAqNYoFDmrN+qE3rhrymKf47TwurdQUMWSSkmDt3hHOlE+L 7ckDwnAjYPx47kWpfAwgTkm7RX3lWpkv2Ea2SaF0ULsMkBLJ X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable It's the responsibility of the consumer to disable the hardware before it's released. And there are use cases where it's beneficial to keep the PWM on, e.g. to keep a backlight on before kexec()ing into a new kernel. Even if it would be considered right to disable on pwm_put(), this should be done in the core and not each individual driver. So drop the hardware access in .free(). Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/pwm-pca9685.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index eb03ccd5b688..41eb8e034828 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -497,7 +497,6 @@ static void pca9685_pwm_free(struct pwm_chip *chip, str= uct pwm_device *pwm) struct pca9685 *pca =3D to_pca(chip); =20 mutex_lock(&pca->lock); - pca9685_pwm_set_duty(chip, pwm->hwpwm, 0); clear_bit(pwm->hwpwm, pca->pwms_enabled); mutex_unlock(&pca->lock); =20 --=20 2.50.0 From nobody Sun Oct 5 21:57:24 2025 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (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 41D66273D78 for ; Tue, 29 Jul 2025 10:36:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785397; cv=none; b=Tq1z8HHMtuf2IOp7XahYg3/hArPWSe+kQTWGbH0jhPkWinG0Ro55KJmWF7V+ZE8WyviM7qiQMtBLaLSoQudikJ4Y+FuSasdC+cR7wtoCRTlK0KMRUdLIT/Ee3fqynVGE6enXLgvlGB80o0mizJv7WbFOMQjlmgq2bR+0lEEVcB0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785397; c=relaxed/simple; bh=vFkS3MCcz044w85i6x5Sg9hS8f9ssjZYZP9S3l0oUV8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nwpGghrSmgx94p61/aq23xAqrGro/CwreT8XJOaFNg5LDBY3/LNGiOf1C+kmen0L5nhJdLq4gTowWjQVZSGf1WTpvRuY4hs8jE2m0+PIveXjdLJlhesldLz7jdabc6cr9O20hSztvYr9F2IVnMP52iu+A0h6tZly+tDTiQr/6ew= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=3bzUXVXk; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="3bzUXVXk" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-4550709f2c1so42061865e9.3 for ; Tue, 29 Jul 2025 03:36:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1753785393; x=1754390193; 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=y7jjlbIUi5gdyqWR9uROLdSWPZjnUGwKYOi8+eCrVJk=; b=3bzUXVXkBdKFW4ev8y9adFFqwMtwmK6moQiLCAdHIptAOKAa7GteLDse9/Q8dX7Llv Ptxp4Q9ObH7LZeflnp6MZw7uEmmi5Aad2kA1wj/+iquBKNv+t1ZKzKWb3C44XhYtf0t2 EmlduSgtL9bCcUlS5VzTLU0gGYV/HcKy8yMO/JMXjLN+XZSdSN7m3EQqkj8+t+uAYJLs mbh44q8uVn7m3Hk6ARqrqVIWZyr0FUsSetbJUlUAggw1D8AiAlFcDzZ+oQxkl+fACsJ+ qA+XRKaOAhJTpSfs6/U8Uesyp78Neu5dKhsSJSduKlYn5rNJGz76PtmEPfXrcVDZP/0h N+pA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753785393; x=1754390193; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=y7jjlbIUi5gdyqWR9uROLdSWPZjnUGwKYOi8+eCrVJk=; b=oFouTXT+eMtE+lXYcEZ1J4j7hSWO9fkpT1ZPG4/iCfYnd3wRX3bR3G6KBRjEThAEiq SoMCd9a1slmJCwPdsBHHv3YpSnaPVwAoM+BCQ7Woc7A2UROKc952F0MqvE7O8Ogqachq l5QnZrEs+cM24Bxp5nZ4PUAEcg/Eu8ERPJOcnkykS/bJx3Kvlysd5dpzCZc8jyLQHRgW ZhT7rs4TfiVRBCjXwcxx0Ffji8MP4qVG8JI3CIKI2AB84DXhe48lKZnBWZ78s9tntV7b eS3FD8BZPY61+sBIJUoXf/JefgGsMJ2E4YepcWKW5IyA1Nk7KgpjkAwSx0wL+1iPpXDX i0tQ== X-Forwarded-Encrypted: i=1; AJvYcCX+73NcnnnZy4evWmmBwu+0WSvwEKBaIwRxCINMYxWaZzj1vwN9cmb+bQ0GUO4M6ztVQu1D3KgsZAUgc7c=@vger.kernel.org X-Gm-Message-State: AOJu0YzBdTWn4D4pga6NthIYlCVc5ELpyqK/KZc7YcBDlanWtGuJ5MQ+ tVAyMKNb8N3hNbgn6TEADWYkRhiLnofO+H4SgK7ZsPg02Wb0Kvrgc9YGc4b3QHUQcO8= X-Gm-Gg: ASbGnctpIx3ry6uzXViqVdb/JqRBE4ximBfl8geKi3qDNMbr/BLZer9BgDcpXtl/sH0 CeT8VsUInfOMrLPbpL+mBJaS+AgH8of76w/iei7p7hh05v8pf/lv2i0TfgiekTgfLy5HGj9wSpG /vCrf3lrw4x5wNU/FIvn+FI110Vs8dzGIj+B2cOtcSDkLK41qImXHyxZfHYcMe2Mts8BRbO6yw4 TdbqquwnK9z5GaWKrBQcL0R5O40xBoLwVsP7wUGbWg1aIqae17bOhsKz9gtkbsIKZIG9wZ9KSi3 7/XB2u6KiclyP89yf0mH3zmc8OAnIBNYkjWXsxDmhtnpoOczXIOaCTSSaufbF6xfrojSQI40iOR QqvBNGfWlSDCwhbWuQqOQlxnY/wx1VE1fWiEsaxoqd8KINRVCyYcMoD8Ti9IQZw8OvgDMJ0FssY U= X-Google-Smtp-Source: AGHT+IE489WzUw79++E6gpy0AVRKNP0OEKvG0wlAV4wlHbkf4ZyMvxG7le8uPm/54WoWsYCi2U1tXQ== X-Received: by 2002:a05:600c:680a:b0:455:ed0f:e8ec with SMTP id 5b1f17b1804b1-4587c828227mr104851665e9.9.1753785393456; Tue, 29 Jul 2025 03:36:33 -0700 (PDT) Received: from localhost (p200300f65f06ab0400000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f06:ab04::1b9]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-4588d86f1basm14853635e9.0.2025.07.29.03.36.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Jul 2025 03:36:33 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Jander , Clemens Gruber , linux-kernel@vger.kernel.org Subject: [PATCH 2/5] pwm: pca9685: Use bulk write to atomicially update registers Date: Tue, 29 Jul 2025 12:36:01 +0200 Message-ID: X-Mailer: git-send-email 2.50.0 In-Reply-To: References: 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" X-Developer-Signature: v=1; a=openpgp-sha256; l=4024; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=vFkS3MCcz044w85i6x5Sg9hS8f9ssjZYZP9S3l0oUV8=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoiKQWeJfvL02YkeNuhdb3nFbQJem3gmbhqK06N skiqzjuh3qJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaIikFgAKCRCPgPtYfRL+ TpY0CACdPgmKq0PzScj3jiGMLo8lamDzzLLZOz/G4MlOknxDQDIz8iJkKeWKlNtjOU33ecu9PeI jgp4YtGjb+ai5aiCmgqqfo9d1/kcVIgDYMB0N8keYJNRLaJOaFyaDq8I2wy2TP6EFNeyieO+6Xu gDxeSlpc5zBH7OpN9yCz8KgEzyXedOOf8pSMtwLc1bN6h/qFw9ZhonPKQuFbwyzkQCePOHvUNdD GhbTxvHrXGthKx0txJ10tjfdkWftWjCMv5NKosO2Izmo3pBb59Z3WNkVDT5dBHJIc/cniSm3SIE M6U1asG2zV8jn7S13FjUe1wlTnbY7qQ7T0KflFMNhxoI2P2Y X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable The output of a PWM channel is configured by four register values. Write them in a single i2c transaction to ensure glitch free updates. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/pwm-pca9685.c | 46 ++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 41eb8e034828..75cf10f2b269 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -61,6 +61,8 @@ #define MODE1_SUB2 BIT(2) #define MODE1_SUB1 BIT(3) #define MODE1_SLEEP BIT(4) +#define MODE1_AI BIT(5) + #define MODE2_INVRT BIT(4) #define MODE2_OUTDRV BIT(2) =20 @@ -131,6 +133,19 @@ static int pca9685_write_reg(struct pwm_chip *chip, un= signed int reg, unsigned i return err; } =20 +static int pca9685_write_4reg(struct pwm_chip *chip, unsigned int reg, u8 = val[4]) +{ + struct pca9685 *pca =3D to_pca(chip); + struct device *dev =3D pwmchip_parent(chip); + int err; + + err =3D regmap_bulk_write(pca->regmap, reg, val, 4); + if (err) + dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR= (err)); + + return err; +} + /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=3D2= 048 -> 50%) */ static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsig= ned int duty) { @@ -143,12 +158,10 @@ static void pca9685_pwm_set_duty(struct pwm_chip *chi= p, int channel, unsigned in return; } else if (duty >=3D PCA9685_COUNTER_RANGE) { /* Set the full ON bit and clear the full OFF bit */ - pca9685_write_reg(chip, REG_ON_H(channel), LED_FULL); - pca9685_write_reg(chip, REG_OFF_H(channel), 0); + pca9685_write_4reg(chip, REG_ON_L(channel), (u8[4]){ 0, LED_FULL, 0, 0 }= ); return; } =20 - if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) { /* * If usage_power is set, the pca9685 driver will phase shift @@ -163,12 +176,9 @@ static void pca9685_pwm_set_duty(struct pwm_chip *chip= , int channel, unsigned in =20 off =3D (on + duty) % PCA9685_COUNTER_RANGE; =20 - /* Set ON time (clears full ON bit) */ - pca9685_write_reg(chip, REG_ON_L(channel), on & 0xff); - pca9685_write_reg(chip, REG_ON_H(channel), (on >> 8) & 0xf); - /* Set OFF time (clears full OFF bit) */ - pca9685_write_reg(chip, REG_OFF_L(channel), off & 0xff); - pca9685_write_reg(chip, REG_OFF_H(channel), (off >> 8) & 0xf); + /* implicitly clear full ON and full OFF bit */ + pca9685_write_4reg(chip, REG_ON_L(channel), + (u8[4]){ on & 0xff, (on >> 8) & 0xf, off & 0xff, (off >> 8) & 0xf }); } =20 static unsigned int pca9685_pwm_get_duty(struct pwm_chip *chip, int channe= l) @@ -543,9 +553,8 @@ static int pca9685_pwm_probe(struct i2c_client *client) =20 mutex_init(&pca->lock); =20 - ret =3D pca9685_read_reg(chip, PCA9685_MODE2, ®); - if (ret) - return ret; + /* clear MODE2_OCH */ + reg =3D 0; =20 if (device_property_read_bool(&client->dev, "invert")) reg |=3D MODE2_INVRT; @@ -561,16 +570,19 @@ static int pca9685_pwm_probe(struct i2c_client *clien= t) if (ret) return ret; =20 - /* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */ + /* + * Disable all LED ALLCALL and SUBx addresses to avoid bus collisions, + * enable Auto-Increment. + */ pca9685_read_reg(chip, PCA9685_MODE1, ®); reg &=3D ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3); + reg |=3D MODE1_AI; pca9685_write_reg(chip, PCA9685_MODE1, reg); =20 /* Reset OFF/ON registers to POR default */ - pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_L, 0); - pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_H, LED_FULL); - pca9685_write_reg(chip, PCA9685_ALL_LED_ON_L, 0); - pca9685_write_reg(chip, PCA9685_ALL_LED_ON_H, LED_FULL); + ret =3D pca9685_write_4reg(chip, PCA9685_ALL_LED_ON_L, (u8[]){ 0, LED_FUL= L, 0, LED_FULL }); + if (ret < 0) + return dev_err_probe(&client->dev, ret, "Failed to reset ON/OFF register= s\n"); =20 chip->ops =3D &pca9685_pwm_ops; =20 --=20 2.50.0 From nobody Sun Oct 5 21:57:24 2025 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (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 2CEF128A3FA for ; Tue, 29 Jul 2025 10:36:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785400; cv=none; b=Lg6lyh74DR9pVcA/uAQfKnK4vEJkWzeqzNMI0+I8cUpBQ1DXxVHEdH6LGTGkqMNOkLZW74BCZszo+0K9sjbmlnY2oVbw+LmiYXWZ4iSfb4f0mgBTomqOpDpUWF2+vymUdG9HZGpmYcUt6NAhtKoy9YS2864RZwMuyohmEmYKFEY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785400; c=relaxed/simple; bh=xVCQ0H9cdadixp4wtnM9PE8JviA4z1kl3G/Q1/TlS2E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ja3SSdoFOsxzY/UJ9yBufm/iV5W1mqmRUxgMhDJ71u/GOfHZBNHUVEM9NA1DrTSr7/kAEbZf6kH5BXV0/sjOJoCbMUmkyZnLEOB53l3cqAn46CH2Srcu2Y75ZzvQSeZtssNGucrwrMydoZOcy2FB88+NhTRtRAu+r/B17CyXrGM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=ikVhMw9E; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="ikVhMw9E" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-3a54700a46eso2552449f8f.1 for ; Tue, 29 Jul 2025 03:36:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1753785395; x=1754390195; 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=bOT/FGVWZXt1k9nEtD7r2OSEKfVEuUP//VH1iukiEmU=; b=ikVhMw9EP14utVrUyZzTt8vXSxYR+99KaYziRDjooGT/5vRq1fhPRKgz5HF+IcVJr5 z+ZH2229PVJ1m6msbmPnWg4TRkma/XU1RYaCaamBKRGvpU8PNt3k7cuYVAYKSSFIzIIp EuAI/oJGlHMPW3YIgHW4HLk+Ib1J3FoSlzpFPG6AFMD6FpHRxKkSozLjcF4VGgu/Pi4+ tzCPmiqY13v/ba9Y0R8sDTZlryosw1SnTkA142i6t39QZuILYYU6c/UUxav0ctUXVL9e BLaPXQsolLJxvD7L/CwO4xQTshwNGvx2Qpu2Ytq1QY1tCXTgDHOd5hGx8fwD60ImwzLS Ie6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753785395; x=1754390195; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bOT/FGVWZXt1k9nEtD7r2OSEKfVEuUP//VH1iukiEmU=; b=kz8PzODWwQStMTcKk9eV5qCOmLW+mrRKoaZmcBiEkbvEG8A6SFbIiex2nrPuq+QQXj rzgBmf3IXbQCKyZIhG8X+Q/2Cz337EkEi3rrlZ+BnZywhfiRpsgnwNqQtxzdf1oiShzk FuQygJ4KGxGs+6cj4KedIp2modAXhDnwI3M19kojHOK2dLDiaV2HJPzADeeDdeHKKfYU KFjiu6RntilDCXATNmwDGSQtFfEThPQpOfYDJM9Xf+pfiX4AiNKEXuiLuFQUQ3aMOGQq 9r26U51OWywvY8U0KYLdqa+BAMO842bobMjtrP/rqSzPUPFxGOTnCjAyW4sRB7CBw6DA B6FQ== X-Forwarded-Encrypted: i=1; AJvYcCVmt+D6hqZJJTP/FxRMIk0QJ4r9vyM7Q3rj1uqeu77nlP28vhjR1EtaCQBnJhcE7l5gUYY7hvZJaoNosBs=@vger.kernel.org X-Gm-Message-State: AOJu0YzehyrYHWtwO8LQGlO8kbYIy1spXgp03nhQh7WLOHOPkY+dXboq Xx8u9trUHvvhiwt7TKe2P4uzM9a63ImzoRhNO+y5KTKZHGd+dWIHUvMt9pG2++9FBr4= X-Gm-Gg: ASbGncv2O+gu3aQat/EBkoMTir2in9+9kzO2j43Zf68lbuXwKN+LG8BHlT9yoASw5Jj RP79kKo0mrAu0w+vFLstUZ+IPyg4Vd2ychETPq8fT4eDWKnwB5ZfnNBfP3snIfvOZRhvw+A9gd/ 7grRCAoEMDjeL/SfL7b5EXfmtb/saOMZEpmpaMiz1cflb2zPrgrz2mFDGG8wNleW0twNK7Ec/tQ FbuUznlZsg2hukTJ2gWxKYqP+u+N1O06e/B1qaqlKhAF9OiIltssPvpKSvshrDohaviWIPEz9/j Zc67BPId4EHplwaV/8doohl+jyzrquu7QrejwnHsgP87VebnkGoXoowkZLyEX5otRPqKWFvGqXb kATjR1q9yv2jQ2k6pgddhxb2b2lnAnp8GAerP9EXpTaiOMpa60Vl8mZUw3MoZDWzk X-Google-Smtp-Source: AGHT+IEUDe5Y8ch5reMaJR+e1UFpIOuCDt4FLaqjklslZwM9SscKPmK3GMlaAo0W9OWsUQ8airUKaQ== X-Received: by 2002:a5d:5d07:0:b0:3a6:c923:bc5f with SMTP id ffacd0b85a97d-3b7767298a5mr10328260f8f.17.1753785394967; Tue, 29 Jul 2025 03:36:34 -0700 (PDT) Received: from localhost (p200300f65f06ab0400000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f06:ab04::1b9]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-3b778eb284fsm12058183f8f.12.2025.07.29.03.36.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Jul 2025 03:36:34 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Jander , Clemens Gruber , linux-kernel@vger.kernel.org Subject: [PATCH 3/5] pwm: pca9685: Make use of register caching in regmap Date: Tue, 29 Jul 2025 12:36:02 +0200 Message-ID: X-Mailer: git-send-email 2.50.0 In-Reply-To: References: 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" X-Developer-Signature: v=1; a=openpgp-sha256; l=1711; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=xVCQ0H9cdadixp4wtnM9PE8JviA4z1kl3G/Q1/TlS2E=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoiKQYvIpI9MwDeOqnxPYjnZJTPNea9xJ6Rux4Y vHLCAtxEzWJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaIikGAAKCRCPgPtYfRL+ Ti17B/4qD2l36dVNP600NKdoY5Ft0nkFPN587ZhFvA4yMAWrWTr6u5NufyUWbuOIcgmHFI65X19 0UXABHvyhfqtECZhRzLSwa82q+zh6ZTLMZzNb6OQm7BPPJqYKsVfBMueQWF13bR8IWdLTHRNnAk m968ublJe/gsicp9OxjuVrAnoLqqKJR10OUuwn3Umkbg2XsdLFJWFA1tgKzSc/xOP40BK6cEZ26 jqPR3oUFNObN3rzEHi/S0m79KunyTywv8C3VhPosbWmIy+0CNphK2EhxknGmzkUJXWA/d0V8CZ/ zzGHrOmnE26xGk/tROM9WwXViXOygE+PggP7XoehZz31NKAf X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable This essentially only caches the PRESCALE register because the per channel registers are affected by the ALL configuration that is used by the virtual pwm #16. The PRESCALE register is read often so caching it saves quite some i2c transfers. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/pwm-pca9685.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 75cf10f2b269..536a3e15a254 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -521,11 +521,36 @@ static const struct pwm_ops pca9685_pwm_ops =3D { .free =3D pca9685_pwm_free, }; =20 +static bool pca9685_readable_reg(struct device *dev, unsigned int reg) +{ + /* The ALL_LED registers are readable but read as zero */ + return reg <=3D REG_OFF_H(15) || reg >=3D PCA9685_PRESCALE; +} + +static bool pca9685_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg <=3D REG_OFF_H(15) || reg >=3D PCA9685_ALL_LED_ON_L; +} + +static bool pca9685_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Writing to an ALL_LED register affects all LEDi registers, so they + * are not cachable. :-\ + */ + return reg < PCA9685_PRESCALE; +} + static const struct regmap_config pca9685_regmap_i2c_config =3D { .reg_bits =3D 8, .val_bits =3D 8, + + .readable_reg =3D pca9685_readable_reg, + .writeable_reg =3D pca9685_writeable_reg, + .volatile_reg =3D pca9685_volatile_reg, + .max_register =3D PCA9685_NUMREGS, - .cache_type =3D REGCACHE_NONE, + .cache_type =3D REGCACHE_MAPLE, }; =20 static int pca9685_pwm_probe(struct i2c_client *client) --=20 2.50.0 From nobody Sun Oct 5 21:57:24 2025 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (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 2CF5A28A3FC for ; Tue, 29 Jul 2025 10:36:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785400; cv=none; b=Q2sTFXH9WboWzfzrdecLcDJnEPioSiwSKVouoRyrVWyDPY4RcT34jY7If/igY7X65WmpyZxPOWtO3unneNLOZTl+mVMnTSvHxnDCJ+y2Tto1LTw7BVwELR2aEEPg6Ft8n+2kkX7L9CJbLe5AX4o1RcwRvYv8q7jfEQt7usKNfGY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785400; c=relaxed/simple; bh=vbJJ56VU7p92Dn6IGl4obLt5d57ZoN9r6yd+NE7p+Ik=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tVH4AAzNbHH5VPilSsIuB5OvlW1inJXnhxyh3VSvCfZ/gq/nuB3egTgxqsfHG+4X8ll5T8nT2fbLBq+6tj3mAdu+OSMPIsY7frKMiH1/xAHP5aHFirMPhEVIxEG0PfogcfVu0VoHNJUd7tenwZj+2npwZXmRjr4oxsFvkEa7D6o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=z0Mwb1NP; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="z0Mwb1NP" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-3b78b2c6ecfso1053430f8f.0 for ; Tue, 29 Jul 2025 03:36:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1753785396; x=1754390196; 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=ILZsmFm+KaxI485jnWnzugD9ziJLMIRNNh5UIMPlOzk=; b=z0Mwb1NP26m1ooTa/067jD3gtvhVsjtYJWNZ42Lh5RxFAgSLeNaKWgS7soTwz9FyKl U8zh5hU1kJequWxvHtN8BxVyhywsFxE0+le2aw4h41jEPb+I54AIBtlnvlpFlTgOu8Sv 5nLA9O54B9HZVdGJepNzwKWZ9iWRDrej66ReK674vsRp9AFLjwoGkMeQQhxZD0LNa907 kxGfJo3UcOxXvr5jCoEOZoVifLuig/26+a1fO1pvLbyevYCeB5JQC8Sasua6arFuiM9z FJL890w42oLDePUhGZnh7tOKmTO/rwj/ItS8K7qX7OmroJWWJBulXzEvrLsXTwTfgVWH vbvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753785396; x=1754390196; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ILZsmFm+KaxI485jnWnzugD9ziJLMIRNNh5UIMPlOzk=; b=QBgo8yJj7WIPmnjqXqrNr6FRL4w2vaz8pFEhtSa2QrO5pTaYDCZUc7Z3jUZMfegaRO oZXK/4NEwNxbMgiTm/SO02dq2/55gmTynzhsbhoBWtj1Va0FBmh6ZkzbP04K2OEGgxbu ySbV+O6VPrp6jaXD4MasqKKi0DUmBHcxX5S8+Y084rHh3ytEaan59mKI4L6fdW1kGczT W8orvIONJyeG8kx2bOhKtm14rgws5B6KQ6CW+8AmGEs/dIRJPsOMD/+Q61ufIlHHQVIm CZUroqkFrO5tkg5GGI0Efd2dWwCJlPjItlL0NtvTIb+KXn9lVgpW8+veSaLdg4Gx/pGo 3k7g== X-Forwarded-Encrypted: i=1; AJvYcCUZvRqnesaiADLF2tKbpK2WI1SSReKSQjMHbaysgf7vqMA1l4xv+gl65PFgTywSt8bLxazrMWck6+WGSF8=@vger.kernel.org X-Gm-Message-State: AOJu0YwSsYh8bbS0B94DwPwQW8AroXVCD36SmtkWS7OAN1ADC66Y5j9N 0RBPi+92lQXeVIOPOYDG4XWJW/eClXDPMovpeQo1lbpEfkxgfO8R8zZlfToTwitRCkE= X-Gm-Gg: ASbGncuA1NvJUcWoOKJYEnlDuxMwIMqsZPx69o75prOLMZE9hAgrjtEvmh83GBPXs1K gdPXZ/rmyDsxfkH8w0OnT+psP8xlZAtMTZpzeaqvITvBuhX3Ju37XVPNHg7R7hRzJlBvHQIAE4p 58Ter3ClF3s93hlE4OUNRB+oZJHui066ak6LpiaEg0Y6Q+HXp1urStiex+AH0/vnTcG8s/aTO8T zO9oVXgIAmpAzLkYVcV5FPUFoeWxUnOZKq3hH7sp9x5HL45/9B3aBWzBxEJson4f9OiEKwUfCj8 avYIKhnqXqx/32npCjWjQUWPpCM6ilaw5pUq7kmYx7fMiZPpqgjVGDThZp6189wuqK5yu7+QeWq NuxpodL2nq5IGjW///P2JY3doTSJF30xYBLpmbqohEac1gyhNkD/7yUJ3CJhiMquEfR+HtfuYIa 0= X-Google-Smtp-Source: AGHT+IFa/CFDIaAaH9tN7MNxbpnS3kOcobWhqvyDzNhQqLICbSJo5bNe1bjRQG5+K8fTlTpOov4j+A== X-Received: by 2002:a05:6000:18aa:b0:3b7:9233:ebb with SMTP id ffacd0b85a97d-3b79233114cmr965649f8f.6.1753785396364; Tue, 29 Jul 2025 03:36:36 -0700 (PDT) Received: from localhost (p200300f65f06ab0400000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f06:ab04::1b9]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-3b778f0c866sm11498851f8f.55.2025.07.29.03.36.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Jul 2025 03:36:35 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Jander , Clemens Gruber , linux-kernel@vger.kernel.org Subject: [PATCH 4/5] pwm: pca9685: Drop GPIO support Date: Tue, 29 Jul 2025 12:36:03 +0200 Message-ID: X-Mailer: git-send-email 2.50.0 In-Reply-To: References: 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" X-Developer-Signature: v=1; a=openpgp-sha256; l=6256; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=vbJJ56VU7p92Dn6IGl4obLt5d57ZoN9r6yd+NE7p+Ik=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoiKQb9SqfmS4RnreDDX1ciLqZhHV8R1R8o0k2V 160jncMWAqJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaIikGwAKCRCPgPtYfRL+ TlnBCAC6Wopoy4dP5sNZ2aYzStnFhX1+7F9Z9If3RETL7v5qT880/SgjSEYL4J+84zyMtvZHMuj BzZAQvuHlFtGSeXUga8wIuws/aa7sUHGgqJae+l6CeF08Ph5NLsvP5n78J23gHo+qZ6VT2bCtq9 q/saNiFraYFglZSj5kMGfOPtwGb9WIgGPc4R/hM+8pbFQn7ScexGUjUva42fa3sV5dOPlciVrw5 poaRGbL5Tyk1pe+jazRTfXDscUN3XVlDEGxTpQEd45vELVXA80ZhaQAv/7N11NfqCpUJUm8SU88 7ZMp1cxNvJZHq6nyaPabI5UXDkwDYd90yw4HNx6rFbVudXE6 X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable The functionality will be restored after the driver is converted to the waveform API as the pwm core optionally provides a gpio chip for all pwm chips that support the waveform API. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/pwm-pca9685.c | 156 -------------------------------------- 1 file changed, 156 deletions(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 536a3e15a254..3f04defd3718 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -26,7 +26,6 @@ * that is enabled is allowed to change the prescale register. * PWM channels requested afterwards must use a period that results in the= same * prescale setting as the one set by the first requested channel. - * GPIOs do not count as enabled PWMs as they are not using the prescaler. */ =20 #define PCA9685_MODE1 0x00 @@ -80,10 +79,6 @@ struct pca9685 { struct regmap *regmap; struct mutex lock; DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1); -#if IS_ENABLED(CONFIG_GPIOLIB) - struct gpio_chip gpio; - DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1); -#endif }; =20 static inline struct pca9685 *to_pca(struct pwm_chip *chip) @@ -217,147 +212,6 @@ static unsigned int pca9685_pwm_get_duty(struct pwm_c= hip *chip, int channel) return (off - on) & (PCA9685_COUNTER_RANGE - 1); } =20 -#if IS_ENABLED(CONFIG_GPIOLIB) -static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_id= x) -{ - bool is_inuse; - - mutex_lock(&pca->lock); - if (pwm_idx >=3D PCA9685_MAXCHAN) { - /* - * "All LEDs" channel: - * pretend already in use if any of the PWMs are requested - */ - if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) { - is_inuse =3D true; - goto out; - } - } else { - /* - * Regular channel: - * pretend already in use if the "all LEDs" channel is requested - */ - if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) { - is_inuse =3D true; - goto out; - } - } - is_inuse =3D test_and_set_bit(pwm_idx, pca->pwms_inuse); -out: - mutex_unlock(&pca->lock); - return is_inuse; -} - -static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) -{ - mutex_lock(&pca->lock); - clear_bit(pwm_idx, pca->pwms_inuse); - mutex_unlock(&pca->lock); -} - -static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int o= ffset) -{ - struct pwm_chip *chip =3D gpiochip_get_data(gpio); - struct pca9685 *pca =3D to_pca(chip); - - if (pca9685_pwm_test_and_set_inuse(pca, offset)) - return -EBUSY; - pm_runtime_get_sync(pwmchip_parent(chip)); - return 0; -} - -static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offse= t) -{ - struct pwm_chip *chip =3D gpiochip_get_data(gpio); - - return pca9685_pwm_get_duty(chip, offset) !=3D 0; -} - -static int pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offse= t, - int value) -{ - struct pwm_chip *chip =3D gpiochip_get_data(gpio); - - pca9685_pwm_set_duty(chip, offset, value ? PCA9685_COUNTER_RANGE : 0); - - return 0; -} - -static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int off= set) -{ - struct pwm_chip *chip =3D gpiochip_get_data(gpio); - struct pca9685 *pca =3D to_pca(chip); - - pca9685_pwm_set_duty(chip, offset, 0); - pm_runtime_put(pwmchip_parent(chip)); - pca9685_pwm_clear_inuse(pca, offset); -} - -static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip, - unsigned int offset) -{ - /* Always out */ - return GPIO_LINE_DIRECTION_OUT; -} - -static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio, - unsigned int offset) -{ - return -EINVAL; -} - -static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio, - unsigned int offset, int value) -{ - pca9685_pwm_gpio_set(gpio, offset, value); - - return 0; -} - -/* - * The PCA9685 has a bit for turning the PWM output full off or on. Some - * boards like Intel Galileo actually uses these as normal GPIOs so we - * expose a GPIO chip here which can exclusively take over the underlying - * PWM channel. - */ -static int pca9685_pwm_gpio_probe(struct pwm_chip *chip) -{ - struct pca9685 *pca =3D to_pca(chip); - struct device *dev =3D pwmchip_parent(chip); - - pca->gpio.label =3D dev_name(dev); - pca->gpio.parent =3D dev; - pca->gpio.request =3D pca9685_pwm_gpio_request; - pca->gpio.free =3D pca9685_pwm_gpio_free; - pca->gpio.get_direction =3D pca9685_pwm_gpio_get_direction; - pca->gpio.direction_input =3D pca9685_pwm_gpio_direction_input; - pca->gpio.direction_output =3D pca9685_pwm_gpio_direction_output; - pca->gpio.get =3D pca9685_pwm_gpio_get; - pca->gpio.set_rv =3D pca9685_pwm_gpio_set; - pca->gpio.base =3D -1; - pca->gpio.ngpio =3D PCA9685_MAXCHAN; - pca->gpio.can_sleep =3D true; - - return devm_gpiochip_add_data(dev, &pca->gpio, chip); -} -#else -static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, - int pwm_idx) -{ - return false; -} - -static inline void -pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) -{ -} - -static inline int pca9685_pwm_gpio_probe(struct pwm_chip *chip) -{ - return 0; -} -#endif - static void pca9685_set_sleep_mode(struct pwm_chip *chip, bool enable) { struct device *dev =3D pwmchip_parent(chip); @@ -487,9 +341,6 @@ static int pca9685_pwm_request(struct pwm_chip *chip, s= truct pwm_device *pwm) { struct pca9685 *pca =3D to_pca(chip); =20 - if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm)) - return -EBUSY; - if (pwm->hwpwm < PCA9685_MAXCHAN) { /* PWMs - except the "all LEDs" channel - default to enabled */ mutex_lock(&pca->lock); @@ -511,7 +362,6 @@ static void pca9685_pwm_free(struct pwm_chip *chip, str= uct pwm_device *pwm) mutex_unlock(&pca->lock); =20 pm_runtime_put(pwmchip_parent(chip)); - pca9685_pwm_clear_inuse(pca, pwm->hwpwm); } =20 static const struct pwm_ops pca9685_pwm_ops =3D { @@ -615,12 +465,6 @@ static int pca9685_pwm_probe(struct i2c_client *client) if (ret < 0) return ret; =20 - ret =3D pca9685_pwm_gpio_probe(chip); - if (ret < 0) { - pwmchip_remove(chip); - return ret; - } - pm_runtime_enable(&client->dev); =20 if (pm_runtime_enabled(&client->dev)) { --=20 2.50.0 From nobody Sun Oct 5 21:57:24 2025 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (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 B095F28B3FA for ; Tue, 29 Jul 2025 10:36:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785402; cv=none; b=Vg9I2agDRx35lpjGfydy9iEszoLdnXAajXFKH4SwTcuc/AwnK3ywFgslIzovbH1hFK827CIoHb8sqFxYuIzK+162P6pCUTYPGJelEDUuOjyNH7e3Ntg/GScBcHJP2gMFbI99TmuFWz2fUCN6JpjBFoWqPEiTeLdVcUTb122jibM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753785402; c=relaxed/simple; bh=8SgViRt/rg/dYGQ12Q07Sv043x5SZDkHh/R0OGzTYEo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JcfZJd7POxNoxMK5SGXVPMNd84fLn6jij1ouMfNrj8JqoyTfkWDtdSws4yNm+IzJO0xaCaurUFzEkBBCyUOJOKHx3w996S2BC61MyxKU5hsmJDtYrXZOoCWAYDP0LT99k8UEzo4TelPvtZO5H3QpRgX2SHMnSNSA28DO87RqiTA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=Wb/bGXJO; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="Wb/bGXJO" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4561514c7f0so51787555e9.0 for ; Tue, 29 Jul 2025 03:36:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1753785398; x=1754390198; 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=uEiED8GGvScDQ4pdNirKSqFAan2eh/uwLFtQfQ9k+BI=; b=Wb/bGXJOoatWy8OEJwrqjaHJPqPhMSOWFlF8EGGZtA4QpwQkbeXrniD5w/+5fKlGNR sJKP8ECwJt5EDSo2VEyWjFwwc/9eSuEy8LlH72wvJjWk7GayZ3dSXHv3SFKo2KUqUlrZ e7V2NsbsBh7WXFxX9pem42LUMR3Rm9BZw7rCxn4HDf4KlP1Rw91Dgvkj3pjYbyk23/x7 DnCXBB7th4qvmbR1oaI3BwOjUnD4z65ZIlmv1xuu/Cf0Gc7qMI3a3JSHK2PTU0+RJjuS BpgxlpOfMvrQmL5pwgbOZJHKOZArebXZ2ZytpXpW1OJ+cNFqXcndSUnhbKzDabHXQu8D R5gQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753785398; x=1754390198; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uEiED8GGvScDQ4pdNirKSqFAan2eh/uwLFtQfQ9k+BI=; b=oYbOlPMqJJu1QyVjkaWA+Iej5UiJhlvNJqblfDnSTPFc4u3xtNQoKxHQRFYK+0VKGb AkRjaMt6AwIeo4QUxyaOjJevsKVJJIghL5W6uoIU0uUF0UZXz71E0KQ/OzoTjc5BJUYa uWDwT+yRWGSI3bzu/RkZAXjQVdR79bmqNiJxkEH+ktirguXe/paf6zvEJ2HINFhmXLIe qRpvpmVLHIEolz/0K/0k5sRkbHHp6T+o7X8kH7NU1my6vbXRyAfbr5UJ9M5JkK7cjMLV 9ocYsE94Eli2NLQt2jlGwzvl6FvIaiRB2vHAT0UzFMhZ1MOtpPaSFGxmb4T4jZyL2tq0 lu8w== X-Forwarded-Encrypted: i=1; AJvYcCUYd4q41y5hOcH5MeYVcVajAP5SgCdceEIcvrmTtaYZCugl2tw6ijRr0X32e3dDu6cIsIZFcgWjFCpHNGY=@vger.kernel.org X-Gm-Message-State: AOJu0YzYececAQ42m61RZvLOKy9QwLWkJpZxVoE0f+m56Fqi2bOKBWxx 2l+hCJZEtYb8HXcTWfvnR2xdmng3ltlcXYHp8jaXg/eUeuszWFJDZWE1lYnp99gWCRg= X-Gm-Gg: ASbGnctq/N2lwepn7xWDxJAXvKMzwvBUyXK1f40cThFd821voxvbB2shgmy//HUxhRm R91xYE3m0wgCh5bugBSF/5MgspIsWu8PqpaUi3DRuApP3if3+Dbb8HU0r7q5W6NavucdFVD8Bzz 6qHL29IpH2MTPyqvCkwZELFI8y+iPXnLEhqTDrMl7+0ob+VhhVbJNMqvswCnqdc5MQuaHXkS8Nx e0QQYKGfwWHEfIcK3cXmZytDe2yBanihF9CNaH/BDNco9MMMVMErTYlcM3xXCVI9a55wRer3UEX ciAHiC79LmtzlGyytB6F/DHzbVHwM1ewMijhGtBIFg9MlHBBXUHZCRk4WpE4u95/VoA8W2tN0Gd yqwN2p9GK/zKzqDBazNvcYgbFRbZOK4NndbWLFmUG5h15qcXSa0aFfEhNgcMDXh11YGDdS1hxui g= X-Google-Smtp-Source: AGHT+IFf8Hzl3zLHh4WUfvZW0IgHqfWFb7jfiHvMFPiClvMOX1fd580vq9CmSQs+m5pcyA/37+laUQ== X-Received: by 2002:a05:600c:4e0c:b0:44a:b478:1387 with SMTP id 5b1f17b1804b1-45882a37dc7mr83918765e9.17.1753785397897; Tue, 29 Jul 2025 03:36:37 -0700 (PDT) Received: from localhost (p200300f65f06ab0400000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f06:ab04::1b9]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-4588e5e4aeasm21870085e9.29.2025.07.29.03.36.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Jul 2025 03:36:37 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Jander , Clemens Gruber , linux-kernel@vger.kernel.org Subject: [PATCH 5/5] pwm: pca9586: Convert to waveform API Date: Tue, 29 Jul 2025 12:36:04 +0200 Message-ID: <1927d115ae6797858e6c4537971dacf1d563854f.1753784092.git.u.kleine-koenig@baylibre.com> X-Mailer: git-send-email 2.50.0 In-Reply-To: References: 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" X-Developer-Signature: v=1; a=openpgp-sha256; l=13712; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=8SgViRt/rg/dYGQ12Q07Sv043x5SZDkHh/R0OGzTYEo=; b=owGbwMvMwMXY3/A7olbonx/jabUkhoyOJXIN+zKXyb2yD3JkvsTUEWOXIJLD9S7vkGFl3tXC/ oy9Ie86GY1ZGBi5GGTFFFnsG9dkWlXJRXau/XcZZhArE8gUBi5OAZhIYCz7P5uWqCJHGXH/fsFt LCvmJLl09tx14neL1roas/qIRrjtbrUihgC5drZFvQUac+TTGG5+f2JwJqTj+Lxg7z/XDZ5xcS9 WrH/Xr2V9mFEm9dtH5i2XS3aszrM5aif5Yuv/RcmLL1wr3CzBffbxVLYvU5erXdlfqrFeVGzx8e db3C7cTtNsM9i6Nsy17YWS/CWj3tC/WibmW6QYxMsm/guw8l/Bc/vO1Jmef3PKwvvEYyxfF9S2e i3Z7t60lkuuLTe1NP+/BJP1/Mz//B/jXf2//Xdcu9uEfcP/qVZdwcsfh/Xxf0qKecLySmq/mYzZ 80tVUoYzXnXnelicW6Nr5izI90I2Wja+tDFMliHs8x0A X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable This allows to expose the duty_offset feature that the chip supports, and so also emit inverted polarity waveforms. The conversion from a waveform to hardware settings (and vice versa) is aligned to the usual rounding rules silencing warnings with PWM_DEBUG. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/pwm-pca9685.c | 347 ++++++++++++++++++++------------------ 1 file changed, 185 insertions(+), 162 deletions(-) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 3f04defd3718..107bebec3546 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -49,7 +49,14 @@ #define PCA9685_PRESCALE_MAX 0xFF /* =3D> min. frequency of 24 Hz */ =20 #define PCA9685_COUNTER_RANGE 4096 -#define PCA9685_OSC_CLOCK_MHZ 25 /* Internal oscillator with 25 MHz */ +#define PCA9685_OSC_CLOCK_HZ 25000000 /* Internal oscillator with 25 MHz */ + +/* + * The time value of one counter tick. Note that NSEC_PER_SEC is an integer + * multiple of PCA9685_OSC_CLOCK_HZ, so there is no rounding involved and = we're + * not loosing precision due to the early division. + */ +#define PCA9685_QUANTUM_NS(_prescale) ((NSEC_PER_SEC / PCA9685_OSC_CLOCK_H= Z) * (_prescale + 1)) =20 #define PCA9685_NUMREGS 0xFF #define PCA9685_MAXCHAN 0x10 @@ -141,202 +148,215 @@ static int pca9685_write_4reg(struct pwm_chip *chip= , unsigned int reg, u8 val[4] return err; } =20 -/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=3D2= 048 -> 50%) */ -static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsig= ned int duty) +static int pca9685_set_sleep_mode(struct pwm_chip *chip, bool enable) { - struct pwm_device *pwm =3D &chip->pwms[channel]; - unsigned int on, off; - - if (duty =3D=3D 0) { - /* Set the full OFF bit, which has the highest precedence */ - pca9685_write_reg(chip, REG_OFF_H(channel), LED_FULL); - return; - } else if (duty >=3D PCA9685_COUNTER_RANGE) { - /* Set the full ON bit and clear the full OFF bit */ - pca9685_write_4reg(chip, REG_ON_L(channel), (u8[4]){ 0, LED_FULL, 0, 0 }= ); - return; - } - - if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) { - /* - * If usage_power is set, the pca9685 driver will phase shift - * the individual channels relative to their channel number. - * This improves EMI because the enabled channels no longer - * turn on at the same time, while still maintaining the - * configured duty cycle / power output. - */ - on =3D channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN; - } else - on =3D 0; - - off =3D (on + duty) % PCA9685_COUNTER_RANGE; - - /* implicitly clear full ON and full OFF bit */ - pca9685_write_4reg(chip, REG_ON_L(channel), - (u8[4]){ on & 0xff, (on >> 8) & 0xf, off & 0xff, (off >> 8) & 0xf }); -} - -static unsigned int pca9685_pwm_get_duty(struct pwm_chip *chip, int channe= l) -{ - struct pwm_device *pwm =3D &chip->pwms[channel]; - unsigned int off =3D 0, on =3D 0, val =3D 0; - - if (WARN_ON(channel >=3D PCA9685_MAXCHAN)) { - /* HW does not support reading state of "all LEDs" channel */ - return 0; - } - - pca9685_read_reg(chip, LED_N_OFF_H(channel), &off); - if (off & LED_FULL) { - /* Full OFF bit is set */ - return 0; - } - - pca9685_read_reg(chip, LED_N_ON_H(channel), &on); - if (on & LED_FULL) { - /* Full ON bit is set */ - return PCA9685_COUNTER_RANGE; - } - - pca9685_read_reg(chip, LED_N_OFF_L(channel), &val); - off =3D ((off & 0xf) << 8) | (val & 0xff); - if (!pwm->state.usage_power) - return off; - - /* Read ON register to calculate duty cycle of staggered output */ - if (pca9685_read_reg(chip, LED_N_ON_L(channel), &val)) { - /* Reset val to 0 in case reading LED_N_ON_L failed */ - val =3D 0; - } - on =3D ((on & 0xf) << 8) | (val & 0xff); - return (off - on) & (PCA9685_COUNTER_RANGE - 1); -} - -static void pca9685_set_sleep_mode(struct pwm_chip *chip, bool enable) -{ - struct device *dev =3D pwmchip_parent(chip); struct pca9685 *pca =3D to_pca(chip); - int err =3D regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_SLEEP, enable ? MODE1_SLEEP : 0); - if (err) { - dev_err(dev, "regmap_update_bits of register 0x%x failed: %pe\n", - PCA9685_MODE1, ERR_PTR(err)); - return; - } + int err; + + err =3D regmap_update_bits(pca->regmap, PCA9685_MODE1, + MODE1_SLEEP, enable ? MODE1_SLEEP : 0); + if (err) + return err; =20 if (!enable) { /* Wait 500us for the oscillator to be back up */ udelay(500); } + + return 0; } =20 -static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *p= wm, - const struct pwm_state *state) +struct pca9685_waveform { + u8 onoff[4]; + u8 prescale; +}; + +static int pca9685_round_waveform_tohw(struct pwm_chip *chip, struct pwm_d= evice *pwm, const struct pwm_waveform *wf, void *_wfhw) { + struct pca9685_waveform *wfhw =3D _wfhw; struct pca9685 *pca =3D to_pca(chip); - unsigned long long duty, prescale; - unsigned int val =3D 0; + unsigned int best_prescale; + u8 prescale; + unsigned int period_ns, duty; + int ret_tohw =3D 0; =20 - if (state->polarity !=3D PWM_POLARITY_NORMAL) - return -EINVAL; + if (!wf->period_length_ns) { + *wfhw =3D (typeof(*wfhw)){ + .onoff =3D { 0, 0, 0, LED_FULL, }, + .prescale =3D 0, + }; =20 - prescale =3D DIV_ROUND_CLOSEST_ULL(PCA9685_OSC_CLOCK_MHZ * state->period, - PCA9685_COUNTER_RANGE * 1000) - 1; - if (prescale < PCA9685_PRESCALE_MIN || prescale > PCA9685_PRESCALE_MAX) { - dev_err(pwmchip_parent(chip), "pwm not changed: period out of bounds!\n"= ); - return -EINVAL; - } + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] -> [%hhx %hhx %hhx %hhx] = PSC:%hhx\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_n= s, + wfhw->onoff[0], wfhw->onoff[1], wfhw->onoff[2], wfhw->onoff[3], wfhw->p= rescale); =20 - if (!state->enabled) { - pca9685_pwm_set_duty(chip, pwm->hwpwm, 0); return 0; } =20 - pca9685_read_reg(chip, PCA9685_PRESCALE, &val); - if (prescale !=3D val) { - if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) { - dev_err(pwmchip_parent(chip), - "pwm not changed: periods of enabled pwms must match!\n"); - return -EBUSY; + if (wf->period_length_ns >=3D PCA9685_COUNTER_RANGE * PCA9685_QUANTUM_NS(= 255)) { + best_prescale =3D 255; + } else if (wf->period_length_ns < PCA9685_COUNTER_RANGE * PCA9685_QUANTUM= _NS(3)) { + best_prescale =3D 3; + ret_tohw =3D 1; + } else { + best_prescale =3D (unsigned int)wf->period_length_ns / (PCA9685_COUNTER_= RANGE * (NSEC_PER_SEC / PCA9685_OSC_CLOCK_HZ)) - 1; + } + + guard(mutex)(&pca->lock); + + if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) { + unsigned int current_prescale; + int ret; + + ret =3D regmap_read(pca->regmap, PCA9685_PRESCALE, ¤t_prescale); + if (ret) + return ret; + + if (current_prescale > best_prescale) + ret_tohw =3D 1; + + prescale =3D current_prescale; + } else { + prescale =3D best_prescale; + } + + period_ns =3D PCA9685_COUNTER_RANGE * PCA9685_QUANTUM_NS(prescale); + + duty =3D (unsigned)min_t(u64, wf->duty_length_ns, period_ns) / PCA9685_QU= ANTUM_NS(prescale); + + if (duty < PCA9685_COUNTER_RANGE) { + unsigned int on, off; + + on =3D (unsigned)min_t(u64, wf->duty_offset_ns, period_ns) / PCA9685_QUA= NTUM_NS(prescale); + off =3D (on + duty) % PCA9685_COUNTER_RANGE; + + /* + * With a zero duty cycle, it doesn't matter if period was + * rounded up + */ + if (!duty) + ret_tohw =3D 0; + + *wfhw =3D (typeof(*wfhw)){ + .onoff =3D { on & 0xff, (on >> 8) & 0xf, off & 0xff, (off >> 8) & 0xf }, + .prescale =3D prescale, + }; + } else { + *wfhw =3D (typeof(*wfhw)){ + .onoff =3D { 0, LED_FULL, 0, 0, }, + .prescale =3D prescale, + }; + } + + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] -> %s[%hhx %hhx %hhx %hhx]= PSC:%hhx\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + ret_tohw ? "#" : "", wfhw->onoff[0], wfhw->onoff[1], wfhw->onoff[2], wfh= w->onoff[3], wfhw->prescale); + + return ret_tohw; +} + +static int pca9685_round_waveform_fromhw(struct pwm_chip *chip, struct pwm= _device *pwm, + const void *_wfhw, struct pwm_waveform *wf) +{ + const struct pca9685_waveform *wfhw =3D _wfhw; + struct pca9685 *pca =3D to_pca(chip); + unsigned int prescale; + + if (wfhw->prescale) + prescale =3D wfhw->prescale; + else + scoped_guard(mutex, &pca->lock) { + int ret; + + ret =3D regmap_read(pca->regmap, PCA9685_PRESCALE, &prescale); + if (ret) + return ret; } =20 - /* - * Putting the chip briefly into SLEEP mode - * at this point won't interfere with the - * pm_runtime framework, because the pm_runtime - * state is guaranteed active here. - */ - /* Put chip into sleep mode */ - pca9685_set_sleep_mode(chip, true); + wf->period_length_ns =3D PCA9685_COUNTER_RANGE * PCA9685_QUANTUM_NS(presc= ale); =20 - /* Change the chip-wide output frequency */ - pca9685_write_reg(chip, PCA9685_PRESCALE, prescale); + if (wfhw->onoff[3] & LED_FULL) { + wf->duty_length_ns =3D 0; + wf->duty_offset_ns =3D 0; + } else if (wfhw->onoff[1] & LED_FULL) { + wf->duty_length_ns =3D wf->period_length_ns; + wf->duty_offset_ns =3D 0; + } else { + unsigned int on =3D wfhw->onoff[0] | (wfhw->onoff[1] & 0xf) << 8; + unsigned int off =3D wfhw->onoff[2] | (wfhw->onoff[3] & 0xf) << 8; =20 - /* Wake the chip up */ - pca9685_set_sleep_mode(chip, false); + wf->duty_length_ns =3D (off - on) % PCA9685_COUNTER_RANGE * PCA9685_QUAN= TUM_NS(prescale); + wf->duty_offset_ns =3D on * PCA9685_QUANTUM_NS(prescale); } =20 - duty =3D PCA9685_COUNTER_RANGE * state->duty_cycle; - duty =3D DIV_ROUND_UP_ULL(duty, state->period); - pca9685_pwm_set_duty(chip, pwm->hwpwm, duty); + dev_dbg(&chip->dev, "pwm#%u: [%hhx %hhx %hhx %hhx] PSC:%hhx -> %lld/%lld = [+%lld]\n", + pwm->hwpwm, + wfhw->onoff[0], wfhw->onoff[1], wfhw->onoff[2], wfhw->onoff[3], wfhw->pr= escale, + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns); + return 0; } =20 -static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) +static int pca9685_read_waveform(struct pwm_chip *chip, struct pwm_device = *pwm, void *_wfhw) { + struct pca9685_waveform *wfhw =3D _wfhw; struct pca9685 *pca =3D to_pca(chip); + unsigned int prescale; int ret; =20 - mutex_lock(&pca->lock); - ret =3D __pca9685_pwm_apply(chip, pwm, state); - if (ret =3D=3D 0) { - if (state->enabled) - set_bit(pwm->hwpwm, pca->pwms_enabled); - else - clear_bit(pwm->hwpwm, pca->pwms_enabled); - } - mutex_unlock(&pca->lock); + guard(mutex)(&pca->lock); =20 - return ret; -} + ret =3D regmap_bulk_read(pca->regmap, REG_ON_L(pwm->hwpwm), &wfhw->onoff,= 4); + if (ret) + return ret; =20 -static int pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device = *pwm, - struct pwm_state *state) -{ - unsigned long long duty; - unsigned int val =3D 0; + ret =3D regmap_read(pca->regmap, PCA9685_PRESCALE, &prescale); + if (ret) + return ret; =20 - /* Calculate (chip-wide) period from prescale value */ - pca9685_read_reg(chip, PCA9685_PRESCALE, &val); - /* - * PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000. - * The following calculation is therefore only a multiplication - * and we are not losing precision. - */ - state->period =3D (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) * - (val + 1); - - /* The (per-channel) polarity is fixed */ - state->polarity =3D PWM_POLARITY_NORMAL; - - if (pwm->hwpwm >=3D PCA9685_MAXCHAN) { - /* - * The "all LEDs" channel does not support HW readout - * Return 0 and disabled for backwards compatibility - */ - state->duty_cycle =3D 0; - state->enabled =3D false; - return 0; - } - - state->enabled =3D true; - duty =3D pca9685_pwm_get_duty(chip, pwm->hwpwm); - state->duty_cycle =3D DIV_ROUND_DOWN_ULL(duty * state->period, PCA9685_CO= UNTER_RANGE); + wfhw->prescale =3D prescale; =20 return 0; } =20 +static int pca9685_write_waveform(struct pwm_chip *chip, struct pwm_device= *pwm, const void *_wfhw) +{ + const struct pca9685_waveform *wfhw =3D _wfhw; + struct pca9685 *pca =3D to_pca(chip); + unsigned int current_prescale; + int ret; + + guard(mutex)(&pca->lock); + + if (wfhw->prescale) { + ret =3D regmap_read(pca->regmap, PCA9685_PRESCALE, ¤t_prescale); + if (ret) + return ret; + + if (current_prescale !=3D wfhw->prescale) { + if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) + return -EBUSY; + + /* Put chip into sleep mode */ + ret =3D pca9685_set_sleep_mode(chip, true); + if (ret) + return ret; + + /* Change the chip-wide output frequency */ + ret =3D regmap_write(pca->regmap, PCA9685_PRESCALE, wfhw->prescale); + if (ret) + return ret; + + /* Wake the chip up */ + ret =3D pca9685_set_sleep_mode(chip, false); + if (ret) + return ret; + } + } + + return regmap_bulk_write(pca->regmap, REG_ON_L(pwm->hwpwm), &wfhw->onoff,= 4); +} + static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *p= wm) { struct pca9685 *pca =3D to_pca(chip); @@ -365,8 +385,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, st= ruct pwm_device *pwm) } =20 static const struct pwm_ops pca9685_pwm_ops =3D { - .apply =3D pca9685_pwm_apply, - .get_state =3D pca9685_pwm_get_state, + .sizeof_wfhw =3D sizeof(struct pca9685_waveform), + .round_waveform_tohw =3D pca9685_round_waveform_tohw, + .round_waveform_fromhw =3D pca9685_round_waveform_fromhw, + .read_waveform =3D pca9685_read_waveform, + .write_waveform =3D pca9685_write_waveform, .request =3D pca9685_pwm_request, .free =3D pca9685_pwm_free, }; --=20 2.50.0