From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B28BC4332B for ; Mon, 23 Mar 2020 14:24:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 429F3206F8 for ; Mon, 23 Mar 2020 14:24:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b="bpy/U09d" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726958AbgCWOYh (ORCPT ); Mon, 23 Mar 2020 10:24:37 -0400 Received: from outils.crapouillou.net ([89.234.176.41]:44088 "EHLO crapouillou.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725839AbgCWOYf (ORCPT ); Mon, 23 Mar 2020 10:24:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1584973467; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=95wMub9nY6u9MV52UWW3aECJJj2d6AIHToEhTTOULPw=; b=bpy/U09dxylSOyr8FiF84ixp3hKw1ToamcGYoF8O/7nYAiwEM9DLRAySB2yuduWS71FC8A x+Zsfz71M7N6OTcegZQQiIEtpYo0nOpcbtQOTcN6cHL6c1UhcPrLg4icBM2m8qKpgHbZIP UeTpLYG3pdJthoxexNxzScI4wxsZto4= From: Paul Cercueil To: Thierry Reding , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Cc: od@zcrc.me, linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Cercueil , Mathieu Malaterre , Artur Rojek Subject: [PATCH v4 2/4] pwm: jz4740: Improve algorithm of clock calculation Date: Mon, 23 Mar 2020 15:24:19 +0100 Message-Id: <20200323142421.42817-2-paul@crapouillou.net> In-Reply-To: <20200323142421.42817-1-paul@crapouillou.net> References: <20200323142421.42817-1-paul@crapouillou.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The previous algorithm hardcoded details about how the TCU clocks work. The new algorithm will use clk_round_rate to find the perfect clock rate for the PWM channel. This code relies on the fact that clk_round_rate() will always round down, which is not a valid assumption given by the clk API, but only happens to be true with the clk drivers used for Ingenic SoCs. Right now, there is no alternative as the clk API does not have a round-down function (and won't have one for a while), but if it ever comes to light, a round-down function should be used instead. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek --- Notes: v4: New patch drivers/pwm/pwm-jz4740.c | 44 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index ee50ac5fabb6..0b41baf40e4a 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -111,28 +111,42 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); - struct clk *clk = pwm_get_chip_data(pwm), - *parent_clk = clk_get_parent(clk); - unsigned long rate, period, duty; - unsigned long long tmp; - unsigned int prescaler = 0; + struct clk *clk = pwm_get_chip_data(pwm); + unsigned long long tmp = 0xffffull * NSEC_PER_SEC; + unsigned long period, duty; uint16_t ctrl; + long rate; int err; - rate = clk_get_rate(parent_clk); - tmp = (unsigned long long)rate * state->period; - do_div(tmp, 1000000000); - period = tmp; + /* + * Limit the clock to a maximum rate that still gives us a period value + * which fits in 16 bits. + */ + do_div(tmp, state->period); - while (period > 0xffff && prescaler < 6) { - period >>= 2; - rate >>= 2; - ++prescaler; + /* + * /!\ IMPORTANT NOTE: + * ------------------- + * This code relies on the fact that clk_round_rate() will always round + * down, which is not a valid assumption given by the clk API, but only + * happens to be true with the clk drivers used for Ingenic SoCs. + * + * Right now, there is no alternative as the clk API does not have a + * round-down function (and won't have one for a while), but if it ever + * comes to light, a round-down function should be used instead. + */ + rate = clk_round_rate(clk, tmp); + if (rate < 0) { + dev_err(chip->dev, "Unable to round rate: %ld", rate); + return rate; } - if (prescaler == 6) - return -EINVAL; + /* Calculate period value */ + tmp = (unsigned long long)rate * state->period; + do_div(tmp, NSEC_PER_SEC); + period = (unsigned long)tmp; + /* Calculate duty value */ tmp = (unsigned long long)period * state->duty_cycle; do_div(tmp, state->period); duty = period - tmp; -- 2.25.1