From 874b31585650afa6745de5133849365e7e6af418 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 11:44:49 +0100 Subject: spi/bitbang: Unexport spi_bitbang_transfer() Currently no drivers use the ability to override spi_bitbang_transfer() and if any started this would make it harder to convert the bitbang code to use transfer_one_message() so remove the export in order to prevent anyone starting. Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a63d7da3bfe..495ce0a51d2 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -376,7 +376,7 @@ static void bitbang_work(struct work_struct *work) /** * spi_bitbang_transfer - default submit to transfer queue */ -int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) +static int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) { struct spi_bitbang *bitbang; unsigned long flags; @@ -398,7 +398,6 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) return status; } -EXPORT_SYMBOL_GPL(spi_bitbang_transfer); /*----------------------------------------------------------------------*/ -- cgit v1.2.3-70-g09d2 From 91b308586793b48c590c9ac3528bbacb8ef53e15 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 12:06:44 +0100 Subject: spi/bitbang: Factor out message transfer from message pump loop In order to make it easier to convert to transfer_one_message() lift the code that does the actual message transfer out of the work function that implements the message pump. This should have no functional impact, it's just a simple code motion patch. Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 199 ++++++++++++++++++++++++---------------------- 1 file changed, 104 insertions(+), 95 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 495ce0a51d2..8b8487c9694 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,117 +255,126 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * 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(struct spi_device *spi, + struct spi_message *m) { - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); - unsigned long flags; - struct spi_message *m, *_m; + struct spi_bitbang *bitbang; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned tmp; + unsigned cs_change; + int status; + int do_setup = -1; - 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; + bitbang = spi_master_get_devdata(spi->master); - 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; - /* 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; + tmp = 0; + cs_change = 1; + status = 0; - spi = m->spi; - tmp = 0; - cs_change = 1; - status = 0; + list_for_each_entry (t, &m->transfers, transfer_list) { - 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; - } + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; - /* 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; + /* 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); } + } + + m->status = status; + m->complete(m->context); + + /* 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); + } + + return status; +} + +static void bitbang_work(struct work_struct *work) +{ + struct spi_bitbang *bitbang = + container_of(work, struct spi_bitbang, work); + unsigned long flags; + struct spi_message *m, *_m; + + spin_lock_irqsave(&bitbang->lock, flags); + bitbang->busy = 1; + list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { + list_del(&m->queue); + spin_unlock_irqrestore(&bitbang->lock, flags); + + spi_bitbang_transfer_one(m->spi, m); spin_lock_irqsave(&bitbang->lock, flags); } -- cgit v1.2.3-70-g09d2 From 2025172e32808a327b00f968c72baa79adc594c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 20:07:27 +0100 Subject: spi/bitbang: Use core message pump Convert drivers using bitbang to use the core mesasge pump infrastructure, saving some code and meaning that these drivers get to take advantage of work done on improving the core implementation. Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 100 ++++++++++++---------------------------- include/linux/spi/spi_bitbang.h | 4 -- 2 files changed, 30 insertions(+), 74 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 8b8487c9694..c100875cfd4 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,6 +255,21 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ + +static int spi_bitbang_prepare_hardware(struct spi_master *spi) +{ + struct spi_bitbang *bitbang; + unsigned long flags; + + bitbang = spi_master_get_devdata(spi); + + spin_lock_irqsave(&bitbang->lock, flags); + bitbang->busy = 1; + spin_unlock_irqrestore(&bitbang->lock, flags); + + return 0; +} + static int spi_bitbang_transfer_one(struct spi_device *spi, struct spi_message *m) { @@ -346,7 +361,6 @@ static int spi_bitbang_transfer_one(struct spi_device *spi, } m->status = status; - m->complete(m->context); /* normally deactivate chipselect ... unless no error and * cs_change has hinted that the next message will probably @@ -358,54 +372,23 @@ static int spi_bitbang_transfer_one(struct spi_device *spi, ndelay(nsecs); } - return status; -} - -static void bitbang_work(struct work_struct *work) -{ - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); - unsigned long flags; - struct spi_message *m, *_m; - - spin_lock_irqsave(&bitbang->lock, flags); - bitbang->busy = 1; - list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { - list_del(&m->queue); - spin_unlock_irqrestore(&bitbang->lock, flags); - - spi_bitbang_transfer_one(m->spi, m); + spi_finalize_current_message(spi->master); - spin_lock_irqsave(&bitbang->lock, flags); - } - bitbang->busy = 0; - spin_unlock_irqrestore(&bitbang->lock, flags); + return status; } -/** - * spi_bitbang_transfer - default submit to transfer queue - */ -static int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) +static int spi_bitbang_unprepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang; + struct spi_bitbang *bitbang; unsigned long flags; - int status = 0; - - m->actual_length = 0; - m->status = -EINPROGRESS; - bitbang = spi_master_get_devdata(spi->master); + bitbang = spi_master_get_devdata(spi); 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; + return 0; } /*----------------------------------------------------------------------*/ @@ -436,20 +419,22 @@ static int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) 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; + if (master->transfer || master->transfer_one_message) + return -EINVAL; + + master->prepare_transfer_hardware = spi_bitbang_prepare_hardware; + master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware; + master->transfer_one_message = spi_bitbang_transfer_one; + if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; @@ -462,32 +447,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); @@ -498,10 +462,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 b5aa215493f..daebaba886a 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -4,11 +4,7 @@ #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 */ -- cgit v1.2.3-70-g09d2 From d60990d597bfa2816dfe28a5c5c6787610b423e6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 17 Jul 2013 15:49:54 -0300 Subject: spi: spi-bitbang: Fix conversion of spi_bitbang_transfer_one() Since commit 2025172e3 (spi/bitbang: Use core message pump), the following kernel crash is seen: Unable to handle kernel NULL pointer dereference at virtual address 0000000d pgd = 80004000 [0000000d] *pgd=00000000 Internal error: Oops: 5 [#1] SMP ARM Modules linked in: CPU: 1 PID: 48 Comm: spi32766 Not tainted 3.11.0-rc1+ #4 task: bfa3e580 ti: bfb90000 task.ti: bfb90000 PC is at spi_bitbang_transfer_one+0x50/0x248 LR is at spi_bitbang_transfer_one+0x20/0x248 ... ,and also the following build warning: drivers/spi/spi-bitbang.c: In function 'spi_bitbang_start': drivers/spi/spi-bitbang.c:436:31: warning: assignment from incompatible pointer type [enabled by default] In order to fix it, we need to change the first parameter of spi_bitbang_transfer_one() to 'struct spi_master *master'. Tested on a mx6qsabrelite by succesfully probing a SPI NOR flash. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index c100875cfd4..a89178dc849 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -270,7 +270,7 @@ static int spi_bitbang_prepare_hardware(struct spi_master *spi) return 0; } -static int spi_bitbang_transfer_one(struct spi_device *spi, +static int spi_bitbang_transfer_one(struct spi_master *master, struct spi_message *m) { struct spi_bitbang *bitbang; @@ -280,8 +280,9 @@ static int spi_bitbang_transfer_one(struct spi_device *spi, unsigned cs_change; int status; int do_setup = -1; + struct spi_device *spi = m->spi; - bitbang = spi_master_get_devdata(spi->master); + bitbang = spi_master_get_devdata(master); /* FIXME this is made-up ... the correct value is known to * word-at-a-time bitbang code, and presumably chipselect() @@ -372,7 +373,7 @@ static int spi_bitbang_transfer_one(struct spi_device *spi, ndelay(nsecs); } - spi_finalize_current_message(spi->master); + spi_finalize_current_message(master); return status; } -- cgit v1.2.3-70-g09d2 From 52ade736215fb4421a6dc2b6900703a6fadba9e9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 8 Aug 2013 16:09:49 +0200 Subject: spi/bitbang: don't error out if there is no setup callback provided MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's perfectly valid not to have a setup callback when the probe routine does all the needed things. So don't even check for this case and trust the caller. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a89178dc849..dd2e5d7332f 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -446,8 +446,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) master->setup = spi_bitbang_setup; master->cleanup = spi_bitbang_cleanup; } - } else if (!master->setup) - return -EINVAL; + } /* driver may get busy before register() returns, especially * if someone registered boardinfo for devices -- cgit v1.2.3-70-g09d2 From 2e29db400c4898ff72e2ea87d262921df00f1c87 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 15 Aug 2013 14:06:37 +0800 Subject: spi: bitbang: Remove unused tmp variable Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index dd2e5d7332f..e3946e44e07 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -276,7 +276,6 @@ static int spi_bitbang_transfer_one(struct spi_master *master, struct spi_bitbang *bitbang; unsigned nsecs; struct spi_transfer *t = NULL; - unsigned tmp; unsigned cs_change; int status; int do_setup = -1; @@ -290,7 +289,6 @@ static int spi_bitbang_transfer_one(struct spi_master *master, */ nsecs = 100; - tmp = 0; cs_change = 1; status = 0; -- cgit v1.2.3-70-g09d2 From 03ddcbc5d80443c9e0cf1b263b68b4df9759af18 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 7 Aug 2013 21:22:20 +0200 Subject: spi/bitbang: trivial: fix doubled word "use" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- drivers/spi/spi-bitbang.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi/spi-bitbang.c') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a63d7da3bfe..1c2ba17760b 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -40,7 +40,7 @@ * to glue code. These bitbang setup() and cleanup() routines are always * used, though maybe they're called from controller-aware code. * - * chipselect() and friends may use use spi_device->controller_data and + * chipselect() and friends may use spi_device->controller_data and * controller registers as appropriate. * * -- cgit v1.2.3-70-g09d2