From patchwork Sat Dec 26 15:53:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcus Weseloh X-Patchwork-Id: 7922091 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 311BC9F387 for ; Sat, 26 Dec 2015 15:53:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4BB4620373 for ; Sat, 26 Dec 2015 15:53:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 515DF20361 for ; Sat, 26 Dec 2015 15:53:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751145AbbLZPx1 (ORCPT ); Sat, 26 Dec 2015 10:53:27 -0500 Received: from mail-wm0-f45.google.com ([74.125.82.45]:34795 "EHLO mail-wm0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753453AbbLZPxZ (ORCPT ); Sat, 26 Dec 2015 10:53:25 -0500 Received: by mail-wm0-f45.google.com with SMTP id l126so222443443wml.1; Sat, 26 Dec 2015 07:53:24 -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=ta3DI3b3mAnsSmL7TgPNotlpGBU0J9ZUCCNucDJqwh8=; b=x7czmGR4vra56+SZ7Bh55979qwQzIMEF+k7L2JQQI2exryQYqYP1fidaX3JQEHisGB ioCxmokWoPdbIy3NVTJsvMpdxTsMOulrkR/W4izfTYsMe6+naysIPHWmvv450QwjMf+8 Z3y1z5ikvN8m/b06HSWx0z11oVNh3EqQ88WCAFE9ERWBB6nqqY/zPXI2XedAtaFQD+Zp PkCT7WELmpgdRxmdLySAFbalm5h0EPgUUE9k3ZD9/KPH4FNUaXGXjktgtqolO2fE8G0s mCGuDUfd0KD01XI18C8GEZ02iKUYqJxmkWbWjWLXt4VJDOXWzp7UmnuFq7LhBCBkO6yh +QqA== X-Received: by 10.28.156.198 with SMTP id f189mr16591995wme.25.1451145203756; Sat, 26 Dec 2015 07:53:23 -0800 (PST) Received: from speedy.fritz.box (p5793D053.dip0.t-ipconnect.de. [87.147.208.83]) by smtp.gmail.com with ESMTPSA id l7sm49396737wjx.14.2015.12.26.07.53.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 26 Dec 2015 07:53:22 -0800 (PST) From: Marcus Weseloh To: linux-sunxi@googlegroups.com Cc: Chen-Yu Tsai , devicetree@vger.kernel.org, Ian Campbell , Kumar Gala , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, Marcus Weseloh , Mark Brown , Mark Rutland , Maxime Ripard , Pawel Moll , Rob Herring Subject: [PATCH v6 2/3] spi: sun4i: Fix clock calculations to be predictable and never exceed the requested rate Date: Sat, 26 Dec 2015 16:53:05 +0100 Message-Id: <1451145186-14235-3-git-send-email-mweseloh42@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1451145186-14235-1-git-send-email-mweseloh42@gmail.com> References: <1451145186-14235-1-git-send-email-mweseloh42@gmail.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@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 This patch fixes multiple problems with the current clock calculations: 1. The A10/A20 datasheet contains the formula AHB_CLK / (2^(n+1)) to calculate SPI_CLK from CDR1, but this formula is wrong. The actual formula - determined by analyzing the actual waveforms - is AHB_CLK / (2^n). 2. The divisor calculations for CDR1 and CDR2 both rounded to the nearest integer. This could lead to a transfer speed that is higher than the requested speed. This patch changes both calculations to always round down. 3. The mclk frequency was only ever increased, never decreased. This could lead to unpredictable transfer speeds, depending on the order in which transfers with different speeds where serviced by the SPI driver. Signed-off-by: Marcus Weseloh --- drivers/spi/spi-sun4i.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index f60a6d6..d67e142 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -79,6 +79,9 @@ struct sun4i_spi { struct clk *hclk; struct clk *mclk; + int cur_max_speed; + int cur_mclk; + struct completion done; const u8 *tx_buf; @@ -227,11 +230,17 @@ static int sun4i_spi_transfer_one(struct spi_master *master, sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); - /* Ensure that we have a parent clock fast enough */ + /* + * Ensure that the parent clock is set to twice the max speed + * of the spi device (possibly rounded up by the clk driver) + */ mclk_rate = clk_get_rate(sspi->mclk); - if (mclk_rate < (2 * tfr->speed_hz)) { - clk_set_rate(sspi->mclk, 2 * tfr->speed_hz); + if (spi->max_speed_hz != sspi->cur_max_speed || + mclk_rate != sspi->cur_mclk) { + clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); mclk_rate = clk_get_rate(sspi->mclk); + sspi->cur_mclk = mclk_rate; + sspi->cur_max_speed = spi->max_speed_hz; } /* @@ -239,7 +248,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master, * * We have two choices there. Either we can use the clock * divide rate 1, which is calculated thanks to this formula: - * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) + * SPI_CLK = MOD_CLK / (2 ^ cdr) * Or we can use CDR2, which is calculated with the formula: * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) * Wether we use the former or the latter is set through the @@ -248,14 +257,11 @@ static int sun4i_spi_transfer_one(struct spi_master *master, * First try CDR2, and if we can't reach the expected * frequency, fall back to CDR1. */ - div = mclk_rate / (2 * tfr->speed_hz); - if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { - if (div > 0) - div--; - + div = DIV_ROUND_UP(mclk_rate, 2 * tfr->speed_hz) - 1; + if (div <= SUN4I_CLK_CTL_CDR2_MASK) { reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS; } else { - div = ilog2(mclk_rate) - ilog2(tfr->speed_hz); + div = ilog2(roundup_pow_of_two(mclk_rate / tfr->speed_hz)); reg = SUN4I_CLK_CTL_CDR1(div); }