From patchwork Sat Feb 10 12:25:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Jan_Kundr=C3=A1t?= X-Patchwork-Id: 10221397 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 BE71E6055C for ; Thu, 15 Feb 2018 14:31:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF5AC29387 for ; Thu, 15 Feb 2018 14:31:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A31232939B; Thu, 15 Feb 2018 14:31:49 +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=-3.4 required=2.0 tests=BAYES_00, DATE_IN_PAST_96_XX, DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID 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 6690929385 for ; Thu, 15 Feb 2018 14:31:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1033016AbeBOObh (ORCPT ); Thu, 15 Feb 2018 09:31:37 -0500 Received: from office2.cesnet.cz ([195.113.144.244]:43666 "EHLO office2.cesnet.cz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1033243AbeBOOb1 (ORCPT ); Thu, 15 Feb 2018 09:31:27 -0500 Received: from localhost (unknown [IPv6:2001:718:1:2c:15f8:b813:1f49:2432]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by office2.cesnet.cz (Postfix) with ESMTPSA id 52A00400066; Thu, 15 Feb 2018 15:31:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cesnet.cz; s=office2; t=1518705086; bh=wMD7aX0wg9ytIa9QY2h7+GfXyPlff8RApO9XQSDrktc=; h=Resent-Date:Resent-From:Resent-To:Resent-Cc:In-Reply-To: References:From:Date:Subject:To:Cc; b=XAa8AWLrMS1aJrxnbCMWZyzCjFyW2xsywikf7rx+cyMW5SEFyUFmW3pOACjXV61JJ JGH4Qthc/NCxF9TyLMM/YvhZFo6exDr2WqPA7vbN7xO44KRfAuP0DlTqjvl9a52rcM QU4qkXdVkGgd8X4FkQUKEL6CHkqXvs4UVHPgj/4I= Message-Id: <475b63c52b17187089d3f2ecf8ff4b8c45a7e58b.1518704854.git.jan.kundrat@cesnet.cz> In-Reply-To: References: From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= Date: Sat, 10 Feb 2018 13:25:32 +0100 Subject: [PATCH 4/4] spi: orion: Software control for inter-word delays MIME-Version: 1.0 To: linux-spi@vger.kernel.org Cc: Mark Brown , Geert Uytterhoeven , Chris Packham , Andy Shevchenko , Gregory CLEMENT , Christophe JAILLET , Murali Karicheri , Grygorii Strashko 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 Add a SW-controlled timer for inserting delays between individual words as transmitted over the SPI bus. The DT property name is loosely modelled after a similar, but HW-based feature in spi-davinci.c (commit 365a7bb32e09) -- hence the DT property name. My HW sucks. One of the less-serious troubles is that it requires a 3us delay between all SPI words. It also requires "big" transfers, easily around 40kB, which is 20k of 16-bit words. It's also a specialised, proprietary thing with no need for an in-kernel driver, so I'm using spidev to access it. There's a limit in spidev's SPI_IOC_MESSAGE and ioctl architecture in general which means that I can stash at most 512 individual spi_ioc_transfer into one ioctl. When I needed to transfer small pockets, that was enough -- I could simply build a series of hundreds of spi_ioc_trnasfers, two bytes each, with a proper delay_usecs to persuade the SPI core to implement these delays for me. However, this won't work if I need to send more than 1kB of data that way. It seems that there's nothing generic in Linux to implement this feature. The TI's spi-davinci.c can do something liek this in HW. People at various forums apparently want to do something similar on Zynq and on RPis, perhaps in SW. I wasn't able to find any ready-made patches, though. My SoC (88F68xx, Marvell Armada A38x) apparently cannot do this natively, so this patch simply adds a call to udelay which does the trick for me. Signed-off-by: Jan Kundrát --- Documentation/devicetree/bindings/spi/spi-orion.txt | 20 ++++++++++++++++++++ drivers/spi/spi-orion.c | 19 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt index 8434a65fc12a..ed35cba1bc33 100644 --- a/Documentation/devicetree/bindings/spi/spi-orion.txt +++ b/Documentation/devicetree/bindings/spi/spi-orion.txt @@ -29,6 +29,10 @@ Optional properties: used, the name must be "core", and "axi" (the latter is only for Armada 7K/8K). +Optional properties of child nodes (SPI slave devices): +- linux,spi-wdelay : If present and non-zero, specifies a delay in + microseconds between words transferred over the SPI bus. + Example: spi@10600 { @@ -77,3 +81,19 @@ are used in the default indirect (PIO) mode): For further information on the MBus bindings, please see the MBus DT documentation: Documentation/devicetree/bindings/bus/mvebu-mbus.txt + +Example of a per-child inter-word delay: + + spi0: spi@10600 { + /* ... */ + + some_slave_device@2 { + reg = <2>; + compatible = "something"; + /* ... */ + + /* Wait 3 microseconds between all words within all + SPI transactions */ + linux,spi-wdelay = /bits/ 16 <3>; + }; + }; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 1eccc2287079..1a9475857808 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -92,6 +92,7 @@ struct orion_direct_acc { struct orion_child_options { struct orion_direct_acc direct_access; + u16 word_delay; }; struct orion_spi { @@ -469,6 +470,8 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0) goto out; count--; + if (orion_spi->child[cs].word_delay) + udelay(orion_spi->child[cs].word_delay); } while (count); } else if (word_len == 16) { const u16 *tx = xfer->tx_buf; @@ -477,6 +480,8 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) do { if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0) goto out; + if (orion_spi->child[cs].word_delay) + udelay(orion_spi->child[cs].word_delay); count -= 2; } while (count); } @@ -681,7 +686,7 @@ static int orion_spi_probe(struct platform_device *pdev) goto out_rel_axi_clk; } - /* Scan all SPI devices of this controller for direct mapped devices */ + /* Scan all SPI devices of this controller for direct mapped devices and word delay */ for_each_available_child_of_node(pdev->dev.of_node, np) { u32 cs; @@ -694,6 +699,12 @@ static int orion_spi_probe(struct platform_device *pdev) continue; } + spi->child[cs].word_delay = 0; + if (!of_property_read_u16(np, "linux,spi-wdelay", + &spi->child[cs].word_delay)) + dev_info(&pdev->dev, "%pOF: %dus delay between words\n", + np, spi->child[cs].word_delay); + /* * Check if an address is configured for this SPI device. If * not, the MBus mapping via the 'ranges' property in the 'soc' @@ -705,6 +716,12 @@ static int orion_spi_probe(struct platform_device *pdev) if (status) continue; + if (spi->child[cs].word_delay) { + dev_warn(&pdev->dev, + "%pOF linux,spi-wdelay takes preference over a direct-mode", np); + continue; + } + /* * Only map one page for direct access. This is enough for the * simple TX transfer which only writes to the first word.