From patchwork Fri Jan 26 15:11:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 10186247 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7931E602C8 for ; Fri, 26 Jan 2018 15:13:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A08322376 for ; Fri, 26 Jan 2018 15:13:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5DDD729797; Fri, 26 Jan 2018 15:13:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BA2DF22376 for ; Fri, 26 Jan 2018 15:13:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=l6+wlKScuZ5dtjsBDpm2OZK5f9RNKKWY6707aCBHslU=; b=Q/f+UbAphpYocg 6jb7xlmGFzyTRjjq/LF4IpOPeQhm50paepYBxadJXPgMIWrcuub2DoufS1ZdLrvGaq6MeoIUMajHm Mwm5c8Qkwu3sYS3bxHinsOMhj4RGwiDS97KOW0CPR5dTgcwpB/zPZf3VzpXWumWrl8Xd60GdQBCvh Qb2hJdwjYJDi2jpm2Ft8ZTB5mcWp0dKQiDIKwLZl3/6MkPH9qsG7qaGP39KmNDYUQDT1rM5B6l6fr /h/HJLy1PZVqVJLcZd6nww8Po7TBetcmTakTtGpYkWOeXKZyrul/THNCfAW5HMP8E2PdIsUmd1Q0B DidBvvsmSx+e312/a1pw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1ef5gz-00050i-Cw; Fri, 26 Jan 2018 15:13:25 +0000 Received: from mx08-00178001.pphosted.com ([91.207.212.93] helo=mx07-00178001.pphosted.com) by bombadil.infradead.org with esmtps (Exim 4.89 #1 (Red Hat Linux)) id 1ef5gD-00048C-69 for linux-arm-kernel@lists.infradead.org; Fri, 26 Jan 2018 15:12:40 +0000 Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id w0QF4C3Q012849; Fri, 26 Jan 2018 16:11:59 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2fq4fm1g3c-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 26 Jan 2018 16:11:59 +0100 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A262D31; Fri, 26 Jan 2018 15:11:58 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag5node3.st.com [10.75.127.15]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 5C6B02CE6; Fri, 26 Jan 2018 15:11:58 +0000 (GMT) Received: from localhost (10.75.127.47) by SFHDAG5NODE3.st.com (10.75.127.15) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Fri, 26 Jan 2018 16:11:58 +0100 From: Fabrice Gasnier To: , , , , Subject: [PATCH v2 7/8] pwm: stm32: use input prescaler to improve period capture Date: Fri, 26 Jan 2018 16:11:38 +0100 Message-ID: <1516979499-3665-8-git-send-email-fabrice.gasnier@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1516979499-3665-1-git-send-email-fabrice.gasnier@st.com> References: <1516979499-3665-1-git-send-email-fabrice.gasnier@st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.47] X-ClientProxiedBy: SFHDAG3NODE3.st.com (10.75.127.9) To SFHDAG5NODE3.st.com (10.75.127.15) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-01-26_08:, , signatures=0 X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, benjamin.gaignard@st.com, linux-pwm@vger.kernel.org, linux@armlinux.org.uk, linux-kernel@vger.kernel.org, mcoquelin.stm32@gmail.com, fabrice.gasnier@st.com, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Using input prescaler, capture unit will trigger DMA once every configurable /2, /4 or /8 events (rising edge). This helps improve period (only) capture accuracy at high rates. Signed-off-by: Fabrice Gasnier --- Changes in v2: - Adopt DMA read from MFD core. --- drivers/pwm/pwm-stm32.c | 63 ++++++++++++++++++++++++++++++++++++++-- include/linux/mfd/stm32-timers.h | 1 + 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 5dfb296..67964f5 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -9,6 +9,7 @@ * pwm-atmel.c from Bo Shen */ +#include #include #include #include @@ -169,7 +170,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, struct stm32_pwm *priv = to_stm32_pwm_dev(chip); unsigned long long prd, div, dty; unsigned long rate; - unsigned int psc = 0, scale; + unsigned int psc = 0, icpsc, scale; u32 raw_prd, raw_dty; int ret = 0; @@ -223,6 +224,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, /* * Got a capture. Try to improve accuracy at high rates: * - decrease counter clock prescaler, scale up to max rate. + * - use input prescaler, capture once every /2 /4 or /8 edges. */ if (raw_prd) { u32 max_arr = priv->max_arr - 0x1000; /* arbitrary margin */ @@ -242,8 +244,65 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, goto stop; } + /* Compute intermediate period not to exceed timeout at low rates */ prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC; - result->period = DIV_ROUND_UP_ULL(prd, rate); + do_div(prd, rate); + + for (icpsc = 0; icpsc < MAX_TIM_ICPSC ; icpsc++) { + /* input prescaler: also keep arbitrary margin */ + if (raw_prd >= (priv->max_arr - 0x1000) >> (icpsc + 1)) + break; + if (prd >= (tmo_ms * NSEC_PER_MSEC) >> (icpsc + 2)) + break; + } + + if (!icpsc) + goto done; + + /* Last chance to improve period accuracy, using input prescaler */ + regmap_update_bits(priv->regmap, + pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, + TIM_CCMR_IC1PSC | TIM_CCMR_IC2PSC, + FIELD_PREP(TIM_CCMR_IC1PSC, icpsc) | + FIELD_PREP(TIM_CCMR_IC2PSC, icpsc)); + + ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty); + if (ret) + goto stop; + + if (raw_dty >= (raw_prd >> icpsc)) { + /* + * We may fall here using input prescaler, when input + * capture starts on high side (before falling edge). + * Example with icpsc to capture on each 4 events: + * + * start 1st capture 2nd capture + * v v v + * ___ _____ _____ _____ _____ ____ + * TI1..4 |__| |__| |__| |__| |__| + * v v . . . . . v v + * icpsc1/3: . 0 . 1 . 2 . 3 . 0 + * icpsc2/4: 0 1 2 3 0 + * v v v v + * CCR1/3 ......t0..............................t2 + * CCR2/4 ..t1..............................t1'... + * . . . + * Capture0: .<----------------------------->. + * Capture1: .<-------------------------->. . + * . . . + * Period: .<------> . . + * Low side: .<>. + * + * Result: + * - Period = Capture0 / icpsc + * - Duty = Period - Low side = Period - (Capture0 - Capture1) + */ + raw_dty = (raw_prd >> icpsc) - (raw_prd - raw_dty); + } + +done: + prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC; + result->period = DIV_ROUND_UP_ULL(prd, rate << icpsc); dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC; result->duty_cycle = DIV_ROUND_UP_ULL(dty, rate); stop: diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index 3abfa04..734cbca 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -82,6 +82,7 @@ #define TIM_DCR_DBL GENMASK(12, 8) /* DMA burst len */ #define MAX_TIM_PSC 0xFFFF +#define MAX_TIM_ICPSC 0x3 #define TIM_CR2_MMS_SHIFT 4 #define TIM_CR2_MMS2_SHIFT 20 #define TIM_SMCR_TS_SHIFT 4