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: 8301691 Return-Path: X-Original-To: patchwork-linux-spi@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 92D2DC02AA for ; Sun, 14 Feb 2016 10:05:51 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A307E20384 for ; Sun, 14 Feb 2016 10:05:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 67613203DA for ; Sun, 14 Feb 2016 10:05:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751272AbcBNKFr (ORCPT ); Sun, 14 Feb 2016 05:05:47 -0500 Received: from mout.gmx.net ([212.227.15.19]:60782 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751247AbcBNKFl (ORCPT ); Sun, 14 Feb 2016 05:05:41 -0500 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 Cc: Stephan Olbrich 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:sNIvM8jwkkc=:PFCREyXT3VPhlVdfTSnRD1 6DjZR0KyW/rRiUbeHfji5EnlMhQgN+SIwVbwwnGpEEAu4jXAShAoPkUjsXZ1dZ/EyvcJDOaup 9DoNiyTV63inCzV+lNZZBejHpCW4Z5jJ/L6/64rTY4tQ1xMAtXAqOpFvGG9T6LAk43aHF2nGn jW6ztjzFlN0FJobSsB6ydg0A5SipirMBREoVL0eEODsFNT8t5JSwb8cWR/DUM58ufZ3N7jmT0 mtADR75YWFp06EhwC2SicXFSqCb+seso0KHTVMhYZbrq5tgGcSu/ouuu/nmd/jUHycPPdb3pm SuWYXdXDeE7iZmfJwSB/50ylNgjhF2BrF6T8ktZGFXxMDbyr7S+FLDPZQa2TzeaY4rp8XipQk qrKy/Ro+bdz0jsfj3gixqKiFRj3Uq3q5PSb6XLWbhrFHRIZT94JBNqQY0h7k3h2ac7MCsNbSr TKzL5kBrHNtbDd7Q8egRw3ptq4E5yGHLudnTAYSai/BT3HjK2R3rqWDfA2mNgtiJd36SiKJ0m nDAlZz8wqCyuGIiH+ldwAJ09TOAOVxu4foUz1ILUXk3LDxr2Ht7DY5kzeX1n62rBatXGS9NiL YH/tpYZ7efNZ0ywbJ10CzFTj0hVKdfjdnX7AzptO2iHTnsHyJgfm2CkyY0s1A7jKNUvl8xs44 dqINfjZ5hJadLfJ7Mb9pNqFCBvFk7E9ZX/B244y5lvTmS7Fy6JESgAzX+Vz96BfBodegx8eFx DjLdY1x/Yaf1Hsu0k0w8A6mSu0lPp54sgWe+Q9mJ5f/5/t7rK/i9t7wsRHA= 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.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI, 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);