From nobody Mon Feb 9 03:12:46 2026 Received: from mail-yw1-f179.google.com (mail-yw1-f179.google.com [209.85.128.179]) (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 214D617F8 for ; Fri, 5 Apr 2024 00:30:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277034; cv=none; b=H4/hWMviqTf1D3lRpX+H5dErUgm49sMqLSzoABnaqplKCVOU2fHpzZ+rg0XciObVLDZIuWm8ssoMpInr5Bhncd4bcntfBwMUf7Irw5ilEpSJ1nW6c0orUq7zw8cWbjgjNkpsB4rTwlUkXMaVDNYs05dWjqhwF4V2ArEIxh+EkhY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277034; c=relaxed/simple; bh=4AgyvYLStYaefPpieUHnAMDvsbOsjZpYhGh6QgQbxo0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SRrKibR7D0uiPR3S40YlfWPIcDe0COpQLyjOKtf/laM46PTr3dKywP6d2tU8kYPmmZO9EDN+cd02yi8bC14LLdXoA1cI2uVr68QHZlAkWTpGxNet8DRRglcZGqJqNC/ADygPZlQQwQcMry+c0mM49pZbuCQBsy9D/0xj6GlnMfM= 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=Mw4enQKX; arc=none smtp.client-ip=209.85.128.179 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="Mw4enQKX" Received: by mail-yw1-f179.google.com with SMTP id 00721157ae682-615038fc5baso17429787b3.3 for ; Thu, 04 Apr 2024 17:30:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1712277029; x=1712881829; 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=ShutlIE8DACdzeSSC3XVEeXZaPNv1RHdPHW39J6XIEY=; b=Mw4enQKXzGDUW91byFQ//+UjBHOOnZa9PoPXty9Q6mFnnxn8icMNytl89Yn2gANoAb EVOCrAmmA3q9TolkXoao0QlFYBwRAC4xxkPE4xuJ1j+2d8/ty4+PqRHbspTxEj/jZeqD iDdle8CEl/EHZqI+cycUkxD92/gjFIlomHq9iPyonTWc7B+sXel3esOftgja+yCXn17q 0fhCm3Ba5JHr8qEf9c+MFuadG6GhgtuPeUwix44zYhAY2X0Xd0JSdvIG2RZeWsBlPg11 bY+obqdAfqrmWi77O0QqlkLlVi7fSKQg/D+DhJN3RiimRgVjWni1NuX4YpctP7Zh5A3a /rkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712277029; x=1712881829; 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=ShutlIE8DACdzeSSC3XVEeXZaPNv1RHdPHW39J6XIEY=; b=jZaFAA5KpWNaK0L1KxVhqWjsLEIWwynXeyuCV4D/3GOhF/6fMPhdabmPOsrUZidEAZ r5nRa/7UUNths9OlgRhcV6Hf/bFcJ7xdAHhFIDepXseg2RKrC8Jkc7tt7hEHXCcBEIy7 4RU2zAoo1AKnC2j/DnU2i05H6Fq7OfaAyV+cMCayLmYzUiDUfdGiJ6+zW4xHTqdD2ec3 YSyxWJ54BbK/18944JbqM5kyUp6/Mdjm8i700dTFrgPJZoOVk1JZYGQPa94rrfyLc2gr Ds/lCQbGJLgCuc6X1zq6zgiKO1qFdAHYXhYau1OZ9VjN5ouQm/apReKCYj+jXaTImBza Xziw== X-Gm-Message-State: AOJu0YyDypSXJisDfcVZB8e3+gtkU2oZXF8QtQufE1/UGSJvs7x8ZXX8 LXw5JLvsbqZOjCy3dz+byJPXIYpxzb2PqLHnFaXaBRROG1/h9/BOIeFUh7susLxnW9hhpttg5VM 5Vhg= X-Google-Smtp-Source: AGHT+IG4nNl8NLkWyptttyOjJv5e8/6gL5vdyaS5k8cT6wp2uWJiNGzpKwk4N7atiVBD6rvmfaDxQQ== X-Received: by 2002:a25:8745:0:b0:dcc:cadf:3376 with SMTP id e5-20020a258745000000b00dcccadf3376mr1118624ybn.18.1712277029082; Thu, 04 Apr 2024 17:30:29 -0700 (PDT) Received: from megalith.oryx-coho.ts.net (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id o4-20020ac86d04000000b00432feda5986sm232728qtt.35.2024.04.04.17.30.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Apr 2024 17:30:28 -0700 (PDT) From: Trevor Gamblin To: linux-pwm@vger.kernel.org Cc: linux-kernel@vger.kernel.org, u.kleine-koenig@pengutronix.de, michael.hennerich@analog.com, nuno.sa@analog.com, tgamblin@baylibre.com, dlechner@baylibre.com Subject: [RFC PATCH 1/3] pwm: add duty offset support Date: Thu, 4 Apr 2024 20:30:23 -0400 Message-ID: <20240405003025.739603-2-tgamblin@baylibre.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240405003025.739603-1-tgamblin@baylibre.com> References: <20240405003025.739603-1-tgamblin@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some PWM chips support a "phase" or "duty_offset" feature. This patch continues adding support for configuring this property in the PWM subsystem. The pwm_chip struct gains a new supports_offset flag, which can be set for compatible parts. This is checked in __pwm_apply, where attempts to set duty_offset result in an EOPNOTSUPP if the flag is not set. Functions duty_offset_show(), duty_offset_store(), and pwm_get_duty_offset() are added to match what exists for duty_cycle. Handle duty_offset in the new pwmchip char device logic. Also add duty_offset to TP_printk in include/trace/events/pwm.h so that it is reported with other properties when using the event tracing pipe for debug. Signed-off-by: Trevor Gamblin --- drivers/pwm/core.c | 75 +++++++++++++++++++++++++++++++++++--- include/linux/pwm.h | 17 +++++++++ include/trace/events/pwm.h | 6 ++- 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 2745941a008b..0e05518feb21 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -80,6 +80,7 @@ static void pwm_apply_debug(struct pwm_device *pwm, */ if (s1.enabled && s1.polarity !=3D state->polarity) { s2.polarity =3D state->polarity; + s2.duty_offset =3D s1.duty_cycle; s2.duty_cycle =3D s1.period - s1.duty_cycle; s2.period =3D s1.period; s2.enabled =3D s1.enabled; @@ -121,6 +122,23 @@ static void pwm_apply_debug(struct pwm_device *pwm, state->duty_cycle, state->period, s2.duty_cycle, s2.period); =20 + if (state->enabled && + last->polarity =3D=3D state->polarity && + last->period =3D=3D s2.period && + last->duty_offset > s2.duty_offset && + last->duty_offset <=3D state->duty_offset) + dev_warn(pwmchip_parent(chip), + ".apply didn't pick the best available duty offset (requested: %llu/%l= lu, applied: %llu/%llu, possible: %llu/%llu)\n", + state->duty_offset, state->period, + s2.duty_offset, s2.period, + last->duty_offset, last->period); + + if (state->enabled && state->duty_offset < s2.duty_offset) + dev_warn(pwmchip_parent(chip), + ".apply is supposed to round down duty_offset (requested: %llu/%llu, a= pplied: %llu/%llu)\n", + state->duty_offset, state->period, + s2.duty_offset, s2.period); + if (!state->enabled && s2.enabled && s2.duty_cycle > 0) dev_warn(pwmchip_parent(chip), "requested disabled, but yielded enabled with duty > 0\n"); @@ -144,12 +162,13 @@ static void pwm_apply_debug(struct pwm_device *pwm, if (s1.enabled !=3D last->enabled || s1.polarity !=3D last->polarity || (s1.enabled && s1.period !=3D last->period) || + (s1.enabled && s1.duty_offset !=3D last->duty_offset) || (s1.enabled && s1.duty_cycle !=3D last->duty_cycle)) { dev_err(pwmchip_parent(chip), - ".apply is not idempotent (ena=3D%d pol=3D%d %llu/%llu) -> (ena=3D%d po= l=3D%d %llu/%llu)\n", + ".apply is not idempotent (ena=3D%d pol=3D%d %llu/%llu/%llu) -> (ena=3D= %d pol=3D%d %llu/%llu/%llu)\n", s1.enabled, s1.polarity, s1.duty_cycle, s1.period, - last->enabled, last->polarity, last->duty_cycle, - last->period); + s1.duty_offset, last->enabled, last->polarity, + last->duty_cycle, last->period, last->duty_offset); } } =20 @@ -164,13 +183,17 @@ static int __pwm_apply(struct pwm_device *pwm, const = struct pwm_state *state) int err; =20 if (!pwm || !state || !state->period || - state->duty_cycle > state->period) + state->duty_offset + state->duty_cycle > state->period) return -EINVAL; =20 chip =3D pwm->chip; =20 + if (!chip->supports_offset && state->duty_offset) + return -EOPNOTSUPP; + if (state->period =3D=3D pwm->state.period && state->duty_cycle =3D=3D pwm->state.duty_cycle && + state->duty_offset =3D=3D pwm->state.duty_offset && state->polarity =3D=3D pwm->state.polarity && state->enabled =3D=3D pwm->state.enabled && state->usage_power =3D=3D pwm->state.usage_power) @@ -292,10 +315,11 @@ int pwm_adjust_config(struct pwm_device *pwm) * been configured. * * In either case, we setup the new period and polarity, and assign a - * duty cycle of 0. + * duty cycle and offset of 0. */ if (!state.period) { state.duty_cycle =3D 0; + state.duty_offset =3D 0; state.period =3D pargs.period; state.polarity =3D pargs.polarity; =20 @@ -617,6 +641,41 @@ static ssize_t duty_cycle_store(struct device *pwm_dev, return ret ? : size; } =20 +static ssize_t duty_offset_show(struct device *pwm_dev, + struct device_attribute *attr, + char *buf) +{ + const struct pwm_device *pwm =3D pwm_from_dev(pwm_dev); + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return sysfs_emit(buf, "%llu\n", state.duty_offset); +} + +static ssize_t duty_offset_store(struct device *pwm_dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pwm_export *export =3D pwmexport_from_dev(pwm_dev); + struct pwm_device *pwm =3D export->pwm; + struct pwm_state state; + u64 val; + int ret; + + ret =3D kstrtou64(buf, 0, &val); + if (ret) + return ret; + + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.duty_offset =3D val; + ret =3D pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +} + static ssize_t enable_show(struct device *pwm_dev, struct device_attribute *attr, char *buf) @@ -731,6 +790,7 @@ static ssize_t capture_show(struct device *pwm_dev, =20 static DEVICE_ATTR_RW(period); static DEVICE_ATTR_RW(duty_cycle); +static DEVICE_ATTR_RW(duty_offset); static DEVICE_ATTR_RW(enable); static DEVICE_ATTR_RW(polarity); static DEVICE_ATTR_RO(capture); @@ -738,6 +798,7 @@ static DEVICE_ATTR_RO(capture); static struct attribute *pwm_attrs[] =3D { &dev_attr_period.attr, &dev_attr_duty_cycle.attr, + &dev_attr_duty_offset.attr, &dev_attr_enable.attr, &dev_attr_polarity.attr, &dev_attr_capture.attr, @@ -1290,7 +1351,7 @@ static long pwm_cdev_ioctl(struct file *file, unsigne= d int cmd, unsigned long ar if (state.enabled) { cstate.period =3D state.period; if (state.polarity =3D=3D PWM_POLARITY_NORMAL) { - cstate.duty_offset =3D 0; + cstate.duty_offset =3D state.duty_offset; cstate.duty_cycle =3D state.duty_cycle; } else { cstate.duty_offset =3D state.duty_cycle; @@ -1356,6 +1417,7 @@ static long pwm_cdev_ioctl(struct file *file, unsigne= d int cmd, unsigned long ar state.period =3D cstate.period; state.polarity =3D PWM_POLARITY_NORMAL; state.duty_cycle =3D cstate.duty_cycle; + state.duty_offset =3D cstate.duty_offset; } else { state.enabled =3D false; } @@ -1991,6 +2053,7 @@ static void pwm_dbg_show(struct pwm_chip *chip, struc= t seq_file *s) =20 seq_printf(s, " period: %llu ns", state.period); seq_printf(s, " duty: %llu ns", state.duty_cycle); + seq_printf(s, " duty_offset: %llu ns", state.duty_offset); seq_printf(s, " polarity: %s", state.polarity ? "inverse" : "normal"); =20 diff --git a/include/linux/pwm.h b/include/linux/pwm.h index a58db7011807..e0e5960f91ba 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -51,6 +51,7 @@ enum { * struct pwm_state - state of a PWM channel * @period: PWM period (in nanoseconds) * @duty_cycle: PWM duty cycle (in nanoseconds) + * @duty_offset: PWM duty offset (in nanoseconds) * @polarity: PWM polarity * @enabled: PWM enabled status * @usage_power: If set, the PWM driver is only required to maintain the p= ower @@ -61,6 +62,7 @@ enum { struct pwm_state { u64 period; u64 duty_cycle; + u64 duty_offset; enum pwm_polarity polarity; bool enabled; bool usage_power; @@ -130,6 +132,15 @@ static inline u64 pwm_get_duty_cycle(const struct pwm_= device *pwm) return state.duty_cycle; } =20 +static inline u64 pwm_get_duty_offset(const struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return state.duty_offset; +} + static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *= pwm) { struct pwm_state state; @@ -161,6 +172,9 @@ static inline void pwm_get_args(const struct pwm_device= *pwm, * ->duty_cycle value exceed the pwm_args->period one, which would trigger * an error if the user calls pwm_apply_might_sleep() without adjusting ->= duty_cycle * first. + * + * ->duty_offset is likewise set to zero to avoid inconsistent default + * states. */ static inline void pwm_init_state(const struct pwm_device *pwm, struct pwm_state *state) @@ -176,6 +190,7 @@ static inline void pwm_init_state(const struct pwm_devi= ce *pwm, state->period =3D args.period; state->polarity =3D args.polarity; state->duty_cycle =3D 0; + state->duty_offset =3D 0; state->usage_power =3D false; } =20 @@ -275,6 +290,7 @@ struct pwm_ops { * @npwm: number of PWMs controlled by this chip * @of_xlate: request a PWM device given a device tree PWM specifier * @atomic: can the driver's ->apply() be called in atomic context + * @supports_offset: does the driver support duty cycle offset * @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this= chip * @operational: signals if the chip can be used (or is already deregister= ed) * @nonatomic_lock: mutex for nonatomic chips @@ -292,6 +308,7 @@ struct pwm_chip { struct pwm_device * (*of_xlate)(struct pwm_chip *chip, const struct of_phandle_args *args); bool atomic; + bool supports_offset; =20 /* only used internally by the PWM framework */ bool uses_pwmchip_alloc; diff --git a/include/trace/events/pwm.h b/include/trace/events/pwm.h index 12b35e4ff917..2d25ac5de816 100644 --- a/include/trace/events/pwm.h +++ b/include/trace/events/pwm.h @@ -18,6 +18,7 @@ DECLARE_EVENT_CLASS(pwm, __field(struct pwm_device *, pwm) __field(u64, period) __field(u64, duty_cycle) + __field(u64, duty_offset) __field(enum pwm_polarity, polarity) __field(bool, enabled) __field(int, err) @@ -27,13 +28,14 @@ DECLARE_EVENT_CLASS(pwm, __entry->pwm =3D pwm; __entry->period =3D state->period; __entry->duty_cycle =3D state->duty_cycle; + __entry->duty_offset =3D state->duty_offset; __entry->polarity =3D state->polarity; __entry->enabled =3D state->enabled; __entry->err =3D err; ), =20 - TP_printk("%p: period=3D%llu duty_cycle=3D%llu polarity=3D%d enabled=3D%d= err=3D%d", - __entry->pwm, __entry->period, __entry->duty_cycle, + TP_printk("%p: period=3D%llu duty_cycle=3D%llu duty_offset=3D%llu polarit= y=3D%d enabled=3D%d err=3D%d", + __entry->pwm, __entry->period, __entry->duty_cycle, __entry->duty_offs= et, __entry->polarity, __entry->enabled, __entry->err) =20 ); --=20 2.44.0 From nobody Mon Feb 9 03:12:46 2026 Received: from mail-ot1-f51.google.com (mail-ot1-f51.google.com [209.85.210.51]) (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 77AD8160 for ; Fri, 5 Apr 2024 00:30:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277033; cv=none; b=RDpyDhTBlq4a7RneEdumMkxIO6TI7i7aD/rK98X5DucrApZs5j3JYfP4DFkS9RO4kzwT7FKXmEHRUcqSAepzJbgga8HaGfOmO3t4zuYlnhmXqpyErTOnfNyaQkyjfPCzzyGx8DFYT/QVxNChnl2+5ARYEMzdjRzfDe+h8q8Rq/k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277033; c=relaxed/simple; bh=xo/5zy7BKD5MQNwqWrK5Y7aZc4xuWO41L1gezsqpgM0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z5t9rDIb/Ng8QwyeWIhkfwG9CvJMzh8ekT6ef9497kYQGbHHam9DRtC9mlMoueHwLxwczXBJDivl+15SlXVcJa7I5x1SbLht27GHO3J6fWDIPrLaPTLWY2qeKKPznZez7P/qVIeWe9UvZCmq79uRKB4d1HArImlQdsD32/H9Wck= 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=Fa2NAhNg; arc=none smtp.client-ip=209.85.210.51 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="Fa2NAhNg" Received: by mail-ot1-f51.google.com with SMTP id 46e09a7af769-6e0f43074edso1018571a34.1 for ; Thu, 04 Apr 2024 17:30:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1712277030; x=1712881830; 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=mflIGl0JabM93wYA4asHh3PZJ7LJW93To1t++JIDmfs=; b=Fa2NAhNg6kkwFytftj+oDsjgnaUUd4/KoFeFjaBOunkuROV4mwqUgrHD3XNk7cUAHd BZgbN8ii6I/k5M3YWqybW1oX77rErtpeW1VsbleWWN063hiNPrgpgfosDn6kGqDriIbP IODvwdG6GxsTZ5sL47UVuljKcaz2tzBip3ALnBq1u2NC4SqdxK6FgVgXWWIsg6n08c7X gMU9HWa5f41fBFcBs3OHjHb5ogCXnri1CONgSLzvxDyW0XJnmAOmycRjrjGewBk0qu73 N5AtaU57m9freAkvmr7eOBKnacx+n3NAIxOdiO863GzzGIqwRc3ALPeEp29zvluiF/PG e1WQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712277030; x=1712881830; 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=mflIGl0JabM93wYA4asHh3PZJ7LJW93To1t++JIDmfs=; b=QoAU/WTx9RWpEdbbRC2W30hjCaKghFhA4jvqCTM9EONtjDWjvViR9IBLZ4QcDYVM88 6Uh3oovlOTqhqe4Vikb2DCTwa/XTRecEItTNGzTqKZuiQRAAsdbZGyvHjh86y4dy/uHn I+9e5sPe2lNF5nzkgkttvdYQusJU9ERnI32Hw41VSnc5BT47yYr3ikFFwj75JwNedbw3 6RA3iFAStZZjopnsM0nEQOiPsf+0v7ACCv5Ab0xWSYRsWznpbo1D9zfmsasO0ZapuYIl MO+VYSMVrh+eB8tM6dHouQZNpe37zGuD2lpIw+B/1WkT2ufZA6ehyM1zVdshA2EbeFM3 /k2Q== X-Gm-Message-State: AOJu0Yxv5vwqWziOt/5Hkzzj770uIovCTm+HoCstUWLKi8RBSzklMCL1 ESCuIkbUIdszj/qtRJ0JHCL2x1bFsQSYXc7R/DKiBzRZ5XbMerDW2eJIELy6+I0= X-Google-Smtp-Source: AGHT+IGeFIba7Fjoy+Lh5imxQMFJ60kylklXD567TEN4HDRnVJ4VBUmRGP0suOKAmd/UdpjTU1+F8w== X-Received: by 2002:a9d:7a57:0:b0:6e9:df99:77c6 with SMTP id z23-20020a9d7a57000000b006e9df9977c6mr29202otm.27.1712277030414; Thu, 04 Apr 2024 17:30:30 -0700 (PDT) Received: from megalith.oryx-coho.ts.net (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id o4-20020ac86d04000000b00432feda5986sm232728qtt.35.2024.04.04.17.30.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Apr 2024 17:30:29 -0700 (PDT) From: Trevor Gamblin To: linux-pwm@vger.kernel.org Cc: linux-kernel@vger.kernel.org, u.kleine-koenig@pengutronix.de, michael.hennerich@analog.com, nuno.sa@analog.com, tgamblin@baylibre.com, dlechner@baylibre.com Subject: [RFC PATCH 2/3] pwm: axi-pwmgen: add duty offset support Date: Thu, 4 Apr 2024 20:30:24 -0400 Message-ID: <20240405003025.739603-3-tgamblin@baylibre.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240405003025.739603-1-tgamblin@baylibre.com> References: <20240405003025.739603-1-tgamblin@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable duty_offset feature now that it is supported in the pwm subsystem. Related macros and struct fields related to duty_offset are renamed to be consistent. Signed-off-by: Trevor Gamblin --- drivers/pwm/pwm-axi-pwmgen.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 539625c404ac..84ecb12e1e21 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -6,9 +6,9 @@ * Copyright 2024 Baylibre SAS * * Limitations: - * - The writes to registers for period and duty are shadowed until - * LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG at the end of the - * current period. + * - The writes to registers for period, duty, and duty_offset are + * shadowed until LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG at + * the end of the current period. * - Writing LOAD_CONFIG also has the effect of re-synchronizing all * enabled channels, which could cause glitching on other channels. It * is therefore expected that channels are assigned harmonic periods @@ -34,7 +34,7 @@ #define AXI_PWMGEN_REG_NPWM 0x14 #define AXI_PWMGEN_CHX_PERIOD(v, ch) ((v)->period_base + (v)->ch_step * (c= h)) #define AXI_PWMGEN_CHX_DUTY(v, ch) ((v)->duty_base + (v)->ch_step * (ch)) -#define AXI_PWMGEN_CHX_OFFSET(v, ch) ((v)->offset_base + (v)->ch_step * (c= h)) +#define AXI_PWMGEN_CHX_DUTY_OFFSET(v, ch) ((v)->duty_offset_base + (v)->ch= _step * (ch)) #define AXI_PWMGEN_REG_CORE_MAGIC_VAL 0x601A3471 /* Identification number = to test during setup */ #define AXI_PWMGEN_LOAD_CONFIG BIT(1) #define AXI_PWMGEN_RESET BIT(0) @@ -42,7 +42,7 @@ struct axi_pwm_variant { u8 period_base; u8 duty_base; - u8 offset_base; + u8 duty_offset_base; u8 major_version; u8 ch_step; }; @@ -62,7 +62,7 @@ static const struct regmap_config axi_pwmgen_regmap_confi= g =3D { static const struct axi_pwm_variant pwmgen_1_00_variant =3D { .period_base =3D 0x40, .duty_base =3D 0x44, - .offset_base =3D 0x48, + .duty_offset_base =3D 0x48, .major_version =3D 1, .ch_step =3D 12, }; @@ -70,7 +70,7 @@ static const struct axi_pwm_variant pwmgen_1_00_variant = =3D { static const struct axi_pwm_variant pwmgen_2_00_variant =3D { .period_base =3D 0x40, .duty_base =3D 0x80, - .offset_base =3D 0xC0, + .duty_offset_base =3D 0xC0, .major_version =3D 2, .ch_step =3D 4, }; @@ -83,7 +83,7 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct= pwm_device *pwm, unsigned int ch =3D pwm->hwpwm; struct regmap *regmap =3D ddata->regmap; const struct axi_pwm_variant *variant =3D ddata->variant; - u64 period_cnt, duty_cnt; + u64 period_cnt, duty_cnt, duty_offset_cnt; int ret; =20 if (state->polarity !=3D PWM_POLARITY_NORMAL) @@ -108,6 +108,14 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, str= uct pwm_device *pwm, ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(variant, ch), duty_cnt); if (ret) return ret; + + duty_offset_cnt =3D mul_u64_u64_div_u64(state->duty_offset, ddata->clk_r= ate_hz, NSEC_PER_SEC); + if (duty_offset_cnt > UINT_MAX) + duty_offset_cnt =3D UINT_MAX; + + ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), du= ty_offset_cnt); + if (ret) + return ret; } else { ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(variant, ch), 0); if (ret) @@ -116,6 +124,10 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, str= uct pwm_device *pwm, ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(variant, ch), 0); if (ret) return ret; + + ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), 0); + if (ret) + return ret; } =20 return regmap_write(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONFIG= ); @@ -145,6 +157,12 @@ static int axi_pwmgen_get_state(struct pwm_chip *chip,= struct pwm_device *pwm, =20 state->duty_cycle =3D DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->cl= k_rate_hz); =20 + ret =3D regmap_read(regmap, AXI_PWMGEN_CHX_DUTY_OFFSET(variant, ch), &cnt= ); + if (ret) + return ret; + + state->duty_offset =3D DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->c= lk_rate_hz); + state->polarity =3D PWM_POLARITY_NORMAL; =20 return 0; @@ -254,6 +272,7 @@ static int axi_pwmgen_probe(struct platform_device *pde= v) =20 chip->ops =3D &axi_pwmgen_pwm_ops; chip->atomic =3D true; + chip->supports_offset =3D true; =20 return devm_pwmchip_add(dev, chip); } --=20 2.44.0 From nobody Mon Feb 9 03:12:46 2026 Received: from mail-yb1-f172.google.com (mail-yb1-f172.google.com [209.85.219.172]) (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 57E314C9B for ; Fri, 5 Apr 2024 00:30:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277034; cv=none; b=UywIfLptyJg65OjiREgVt/RODetYis7L9c8XIFBU6babYf87MsTXeDt6D+12H+Z449zHmAbZ/aqbckdY3uvLJdBd04qdGxWXglqRL0k+xk3t8Xz24i9lmC/HP+f7vo+UMrPRJ57+fk5SXFAblI6AiK39ll4JVSssJZghgQkHa+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712277034; c=relaxed/simple; bh=BTYBKY7/0T17C/Uz4+eZw1Bz3APXr+o6lqJ6srlxLh0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BA05HBlwkQDFjwJle4A31v0NYPq+xhJfiTcZJ38I/qRz2Fnc8XfctzuR/uyNN2kI9K3FkBOdScrixdEjgi8ZvPbiDThU5LCtw7QLrUlnSeR532xGStGHvqcDPXhxAX9+9Y82DC/7+sxjGI7RwWeMdwLKHlEOUxv+SW7VtdfuHXk= 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=RTXSzEYr; arc=none smtp.client-ip=209.85.219.172 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="RTXSzEYr" Received: by mail-yb1-f172.google.com with SMTP id 3f1490d57ef6-dcbf82cdf05so1589006276.2 for ; Thu, 04 Apr 2024 17:30:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1712277031; x=1712881831; 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=kx5GqimBqgoxRtDb4HVslENXxE3yEwOSa53ix8sBFFY=; b=RTXSzEYrTxabVpZfl6T62D8Q1k+niCTZ9Kb2rscLkDPejaZkdqqud10005edKx+0P8 qS1rrogzrNK1JMXzpw9TSU43PGUJvoWh07KIxd5+9pcLI1if8MiOBTV+Y02xAyuWotIm jIPoCfhxt9apM4MI9Xt2RaP4Ga8vj73lWo5v+jH46L03tZJKC7dIm0JdbOKO6MJCmZ5h 83NL3w75qvoJsKwT7A4nTz9ujCNWrrk+spF1J4HorodsKNBiHCiQtv0LeiWkS8ROEmcz Qhnw1xvIh7xeHunboqo1IHFBiiJbjx8xfV79bQqcNG/iBeXM1o5/tmenUwS7yIVwVQhp oH7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712277031; x=1712881831; 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=kx5GqimBqgoxRtDb4HVslENXxE3yEwOSa53ix8sBFFY=; b=crpzjJuQoRyNHkQ1ChXrTD6kA4X1QFsuYlCL83zy6b3bq1dcSjZRBBABmZENROTpZz lUVeLNrpFLCWxHV2MCwJRPx4NKPmD2xNIRANlvjognkAr5etVxCSvD/6pX9o0WQ46Jlk R90GE0F5BnTO5aSm4zjNZbZAMcR4lq6wpULMF2e9cJOatfOJOryDvjNzuO+KY33gAOjm ML0jeUd+qEZFcYRjM62Y9LvIZlSVpH4ni8NqJxzAz9tcieqFebVcbq8HzaW+jzsIMa1p IDONsxbOnsxvBhfuxzgwmY26DZXtwe/1XdAQXQA7iGqzMFfeooKLbmN1+4bi4wjTad5q e9rA== X-Gm-Message-State: AOJu0Yys5Y6Bo71j5DI05a1GXgk5iIjwwAuG+GiLT0upSPgtFOlj+qgp U/jNGyAYtbMi47671vtj+HzpPOLUBXnLuKWtwWrF0tlB0SG9s/2qBzSHjH8yjHE= X-Google-Smtp-Source: AGHT+IHs3gngUHw+CwSkJUZTlJ+6mEDrxlOE7X4g8tSplLT8zaqzOgjvQ/enLCKFueM09BlvER07kw== X-Received: by 2002:a25:69c2:0:b0:dd0:471:712 with SMTP id e185-20020a2569c2000000b00dd004710712mr4151943ybc.33.1712277031320; Thu, 04 Apr 2024 17:30:31 -0700 (PDT) Received: from megalith.oryx-coho.ts.net (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id o4-20020ac86d04000000b00432feda5986sm232728qtt.35.2024.04.04.17.30.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Apr 2024 17:30:31 -0700 (PDT) From: Trevor Gamblin To: linux-pwm@vger.kernel.org Cc: linux-kernel@vger.kernel.org, u.kleine-koenig@pengutronix.de, michael.hennerich@analog.com, nuno.sa@analog.com, tgamblin@baylibre.com, dlechner@baylibre.com Subject: [RFC PATCH 3/3] pwm: add pwm_config_full to pwm.h Date: Thu, 4 Apr 2024 20:30:25 -0400 Message-ID: <20240405003025.739603-4-tgamblin@baylibre.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240405003025.739603-1-tgamblin@baylibre.com> References: <20240405003025.739603-1-tgamblin@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a function that performs the old pwm_config operations while also handling duty_offset. Change pwm_config to use pwm_config_full with the duty_offset_ns argument set to 0. Signed-off-by: Trevor Gamblin --- include/linux/pwm.h | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index e0e5960f91ba..eb018f11a48f 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -347,33 +347,51 @@ int pwm_apply_atomic(struct pwm_device *pwm, const st= ruct pwm_state *state); int pwm_adjust_config(struct pwm_device *pwm); =20 /** - * pwm_config() - change a PWM device configuration + * pwm_config_full() - change a PWM device configuration, including duty + * offset * @pwm: PWM device * @duty_ns: "on" time (in nanoseconds) + * @duty_offset_ns: offset (in nanoseconds) of "on" pulse * @period_ns: duration (in nanoseconds) of one cycle * * Returns: 0 on success or a negative error code on failure. */ -static inline int pwm_config(struct pwm_device *pwm, int duty_ns, - int period_ns) +static inline int pwm_config_full(struct pwm_device *pwm, int duty_ns, + int duty_offset_ns, int period_ns) { struct pwm_state state; =20 if (!pwm) return -EINVAL; =20 - if (duty_ns < 0 || period_ns < 0) + if (duty_ns < 0 || period_ns < 0 || duty_offset_ns < 0) return -EINVAL; =20 pwm_get_state(pwm, &state); - if (state.duty_cycle =3D=3D duty_ns && state.period =3D=3D period_ns) + if (state.duty_cycle =3D=3D duty_ns && state.period =3D=3D period_ns && + state.duty_offset =3D=3D duty_offset_ns) return 0; =20 state.duty_cycle =3D duty_ns; + state.duty_offset =3D duty_offset_ns; state.period =3D period_ns; return pwm_apply_might_sleep(pwm, &state); } =20 +/** + * pwm_config() - change a PWM device configuration + * @pwm: PWM device + * @duty_ns: "on" time (in nanoseconds) + * @period_ns: duration (in nanoseconds) of one cycle + * + * Returns: 0 on success or a negative error code on failure. + */ +static inline int pwm_config(struct pwm_device *pwm, int duty_ns, + int period_ns) +{ + return pwm_config_full(pwm, duty_ns, 0, period_ns); +} + /** * pwm_enable() - start a PWM output toggling * @pwm: PWM device @@ -480,6 +498,13 @@ static inline int pwm_adjust_config(struct pwm_device = *pwm) return -EOPNOTSUPP; } =20 +static inline int pwm_config_full(struct pwm_device *pwm, int duty_ns, + int duty_offset_ns, int period_ns) +{ + might_sleep(); + return -EINVAL; +} + static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) { --=20 2.44.0