From patchwork Sat Jan 30 04:26:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David Rivshin (Allworx)" X-Patchwork-Id: 8169481 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 30828BEEE5 for ; Sat, 30 Jan 2016 04:30:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 19C8420398 for ; Sat, 30 Jan 2016 04:30:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2FCC320396 for ; Sat, 30 Jan 2016 04:30:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754204AbcA3Eaf (ORCPT ); Fri, 29 Jan 2016 23:30:35 -0500 Received: from mail-qk0-f195.google.com ([209.85.220.195]:35208 "EHLO mail-qk0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753905AbcA3Eae (ORCPT ); Fri, 29 Jan 2016 23:30:34 -0500 Received: by mail-qk0-f195.google.com with SMTP id s5so2647813qkd.2; Fri, 29 Jan 2016 20:30:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5pFa6dqew6cGuQNTo/VK0SoZ/RtIkD7frAHwtaMVYlQ=; b=0FSz2hdc3vb301H5gViA7wpNXbznQHb0qWsmuBMoxsowKToL6fEukUymse6hidpi93 xsIFyrJYuS+mfbzVfja0Uvvq3Vi9ghJdJuH8m+DpuODW6RVEk74ZRLLrbqEFUkhRNqIs WULXfFixHksc0zCnE76mipB6aT9WLJk50WPO/1/qbHzpDwkXE2sIptGX/QBOXGJlV/7B 4tF+CXMKe9ybGzD34B3/ZlYtC906tG6h2Hb/D7bpCbwR7yCMknBHSQGG+feMuJDHGCHX ZJux0OX8LCYuyUkCdcJ9dgdJPadF4UJwbjeAr1h+4Rf/UhFxIYvrNBc+CTKhCXUw2qSW LDPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5pFa6dqew6cGuQNTo/VK0SoZ/RtIkD7frAHwtaMVYlQ=; b=fZThqdb9yCPfIG+HRM3+8mvMDD0aOcSzsH89+gpt6cFVEu+N9+2HsSW3gwYrBmB4Iv AXGtYGvmkM0AZLiVOBKoTzKy0vHiGKK8lqx5GXpecM5M5is/GWhpelfD1kFP40UHOK7u GQ9YkqwBh8zofnRZCXaxl2H9fHbsnu2x/+rE2oLsW4hNxbbX8HDGrWRPsG/qFcWHNrtn HvAC7POln9craIRAqpdeMIIW0j1gKQiise+n1zckXAH3FgCbRYA4xvgfXhw+ooCxr/Pv Fc8E2X5fHY8ZXjS1FYnGZc1Zb6FjFQLK9KwDjo5xYBO3IEOtLcYefcjDRQvh7dcLkkvC 4Vgg== X-Gm-Message-State: AG10YORBFQCTlso9j/NjsPP8AAu+AJkvIPNjQdKxFV/3YPQTR23NiGtgGkTtwQrDUa7kYA== X-Received: by 10.55.77.206 with SMTP id a197mr14983120qkb.43.1454128233514; Fri, 29 Jan 2016 20:30:33 -0800 (PST) Received: from drivshin-linux.crosskeys.inscitek.com ([24.213.148.66]) by smtp.gmail.com with ESMTPSA id y104sm8404563qgd.33.2016.01.29.20.30.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 29 Jan 2016 20:30:33 -0800 (PST) From: "David Rivshin (Allworx)" To: linux-pwm@vger.kernel.org, Thierry Reding , Neil Armstrong Cc: linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Tony Lindgren , Grant Erickson , NeilBrown , Joachim Eastwood Subject: [PATCH 1/4] pwm: omap-dmtimer: fix inaccurate period/duty_cycle calculation Date: Fri, 29 Jan 2016 23:26:51 -0500 Message-Id: <1454128014-22866-2-git-send-email-drivshin.allworx@gmail.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1454128014-22866-1-git-send-email-drivshin.allworx@gmail.com> References: <1454128014-22866-1-git-send-email-drivshin.allworx@gmail.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: David Rivshin Fix the calculation of load_value and match_value. Currently they are slightly too low, which produces a noticeably wrong PWM rate with sufficiently short periods (i.e. when 1/period approaches clk_rate/2). Example: clk_rate=32768Hz, period=122070ns, duty_cycle=61035ns (8192Hz/50% PWM) Correct values: load = 0xfffffffc, match = 0xfffffffd Current values: load = 0xfffffffa, match = 0xfffffffc effective PWM: period=183105ns, duty_cycle=91553ns (5461Hz/50% PWM) Fixes: 6604c6556db9 ("pwm: Add PWM driver for OMAP using dual-mode timers") Signed-off-by: David Rivshin Acked-by: Neil Armstrong Tested-by: Adam Ford --- drivers/pwm/pwm-omap-dmtimer.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 826634e..0083e75 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -31,6 +31,7 @@ #include #define DM_TIMER_LOAD_MIN 0xfffffffe +#define DM_TIMER_MAX 0xffffffff struct pwm_omap_dmtimer_chip { struct pwm_chip chip; @@ -46,13 +47,13 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip) return container_of(chip, struct pwm_omap_dmtimer_chip, chip); } -static int pwm_omap_dmtimer_calc_value(unsigned long clk_rate, int ns) +static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns) { u64 c = (u64)clk_rate * ns; do_div(c, NSEC_PER_SEC); - return DM_TIMER_LOAD_MIN - c; + return c; } static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) @@ -99,7 +100,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, int duty_ns, int period_ns) { struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); - int load_value, match_value; + u32 period_cycles, duty_cycles; + u32 load_value, match_value; struct clk *fclk; unsigned long clk_rate; bool timer_active; @@ -133,11 +135,22 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, /* * Calculate the appropriate load and match values based on the * specified period and duty cycle. The load value determines the - * cycle time and the match value determines the duty cycle. + * period time and the match value determines the duty time. + * + * The period lasts for (DM_TIMER_MAX-load_value+1) clock cycles. + * Similarly, the active time lasts (match_value-load_value+1) cycles. + * The non-active time is the remainder: (DM_TIMER_MAX-match_value) + * clock cycles. + * + * References: + * OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11 + * AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6 */ - load_value = pwm_omap_dmtimer_calc_value(clk_rate, period_ns); - match_value = pwm_omap_dmtimer_calc_value(clk_rate, - period_ns - duty_ns); + period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns); + duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns); + + load_value = (DM_TIMER_MAX - period_cycles) + 1; + match_value = load_value + duty_cycles - 1; /* * We MUST stop the associated dual-mode timer before attempting to