diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-altera.c | 34 | ||||
-rw-r--r-- | drivers/spi/spi-atmel.c | 36 | ||||
-rw-r--r-- | drivers/spi/spi-bcm2835.c | 10 | ||||
-rw-r--r-- | drivers/spi/spi-bitbang.c | 260 | ||||
-rw-r--r-- | drivers/spi/spi-davinci.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-oc-tiny.c | 22 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 3 |
7 files changed, 158 insertions, 209 deletions
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 8a6bb37910da..156eb888655e 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -124,7 +124,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) hw->tx = t->tx_buf; hw->rx = t->rx_buf; hw->count = 0; - hw->bytes_per_word = t->bits_per_word / 8; + hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8); hw->len = t->len / hw->bytes_per_word; if (hw->irq >= 0) { @@ -140,12 +140,12 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); } else { - /* send the first byte */ - writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA); - - while (1) { + while (hw->count < hw->len) { unsigned int rxd; + writel(hw_txbyte(hw, hw->count), + hw->base + ALTERA_SPI_TXDATA); + while (!(readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)) cpu_relax(); @@ -164,14 +164,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) } hw->count++; - - if (hw->count < hw->len) - writel(hw_txbyte(hw, hw->count), - hw->base + ALTERA_SPI_TXDATA); - else - break; } - } return hw->count * hw->bytes_per_word; @@ -234,15 +227,11 @@ static int altera_spi_probe(struct platform_device *pdev) /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) - goto exit_busy; - hw->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!hw->base) - goto exit_busy; + hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base)) { + err = PTR_ERR(hw->base); + goto exit; + } /* program defaults into the registers */ hw->imr = 0; /* disable spi interrupts */ writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); @@ -269,9 +258,6 @@ static int altera_spi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); return 0; - -exit_busy: - err = -EBUSY; exit: spi_master_put(master); return err; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index ea1ec009f44d..fd7cc566095a 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -360,12 +360,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) gpio_set_value(asd->npcs_pin, !active); } -static void atmel_spi_lock(struct atmel_spi *as) +static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) { spin_lock_irqsave(&as->lock, as->flags); } -static void atmel_spi_unlock(struct atmel_spi *as) +static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock) { spin_unlock_irqrestore(&as->lock, as->flags); } @@ -629,9 +629,9 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, goto err_dma; dev_dbg(master->dev.parent, - " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, + xfer->rx_buf, (unsigned long long)xfer->rx_dma); /* Enable relevant interrupts */ spi_writel(as, IER, SPI_BIT(OVRES)); @@ -732,9 +732,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, TCR, len); dev_dbg(&msg->spi->dev, - " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); } else { xfer = as->next_transfer; remaining = as->next_remaining_bytes; @@ -771,9 +772,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, TNCR, len); dev_dbg(&msg->spi->dev, - " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES); } else { spi_writel(as, RNCR, 0); @@ -1579,7 +1581,9 @@ static int atmel_spi_probe(struct platform_device *pdev) goto out_unmap_regs; /* Initialize the hardware */ - clk_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + goto out_unmap_regs; spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ if (as->caps.has_wdrbt) { @@ -1609,7 +1613,7 @@ out_free_dma: spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - clk_disable(clk); + clk_disable_unprepare(clk); free_irq(irq, master); out_unmap_regs: iounmap(as->regs); @@ -1661,7 +1665,7 @@ static int atmel_spi_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, as->buffer_dma); - clk_disable(as->clk); + clk_disable_unprepare(as->clk); clk_put(as->clk); free_irq(as->irq, master); iounmap(as->regs); @@ -1678,7 +1682,7 @@ static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg) struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); - clk_disable(as->clk); + clk_disable_unprepare(as->clk); return 0; } @@ -1687,7 +1691,7 @@ static int atmel_spi_resume(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); - clk_enable(as->clk); + return clk_prepare_enable(as->clk); return 0; } diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index a4185e492321..52c81481c5c7 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -314,7 +314,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); master->mode_bits = BCM2835_SPI_MODE_BITS; - master->bits_per_word_mask = BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(8); master->bus_num = -1; master->num_chipselect = 3; master->transfer_one_message = bcm2835_spi_transfer_one; @@ -325,12 +325,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) init_completion(&bs->done); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "could not get memory resource\n"); - err = -ENODEV; - goto out_master_put; - } - bs->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); @@ -383,7 +377,7 @@ out_master_put: static int bcm2835_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct bcm2835_spi *bs = spi_master_get_devdata(master); free_irq(bs->irq, master); diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a63d7da3bfe2..e3946e44e076 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,150 +255,140 @@ 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_prepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); + struct spi_bitbang *bitbang; unsigned long flags; - struct spi_message *m, *_m; + + bitbang = spi_master_get_devdata(spi); 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; + return 0; +} - 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; - } +static int spi_bitbang_transfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct spi_bitbang *bitbang; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned cs_change; + int status; + int do_setup = -1; + struct spi_device *spi = m->spi; + + 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() + * should enforce these requirements too? + */ + nsecs = 100; - /* 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; + cs_change = 1; + status = 0; + + 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); } + } + + m->status = status; - spin_lock_irqsave(&bitbang->lock, flags); + /* 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); } - bitbang->busy = 0; - spin_unlock_irqrestore(&bitbang->lock, flags); + + spi_finalize_current_message(master); + + return status; } -/** - * spi_bitbang_transfer - default submit to transfer queue - */ -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; } -EXPORT_SYMBOL_GPL(spi_bitbang_transfer); /*----------------------------------------------------------------------*/ @@ -428,20 +418,22 @@ 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; + 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; @@ -452,34 +444,12 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) master->setup = spi_bitbang_setup; master->cleanup = spi_bitbang_cleanup; } - } 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 +460,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/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 222d3e37fc28..707966bd5610 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -609,7 +609,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) else buf = (void *)t->tx_buf; t->tx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_FROM_DEVICE); + t->len, DMA_TO_DEVICE); if (!t->tx_dma) { ret = -EFAULT; goto err_tx_map; diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 58deb79d046b..d36ba907743d 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -315,15 +315,11 @@ static int tiny_spi_probe(struct platform_device *pdev) /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) - goto exit_busy; - hw->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!hw->base) - goto exit_busy; + hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base)) { + err = PTR_ERR(hw->base); + goto exit; + } /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); if (hw->irq >= 0) { @@ -337,8 +333,10 @@ static int tiny_spi_probe(struct platform_device *pdev) if (platp) { hw->gpio_cs_count = platp->gpio_cs_count; hw->gpio_cs = platp->gpio_cs; - if (platp->gpio_cs_count && !platp->gpio_cs) - goto exit_busy; + if (platp->gpio_cs_count && !platp->gpio_cs) { + err = -EBUSY; + goto exit; + } hw->freq = platp->freq; hw->baudwidth = platp->baudwidth; } else { @@ -365,8 +363,6 @@ static int tiny_spi_probe(struct platform_device *pdev) exit_gpio: while (i-- > 0) gpio_free(hw->gpio_cs[i]); -exit_busy: - err = -EBUSY; exit: spi_master_put(master); return err; diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index eb53df27e7ea..63e2070c6c14 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -434,6 +434,9 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) dma_cap_mask_t mask; int ret; + if (is_polling(sdd)) + return 0; + dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); |