From nobody Sun Feb 8 14:21:58 2026 Received: from mail-qk1-f182.google.com (mail-qk1-f182.google.com [209.85.222.182]) (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 A80C5148FEC for ; Tue, 21 May 2024 19:49:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716320963; cv=none; b=KRtCCkvM5RCC6K9DpU6VbO54MhrJPesmjUagQM6acdFkuL+96otrRE8aBzQoo3T91EkFMj3oPhnErSyrAaR+m/wBfQiDtbG5YpVJIP6gVHEwTOUOYe0Nry5mEXSGUioFHueZoAWt1ce64CpBZ+naoes4+Z9BwYOqDkwqEI6AJ8Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716320963; c=relaxed/simple; bh=8jAltw4/ZXbcJw+njVcL04mrZ7tJRL5lxZIeKt8Sevg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tUeWGs7fDNFeeyypLRSvyDA5PpZc4jJi5X2YPBNB6qav8sAkFfQNcJI4urwFYZ6JDJD+1nbTsx8l4aqDrr9z19koEJ/p6zxVeSNrjTFaAB7DH49XUnKUOh7pIF0wSbMSdLaiQNfK9RHMmSt37RfpAP6kxYmlhVXpX8X8RxQ0m0k= 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=IsR7aULu; arc=none smtp.client-ip=209.85.222.182 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="IsR7aULu" Received: by mail-qk1-f182.google.com with SMTP id af79cd13be357-7930504b2e2so31325085a.3 for ; Tue, 21 May 2024 12:49:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1716320959; x=1716925759; 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=26sqe/9M6qKSDnSFeiksxdAuHDavgCthn7zRVCyiwkU=; b=IsR7aULuesr4PsQQ5hxMAfjTQ9k9wLedCRQFz4MeZ/G39a/s3Hd1CwnUUTX4peUlAr fk6BUmpoHcRTUicfNVPf6N4ed9DqaeNvdDOMfJPCT8CPOaXy7EOdrahH/RXphtWRyjIv ilR7ppRBGY67fSm3LCdLYJqH0TRVsJZZBfJrhaD3XiBHUKehAI8LhPTPZmTpYK4QKHCj f4oLzn0xtXH3XEnp25z1ckzc88KRIEbrW7hDpLbfn18n2aVRMAecyhwp4EAgZka1iuUh gsy5GCP1BE2UanplnZ4tdNQ7k3r3F0dF0uZB/y/CDOUOHbQ3qvDtgia9kGbIiWtzey0o TTeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716320959; x=1716925759; 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=26sqe/9M6qKSDnSFeiksxdAuHDavgCthn7zRVCyiwkU=; b=FWaKW4lqVNVsGTyDeYhf8MzMAGofzSM1evlzsKY//WWCYlIPs6+yu2imClijb0+L1d Gax6CYduqdNcAoRVtrNuCtxjB3Uziq3/nUvlZRVraJSmHtMUPi+QqamP3MxjsKGHY4pH qmvzYgLeI/MyWFozLnG4d/IQLiAjQr4Yvw8vQy4vAcQu0oZQV8APNrvXGAdWtzxPzDou 9MDfs7xgoGPQK8EYil0fDdtFQSIah7ijwCT3rQpVysQFDllZhWwzER3ziGars36ImZiE wjKSn3/wLx23hHYOoc+0cIEl0QrYUJbsGIKBXkYXdrpxUIqNORIU4UcR4JvuIR1vEZ17 oZHA== X-Gm-Message-State: AOJu0YzzegQlQ8jLKWAPI/ICMk/6a7OZEA2tIVcS4PkvZyENooU1CyPN UJmrFNB8DdSRSLgRJ4DoMvznVTsA6lu9qhZLib5ELncYPcLKeOtkzVFVybotM3k= X-Google-Smtp-Source: AGHT+IGQ4gcZx0Znofa05ILEolx2511anpSCZhpCdMX5etGrdkjYL+m4SxrtEc4Jz6F9ktiuBUoaYQ== X-Received: by 2002:a05:620a:22eb:b0:792:7d2f:156f with SMTP id af79cd13be357-792c75ff6b5mr3158444185a.77.1716320959543; Tue, 21 May 2024 12:49:19 -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 d75a77b69052e-43df54d85a0sm161723611cf.23.2024.05.21.12.49.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 May 2024 12:49:19 -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: [PATCH 1/2 v3] pwm: add duty offset support Date: Tue, 21 May 2024 15:49:15 -0400 Message-ID: <20240521194916.1897909-2-tgamblin@baylibre.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240521194916.1897909-1-tgamblin@baylibre.com> References: <20240521194916.1897909-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. Functions duty_offset_show(), duty_offset_store(), and pwm_get_duty_offset() are added to match what exists for duty_cycle. Add a check to disallow applying a state with both inversed polarity and a nonzero duty_offset. 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 --- v3 changes: * rebased on top of latest pwm/for-next * removed changes related to cdev to match current pwm tree * fixed minor whitespace issue caught by checkpatch v2 changes: * Address feedback for driver in v1: * Remove line setting supports_offset flag in pwm_chip, since that has been removed from the struct in core.c. --- drivers/pwm/core.c | 79 +++++++++++++++++++++++++++++++++++--- include/linux/pwm.h | 15 ++++++++ include/trace/events/pwm.h | 6 ++- 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 18574857641e..2ebfc7f3de8a 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -62,6 +62,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; @@ -103,6 +104,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"); @@ -126,12 +144,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 @@ -146,13 +165,24 @@ 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_cycle > state->period || + state->duty_offset > state->period) return -EINVAL; =20 chip =3D pwm->chip; =20 + /* + * There is no need to set duty_offset with inverse polarity, + * since signals with duty_offset values greater than 0.5 * + * period can equivalently be represented by an inverted signal + * without offset. + */ + if (state->polarity =3D=3D PWM_POLARITY_INVERSED && state->duty_offset) + return -EINVAL; + 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) @@ -246,10 +276,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 @@ -555,6 +586,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) @@ -669,6 +735,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); @@ -676,6 +743,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, @@ -1639,6 +1707,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 60b92c2c75ef..03e3fc00d236 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -50,6 +50,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 @@ -60,6 +61,7 @@ enum { struct pwm_state { u64 period; u64 duty_cycle; + u64 duty_offset; enum pwm_polarity polarity; bool enabled; bool usage_power; @@ -129,6 +131,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; @@ -160,6 +171,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) @@ -175,6 +189,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 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.45.1 From nobody Sun Feb 8 14:21:58 2026 Received: from mail-oa1-f48.google.com (mail-oa1-f48.google.com [209.85.160.48]) (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 03238149015 for ; Tue, 21 May 2024 19:49:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716320964; cv=none; b=Ux30amFz0oNCvRDIrYTw7bxYC2XPqlbWN/QcbQpcleHlsO0YDVDl5ST3FpFxTgZiC1zQNiY53vnUi6vL8XBo+KmJ76G5nJXb8fO6s+s42rYeaTd3x4M8Z5d/g21VRhAHuQUHimSCnMgosPNDHowHUYfES1WZDW/XoaD+CkknS+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716320964; c=relaxed/simple; bh=Tooj6Y95pxQ5NpSlmeomxmuNcm9R63NtHWlrO8VM0ZQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tFlY3xwQXSD+zxSSh12AIjH7aF1/XDuG23rAghqF1j9iFQDrzMdOZ+LFwQfPlUr23YyMk+1Pg4l4pYe/ocsIcIHq/MQStyxaNT8642DJBLSaAXQZ8l9by0svDjHa5o8yYBUND72/VlDCxk3Dap413AcGKqSLkUPs2NLTA5OXOEM= 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=sBmPlD3F; arc=none smtp.client-ip=209.85.160.48 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="sBmPlD3F" Received: by mail-oa1-f48.google.com with SMTP id 586e51a60fabf-23f0d7d2ce6so3031342fac.2 for ; Tue, 21 May 2024 12:49:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1716320961; x=1716925761; 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=nZqjqst6IA8s4Y0Tix3Y2ed1HRW8o5RgtxqsUgjpfM8=; b=sBmPlD3FiShGzMSRE1qIn4c9t6NoypMiypCaiqR/LsouXj3cQjHZINdoIk5XI5nX5C q4m51xRNFallri6Rpq5lTREUd7gdYfB9IsW+f+sF/puAI7AYWsePCnaog9akR5VIBcfi E0lHo0iCHjR8x210+ZmNs4MFAi5lAubWHFPfBqeLGwCqpZNmvWmCkK3J/WeEg3CIxVGk pBBn41wXJOsdFipOpLwAofMJzl3EQ2hyYYUFAgbTEABBKqo/JopyDB55/W1kvFJma4if yTL4iBz9+Lf449qBxvG9V2EmVkNgF8Li0b+d97cVsVnoOZ7B0lqv+bXQyWabEmBtejzY 5I3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716320961; x=1716925761; 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=nZqjqst6IA8s4Y0Tix3Y2ed1HRW8o5RgtxqsUgjpfM8=; b=kdPERgFdwFktQJqGsNShulmJnmjTapmOLJ16DPZbqKuyJrO9i2YSdCGuKLHPe+VXr4 RSg8w/XSdkOmVqPRZ40jsFimOKBq4e8bjJRcN5MCEFsPOrFsiEvAz5RVgmJkE/lUA9B0 aN45xRSCXqjPXB8mjIV3c1Op1SUC5QES8zwdgB7voFfehZaXD3PMZKqIKF0IdupsGvHG RC+WMCOplD+84SEP5ufW5r+GWlFUjAGiDSbiOHA9PpHcyB4gbMY01tK9dZm1vOGZyw/y Lo/SBXJLNICTtlNN8rfssh1M7D1G2WbotqOnKeen7qQ76029ntIEHGVmtnJ4L5Q5PlYR A4ZQ== X-Gm-Message-State: AOJu0YwBfhNlTxZgVi8/Iw6pkYRje2xeFmmfwcSTO+Ab0dKdgcauhFbb Zypfx7VnMNgxqzy0x7CiFcUkloFPFK5ZUJkiJaxPj7EK2eWUJ+hksF0VIldqsvo= X-Google-Smtp-Source: AGHT+IEXbAcssGSEqg2FFDiVusT4NNfPEryqOcuyeXi3Pw+DSNm9s1FRNgKW5xThmneBDiVA2Juu/A== X-Received: by 2002:a05:6871:712:b0:23d:c09b:e5eb with SMTP id 586e51a60fabf-24c68ddeb4emr106959fac.36.1716320960765; Tue, 21 May 2024 12:49:20 -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 d75a77b69052e-43df54d85a0sm161723611cf.23.2024.05.21.12.49.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 May 2024 12:49:20 -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: [PATCH 2/2 v3] pwm: axi-pwmgen: add duty offset support Date: Tue, 21 May 2024 15:49:16 -0400 Message-ID: <20240521194916.1897909-3-tgamblin@baylibre.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240521194916.1897909-1-tgamblin@baylibre.com> References: <20240521194916.1897909-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 --- v3 changes: * rebased on top of latest pwm/for-next v2 changes: * Address feedback for driver in v1: * Remove line setting supports_offset flag in pwm_chip, since that has been removed from the struct in core.c. --- drivers/pwm/pwm-axi-pwmgen.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index e0bf90cc2ba3..9ae06b105d07 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -56,7 +56,7 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struct= pwm_device *pwm, struct axi_pwmgen_ddata *ddata =3D pwmchip_get_drvdata(chip); unsigned int ch =3D pwm->hwpwm; struct regmap *regmap =3D ddata->regmap; - u64 period_cnt, duty_cnt; + u64 period_cnt, duty_cnt, duty_offset_cnt; int ret; =20 if (state->polarity !=3D PWM_POLARITY_NORMAL) @@ -81,6 +81,14 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struc= t pwm_device *pwm, ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(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_OFFSET(ch), duty_offset_cnt); + if (ret) + return ret; } else { ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), 0); if (ret) @@ -89,6 +97,10 @@ static int axi_pwmgen_apply(struct pwm_chip *chip, struc= t pwm_device *pwm, ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), 0); if (ret) return ret; + + ret =3D regmap_write(regmap, AXI_PWMGEN_CHX_OFFSET(ch), 0); + if (ret) + return ret; } =20 return regmap_write(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONFIG= ); @@ -117,6 +129,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_OFFSET(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; --=20 2.45.1