From patchwork Sun Feb 14 10:04:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Olbrich X-Patchwork-Id: 8320881 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E158EC02AA for ; Tue, 16 Feb 2016 03:50:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EF174202F2 for ; Tue, 16 Feb 2016 03:50:10 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BEA47202FE for ; Tue, 16 Feb 2016 03:50:08 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aVWd4-0002Uu-Ao; Tue, 16 Feb 2016 03:48:46 +0000 Received: from mout.gmx.net ([212.227.15.15]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aVWcX-0002BA-Po; Tue, 16 Feb 2016 03:48:28 +0000 Received: from chaos-desktop.fritz.box ([94.218.169.41]) by mail.gmx.com (mrgmx003) with ESMTPSA (Nemesis) id 0M92ZJ-1ahJcV1fMz-00CRPN; Sun, 14 Feb 2016 11:04:58 +0100 From: Stephan Olbrich To: Mark Brown , Stephen Warren , Lee Jones , Eric Anholt , linux-spi@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Martin Sperl Subject: [PATCH v2 1/2] spi: bcm2835aux: set up spi-mode before asserting cs-gpio Date: Sun, 14 Feb 2016 11:04:28 +0100 Message-Id: <1455444269-4797-2-git-send-email-stephanolbrich@gmx.de> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1455444269-4797-1-git-send-email-stephanolbrich@gmx.de> References: <1455444269-4797-1-git-send-email-stephanolbrich@gmx.de> X-Provags-ID: V03:K0:fzBoGXkagiR4vVpiCEMhm0z6kbZ2bA3PeDuWLojVL2lKAJGlsHi ouYf/AkQX3JaG7pwPejaHmAtzBztiI3tQlTaqdSAVER1TC75jnXE2uA4ZN3Szapd+PH1kEF l6ogsLF7DLLJbXC0vB5yjqrZUhHBnDKW7e9toh2x4VFH4eHQ0sJP8iLe7VN+SWbNVchzwBW 7Wee0REoVTBTlFufqewTA== X-UI-Out-Filterresults: notjunk:1; V01:K0:f+qvPmv6nqY=:udy/Ol5r+MWpw9LXVcw3wV kFlzESryJRVGo73eKTUZbiqxuNJ7qG7mdTF0sfSmKrr3+ydYt53Iyu6g8347NENgSaLzXq79D H+rF0p+oHjvYSiwbhxfPhX91laAKXW44HKw6KiLJShxLS0QdeUk5MdkPBpBk6Ck2U0WLU6Sra oK0ldtWyy0OwDp/cAPAHU1ccT9UyYXXXaqSj8qPDhSNvIUSj6VbszlcwTAayC9LNH2iWSRhjD JsH2PaI6GbFhtK+iToggNfsAnv8+cTiBkhib+MtGUWk84WjX3hmLhaFG6S9uXzObSvucq3+We LuFByNZMqvYv1yj3ULJEj5Aa6kPqG8Z521j9qCP0eZG6dnDvkPO0ZER33xvYzMPHYg5zn2rsI 275ycOtXrGrf9lv771BTXnv1Ayku8D3ziEG5G4j8D14poh9o4ayrxKBZPTH+tOps9f20QYuBV wffJWQyUbehb7TuVzCGXneBqbR6Qgq4HOnGyEQqHS+2EzoFlHEb+WdoqDVHNXYYlhGntRqqRP syb0nIZoWphao8Y7KhETwZ8KZI0K81YG1yY9U5LerHZWAeMtDgQlpHFlMjnttIxhelLnL2va8 sfx0R4/6LaPuyvQQGdQAQ3x2rOO/LXBenqvYFNmtPNpMeieqg2+ttFngqRerUfoboafxFaNqe RaXz+szBiCg1o+ttk5EmH4r0Yjvuj/UgRyr9Y79piPgKwDB6npbSaWiiv/PfflZ2bBSevEttA XCon/C3zhdpR3tkLaWvLcuOCKrSJojAw8YwIA4T5bZKh3gcOFwyE9ICz9m4= X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160215_194814_395277_58055377 X-CRM114-Status: GOOD ( 13.42 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stephan Olbrich MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, 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 When using reverse polarity for clock (spi-cpol) on a device the clock line gets altered after chip-select has been asserted resulting in an additional clock beat, which confuses hardware. This happens due to the fact, the the hardware was initialized and reset at the begin and end of each transfer which results in default state for all lines except chip-select which is handled by the spi-subsystem as gpio-cs is used. To avoid this situation this patch moves the setup of polarity (spi-cpol and spi-cpha) outside of the chip-select into prepare_message, which is run prior to asserting chip-select. Signed-off-by: Stephan Olbrich Reviewed-by: Martin Sperl Tested-by: Martin Sperl --- drivers/spi/spi-bcm2835aux.c | 57 +++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index d2f0067..103335e 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -218,9 +218,9 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) BCM2835_AUX_SPI_CNTL1_IDLE); } - /* and if rx_len is 0 then wake up completion and disable spi */ + /* and if rx_len is 0 then disable interrupts and wake up completion */ if (!bs->rx_len) { - bcm2835aux_spi_reset_hw(bs); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); complete(&master->xfer_completion); } @@ -313,9 +313,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, } } - /* Transfer complete - reset SPI HW */ - bcm2835aux_spi_reset_hw(bs); - /* and return without waiting for completion */ return 0; } @@ -336,10 +333,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, * resulting (potentially) in more interrupts when transferring * more than 12 bytes */ - bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE | - BCM2835_AUX_SPI_CNTL0_VAR_WIDTH | - BCM2835_AUX_SPI_CNTL0_MSBF_OUT; - bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN; /* set clock */ spi_hz = tfr->speed_hz; @@ -354,17 +347,13 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, } else { /* the slowest we can go */ speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; } + /* mask out old speed from previous spi_transfer */ + bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED); + /* set the new speed */ bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; spi_used_hz = clk_hz / (2 * (speed + 1)); - /* handle all the modes */ - if (spi->mode & SPI_CPOL) - bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL; - if (spi->mode & SPI_CPHA) - bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT | - BCM2835_AUX_SPI_CNTL0_CPHA_IN; - /* set transmit buffers and length */ bs->tx_buf = tfr->tx_buf; bs->rx_buf = tfr->rx_buf; @@ -388,6 +377,40 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); } +static int bcm2835aux_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct spi_device *spi = msg->spi; + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE | + BCM2835_AUX_SPI_CNTL0_VAR_WIDTH | + BCM2835_AUX_SPI_CNTL0_MSBF_OUT; + bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN; + + /* handle all the modes */ + if (spi->mode & SPI_CPOL) + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL; + if (spi->mode & SPI_CPHA) + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT | + BCM2835_AUX_SPI_CNTL0_CPHA_IN; + + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + return 0; +} + +static int bcm2835aux_spi_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + bcm2835aux_spi_reset_hw(bs); + + return 0; +} + static void bcm2835aux_spi_handle_err(struct spi_master *master, struct spi_message *msg) { @@ -416,6 +439,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) master->num_chipselect = -1; master->transfer_one = bcm2835aux_spi_transfer_one; master->handle_err = bcm2835aux_spi_handle_err; + master->prepare_message = bcm2835aux_spi_prepare_message; + master->unprepare_message = bcm2835aux_spi_unprepare_message; master->dev.of_node = pdev->dev.of_node; bs = spi_master_get_devdata(master);