Commit 8328509c authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'spi/topic/img-spfi', 'spi/topic/imx',...

Merge remote-tracking branches 'spi/topic/img-spfi', 'spi/topic/imx', 'spi/topic/inline', 'spi/topic/meson' and 'spi/topic/mxs' into spi-next
...@@ -160,16 +160,16 @@ static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, ...@@ -160,16 +160,16 @@ static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
unsigned int count = 0; unsigned int count = 0;
u32 status; u32 status;
while (count < max) { while (count < max / 4) {
spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR);
status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
if (status & SPFI_INTERRUPT_SDFUL) if (status & SPFI_INTERRUPT_SDFUL)
break; break;
spfi_writel(spfi, buf[count / 4], SPFI_TX_32BIT_VALID_DATA); spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA);
count += 4; count++;
} }
return count; return count * 4;
} }
static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf,
...@@ -196,17 +196,17 @@ static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, ...@@ -196,17 +196,17 @@ static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf,
unsigned int count = 0; unsigned int count = 0;
u32 status; u32 status;
while (count < max) { while (count < max / 4) {
spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT,
SPFI_INTERRUPT_CLEAR); SPFI_INTERRUPT_CLEAR);
status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
if (!(status & SPFI_INTERRUPT_GDEX32BIT)) if (!(status & SPFI_INTERRUPT_GDEX32BIT))
break; break;
buf[count / 4] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA);
count += 4; count++;
} }
return count; return count * 4;
} }
static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf,
...@@ -251,17 +251,15 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -251,17 +251,15 @@ static int img_spfi_start_pio(struct spi_master *master,
time_before(jiffies, timeout)) { time_before(jiffies, timeout)) {
unsigned int tx_count, rx_count; unsigned int tx_count, rx_count;
switch (xfer->bits_per_word) { if (tx_bytes >= 4)
case 32:
tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes);
rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); else
break;
case 8:
default:
tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes);
if (rx_bytes >= 4)
rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes);
else
rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes);
break;
}
tx_buf += tx_count; tx_buf += tx_count;
rx_buf += rx_count; rx_buf += rx_count;
...@@ -331,14 +329,11 @@ static int img_spfi_start_dma(struct spi_master *master, ...@@ -331,14 +329,11 @@ static int img_spfi_start_dma(struct spi_master *master,
if (xfer->rx_buf) { if (xfer->rx_buf) {
rxconf.direction = DMA_DEV_TO_MEM; rxconf.direction = DMA_DEV_TO_MEM;
switch (xfer->bits_per_word) { if (xfer->len % 4 == 0) {
case 32:
rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA;
rxconf.src_addr_width = 4; rxconf.src_addr_width = 4;
rxconf.src_maxburst = 4; rxconf.src_maxburst = 4;
break; } else {
case 8:
default:
rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA;
rxconf.src_addr_width = 1; rxconf.src_addr_width = 1;
rxconf.src_maxburst = 4; rxconf.src_maxburst = 4;
...@@ -358,18 +353,14 @@ static int img_spfi_start_dma(struct spi_master *master, ...@@ -358,18 +353,14 @@ static int img_spfi_start_dma(struct spi_master *master,
if (xfer->tx_buf) { if (xfer->tx_buf) {
txconf.direction = DMA_MEM_TO_DEV; txconf.direction = DMA_MEM_TO_DEV;
switch (xfer->bits_per_word) { if (xfer->len % 4 == 0) {
case 32:
txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA;
txconf.dst_addr_width = 4; txconf.dst_addr_width = 4;
txconf.dst_maxburst = 4; txconf.dst_maxburst = 4;
break; } else {
case 8:
default:
txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA;
txconf.dst_addr_width = 1; txconf.dst_addr_width = 1;
txconf.dst_maxburst = 4; txconf.dst_maxburst = 4;
break;
} }
dmaengine_slave_config(spfi->tx_ch, &txconf); dmaengine_slave_config(spfi->tx_ch, &txconf);
...@@ -508,9 +499,7 @@ static void img_spfi_set_cs(struct spi_device *spi, bool enable) ...@@ -508,9 +499,7 @@ static void img_spfi_set_cs(struct spi_device *spi, bool enable)
static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
if (xfer->bits_per_word == 8 && xfer->len > SPFI_8BIT_FIFO_SIZE) if (xfer->len > SPFI_32BIT_FIFO_SIZE)
return true;
if (xfer->bits_per_word == 32 && xfer->len > SPFI_32BIT_FIFO_SIZE)
return true; return true;
return false; return false;
} }
......
...@@ -89,7 +89,6 @@ struct spi_imx_data { ...@@ -89,7 +89,6 @@ struct spi_imx_data {
struct completion xfer_done; struct completion xfer_done;
void __iomem *base; void __iomem *base;
int irq;
struct clk *clk_per; struct clk *clk_per;
struct clk *clk_ipg; struct clk *clk_ipg;
unsigned long spi_clk; unsigned long spi_clk;
...@@ -896,6 +895,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -896,6 +895,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
{ {
struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
int ret; int ret;
unsigned long timeout;
u32 dma; u32 dma;
int left; int left;
struct spi_master *master = spi_imx->bitbang.master; struct spi_master *master = spi_imx->bitbang.master;
...@@ -943,17 +943,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -943,17 +943,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
dma_async_issue_pending(master->dma_tx); dma_async_issue_pending(master->dma_tx);
dma_async_issue_pending(master->dma_rx); dma_async_issue_pending(master->dma_rx);
/* Wait SDMA to finish the data transfer.*/ /* Wait SDMA to finish the data transfer.*/
ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion, timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
IMX_DMA_TIMEOUT); IMX_DMA_TIMEOUT);
if (!ret) { if (!timeout) {
pr_warn("%s %s: I/O Error in DMA TX\n", pr_warn("%s %s: I/O Error in DMA TX\n",
dev_driver_string(&master->dev), dev_driver_string(&master->dev),
dev_name(&master->dev)); dev_name(&master->dev));
dmaengine_terminate_all(master->dma_tx); dmaengine_terminate_all(master->dma_tx);
} else { } else {
ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion, timeout = wait_for_completion_timeout(
IMX_DMA_TIMEOUT); &spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
if (!ret) { if (!timeout) {
pr_warn("%s %s: I/O Error in DMA RX\n", pr_warn("%s %s: I/O Error in DMA RX\n",
dev_driver_string(&master->dev), dev_driver_string(&master->dev),
dev_name(&master->dev)); dev_name(&master->dev));
...@@ -968,9 +968,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -968,9 +968,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
spi_imx->dma_finished = 1; spi_imx->dma_finished = 1;
spi_imx->devtype_data->trigger(spi_imx); spi_imx->devtype_data->trigger(spi_imx);
if (!ret) if (!timeout)
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
else if (ret > 0) else
ret = transfer->len; ret = transfer->len;
return ret; return ret;
...@@ -1080,7 +1080,7 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1080,7 +1080,7 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_master *master; struct spi_master *master;
struct spi_imx_data *spi_imx; struct spi_imx_data *spi_imx;
struct resource *res; struct resource *res;
int i, ret, num_cs; int i, ret, num_cs, irq;
if (!np && !mxc_platform_info) { if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n"); dev_err(&pdev->dev, "can't get the platform data\n");
...@@ -1147,16 +1147,16 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1147,16 +1147,16 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_master_put; goto out_master_put;
} }
spi_imx->irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) { if (irq < 0) {
ret = spi_imx->irq; ret = irq;
goto out_master_put; goto out_master_put;
} }
ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0,
dev_name(&pdev->dev), spi_imx); dev_name(&pdev->dev), spi_imx);
if (ret) { if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
goto out_master_put; goto out_master_put;
} }
......
...@@ -85,7 +85,7 @@ struct meson_spifc { ...@@ -85,7 +85,7 @@ struct meson_spifc {
struct device *dev; struct device *dev;
}; };
static struct regmap_config spifc_regmap_config = { static const struct regmap_config spifc_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.val_bits = 32, .val_bits = 32,
.reg_stride = 4, .reg_stride = 4,
......
...@@ -282,9 +282,8 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, ...@@ -282,9 +282,8 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
dmaengine_submit(desc); dmaengine_submit(desc);
dma_async_issue_pending(ssp->dmach); dma_async_issue_pending(ssp->dmach);
ret = wait_for_completion_timeout(&spi->c, if (!wait_for_completion_timeout(&spi->c,
msecs_to_jiffies(SSP_TIMEOUT)); msecs_to_jiffies(SSP_TIMEOUT))) {
if (!ret) {
dev_err(ssp->dev, "DMA transfer timeout\n"); dev_err(ssp->dev, "DMA transfer timeout\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
dmaengine_terminate_all(ssp->dmach); dmaengine_terminate_all(ssp->dmach);
......
...@@ -871,31 +871,59 @@ void spi_finalize_current_transfer(struct spi_master *master) ...@@ -871,31 +871,59 @@ void spi_finalize_current_transfer(struct spi_master *master)
EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
/** /**
* spi_pump_messages - kthread work function which processes spi message queue * __spi_pump_messages - function which processes spi message queue
* @work: pointer to kthread work struct contained in the master struct * @master: master to process queue for
* @in_kthread: true if we are in the context of the message pump thread
* *
* This function checks if there is any spi message in the queue that * This function checks if there is any spi message in the queue that
* needs processing and if so call out to the driver to initialize hardware * needs processing and if so call out to the driver to initialize hardware
* and transfer each message. * and transfer each message.
* *
* Note that it is called both from the kthread itself and also from
* inside spi_sync(); the queue extraction handling at the top of the
* function should deal with this safely.
*/ */
static void spi_pump_messages(struct kthread_work *work) static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
{ {
struct spi_master *master =
container_of(work, struct spi_master, pump_messages);
unsigned long flags; unsigned long flags;
bool was_busy = false; bool was_busy = false;
int ret; int ret;
/* Lock queue and check for queue work */ /* Lock queue */
spin_lock_irqsave(&master->queue_lock, flags); spin_lock_irqsave(&master->queue_lock, flags);
/* Make sure we are not already running a message */
if (master->cur_msg) {
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
/* If another context is idling the device then defer */
if (master->idling) {
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
/* Check if the queue is idle */
if (list_empty(&master->queue) || !master->running) { if (list_empty(&master->queue) || !master->running) {
if (!master->busy) { if (!master->busy) {
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
return; return;
} }
/* Only do teardown in the thread */
if (!in_kthread) {
queue_kthread_work(&master->kworker,
&master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
master->busy = false; master->busy = false;
master->idling = true;
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
kfree(master->dummy_rx); kfree(master->dummy_rx);
master->dummy_rx = NULL; master->dummy_rx = NULL;
kfree(master->dummy_tx); kfree(master->dummy_tx);
...@@ -909,14 +937,13 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -909,14 +937,13 @@ static void spi_pump_messages(struct kthread_work *work)
pm_runtime_put_autosuspend(master->dev.parent); pm_runtime_put_autosuspend(master->dev.parent);
} }
trace_spi_master_idle(master); trace_spi_master_idle(master);
return;
}
/* Make sure we are not already running a message */ spin_lock_irqsave(&master->queue_lock, flags);
if (master->cur_msg) { master->idling = false;
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
return; return;
} }
/* Extract head of queue */ /* Extract head of queue */
master->cur_msg = master->cur_msg =
list_first_entry(&master->queue, struct spi_message, queue); list_first_entry(&master->queue, struct spi_message, queue);
...@@ -981,13 +1008,22 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -981,13 +1008,22 @@ static void spi_pump_messages(struct kthread_work *work)
} }
} }
/**
* spi_pump_messages - kthread work function which processes spi message queue
* @work: pointer to kthread work struct contained in the master struct
*/
static void spi_pump_messages(struct kthread_work *work)
{
struct spi_master *master =
container_of(work, struct spi_master, pump_messages);
__spi_pump_messages(master, true);
}
static int spi_init_queue(struct spi_master *master) static int spi_init_queue(struct spi_master *master)
{ {
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
INIT_LIST_HEAD(&master->queue);
spin_lock_init(&master->queue_lock);
master->running = false; master->running = false;
master->busy = false; master->busy = false;
...@@ -1157,12 +1193,9 @@ static int spi_destroy_queue(struct spi_master *master) ...@@ -1157,12 +1193,9 @@ static int spi_destroy_queue(struct spi_master *master)
return 0; return 0;
} }
/** static int __spi_queued_transfer(struct spi_device *spi,
* spi_queued_transfer - transfer function for queued transfers struct spi_message *msg,
* @spi: spi device which is requesting transfer bool need_pump)
* @msg: spi message which is to handled is queued to driver queue
*/
static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{ {
struct spi_master *master = spi->master; struct spi_master *master = spi->master;
unsigned long flags; unsigned long flags;
...@@ -1177,13 +1210,23 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -1177,13 +1210,23 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
msg->status = -EINPROGRESS; msg->status = -EINPROGRESS;
list_add_tail(&msg->queue, &master->queue); list_add_tail(&msg->queue, &master->queue);
if (!master->busy) if (!master->busy && need_pump)
queue_kthread_work(&master->kworker, &master->pump_messages); queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
return 0; return 0;
} }
/**
* spi_queued_transfer - transfer function for queued transfers
* @spi: spi device which is requesting transfer
* @msg: spi message which is to handled is queued to driver queue
*/
static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
return __spi_queued_transfer(spi, msg, true);
}
static int spi_master_initialize_queue(struct spi_master *master) static int spi_master_initialize_queue(struct spi_master *master)
{ {
int ret; int ret;
...@@ -1605,6 +1648,8 @@ int spi_register_master(struct spi_master *master) ...@@ -1605,6 +1648,8 @@ int spi_register_master(struct spi_master *master)
dynamic = 1; dynamic = 1;
} }
INIT_LIST_HEAD(&master->queue);
spin_lock_init(&master->queue_lock);
spin_lock_init(&master->bus_lock_spinlock); spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex); mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0; master->bus_lock_flag = 0;
...@@ -2110,19 +2155,46 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2110,19 +2155,46 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
DECLARE_COMPLETION_ONSTACK(done); DECLARE_COMPLETION_ONSTACK(done);
int status; int status;
struct spi_master *master = spi->master; struct spi_master *master = spi->master;
unsigned long flags;
status = __spi_validate(spi, message);
if (status != 0)
return status;
message->complete = spi_complete; message->complete = spi_complete;
message->context = &done; message->context = &done;
message->spi = spi;
if (!bus_locked) if (!bus_locked)
mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->bus_lock_mutex);
status = spi_async_locked(spi, message); /* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the
* support for driver implemented message queues.
*/
if (master->transfer == spi_queued_transfer) {
spin_lock_irqsave(&master->bus_lock_spinlock, flags);
trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false);
spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
} else {
status = spi_async_locked(spi, message);
}
if (!bus_locked) if (!bus_locked)
mutex_unlock(&master->bus_lock_mutex); mutex_unlock(&master->bus_lock_mutex);
if (status == 0) { if (status == 0) {
/* Push out the messages in the calling context if we
* can.
*/
if (master->transfer == spi_queued_transfer)
__spi_pump_messages(master, false);
wait_for_completion(&done); wait_for_completion(&done);
status = message->status; status = message->status;
} }
......
...@@ -256,6 +256,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -256,6 +256,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @pump_messages: work struct for scheduling work to the message pump * @pump_messages: work struct for scheduling work to the message pump
* @queue_lock: spinlock to syncronise access to message queue * @queue_lock: spinlock to syncronise access to message queue
* @queue: message queue * @queue: message queue
* @idling: the device is entering idle state
* @cur_msg: the currently in-flight message * @cur_msg: the currently in-flight message
* @cur_msg_prepared: spi_prepare_message was called for the currently * @cur_msg_prepared: spi_prepare_message was called for the currently
* in-flight message * in-flight message
...@@ -421,6 +422,7 @@ struct spi_master { ...@@ -421,6 +422,7 @@ struct spi_master {
spinlock_t queue_lock; spinlock_t queue_lock;
struct list_head queue; struct list_head queue;
struct spi_message *cur_msg; struct spi_message *cur_msg;
bool idling;
bool busy; bool busy;
bool running; bool running;
bool rt; bool rt;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment