From patchwork Wed Jan 9 14:08:59 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 1953001 Return-Path: X-Original-To: patchwork-spi-devel-general@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by patchwork2.kernel.org (Postfix) with ESMTP id 8D4D7DF25A for ; Wed, 9 Jan 2013 14:09:12 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-3.v29.ch3.sourceforge.com) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1TswLA-00069q-6m; Wed, 09 Jan 2013 14:09:12 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1TswL8-00069i-TV for spi-devel-general@lists.sourceforge.net; Wed, 09 Jan 2013 14:09:10 +0000 Received-SPF: pass (sog-mx-1.v43.ch3.sourceforge.com: domain of srs.kundenserver.de designates 212.227.126.187 as permitted sender) client-ip=212.227.126.187; envelope-from=SRS0=dJwT=LC=gmx.de=g.liakhovetski@srs.kundenserver.de; helo=moutng.kundenserver.de; Received: from moutng.kundenserver.de ([212.227.126.187]) by sog-mx-1.v43.ch3.sourceforge.com with esmtps (TLSv1:RC4-SHA:128) (Exim 4.76) id 1TswL7-0003qs-Fu for spi-devel-general@lists.sourceforge.net; Wed, 09 Jan 2013 14:09:10 +0000 Received: from axis700.grange (dslb-178-006-043-106.pools.arcor-ip.net [178.6.43.106]) by mrelayeu.kundenserver.de (node=mreu3) with ESMTP (Nemesis) id 0MNiNa-1TvfM12Hn8-0079MP; Wed, 09 Jan 2013 15:09:00 +0100 Received: by axis700.grange (Postfix, from userid 1000) id 31B4F40B99; Wed, 9 Jan 2013 15:08:59 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by axis700.grange (Postfix) with ESMTP id 2D6C340B98; Wed, 9 Jan 2013 15:08:59 +0100 (CET) Date: Wed, 9 Jan 2013 15:08:59 +0100 (CET) From: Guennadi Liakhovetski X-X-Sender: lyakh@axis700.grange To: Grant Likely Subject: [PATCH v2 2/2] spi: bitbang: convert to using core message queue In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Provags-ID: V02:K0:qJQIgH4mcDQf31ZTonub3RVPYXAT3BSfKovuYETGy71 Upi6oYEI6qHQ7q+mPgXBvEj1kTJeHnLLcwtGHNiMVGGZWitWYu Nl1VHybBYVxcYM7bY/uap3TGSdBzZ+QLDZPeiTznoJK17e7eDt FlpvrfuP32k3T4JLMnXK5c/RkCGq8GAJtgrRCoVz+DbE+mXmCu e0OPYT6vpITn0acrReAsUusqzF80AXeAkuUxEEfCZYNxeIM3nR bNS26Q5xcxF4OquQaXhc/mG8k9HBd9/A/7CyjCF+bO+uC70liI 5yRdE16Ud1swzB4vv1c5fYNFGbzGsUTRTrB1ZpugSUhBZvA6wm wcAcCdUhmhCDxPIXYGstD2B8qTbegd3uVb7ssv46upGZl3YNQX ABwISodpWUvSQ== X-Spam-Score: -1.5 (-) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -1.5 SPF_CHECK_PASS SPF reports sender host as permitted sender for sender-domain 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (g.liakhovetski[at]gmx.de) -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.227.126.187 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Headers-End: 1TswL7-0003qs-Fu Cc: spi-devel-general@lists.sourceforge.net, Linus Walleij , Magnus Damm , linux-sh@vger.kernel.org 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: , Errors-To: spi-devel-general-bounces@lists.sourceforge.net The SPI subsystem core now manages message queues internally. Remove the local message queue implementation from the spi-bitbang driver and migrate to the common one. Signed-off-by: Guennadi Liakhovetski Tested-by: Uwe Kleine-König --- v2: remove unrelated changes, partially dropping them and partially extracting them into a separate patch. drivers/spi/spi-bitbang.c | 266 +++++++++++++++------------------------ include/linux/spi/spi_bitbang.h | 7 - 2 files changed, 101 insertions(+), 172 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 328c4dc..e989ad9 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -244,161 +244,125 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) /*----------------------------------------------------------------------*/ -/* - * SECOND PART ... simple transfer queue runner. - * - * This costs a task context per controller, running the queue by - * performing each transfer in sequence. Smarter hardware can queue - * several DMA transfers at once, and process several controller queues - * in parallel; this driver doesn't match such hardware very well. - * - * Drivers can provide word-at-a-time i/o primitives, or provide - * transfer-at-a-time ones to leverage dma or fifo hardware. - */ -static void bitbang_work(struct work_struct *work) +static int spi_bitbang_transfer_one_message(struct spi_master *master, + struct spi_message *m) { - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); + struct spi_bitbang *bitbang = spi_master_get_devdata(master); unsigned long flags; - struct spi_message *m, *_m; - + struct spi_device *spi; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned cs_change; + int status; + int do_setup = -1; + + /* Protect against chip-select release in .setup() */ spin_lock_irqsave(&bitbang->lock, flags); bitbang->busy = 1; - list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { - struct spi_device *spi; - unsigned nsecs; - struct spi_transfer *t = NULL; - unsigned tmp; - unsigned cs_change; - int status; - int do_setup = -1; - - list_del(&m->queue); - spin_unlock_irqrestore(&bitbang->lock, flags); - - /* FIXME this is made-up ... the correct value is known to - * word-at-a-time bitbang code, and presumably chipselect() - * should enforce these requirements too? - */ - nsecs = 100; + spin_unlock_irqrestore(&bitbang->lock, flags); - spi = m->spi; - tmp = 0; - cs_change = 1; - status = 0; + /* FIXME this is made-up ... the correct value is known to + * word-at-a-time bitbang code, and presumably chipselect() + * should enforce these requirements too? + */ + nsecs = 100; - list_for_each_entry (t, &m->transfers, transfer_list) { - - /* override speed or wordsize? */ - if (t->speed_hz || t->bits_per_word) - do_setup = 1; - - /* init (-1) or override (1) transfer params */ - if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; - if (do_setup == -1) - do_setup = 0; - } - - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). - * (and also deselects any other chip that might be - * selected ...) - */ - if (cs_change) { - bitbang->chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (!t->tx_buf && !t->rx_buf && t->len) { - status = -EINVAL; - break; - } + spi = m->spi; + cs_change = 1; + status = 0; - /* transfer data. the lower level code handles any - * new dma mappings it needs. our caller always gave - * us dma-safe buffers. - */ - if (t->len) { - /* REVISIT dma API still needs a designated - * DMA_ADDR_INVALID; ~0 might be better. - */ - if (!m->is_dma_mapped) - t->rx_dma = t->tx_dma = 0; - status = bitbang->txrx_bufs(spi, t); - } - if (status > 0) - m->actual_length += status; - if (status != t->len) { - /* always report some kind of error */ - if (status >= 0) - status = -EREMOTEIO; + list_for_each_entry (t, &m->transfers, transfer_list) { + + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; + + /* init (-1) or override (1) transfer params */ + if (do_setup != 0) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) break; - } - status = 0; - - /* protocol tweaks before next transfer */ - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + if (do_setup == -1) + do_setup = 0; } - m->status = status; - m->complete(m->context); + /* set up default clock polarity, and activate chip; + * this implicitly updates clock and spi modes as + * previously recorded for this device via setup(). + * (and also deselects any other chip that might be + * selected ...) + */ + if (cs_change) { + bitbang->chipselect(spi, BITBANG_CS_ACTIVE); + ndelay(nsecs); + } + cs_change = t->cs_change; + if (!t->tx_buf && !t->rx_buf && t->len) { + status = -EINVAL; + break; + } - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. + /* transfer data. the lower level code handles any + * new dma mappings it needs. our caller always gave + * us dma-safe buffers. */ - if (!(status == 0 && cs_change)) { + if (t->len) { + /* REVISIT dma API still needs a designated + * DMA_ADDR_INVALID; ~0 might be better. + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) + m->actual_length += status; + if (status != t->len) { + /* always report some kind of error */ + if (status >= 0) + status = -EREMOTEIO; + break; + } + status = 0; + + /* protocol tweaks before next transfer */ + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ ndelay(nsecs); bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ndelay(nsecs); } - - spin_lock_irqsave(&bitbang->lock, flags); } - bitbang->busy = 0; - spin_unlock_irqrestore(&bitbang->lock, flags); -} - -/** - * spi_bitbang_transfer - default submit to transfer queue - */ -int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct spi_bitbang *bitbang; - unsigned long flags; - int status = 0; - m->actual_length = 0; - m->status = -EINPROGRESS; + m->status = status; - bitbang = spi_master_get_devdata(spi->master); + /* normally deactivate chipselect ... unless no error and + * cs_change has hinted that the next message will probably + * be for this chip too. + */ + if (!(status == 0 && cs_change)) { + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } spin_lock_irqsave(&bitbang->lock, flags); - if (!spi->max_speed_hz) - status = -ENETDOWN; - else { - list_add_tail(&m->queue, &bitbang->queue); - queue_work(bitbang->workqueue, &bitbang->work); - } + bitbang->busy = 0; spin_unlock_irqrestore(&bitbang->lock, flags); - return status; + spi_finalize_current_message(master); + + return 0; +} + +static int spi_bitbang_dummy_prepare(struct spi_master *master) +{ + return 0; } -EXPORT_SYMBOL_GPL(spi_bitbang_transfer); /*----------------------------------------------------------------------*/ @@ -407,9 +371,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer); * @bitbang: driver handle * * Caller should have zero-initialized all parts of the structure, and then - * provided callbacks for chip selection and I/O loops. If the master has - * a transfer method, its final step should call spi_bitbang_transfer; or, - * that's the default if the transfer routine is not initialized. It should + * provided callbacks for chip selection and I/O loops. It should * also set up the bus number and number of chipselects. * * For i/o loops, provide callbacks either per-word (for bitbanging, or for @@ -428,20 +390,19 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer); int spi_bitbang_start(struct spi_bitbang *bitbang) { struct spi_master *master = bitbang->master; - int status; if (!master || !bitbang->chipselect) return -EINVAL; - INIT_WORK(&bitbang->work, bitbang_work); spin_lock_init(&bitbang->lock); - INIT_LIST_HEAD(&bitbang->queue); if (!master->mode_bits) master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; - if (!master->transfer) - master->transfer = spi_bitbang_transfer; + master->transfer_one_message = spi_bitbang_transfer_one_message; + master->prepare_transfer_hardware = spi_bitbang_dummy_prepare; + master->unprepare_transfer_hardware = spi_bitbang_dummy_prepare; + if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; @@ -454,32 +415,11 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) } } else if (!master->setup) return -EINVAL; - if (master->transfer == spi_bitbang_transfer && - !bitbang->setup_transfer) - return -EINVAL; - - /* this task is the only thing to touch the SPI bits */ - bitbang->busy = 0; - bitbang->workqueue = create_singlethread_workqueue( - dev_name(master->dev.parent)); - if (bitbang->workqueue == NULL) { - status = -EBUSY; - goto err1; - } /* driver may get busy before register() returns, especially * if someone registered boardinfo for devices */ - status = spi_register_master(master); - if (status < 0) - goto err2; - - return status; - -err2: - destroy_workqueue(bitbang->workqueue); -err1: - return status; + return spi_register_master(master); } EXPORT_SYMBOL_GPL(spi_bitbang_start); @@ -490,10 +430,6 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang) { spi_unregister_master(bitbang->master); - WARN_ON(!list_empty(&bitbang->queue)); - - destroy_workqueue(bitbang->workqueue); - return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_stop); diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index f987a2b..f85a7b8 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -1,14 +1,8 @@ #ifndef __SPI_BITBANG_H #define __SPI_BITBANG_H -#include - struct spi_bitbang { - struct workqueue_struct *workqueue; - struct work_struct work; - spinlock_t lock; - struct list_head queue; u8 busy; u8 use_dma; u8 flags; /* extra spi->mode support */ @@ -41,7 +35,6 @@ struct spi_bitbang { */ extern int spi_bitbang_setup(struct spi_device *spi); extern void spi_bitbang_cleanup(struct spi_device *spi); -extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); extern int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t);