From patchwork Sun Feb 3 14:15:12 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonas Gorski X-Patchwork-Id: 2086461 Return-Path: X-Original-To: patchwork-spi-devel-general@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by patchwork1.kernel.org (Postfix) with ESMTP id 98B793FD56 for ; Sun, 3 Feb 2013 14:31:51 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-4.v29.ch3.sourceforge.com) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1U20bm-0002GO-GL; Sun, 03 Feb 2013 14:31:50 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1U20bk-0002GJ-OP for spi-devel-general@lists.sourceforge.net; Sun, 03 Feb 2013 14:31:48 +0000 X-ACL-Warn: Received: from arrakis.dune.hu ([78.24.191.176]) by sog-mx-1.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1U20bi-0007zt-Vh for spi-devel-general@lists.sourceforge.net; Sun, 03 Feb 2013 14:31:48 +0000 Received: from arrakis.dune.hu ([127.0.0.1]) by localhost (arrakis.dune.hu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id A1jeVeh3lIWB; Sun, 3 Feb 2013 15:15:47 +0100 (CET) Received: from shaker64.lan (dslb-088-073-063-163.pools.arcor-ip.net [88.73.63.163]) by arrakis.dune.hu (Postfix) with ESMTPSA id A22982802BA; Sun, 3 Feb 2013 15:15:47 +0100 (CET) From: Jonas Gorski To: spi-devel-general@lists.sourceforge.net Subject: [PATCH V2 1/2] spi/bcm63xx: reject transfers unable to transfer Date: Sun, 3 Feb 2013 15:15:12 +0100 Message-Id: <1359900913-4472-2-git-send-email-jogo@openwrt.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1359900913-4472-1-git-send-email-jogo@openwrt.org> References: <1359900913-4472-1-git-send-email-jogo@openwrt.org> X-Spam-Score: 3.7 (+++) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 3.7 TVD_SUBJ_NUM_OBFU_MINFP TVD_SUBJ_NUM_OBFU_MINFP X-Headers-End: 1U20bi-0007zt-Vh Cc: Maxime Bizon , Mark Brown , Florian Fainelli , Kevin Cernekee X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: spi-devel-general-bounces@lists.sourceforge.net The hardware does not support keeping CS asserted after sending one FIFO buffer worth of data, so reject transfers requiring CS being kept asserted, either between transers or for a certain time after it, or exceeding the FIFO size. Signed-off-by: Jonas Gorski --- drivers/spi/spi-bcm63xx.c | 91 +++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index f44ab55..27667c1 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -49,16 +49,10 @@ struct bcm63xx_spi { unsigned int msg_type_shift; unsigned int msg_ctl_width; - /* Data buffers */ - const unsigned char *tx_ptr; - unsigned char *rx_ptr; - /* data iomem */ u8 __iomem *tx_io; const u8 __iomem *rx_io; - int remaining_bytes; - struct clk *clk; struct platform_device *pdev; }; @@ -175,24 +169,13 @@ static int bcm63xx_spi_setup(struct spi_device *spi) return 0; } -/* Fill the TX FIFO with as many bytes as possible */ -static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) -{ - u8 size; - - /* Fill the Tx FIFO with as many bytes as possible */ - size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes : - bs->fifo_size; - memcpy_toio(bs->tx_io, bs->tx_ptr, size); - bs->remaining_bytes -= size; -} - -static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi, - struct spi_transfer *t) +static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); u16 msg_ctl; u16 cmd; + u8 rx_tail; + unsigned int timeout = 0; /* Disable the CMD_DONE interrupt */ bcm_spi_writeb(bs, 0, SPI_INT_MASK); @@ -200,14 +183,8 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi, dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", t->tx_buf, t->rx_buf, t->len); - /* Transmitter is inhibited */ - bs->tx_ptr = t->tx_buf; - bs->rx_ptr = t->rx_buf; - - if (t->tx_buf) { - bs->remaining_bytes = t->len; - bcm63xx_spi_fill_tx_fifo(bs); - } + if (t->tx_buf) + memcpy_toio(bs->tx_io, t->tx_buf, t->len); init_completion(&bs->done); @@ -239,7 +216,18 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi, /* Enable the CMD_DONE interrupt */ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); - return t->len - bs->remaining_bytes; + timeout = wait_for_completion_timeout(&bs->done, HZ); + if (!timeout) + return -ETIMEDOUT; + + /* read out all data */ + rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); + + /* Read out all the data */ + if (rx_tail) + memcpy_fromio(t->rx_ptr, bs->rx_io, rx_tail); + + return 0; } static int bcm63xx_spi_prepare_transfer(struct spi_master *master) @@ -267,36 +255,41 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master, struct spi_transfer *t; struct spi_device *spi = m->spi; int status = 0; - unsigned int timeout = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - unsigned int len = t->len; - u8 rx_tail; - status = bcm63xx_spi_check_transfer(spi, t); if (status < 0) goto exit; - /* configure adapter for a new transfer */ - bcm63xx_spi_setup_transfer(spi, t); + /* we can only transfer one fifo worth of data */ + if (t->len > bs->fifo_size) { + dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n", + t->len, bs->fifo_size); + status = -EINVAL; + goto exit; + } - while (len) { - /* send the data */ - len -= bcm63xx_txrx_bufs(spi, t); + /* CS will be deasserted directly after transfer */ + if (t->delay_usecs) { + dev_err(&spi->dev, "unable to keep CS asserted after transfer\n"); + status = -EINVAL; + goto exit; + } - timeout = wait_for_completion_timeout(&bs->done, HZ); - if (!timeout) { - status = -ETIMEDOUT; - goto exit; - } + if (!t->cs_change && + !list_is_last(&t->transfer_list, &m->transfers)) { + dev_err(&spi->dev, "unable to keep CS asserted between transfers\n"); + status = -EINVAL; + goto exit; + } - /* read out all data */ - rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); + /* configure adapter for a new transfer */ + bcm63xx_spi_setup_transfer(spi, t); - /* Read out all the data */ - if (rx_tail) - memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail); - } + /* send the data */ + status = bcm63xx_txrx_bufs(spi, t); + if (status) + goto exit; m->actual_length += t->len; }