From nobody Sun Feb 8 06:53:59 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (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 B249825333E for ; Wed, 30 Apr 2025 11:56:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014185; cv=none; b=KhaFQeUOnS5UZplhKhXgMBjE8hnI9Kjj7dsSw7WgUIoetFmyBTLPZ12d6yah8vDxKQOiM8cIK87vZVhcISrrc0+S4jwQNCaqaU2NAh/WwQUdXnWUd7JwPnXm50xKtbx5ftL6pFSpwNuXQib/ajQSW70/cU03j2ozFOGG5mlyOnU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014185; c=relaxed/simple; bh=hyejLcti/TcNJx1m4d9G/GtC0oEJ7Qey4FsXMzEq1kM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=k30qvQJ4wcuzj7O5ypKo3gX/+wlSQiXYM6g75xKNxHjb3bK/8yXmWoz4f0nrXq/STDVJbSBWAbfIT5nvSU/x/YrvP9VPFaKhfeDKENb/O46O+4l2mMFPOrnbVcgycK7jYZ71bb9ZJS5L5nuJ77qrCaO1TZXzpSTnxdnkom4UP7M= 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=Cmd+EBH6; arc=none smtp.client-ip=209.85.221.42 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="Cmd+EBH6" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-39c0dfad22aso5585116f8f.2 for ; Wed, 30 Apr 2025 04:56:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1746014181; x=1746618981; 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=k9zyhrEUi6nJJ+PGWbcpcUtk00EBlhKzJBA8nF+tlnE=; b=Cmd+EBH6KzksutEoo7mkFf6TTdtPYgI5jqylReWF8QgEU9TR2Y8z4TGL+v6wPiNOIx 2Bo5Vx/JAO3AjS/ozbH8an8PrqqanoSBMWUCWgMzfAAtReANgP93p9a4K7ovQQsh8DfI QtyzpRjGYv+zYMFiFVkqwX3uBT4iqlXBglBQYY0KujyZxNY8Mvqhp44SgOjy9A33UENl qQjgybdSHYpLwAUMMGlu9wejD1kIjBhcJpbYEIBkQ9JlghT7WuIG/CX16cjS1pdPk9Qa GFhEFiZ7dxzQunwoPb5qAaFWyYMlALsHWr0/a4WUme5QY/WPS7vt8uVnsYr3WOBNcPh2 fr/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746014181; x=1746618981; 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=k9zyhrEUi6nJJ+PGWbcpcUtk00EBlhKzJBA8nF+tlnE=; b=GQfvzzjuGFzCr8Ohu4saV7G2DGHN1oYkVm60IVGJK4nASUTJDMz+jNWqYIco9eJdqm gtuelYHtHYNnW+2rBIpgvzLOlyH72qJvLYcG0TZbCbHc7YZuGsg674qAq36bAV0n2YIa uBcSNxZQlqrCIQGdoNSWW1rwdyhNqYnEkzKZmjeSC/3r6ePsYSx+MrT3ioBfYJjn/mMc jzWTOwZn2SB5vA5VkK7TmMZx0Bdq9i5dqJOpvLTDxJMsua9VT1G+zj12J1QyNP41EFaF 4mH7AoDKUhfLuW3tO3HIeC3juUenSg7u7yc2+YzX2irKH5pnFXGr8BHsl33aYPd9P33a M3iQ== X-Forwarded-Encrypted: i=1; AJvYcCVJPHvjjgMrvbQ7yVwbObjRry0I5WMn4m0Ub3UikNwv9e8ucG3FAX00tigqv8s8CZQIy5zJfNTLiAdIR/0=@vger.kernel.org X-Gm-Message-State: AOJu0Yzu9S6Q0WtA9FPJsMz/EGN5ubcopbORDuFepP96JMLe7M2yTieY MTHzuBqq6Cd0GScXvb2JS2OwYayyS80ey/NtpYoXZeQwBdjKWPYS6HkcLZDjosc= X-Gm-Gg: ASbGncsCe0uNi38st8BC0Kh2HSzhzhIvkjgSxV2tDqmjPwcZJbEBoWfl9XRhj+Rte8V 2Vp5N9gI0lj6uOnXtTSxOwT+hPWu59JF8l9QOpASbjj5zmZiW9rDW7Kj2Rg/qaW6nYCirlTsLgM LK8Opb3rbLZyf9oCPJ+XHS2+dm3KHKhG94u5GHEUqkPDYUS8ltpAJ0RIrbyj9L1jhZgmTGv/ofy VJnUUmtms35r3gVrbRegN11IbMw7XG0WiAqR/kJ85UJ6IfLjSU2xtggA7prOGT2vRj5hwa3WnWb HKkfX00huqvC9OjAqU3zYw2dPGpniRUmXyzAziPH4UgAEKwQgGaV49eD/tQ1VGZN5RrZzWy/4rd zDH3k6nI= X-Google-Smtp-Source: AGHT+IE1s1XezmIzMYkUPHDqKoWM6AWJrgqc4UeJ0XNV8UbwybnVCGNfE/QYiRjyiS9OH4wYytTVoQ== X-Received: by 2002:a5d:5f92:0:b0:39e:cbe0:4f3c with SMTP id ffacd0b85a97d-3a08f799858mr2396763f8f.8.1746014180982; Wed, 30 Apr 2025 04:56:20 -0700 (PDT) Received: from localhost (p200300f65f00780800000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f00:7808::1b9]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-3a073e5bc8bsm16507524f8f.81.2025.04.30.04.56.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 04:56:20 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Lechner , Kent Gibson , linux-kernel@vger.kernel.org Subject: [PATCH v7 1/4] pwm: Let pwm_set_waveform_might_sleep() fail for exact but impossible requests Date: Wed, 30 Apr 2025 13:55:58 +0200 Message-ID: <20538a46719584dafd8a1395c886780a97dcdf79.1746010245.git.u.kleine-koenig@baylibre.com> X-Mailer: git-send-email 2.47.2 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=2581; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=hyejLcti/TcNJx1m4d9G/GtC0oEJ7Qey4FsXMzEq1kM=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoEg/TjhmrL1w5soCslBFVn+FiS6bMxvpaMz7kw bhK4duk4ZKJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaBIP0wAKCRCPgPtYfRL+ TrRFB/9SDqf599BXlRzVARugVjRfSAG7ZLX+L0zzUolOI7hTKk4k+Cx/KTz57KcPAm/S7gjyMIO XA4Vq+H9hXub/FU1TutxJflnKT34X7oCAXBSz4Pz0xmZeFs/TcD7ekiSZYYl4xngz4ZoqSLQ0s3 JMvRfxnUh8QiyH3RaUixsF+p6W+Wapt7QmgfwppNyorxAZDfdi/sROV6Nw61IgCVID/9e1pA7CS HfIpXiJMCe0whRDWqwIvc+QLJWdy0KdPvvg7ETYXMm2tYgyGYmwD8sWcxVF8BH+RfHSsY+UlQ8r 0ZtR4FAlNPvZjtfZEVRdyT1NGwBosJXb5XRgnr/4Ok7P7u2b X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable Up to now pwm_set_waveform_might_sleep() returned 1 for exact requests that couldn't be served exactly. In contrast to pwm_round_waveform_might_sleep() and pwm_set_waveform_might_sleep() with exact =3D false this is an error condition. So simplify handling for callers of pwm_set_waveform_might_sleep() by returning -EDOM instead of 1 in this case. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/core.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index e0a90c4cd723..28cb6ab0f62d 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -404,15 +404,16 @@ static int __pwm_set_waveform(struct pwm_device *pwm, * Typically a requested waveform cannot be implemented exactly, e.g. beca= use * you requested .period_length_ns =3D 100 ns, but the hardware can only s= et * periods that are a multiple of 8.5 ns. With that hardware passing @exac= t =3D - * true results in pwm_set_waveform_might_sleep() failing and returning 1.= If - * @exact =3D false you get a period of 93.5 ns (i.e. the biggest period n= ot bigger - * than the requested value). + * true results in pwm_set_waveform_might_sleep() failing and returning -E= DOM. + * If @exact =3D false you get a period of 93.5 ns (i.e. the biggest perio= d not + * bigger than the requested value). * Note that even with @exact =3D true, some rounding by less than 1 ns is * possible/needed. In the above example requesting .period_length_ns =3D = 94 and * @exact =3D true, you get the hardware configured with period =3D 93.5 n= s. * - * Returns: 0 on success, 1 if was rounded up (if !@exact) or no perfect m= atch was - * possible (if @exact), or a negative errno + * Returns: 0 on success, 1 if was rounded up (if !@exact), -EDOM if setti= ng + * failed due to the exact waveform not being possible (if @exact), or a + * different negative errno on failure. * Context: May sleep. */ int pwm_set_waveform_might_sleep(struct pwm_device *pwm, @@ -440,6 +441,16 @@ int pwm_set_waveform_might_sleep(struct pwm_device *pw= m, err =3D __pwm_set_waveform(pwm, wf, exact); } =20 + /* + * map err =3D=3D 1 to -EDOM for exact requests. Also make sure that -EDO= M is + * only returned in exactly that case. Note that __pwm_set_waveform() + * should never return -EDOM which justifies the unlikely(). + */ + if (unlikely(err =3D=3D -EDOM)) + err =3D -EINVAL; + else if (exact && err =3D=3D 1) + err =3D -EDOM; + return err; } EXPORT_SYMBOL_GPL(pwm_set_waveform_might_sleep); --=20 2.47.2 From nobody Sun Feb 8 06:53:59 2026 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (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 D03471E47B4 for ; Wed, 30 Apr 2025 11:56:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014186; cv=none; b=K6cxQp7X9dZmn8+Ei49GEStPMJsoqysQBwXMAUy6mgLCJv9mMBRVw0SjX9lNTKjbFzWmp8YJEUJzZsaaMvbzVUr2j+qbcQfSEL4vpe04Gt6BOWccY08wjG5J5UQUp7WHPKldXx9mizkl8KKOXnvQtaSFHEG/pRtRa/AEaMOQEsk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014186; c=relaxed/simple; bh=pmPfZfdhpe08zFnN5tLlJkVDVkEeNQk+NEZc/D1fbGQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=i8h6ldEIGn+tUiOfCUEnNf8u6KUwMo3DfcgTd2rPLxkQBJv4Nlga46xe+eGKdCSbqB8dvSIUqoN9UohCOVZWdZ/DaTxYSqoDyO/iiVDemXiWFQxZA76g2M4pR/EnLrqcJyM1tCZs8p+PDK/miTB+RdGFK/Z+lv/Fc28+dYFb7JM= 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=U1lTjCq/; arc=none smtp.client-ip=209.85.221.43 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="U1lTjCq/" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-39c14016868so7708819f8f.1 for ; Wed, 30 Apr 2025 04:56:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1746014183; x=1746618983; 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=F2xHxs3KnDeNu7WRbSnqj4aOhMB1CBDFvBqUKG0qcVk=; b=U1lTjCq/A/NsedpPy+FqXPajbHINPe4dUnxJsZ8BGfdZbfFo1915Va7zYqO/BjC613 s9q98Nd6VZ9IvqLu9Hz3TsH0Pe1i+hJHtht2ozjRTll0CH2gFHzKxUxzvS/d3koDj1RC W7C1YPSna6De01HlTqm9w8+OEPbU5quI2mURzJxDyCTRLhmb0yTAtdMg9ik95paBfPKz owH6m+4Ab11AEeOZT6u/7MP9cw/TyzqcK7GSvS0L5uaG48POzBVd/nnamoDSxyZU8b3Y +QKF4esqJWRou94ZpeCt+zkfOe/O6eEayaQZSA1Fpjy2EdsjhbmW2uFG5broEf7RffWy LCGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746014183; x=1746618983; 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=F2xHxs3KnDeNu7WRbSnqj4aOhMB1CBDFvBqUKG0qcVk=; b=J514NbvNJW06GJ7I+QlpzhP+BxGU00oKGLiXalQPo27B0RaavNS4Gcz3vv59kNfXWj BGnpPSKEIXbWjb3wmUHCrGM3Ft8VWqMkI0BI4Q9iJI204J+2cSOmaeRHM6sB5RkJiN8L XvMDLbcxlqr0HZmGBbLY+JMr4hecsZqTEYWbo7EG7c7/cuhTb6wy7WU2cdJAYufMiDd5 rOyqFu7tqNoO0dTdaZMzW5+E83Yh6ghD9i+ONcJWOyfc0810U/LTo8o3zPaTb8x+1TaL ryiolQ0mAD7qYBsfDI9UnJyK1ixNdsGBwghiYs1dbsH6296qG6MaEf6oKmOuDp8TQd8H 9FUg== X-Forwarded-Encrypted: i=1; AJvYcCUq0bMFQ+4hYyaaVlllwdZFxEX07BFe0GZTEHrAPXZkl7oUncEETFddgWlKTPBLSmLjfGm9kJUbZkQUET0=@vger.kernel.org X-Gm-Message-State: AOJu0YwK6iApFUFC+lEiTQCaNsrKARxA1pkxvG72VRdscysiUppw/sR2 joy+MsCTlXP+BJzZCq5mMDASwfGZgc6Tp6DgwAXlW4kzRpaQd0iwBUCnhlkpRJs= X-Gm-Gg: ASbGnctKfr27zs+40+upYmGBIvyORi5M0KU7177n+TQiw53P9GY4grwk7FsgxXQkaXR zRRM5Y/WCVPzRAUFSbGwwWe97UIFkkMQHBwFEGE6UW1RRAOSMY6Gz5TsBnKsOY2ul9oYQkP6J8H phlK1GR1/bdV69dB1s6TN1pokQAx/zwff+XutviOPaQ7LwzL/UeO9fTmid5LsK6X9fXOqw102CJ eKoyvEiXK6TBgK7p25Epv/a4mnrVLbXi6TeoIkJo9/Mr9cQ45kQjpOib3P+NvunTfHUiWuke0BK qyEhBxgHUjicLhD33QbOOXD8iM7A2z1PJJKmpN9FdCvXvbiTNLQVh3MAtHOsz+NERl4KCVb0Xos NQmgLOBQ= X-Google-Smtp-Source: AGHT+IEIVW9hCC7khpxN5eC7lwB7Nqf2uJEp51BVHaLSAHCM2w4LxwKU+3btSCLoZCrVcxQtJJXnLQ== X-Received: by 2002:a05:600c:19c8:b0:43c:fee3:2bce with SMTP id 5b1f17b1804b1-441b1f5be9cmr20071305e9.26.1746014183134; Wed, 30 Apr 2025 04:56:23 -0700 (PDT) Received: from localhost (p200300f65f00780800000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f00:7808::1b9]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-441ad81c19fsm39248705e9.0.2025.04.30.04.56.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 04:56:22 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Lechner , Kent Gibson , linux-kernel@vger.kernel.org Subject: [PATCH v7 2/4] pwm: Let pwm_set_waveform_might_sleep() return 0 instead of 1 after rounding up Date: Wed, 30 Apr 2025 13:55:59 +0200 Message-ID: <528cc3bbd9e35dea8646b1bcc0fbfe6c498bb4ed.1746010245.git.u.kleine-koenig@baylibre.com> X-Mailer: git-send-email 2.47.2 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=2135; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=pmPfZfdhpe08zFnN5tLlJkVDVkEeNQk+NEZc/D1fbGQ=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoEg/VsjKyV93JzbnPFh5tLFh0UPbIAUVfCmmlT MRb5M0C+pSJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaBIP1QAKCRCPgPtYfRL+ TiS6B/sE4DJYf8tPuMmZjF5NMTHFVXtusXFoGZ7tEhv2XsdL4zhkmhdiPGvNJ/Vdo0hmA/+CGF0 ZPc8oeVrDfZpTtmfeitvKJxXrIpmHbOEET7HaqNwgqXDI/jkH5onHb8Q1VM7ndAdIHG6sOzn7eB TxuRnK9NarmXREUKOesQ5by0RYVpW1UM25BPne2kW5z6A/BrscgPkIYVGCtpU07jh9Ra/OE/B9S Zddt+uF0GmECErrKM8z2bRN5HqCnpfqRhVRLx8oIo1nn3m8nHkAu5MIIzPirKhsusSJ6RYcl0Af /nZckWkKkMMiiCBYjalpaxqnkpi0kvlkLQJ+62xuVFlHsyRe X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable While telling the caller of pwm_set_waveform_might_sleep() if the request was completed by rounding down only or (some) rounding up gives additional information, it makes usage this function needlessly hard and the additional information is not used. A prove for that is that currently both users of this function just pass the returned value up to their caller even though a positive value isn't intended there. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 28cb6ab0f62d..5cf64b3a4cdf 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -411,9 +411,8 @@ static int __pwm_set_waveform(struct pwm_device *pwm, * possible/needed. In the above example requesting .period_length_ns =3D = 94 and * @exact =3D true, you get the hardware configured with period =3D 93.5 n= s. * - * Returns: 0 on success, 1 if was rounded up (if !@exact), -EDOM if setti= ng - * failed due to the exact waveform not being possible (if @exact), or a - * different negative errno on failure. + * Returns: 0 on success, -EDOM if setting failed due to the exact wavefor= m not + * being possible (if @exact), or a different negative errno on failure. * Context: May sleep. */ int pwm_set_waveform_might_sleep(struct pwm_device *pwm, @@ -442,14 +441,17 @@ int pwm_set_waveform_might_sleep(struct pwm_device *p= wm, } =20 /* - * map err =3D=3D 1 to -EDOM for exact requests. Also make sure that -EDO= M is - * only returned in exactly that case. Note that __pwm_set_waveform() - * should never return -EDOM which justifies the unlikely(). + * map err =3D=3D 1 to -EDOM for exact requests and 0 for !exact ones. Al= so + * make sure that -EDOM is only returned in exactly that case. Note that + * __pwm_set_waveform() should never return -EDOM which justifies the + * unlikely(). */ if (unlikely(err =3D=3D -EDOM)) err =3D -EINVAL; else if (exact && err =3D=3D 1) err =3D -EDOM; + else if (err =3D=3D 1) + err =3D 0; =20 return err; } --=20 2.47.2 From nobody Sun Feb 8 06:53:59 2026 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (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 A68A1259CBB for ; Wed, 30 Apr 2025 11:56:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014188; cv=none; b=NPzOoYNUuIPJI8zlejKnonb193ZVAIsWVovLUy73QhGZbAoXX6fLtpUwjX5T3y/LBNzWKSXTmASCODaPVYF5+Y968Xf1/lL++mgVuEdeZQdQjA5G/nvO6WelisnbU9cK7ZuVpXTgivDcX6VcJAYdboVUeOzonM+I4pWHXFHBJA8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014188; c=relaxed/simple; bh=RjoEXSIkY3DqTEk4/M+XxiagMUMOfWsaQZWgGc6PuWc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Z3YxuN2f047m4lfgn6841I0SKZwyWUBqW6t2XU1DHQjwX9XPPhgtkVG75RMTL8M1DHbcPtufUV54BP18pJhLl3NZWTO/XyT5X33BGU9DQ6/qATSIykswhtcaBM9Ld+kR7zSRrxc5OJPjKZXH2uSkhU9vp+D7IKEdxaP9nOjaq9w= 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=tD3GNvO7; arc=none smtp.client-ip=209.85.221.52 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="tD3GNvO7" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-39efc1365e4so3324665f8f.1 for ; Wed, 30 Apr 2025 04:56:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1746014185; x=1746618985; 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=iRxmOkREDtNcYi3zS5d08yarRVufAZekuzgf6z5cgxM=; b=tD3GNvO7uBNyIi74rDd3aFQ6CDs8e051ZWkHn0DMjp6+jsbEVVFNLhSrXl1viCHdTr 8JClVAkD9QkWlvMhgthT0AA4lK17ZTQ4izksZ5qVJbl4OrJfRDoj/MhL2CGYXCWYR5IE eJHrsDWdiVNkffUyTfKaFljxIW0Fc4+zk42saJCM07pUFdfNDUcQf3xqKLxSwzEWDjp5 n7yQX/1vVxr/PgeKSLdnIOUU4dmpDOkGnS44SiIzvMor5RVlq2dxH/rSmUVGoaUWpV1I 8/7zbAjtZFTzVVvLjWHGfWShToDCdPxjvTcirp+KyFfr1uX8e0uqT36gzIR6AWPqB2EZ ugqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746014185; x=1746618985; 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=iRxmOkREDtNcYi3zS5d08yarRVufAZekuzgf6z5cgxM=; b=GW6ksnXbX1bD8qx/3v64FrINdJD2avgFCSzNrw5HqeAKEeAeDy7RSdJDi45obwA32o QQi7KdHaLuYk3c4gIE6lGfdtlCWoO2JNgOhXO3FTmCc0QH3WEcy/Qsx+/+zum7CvY5SC wdStBuKV775/HN/zb53CYxqoCXHGA46HMDMM0V7T957uy65ADAMAUAX5WFP06Csg2RI7 A5rAlk1qX5YyFmeufqfxL5/Vui6OaFo6BQNL9E7pIo0s9tDKeKvKFfRpovUXJf02fZiW dmx3fl8K+NybVgz7TvD9kFc03L7/MoH8Fo4q20wlD5O6AqsGDjS8x+V9EyWgYYvZTsr4 afYg== X-Forwarded-Encrypted: i=1; AJvYcCWnOLSIMZz7M8SG8nmw3bG+W6Zf4agAQNMDwkTXljnPOCw7gMvlaZ6MRcfWBUQ7irFXme48mq+0OtC4rJc=@vger.kernel.org X-Gm-Message-State: AOJu0Yzoxo3dnebnraRKe+mMv9+gPM9x+xnordM2qs7lfhbLGEXxa7AH G23r4G4nkdNuubn3NvfhBSQzjRei4BeqCbFYvxm7T4OiuTQmeAWIBbNvEb9oURE= X-Gm-Gg: ASbGncvKpoqpjlQ6ZhR29TQLRulZSlPYpl2Zmjb+AGEJ0mF3CfPFGAb0NpzgHhHVbPa 353s5M8wknO3t9FfsdWIB7LCcJ3NpGU3TPoS7GxcBDBGvjAtrxXWoe0GM4D48gJ8vbvWBHLhcyv 71OBhrLVuKxJ9akrdv/a6w6xqHzAU9dW5xXQuOGdxQMRr1eybLKC5VDTIgtgdL1r+XsHTrra1F3 Z0K5E7oxk4THgdApIDeBspoTGyddWu7T7RqPT6EBdjPbdPzJcMkZtqfT59DqAZy2B20+TF+O7nN TgLmPJisXQceotjIpuicOeSs1UQ05oS+M7IbsnNm38Y6Ka4ObqUtbhcIoUEszebauU6KRXT/q/u wDB1bvuw= X-Google-Smtp-Source: AGHT+IFyQST3rH0YuQYldPgvha6jikAYlv7DUnoof5VueESfC3/kHD0oJ3b0nyoh4FA/mTRr6s2cVw== X-Received: by 2002:a05:6000:1844:b0:3a0:7faa:309d with SMTP id ffacd0b85a97d-3a08f7c8ecdmr1805907f8f.37.1746014184884; Wed, 30 Apr 2025 04:56:24 -0700 (PDT) Received: from localhost (p200300f65f00780800000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f00:7808::1b9]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-3a073cc4025sm17070285f8f.56.2025.04.30.04.56.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 04:56:24 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Lechner , Kent Gibson , linux-kernel@vger.kernel.org Subject: [PATCH v7 3/4] pwm: Formally describe the procedure used to pick a hardware waveform setting Date: Wed, 30 Apr 2025 13:56:00 +0200 Message-ID: X-Mailer: git-send-email 2.47.2 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=2752; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=RjoEXSIkY3DqTEk4/M+XxiagMUMOfWsaQZWgGc6PuWc=; b=owGbwMvMwMXY3/A7olbonx/jabUkhgwh/htfS9ZlvdrfbJkx37ufs2/D9FXxGzJzPIP6srx5k 3Zk777fyWjMwsDIxSArpshi37gm06pKLrJz7b/LMINYmUCmMHBxCsBEGrs5GFY+VLOcGVGw9/6k 9o18nTYnuQu1c9rUBaZa/Dy6Tr063XLlEkWDZfzFk2Rkvr0U7ZRMeO/dqL7W9fLH91crg8WmnPx WLWym/e1/dLHujujGFNbAT4FrZ8e2RGRsf+S4sye12orTOrb9tOc8iW13jHRjp3zeH7jGL183z2 HTpI0VgYk9rjOPJxo2+b1NN3gf1zitoWyZ3/NXtUE2Xpxn+Xc/dbT87mVxNqXbf8HKW27dkXdn3 BEMOFW/nz1u06+Tzu53rs/K4X3D68wSZiMlvr/67uGAfrn6eXJtqtLKEvVl35l+3S6q9pik8tHl cdIZrmW3Q3U1wp+faVrHVBdh+OHayQvrIn99Vra702IMAA== X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable This serves as specification for both, PWM consumers and the respective callback for lowlevel drivers. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/core.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 5cf64b3a4cdf..4d842c692194 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -231,7 +231,9 @@ static int __pwm_write_waveform(struct pwm_chip *chip, = struct pwm_device *pwm, c * * Usually all values passed in @wf are rounded down to the nearest possib= le * value (in the order period_length_ns, duty_length_ns and then - * duty_offset_ns). Only if this isn't possible, a value might grow. + * duty_offset_ns). Only if this isn't possible, a value might grow. See t= he + * documentation for pwm_set_waveform_might_sleep() for a more formal + * description. * * Returns: 0 on success, 1 if at least one value had to be rounded up or a * negative errno. @@ -411,6 +413,26 @@ static int __pwm_set_waveform(struct pwm_device *pwm, * possible/needed. In the above example requesting .period_length_ns =3D = 94 and * @exact =3D true, you get the hardware configured with period =3D 93.5 n= s. * + * Let C be the set of possible hardware configurations for a given PWM de= vice, + * consisting of tuples (p, d, o) where p is the period length, d is the d= uty + * length and o the duty offset. + * + * The following algorithm is implemented to pick the hardware setting + * (p, d, o) =E2=88=88 C for a given request (p', d', o') with @exact =3D = false:: + * + * p =3D max( { =E1=B9=97 | =E2=88=83 =E1=B8=8B, =C8=AF : (=E1=B9=97, = =E1=B8=8B, =C8=AF) =E2=88=88 C =E2=88=A7 =E1=B9=97 =E2=89=A4 p' } =E2=88=AA= { min({ =E1=B9=97 | =E2=88=83 =E1=B8=8B, =C8=AF : (=E1=B9=97, =E1=B8=8B, = =C8=AF) =E2=88=88 C }) }) + * d =3D max( { =E1=B8=8B | =E2=88=83 =C8=AF : (p, =E1=B8=8B, =C8=AF) = =E2=88=88 C =E2=88=A7 =E1=B8=8B =E2=89=A4 d' } =E2=88=AA { min({ =E1=B8=8B = | =E2=88=83 =C8=AF : (p, =E1=B8=8B, =C8=AF) =E2=88=88 C }) }) + * o =3D max( { =C8=AF | (p, d, =C8=AF) =E2=88=88 C =E2=88=A7 =C8=AF =E2= =89=A4 o' } =E2=88=AA { min({ =C8=AF | (p, d, =C8=AF) =E2=88=88 C }) }) + * + * In words: The chosen period length is the maximal possible period lengt= h not + * bigger than the requested period length and if that doesn't exist, the + * minimal period length. The chosen duty length is the maximal possible d= uty + * length that is compatible with the chosen period length and isn't bigge= r than + * the requested duty length. Again if such a value doesn't exist, the min= imal + * duty length compatible with the chosen period is picked. After that the= duty + * offset compatible with the chosen period and duty length is chosen in t= he + * same way. + * * Returns: 0 on success, -EDOM if setting failed due to the exact wavefor= m not * being possible (if @exact), or a different negative errno on failure. * Context: May sleep. --=20 2.47.2 From nobody Sun Feb 8 06:53:59 2026 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 A44FE259CA9 for ; Wed, 30 Apr 2025 11:56:28 +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=1746014191; cv=none; b=YSn1AD+p8jEb12jCQF1EfO3v2BsYzip3n9Po/ITMm5Pm13d7lWM4WtpxOFBLHCDyGidsjnFXissUOkCgfmNJQtYYjMlCgzb8rWYeZgvLL+TT/mucoEp6UMFCk0aKE+AcQNMOcqh3tpNVV8QzA9FKgNsTN80iC1ZBC+1VKORbWzw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746014191; c=relaxed/simple; bh=cqvKQHdAO2SdKfRDdtiMA0uxReCOqHxryeY4lOytsDY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XRnwULOPHbvKsBJ9dlII7+fICdYDANAAuAaCR47CPOp+hOSCWcimYTPhpvk9wwjHjwoerqZk2jomr9G8Lq9wyoju857SAoe7gBilwno4kNCVAuRqK0AwoTB2T+QByQp4IoYEJwi1+/itbsqGTRrGWcsTdM424GDJQIkxFDVoT1A= 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=QPHQsRNg; 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="QPHQsRNg" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-43cfebc343dso49471145e9.2 for ; Wed, 30 Apr 2025 04:56:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1746014187; x=1746618987; 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=mmGLOEXfezbIO4+3KuQiv1vH3EfZhxIl0cjhvPP2kMk=; b=QPHQsRNg/5lKYGth7X5tnVJ8Pz738sPrBWivyR+lU6NrcILR8jc+2vmjgxs04xBbDV vx+c0J0vBCSq1euu/oTzHYi2PDX7aRT0sjHdd5VTLY2s+SmOR+McRoaLZD/+EYfJAapq ENHqK2dFqLAVvVRhLH6RbQu8GVex0G6zSpvAn/AOHCfdc36YADVaWJesFsLibYHq1gHg 3dKJgQic9KIHFyRhmi1STP3gK+kf9Cb3ZdWB2TprabhIas937dHZdX2oTwcug/0dKOA8 YnKfOZQigz0U1XTBaFKSYCg9lcSYWJl7Q6lowpmluzKwrWLWZn4om+IKZcnG5aiwMZxZ VPKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746014187; x=1746618987; 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=mmGLOEXfezbIO4+3KuQiv1vH3EfZhxIl0cjhvPP2kMk=; b=KOjU7WpSThvomVmxbV/QlYb9creadkBKVdgu1UYbyjiTZfnQo6cp+rXkQdi6Z8w+PE ZK1rpqPtx73mxA5N8IzL7X62t8Ma1T5SH2oRMWmF9TYiSxUiotZbc4osjziVq4GeTa7e GpHHvpgSd7isndm404FqEHZ1KokjHFqAA9EC0qi6Gejx+l/LU+3DUw8Pmv+FlJsiG2Zu LJCboc9OdVri0qcV4MwGd1Hcto0tXhZahZfCEuZJJaIXShWuSr5ozElbYD2SjlrRZAoL D8rsnIsN/jRYaJRVgss4mcPDus7wUUqscmPBGkBN7RWt3/aOVn1NRGtrQiyz0xJSwkkW fsFA== X-Forwarded-Encrypted: i=1; AJvYcCXWX5XNSZshaKp31IcBxSKJZadi0r+MZy/sFlZBsR3Ta4/ph4gpAHCzulYrKVlD5g+hDhkfahSKM51mfN8=@vger.kernel.org X-Gm-Message-State: AOJu0YxsfGjYfkQIBlHitKkqYlfzPgBRxL+eD19nxseTEjVtvmjmcWdn WG2fGh/8yJXzQV+Xeu+TSWK/weTiiVEcZQ8WUplM7XaKVBBndslbJXP9EgKZcHzEMFKNZ7+i8Hx 6 X-Gm-Gg: ASbGncuJyeGyhm3zt3QJZ3YHrWIwyuco6jwxF2IvsT3r8z5UQAI5I/+ykwG6zXZBflA po9/tpsVhHL5kRftLCR0KBAuldU3Z4vw4qcoyKVXP0ahAHPwWaoQK6eoxjr17Jo78qJYOSOkEwj nojbKr5Ll9IUJIrux4JGQt/vt9r3Qub1vMEoOE2iugMFhczg/MpKpQFVg72s/VylODODCJsdFyO 91mn3pusKUw08xgYjY+1FOphGRn9gcPm90wX93BmY9QkwhiyzDCnmJwCnKpQ3WukKZ0CC2+wxuq QI5PAtpGoK3N7KptEd8f1otXgZx7pkU2vt6NiWRzWc2t241/JZRvTWf4PVmO1Z+euzbpT18QDw4 iYc12wfBvPPMefCRLew== X-Google-Smtp-Source: AGHT+IEq81+UUX91nuldUGV4F0sX+gzDsrOqf3/ocm8GPyNEKZSiVCgcAXj3r97AqrRNHEpumkNoFA== X-Received: by 2002:a05:600c:c0cb:b0:441:b4b9:4965 with SMTP id 5b1f17b1804b1-441b4b949c7mr6786535e9.11.1746014186752; Wed, 30 Apr 2025 04:56:26 -0700 (PDT) Received: from localhost (p200300f65f00780800000000000001b9.dip0.t-ipconnect.de. [2003:f6:5f00:7808::1b9]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-441b2b97262sm23063255e9.4.2025.04.30.04.56.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 04:56:26 -0700 (PDT) From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: linux-pwm@vger.kernel.org Cc: David Lechner , Kent Gibson , linux-kernel@vger.kernel.org Subject: [PATCH v7 4/4] pwm: Add support for pwmchip devices for faster and easier userspace access Date: Wed, 30 Apr 2025 13:56:01 +0200 Message-ID: X-Mailer: git-send-email 2.47.2 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=12756; i=u.kleine-koenig@baylibre.com; h=from:subject:message-id; bh=cqvKQHdAO2SdKfRDdtiMA0uxReCOqHxryeY4lOytsDY=; b=owEBbQGS/pANAwAKAY+A+1h9Ev5OAcsmYgBoEg/aLHzVbBej5fyrPNooBdntT4CFFEQuGad25 pSgiOmKxtWJATMEAAEKAB0WIQQ/gaxpOnoeWYmt/tOPgPtYfRL+TgUCaBIP2gAKCRCPgPtYfRL+ TrV3B/0Zo3Kn5C9MWrDqOj8ZGcWihAWGWXvxVh1tsV8BY/esIPoV4XqU4nGVqLpqTW9YsfLMO5a QhY6Lq7qQOS1c9gWcwxpZ3dQK7/ZlrAZzlXRrRObc0YW5dX+r9rvGPexp6q7kGDGAknzx2NxPXU CnjQUNEo+kyPGJYalm2aYCsd/2819+SX8sPE/uajz1j9pYEFFdSvOBW4x+JOs/i1vfsgrRwve0w jMbwDqW8Xdfxn52zdLzrC8AqwVq4VMx/KqFhxtNEPZMq4CtBZKTPwn3WYlKaChjGIpLSEHESy9Q dyiEMNWGFdcR1C5QzANiTnF9qOoS01J3DdVdS5Ad1Wzz/z+T X-Developer-Key: i=u.kleine-koenig@baylibre.com; a=openpgp; fpr=0D2511F322BFAB1C1580266BE2DCDD9132669BD6 Content-Transfer-Encoding: quoted-printable With this change each pwmchip defining the new-style waveform callbacks can be accessed from userspace via a character device. Compared to the sysfs-API this is faster and allows to pass the whole configuration in a single ioctl allowing atomic application and thus reducing glitches. On an STM32MP13 I see: root@DistroKit:~ time pwmtestperf real 0m 1.27s user 0m 0.02s sys 0m 1.21s root@DistroKit:~ rm /dev/pwmchip0 root@DistroKit:~ time pwmtestperf real 0m 3.61s user 0m 0.27s sys 0m 3.26s pwmtestperf does essentially: for i in 0 .. 50000: pwm_set_waveform(duty_length_ns=3Di, period_length_ns=3D50000, duty_offse= t_ns=3D0) and in the presence of /dev/pwmchip0 is uses the ioctls introduced here, without that device it uses /sys/class/pwm/pwmchip0. Signed-off-by: Uwe Kleine-K=C3=B6nig --- drivers/pwm/core.c | 322 +++++++++++++++++++++++++++++++++++++-- include/linux/pwm.h | 3 + include/uapi/linux/pwm.h | 53 +++++++ 3 files changed, 363 insertions(+), 15 deletions(-) create mode 100644 include/uapi/linux/pwm.h diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 4d842c692194..b86f06ab2a32 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -23,9 +23,13 @@ =20 #include =20 +#include + #define CREATE_TRACE_POINTS #include =20 +#define PWM_MINOR_COUNT 256 + /* protects access to pwm_chips */ static DEFINE_MUTEX(pwm_lock); =20 @@ -2007,20 +2011,9 @@ struct pwm_device *pwm_get(struct device *dev, const= char *con_id) } EXPORT_SYMBOL_GPL(pwm_get); =20 -/** - * pwm_put() - release a PWM device - * @pwm: PWM device - */ -void pwm_put(struct pwm_device *pwm) +static void __pwm_put(struct pwm_device *pwm) { - struct pwm_chip *chip; - - if (!pwm) - return; - - chip =3D pwm->chip; - - guard(mutex)(&pwm_lock); + struct pwm_chip *chip =3D pwm->chip; =20 /* * Trigger a warning if a consumer called pwm_put() twice. @@ -2041,6 +2034,20 @@ void pwm_put(struct pwm_device *pwm) =20 module_put(chip->owner); } + +/** + * pwm_put() - release a PWM device + * @pwm: PWM device + */ +void pwm_put(struct pwm_device *pwm) +{ + if (!pwm) + return; + + guard(mutex)(&pwm_lock); + + __pwm_put(pwm); +} EXPORT_SYMBOL_GPL(pwm_put); =20 static void devm_pwm_release(void *pwm) @@ -2110,6 +2117,274 @@ struct pwm_device *devm_fwnode_pwm_get(struct devic= e *dev, } EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get); =20 +struct pwm_cdev_data { + struct pwm_chip *chip; + struct pwm_device *pwm[]; +}; + +static int pwm_cdev_open(struct inode *inode, struct file *file) +{ + struct pwm_chip *chip =3D container_of(inode->i_cdev, struct pwm_chip, cd= ev); + struct pwm_cdev_data *cdata; + + guard(mutex)(&pwm_lock); + + if (!chip->operational) + return -ENXIO; + + cdata =3D kzalloc(struct_size(cdata, pwm, chip->npwm), GFP_KERNEL); + if (!cdata) + return -ENOMEM; + + cdata->chip =3D chip; + + file->private_data =3D cdata; + + return nonseekable_open(inode, file); +} + +static int pwm_cdev_release(struct inode *inode, struct file *file) +{ + struct pwm_cdev_data *cdata =3D file->private_data; + unsigned int i; + + for (i =3D 0; i < cdata->chip->npwm; ++i) { + struct pwm_device *pwm =3D cdata->pwm[i]; + + if (pwm) { + const char *label =3D pwm->label; + + pwm_put(cdata->pwm[i]); + kfree(label); + } + } + kfree(cdata); + + return 0; +} + +static int pwm_cdev_request(struct pwm_cdev_data *cdata, unsigned int hwpw= m) +{ + struct pwm_chip *chip =3D cdata->chip; + + if (hwpwm >=3D chip->npwm) + return -EINVAL; + + if (!cdata->pwm[hwpwm]) { + struct pwm_device *pwm =3D &chip->pwms[hwpwm]; + const char *label; + int ret; + + label =3D kasprintf(GFP_KERNEL, "pwm-cdev (pid=3D%d)", current->pid); + if (!label) + return -ENOMEM; + + ret =3D pwm_device_request(pwm, label); + if (ret < 0) { + kfree(label); + return ret; + } + + cdata->pwm[hwpwm] =3D pwm; + } + + return 0; +} + +static int pwm_cdev_free(struct pwm_cdev_data *cdata, unsigned int hwpwm) +{ + struct pwm_chip *chip =3D cdata->chip; + + if (hwpwm >=3D chip->npwm) + return -EINVAL; + + if (cdata->pwm[hwpwm]) { + struct pwm_device *pwm =3D cdata->pwm[hwpwm]; + const char *label =3D pwm->label; + + __pwm_put(pwm); + + kfree(label); + + cdata->pwm[hwpwm] =3D NULL; + } + + return 0; +} + +static struct pwm_device *pwm_cdev_get_requested_pwm(struct pwm_cdev_data = *cdata, + u32 hwpwm) +{ + struct pwm_chip *chip =3D cdata->chip; + + if (hwpwm >=3D chip->npwm) + return ERR_PTR(-EINVAL); + + if (cdata->pwm[hwpwm]) + return cdata->pwm[hwpwm]; + + return ERR_PTR(-EINVAL); +} + +static long pwm_cdev_ioctl(struct file *file, unsigned int cmd, unsigned l= ong arg) +{ + int ret =3D 0; + struct pwm_cdev_data *cdata =3D file->private_data; + struct pwm_chip *chip =3D cdata->chip; + + guard(mutex)(&pwm_lock); + + if (!chip->operational) + return -ENODEV; + + switch (cmd) { + case PWM_IOCTL_REQUEST: + { + unsigned int hwpwm =3D arg; + + return pwm_cdev_request(cdata, hwpwm); + } + + case PWM_IOCTL_FREE: + { + unsigned int hwpwm =3D arg; + + return pwm_cdev_free(cdata, hwpwm); + } + + case PWM_IOCTL_ROUNDWF: + { + struct pwmchip_waveform cwf; + struct pwm_waveform wf; + struct pwm_device *pwm; + + ret =3D copy_from_user(&cwf, + (struct pwmchip_waveform __user *)arg, + sizeof(cwf)); + if (ret) + return -EFAULT; + + if (cwf.__pad !=3D 0) + return -EINVAL; + + pwm =3D pwm_cdev_get_requested_pwm(cdata, cwf.hwpwm); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + + wf =3D (struct pwm_waveform) { + .period_length_ns =3D cwf.period_length_ns, + .duty_length_ns =3D cwf.duty_length_ns, + .duty_offset_ns =3D cwf.duty_offset_ns, + }; + + ret =3D pwm_round_waveform_might_sleep(pwm, &wf); + if (ret < 0) + return ret; + + cwf =3D (struct pwmchip_waveform) { + .hwpwm =3D cwf.hwpwm, + .period_length_ns =3D wf.period_length_ns, + .duty_length_ns =3D wf.duty_length_ns, + .duty_offset_ns =3D wf.duty_offset_ns, + }; + + return copy_to_user((struct pwmchip_waveform __user *)arg, + &cwf, sizeof(cwf)); + } + + case PWM_IOCTL_GETWF: + { + struct pwmchip_waveform cwf; + struct pwm_waveform wf; + struct pwm_device *pwm; + + ret =3D copy_from_user(&cwf, + (struct pwmchip_waveform __user *)arg, + sizeof(cwf)); + if (ret) + return -EFAULT; + + if (cwf.__pad !=3D 0) + return -EINVAL; + + pwm =3D pwm_cdev_get_requested_pwm(cdata, cwf.hwpwm); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + + ret =3D pwm_get_waveform_might_sleep(pwm, &wf); + if (ret) + return ret; + + cwf =3D (struct pwmchip_waveform) { + .hwpwm =3D cwf.hwpwm, + .period_length_ns =3D wf.period_length_ns, + .duty_length_ns =3D wf.duty_length_ns, + .duty_offset_ns =3D wf.duty_offset_ns, + }; + + return copy_to_user((struct pwmchip_waveform __user *)arg, + &cwf, sizeof(cwf)); + } + + case PWM_IOCTL_SETROUNDEDWF: + case PWM_IOCTL_SETEXACTWF: + { + struct pwmchip_waveform cwf; + struct pwm_waveform wf; + struct pwm_device *pwm; + + ret =3D copy_from_user(&cwf, + (struct pwmchip_waveform __user *)arg, + sizeof(cwf)); + if (ret) + return -EFAULT; + + if (cwf.__pad !=3D 0) + return -EINVAL; + + wf =3D (struct pwm_waveform){ + .period_length_ns =3D cwf.period_length_ns, + .duty_length_ns =3D cwf.duty_length_ns, + .duty_offset_ns =3D cwf.duty_offset_ns, + }; + + if (!pwm_wf_valid(&wf)) + return -EINVAL; + + pwm =3D pwm_cdev_get_requested_pwm(cdata, cwf.hwpwm); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + + ret =3D pwm_set_waveform_might_sleep(pwm, &wf, + cmd =3D=3D PWM_IOCTL_SETEXACTWF); + + /* + * If userspace cares about rounding deviations it has + * to check the values anyhow, so simplify handling for + * them and don't signal uprounding. This matches the + * behaviour of PWM_IOCTL_ROUNDWF which also returns 0 + * in that case. + */ + if (ret =3D=3D 1) + ret =3D 0; + + return ret; + } + + default: + return -ENOTTY; + } +} + +static const struct file_operations pwm_cdev_fileops =3D { + .open =3D pwm_cdev_open, + .release =3D pwm_cdev_release, + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D pwm_cdev_ioctl, +}; + +static dev_t pwm_devt; + /** * __pwmchip_add() - register a new PWM chip * @chip: the PWM chip to add @@ -2162,7 +2437,17 @@ int __pwmchip_add(struct pwm_chip *chip, struct modu= le *owner) scoped_guard(pwmchip, chip) chip->operational =3D true; =20 - ret =3D device_add(&chip->dev); + if (chip->ops->write_waveform) { + if (chip->id < PWM_MINOR_COUNT) + chip->dev.devt =3D MKDEV(MAJOR(pwm_devt), chip->id); + else + dev_warn(&chip->dev, "chip id too high to create a chardev\n"); + } + + cdev_init(&chip->cdev, &pwm_cdev_fileops); + chip->cdev.owner =3D owner; + + ret =3D cdev_device_add(&chip->cdev, &chip->dev); if (ret) goto err_device_add; =20 @@ -2213,7 +2498,7 @@ void pwmchip_remove(struct pwm_chip *chip) idr_remove(&pwm_chips, chip->id); } =20 - device_del(&chip->dev); + cdev_device_del(&chip->cdev, &chip->dev); } EXPORT_SYMBOL_GPL(pwmchip_remove); =20 @@ -2357,9 +2642,16 @@ static int __init pwm_init(void) { int ret; =20 + ret =3D alloc_chrdev_region(&pwm_devt, 0, PWM_MINOR_COUNT, "pwm"); + if (ret) { + pr_err("Failed to initialize chrdev region for PWM usage\n"); + return ret; + } + ret =3D class_register(&pwm_class); if (ret) { pr_err("Failed to initialize PWM class (%pe)\n", ERR_PTR(ret)); + unregister_chrdev_region(pwm_devt, 256); return ret; } =20 diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 63a17d2b4ec8..2492c91452f9 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -2,6 +2,7 @@ #ifndef __LINUX_PWM_H #define __LINUX_PWM_H =20 +#include #include #include #include @@ -311,6 +312,7 @@ struct pwm_ops { /** * struct pwm_chip - abstract a PWM controller * @dev: device providing the PWMs + * @cdev: &struct cdev for this device * @ops: callbacks for this PWM controller * @owner: module providing this chip * @id: unique number of this PWM chip @@ -325,6 +327,7 @@ struct pwm_ops { */ struct pwm_chip { struct device dev; + struct cdev cdev; const struct pwm_ops *ops; struct module *owner; unsigned int id; diff --git a/include/uapi/linux/pwm.h b/include/uapi/linux/pwm.h new file mode 100644 index 000000000000..182d59cc07ee --- /dev/null +++ b/include/uapi/linux/pwm.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + +#ifndef _UAPI_PWM_H_ +#define _UAPI_PWM_H_ + +#include +#include + +/** + * struct pwmchip_waveform - Describe a PWM waveform for a pwm_chip's PWM = channel + * @hwpwm: per-chip relative index of the PWM device + * @__pad: padding, must be zero + * @period_length_ns: duration of the repeating period. + * A value of 0 represents a disabled PWM. + * @duty_length_ns: duration of the active part in each period + * @duty_offset_ns: offset of the rising edge from a period's start + */ +struct pwmchip_waveform { + __u32 hwpwm; + __u32 __pad; + __u64 period_length_ns; + __u64 duty_length_ns; + __u64 duty_offset_ns; +}; + +/* Reserves the passed hwpwm for exclusive control. */ +#define PWM_IOCTL_REQUEST _IO(0x75, 1) + +/* counter part to PWM_IOCTL_REQUEST */ +#define PWM_IOCTL_FREE _IO(0x75, 2) + +/* + * Modifies the passed wf according to hardware constraints. All parameter= s are + * rounded down to the next possible value, unless there is no such value,= then + * values are rounded up. Note that zero isn't considered for rounding down + * period_length_ns. + */ +#define PWM_IOCTL_ROUNDWF _IOWR(0x75, 3, struct pwmchip_waveform) + +/* Get the currently implemented waveform */ +#define PWM_IOCTL_GETWF _IOWR(0x75, 4, struct pwmchip_waveform) + +/* Like PWM_IOCTL_ROUNDWF + PWM_IOCTL_SETEXACTWF in one go. */ +#define PWM_IOCTL_SETROUNDEDWF _IOW(0x75, 5, struct pwmchip_waveform) + +/* + * Program the PWM to emit exactly the passed waveform, subject only to ro= unding + * down each value less than 1 ns. Returns 0 on success, -EDOM if the wave= form + * cannot be implemented exactly, or other negative error codes. + */ +#define PWM_IOCTL_SETEXACTWF _IOW(0x75, 6, struct pwmchip_waveform) + +#endif /* _UAPI_PWM_H_ */ --=20 2.47.2