From patchwork Wed Jan 24 11:59:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Shevchenko X-Patchwork-Id: 10182387 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 207D860233 for ; Wed, 24 Jan 2018 11:59:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E90F288DF for ; Wed, 24 Jan 2018 11:59:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 029A9288E1; Wed, 24 Jan 2018 11:59:57 +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=ham 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 6CEB9288DF for ; Wed, 24 Jan 2018 11:59:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933300AbeAXL75 (ORCPT ); Wed, 24 Jan 2018 06:59:57 -0500 Received: from mga09.intel.com ([134.134.136.24]:10290 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933261AbeAXL74 (ORCPT ); Wed, 24 Jan 2018 06:59:56 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2018 03:59:55 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.46,406,1511856000"; d="scan'208";a="195887304" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga005.jf.intel.com with ESMTP; 24 Jan 2018 03:59:54 -0800 Received: by black.fi.intel.com (Postfix, from userid 1003) id 4CACE239; Wed, 24 Jan 2018 13:59:53 +0200 (EET) From: Andy Shevchenko To: Mark Brown , linux-spi@vger.kernel.org, Jarkko Nikula Cc: Andy Shevchenko Subject: [PATCH v1] spi: pxa2xx: set clock divider according to rate Date: Wed, 24 Jan 2018 13:59:52 +0200 Message-Id: <20180124115952.51765-1-andriy.shevchenko@linux.intel.com> X-Mailer: git-send-email 2.15.1 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Skylake and recent Intel SoCs we have a fractional divider installed on the reference clock for SPI host controller. It allows to much more precisely set clock rate on the interface. Use it to get better rate approximation especially on lowest speed. This has been tested on updated version of clk-fractional-divider.c that uses rational best approximation algorithm [1]. [1] http://www.spinics.net/lists/linux-clk/msg03135.html Signed-off-by: Andy Shevchenko --- drivers/spi/spi-pxa2xx.c | 30 +++++++++++++++++++++++------- drivers/spi/spi-pxa2xx.h | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 4cb515a3104c..1bbc7e116613 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -933,8 +933,9 @@ static unsigned int quark_x1000_get_clk_div(int rate, u32 *dds) static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) { - unsigned long ssp_clk = drv_data->master->max_speed_hz; const struct ssp_device *ssp = drv_data->ssp; + struct chip_data *chip = drv_data->cur_chip; + unsigned long ssp_clk = chip->ssp_clk; rate = min_t(int, ssp_clk, rate); @@ -944,6 +945,19 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) return (ssp_clk / rate - 1) & 0xfff; } +static unsigned int spt_get_clk_div(struct driver_data *drv_data, int rate) +{ + const struct ssp_device *ssp = drv_data->ssp; + struct chip_data *chip = drv_data->cur_chip; + long round; + + round = clk_round_rate(ssp->clk, rate); + clk_set_rate(ssp->clk, round); + + chip->ssp_clk = round; + return ssp_get_clk_div(drv_data, rate); +} + static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, int rate) { @@ -951,10 +965,14 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, spi_get_ctldata(drv_data->master->cur_msg->spi); unsigned int clk_div; + chip->ssp_clk = drv_data->master->max_speed_hz; switch (drv_data->ssp_type) { case QUARK_X1000_SSP: clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate); break; + case LPSS_SPT_SSP: + clk_div = spt_get_clk_div(drv_data, rate); + break; default: clk_div = ssp_get_clk_div(drv_data, rate); break; @@ -1132,14 +1150,12 @@ static void pump_transfers(unsigned long data) /* NOTE: PXA25x_SSP _could_ use external clocking ... */ cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits); if (!pxa25x_ssp_comp(drv_data)) - dev_dbg(&message->spi->dev, "%u Hz actual, %s\n", - master->max_speed_hz - / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)), + dev_dbg(&message->spi->dev, "%ld Hz actual, %s\n", + chip->ssp_clk / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)), dma_mapped ? "DMA" : "PIO"); else - dev_dbg(&message->spi->dev, "%u Hz actual, %s\n", - master->max_speed_hz / 2 - / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)), + dev_dbg(&message->spi->dev, "%ld Hz actual, %s\n", + chip->ssp_clk / 2 / (1 + ((cr0 & SSCR0_SCR(0xff)) >> 8)), dma_mapped ? "DMA" : "PIO"); if (is_lpss_ssp(drv_data)) { diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 94f7b0713281..368dc7ab9935 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -82,6 +82,7 @@ struct chip_data { u16 lpss_rx_threshold; u16 lpss_tx_threshold; u8 enable_dma; + long ssp_clk; union { struct gpio_desc *gpiod_cs; unsigned int frm;