From patchwork Fri Aug 12 16:38:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 9277461 X-Patchwork-Delegate: geert@linux-m68k.org 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 5B316600CB for ; Fri, 12 Aug 2016 16:39:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4C1E428A9F for ; Fri, 12 Aug 2016 16:39:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4102028AA8; Fri, 12 Aug 2016 16:39:16 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D1C3E28AA7 for ; Fri, 12 Aug 2016 16:39:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932185AbcHLQjD (ORCPT ); Fri, 12 Aug 2016 12:39:03 -0400 Received: from albert.telenet-ops.be ([195.130.137.90]:50824 "EHLO albert.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752927AbcHLQi5 (ORCPT ); Fri, 12 Aug 2016 12:38:57 -0400 Received: from ayla.of.borg ([84.193.137.253]) by albert.telenet-ops.be with bizsmtp id WGet1t0075UCtCs06GetpP; Fri, 12 Aug 2016 18:38:53 +0200 Received: from ramsan.of.borg ([192.168.97.29] helo=ramsan) by ayla.of.borg with esmtp (Exim 4.82) (envelope-from ) id 1bYFTx-0006ES-2k; Fri, 12 Aug 2016 18:38:53 +0200 Received: from geert by ramsan with local (Exim 4.82) (envelope-from ) id 1bYFTy-0007aV-AK; Fri, 12 Aug 2016 18:38:54 +0200 From: Geert Uytterhoeven To: linux-renesas-soc@vger.kernel.org Cc: linux-spi@vger.kernel.org, linux-clk@vger.kernel.org, Geert Uytterhoeven Subject: [PATCH/PROTO 7/9 option 2] spi: sh-msiof: Configure MSIOF parent clock Date: Fri, 12 Aug 2016 18:38:43 +0200 Message-Id: <1471019925-29083-8-git-send-email-geert+renesas@glider.be> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1471019925-29083-1-git-send-email-geert+renesas@glider.be> References: <1471019925-29083-1-git-send-email-geert+renesas@glider.be> Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Change the clock rate in spi_master.setup() to accomodate the desired maximum clock rate for the device being set up: - Change the clock rate if the msiofX (and thus mso) clock rate is too high. Failure to do so is considered an error. - Try to change the clock rate if the msiofX (and thus mso) clock rate is too low to achieve the desired performance. Failure to do so is not considered an error, as the device will still work, but slower. Results (sequential operations during probing): 1. msiof0 (and mso) set to 30.8 MHz, 15.4 MHz after internal divider, 2. msiof2 kept at 30.8 MHz, 993 kHz after internal divider, 3. msiof3 (and mso) set to 20 MHz, 19.5 kHz after internal divider. Observations: - As the requested rate of 30 MHz is rounded to 30.8 MHz, which is higher than 30 MHz, an mso internal divider of 2 is used, leading to a much lower rate of 15.4 MHz, and thus lower performance than expected. - The parent clock frequency cannot be changed while the mso clock is enabled. This is tricky, as the MSIOF modules are part of a Clock Domain, hence their clocks (and its parent clock) are under control of Runtime PM. So the parent clock may still be enabled due to asynchronous runtime-suspend not having disabled it yet, causing clk_set_rate() to fail sometimes with -EBUSY. Not-Signed-off-by: Geert Uytterhoeven --- Not intended for upstream merge. --- drivers/spi/spi-sh-msiof.c | 74 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 656eaa4d03ed497b..0b69643936cdb941 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -584,7 +584,8 @@ static int sh_msiof_spi_setup(struct spi_device *spi) struct device_node *np = spi->master->dev.of_node; struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); u32 max_speed_hz, min_speed_hz; - unsigned long rate; + unsigned long rate, req_rate; + int error; rate = clk_get_rate(p->clk); max_speed_hz = rate; @@ -594,6 +595,77 @@ static int sh_msiof_spi_setup(struct spi_device *spi) "%s: master speed min %u max %u, device speed max = %u\n", __func__, min_speed_hz, max_speed_hz, spi->max_speed_hz); + if (spi->max_speed_hz < min_speed_hz) { + dev_err(&p->pdev->dev, + "Parent clock rate %lu too high for %u!\n", rate, + spi->max_speed_hz); + + req_rate = spi->max_speed_hz * MAX_DIV; + + error = clk_set_rate(p->clk, req_rate); + if (error) { + dev_err(&p->pdev->dev, + "Failed to set parent clock rate to %lu: %d\n", + req_rate, error); + return error; + } + + rate = clk_get_rate(p->clk); + dev_info(&p->pdev->dev, + "Changed parent clock rate to %lu actual %lu\n", + req_rate, rate); + + max_speed_hz = rate; + min_speed_hz = rate / MAX_DIV; + + dev_info(&p->pdev->dev, + "%s: new master speed min %u max %u, device speed max = %u\n", + __func__, min_speed_hz, max_speed_hz, + spi->max_speed_hz); + + if (spi->max_speed_hz < min_speed_hz) { + dev_err(&p->pdev->dev, + "New parent clock rate %lu too high for %u!\n", + rate, spi->max_speed_hz); + return -EINVAL; + } + } else if (spi->max_speed_hz * 4 > max_speed_hz * 5) { + /* More than 20% lower than desired */ + dev_warn(&p->pdev->dev, + "Parent clock rate %lu too low for %u\n", rate, + spi->max_speed_hz); + + req_rate = spi->max_speed_hz; + + error = clk_set_rate(p->clk, req_rate); + if (error) { + dev_warn(&p->pdev->dev, + "Failed to set parent clock rate to %lu: %d, ignoring\n", + req_rate, error); + goto done; + } + + rate = clk_get_rate(p->clk); + dev_info(&p->pdev->dev, + "Changed parent clock rate to %lu actual %lu\n", + req_rate, rate); + + max_speed_hz = rate; + min_speed_hz = rate / MAX_DIV; + + dev_info(&p->pdev->dev, + "%s: new master speed min %u max %u, device speed max = %u\n", + __func__, min_speed_hz, max_speed_hz, + spi->max_speed_hz); + + if (spi->max_speed_hz * 4 > max_speed_hz * 5) { + dev_warn(&p->pdev->dev, + "New parent clock rate %lu too high for %u, ignoring\n", + rate, spi->max_speed_hz); + } + } + +done: p->dev_max_speed_hz = spi->max_speed_hz; pm_runtime_get_sync(&p->pdev->dev);