Commit ec37e8e1 authored by Baruch Siach's avatar Baruch Siach Committed by Mark Brown

spi: dw: migrate to generic queue infrastructure

Signed-off-by: default avatarBaruch Siach <baruch@tkos.co.il>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent c9eaa447
...@@ -36,9 +36,6 @@ ...@@ -36,9 +36,6 @@
#define DONE_STATE ((void *)2) #define DONE_STATE ((void *)2)
#define ERROR_STATE ((void *)-1) #define ERROR_STATE ((void *)-1)
#define QUEUE_RUNNING 0
#define QUEUE_STOPPED 1
#define MRST_SPI_DEASSERT 0 #define MRST_SPI_DEASSERT 0
#define MRST_SPI_ASSERT 1 #define MRST_SPI_ASSERT 1
...@@ -263,18 +260,14 @@ static int map_dma_buffers(struct dw_spi *dws) ...@@ -263,18 +260,14 @@ static int map_dma_buffers(struct dw_spi *dws)
static void giveback(struct dw_spi *dws) static void giveback(struct dw_spi *dws)
{ {
struct spi_transfer *last_transfer; struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg; struct spi_message *msg;
spin_lock_irqsave(&dws->lock, flags);
msg = dws->cur_msg; msg = dws->cur_msg;
dws->cur_msg = NULL; dws->cur_msg = NULL;
dws->cur_transfer = NULL; dws->cur_transfer = NULL;
dws->prev_chip = dws->cur_chip; dws->prev_chip = dws->cur_chip;
dws->cur_chip = NULL; dws->cur_chip = NULL;
dws->dma_mapped = 0; dws->dma_mapped = 0;
queue_work(dws->workqueue, &dws->pump_messages);
spin_unlock_irqrestore(&dws->lock, flags);
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list); transfer_list);
...@@ -282,9 +275,7 @@ static void giveback(struct dw_spi *dws) ...@@ -282,9 +275,7 @@ static void giveback(struct dw_spi *dws)
if (!last_transfer->cs_change && dws->cs_control) if (!last_transfer->cs_change && dws->cs_control)
dws->cs_control(MRST_SPI_DEASSERT); dws->cs_control(MRST_SPI_DEASSERT);
msg->state = NULL; spi_finalize_current_message(dws->master);
if (msg->complete)
msg->complete(msg->context);
} }
static void int_error_stop(struct dw_spi *dws, const char *msg) static void int_error_stop(struct dw_spi *dws, const char *msg)
...@@ -529,30 +520,12 @@ static void pump_transfers(unsigned long data) ...@@ -529,30 +520,12 @@ static void pump_transfers(unsigned long data)
return; return;
} }
static void pump_messages(struct work_struct *work) static int dw_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{ {
struct dw_spi *dws = struct dw_spi *dws = spi_master_get_devdata(master);
container_of(work, struct dw_spi, pump_messages);
unsigned long flags;
/* Lock queue and check for queue work */
spin_lock_irqsave(&dws->lock, flags);
if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
dws->busy = 0;
spin_unlock_irqrestore(&dws->lock, flags);
return;
}
/* Make sure we are not already running a message */
if (dws->cur_msg) {
spin_unlock_irqrestore(&dws->lock, flags);
return;
}
/* Extract head of queue */
dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
list_del_init(&dws->cur_msg->queue);
dws->cur_msg = msg;
/* Initial message state*/ /* Initial message state*/
dws->cur_msg->state = START_STATE; dws->cur_msg->state = START_STATE;
dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
...@@ -560,46 +533,9 @@ static void pump_messages(struct work_struct *work) ...@@ -560,46 +533,9 @@ static void pump_messages(struct work_struct *work)
transfer_list); transfer_list);
dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
/* Mark as busy and launch transfers */ /* Launch transfers */
tasklet_schedule(&dws->pump_transfers); tasklet_schedule(&dws->pump_transfers);
dws->busy = 1;
spin_unlock_irqrestore(&dws->lock, flags);
}
/* spi_device use this to queue in their spi_msg */
static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct dw_spi *dws = spi_master_get_devdata(spi->master);
unsigned long flags;
spin_lock_irqsave(&dws->lock, flags);
if (dws->run == QUEUE_STOPPED) {
spin_unlock_irqrestore(&dws->lock, flags);
return -ESHUTDOWN;
}
msg->actual_length = 0;
msg->status = -EINPROGRESS;
msg->state = START_STATE;
list_add_tail(&msg->queue, &dws->queue);
if (dws->run == QUEUE_RUNNING && !dws->busy) {
if (dws->cur_transfer || dws->cur_msg)
queue_work(dws->workqueue,
&dws->pump_messages);
else {
/* If no other data transaction in air, just go */
spin_unlock_irqrestore(&dws->lock, flags);
pump_messages(&dws->pump_messages);
return 0;
}
}
spin_unlock_irqrestore(&dws->lock, flags);
return 0; return 0;
} }
...@@ -664,79 +600,10 @@ static int dw_spi_setup(struct spi_device *spi) ...@@ -664,79 +600,10 @@ static int dw_spi_setup(struct spi_device *spi)
return 0; return 0;
} }
static int init_queue(struct dw_spi *dws) static void dw_spi_cleanup(struct spi_device *spi)
{ {
INIT_LIST_HEAD(&dws->queue); struct chip_data *chip = spi_get_ctldata(spi);
spin_lock_init(&dws->lock); kfree(chip);
dws->run = QUEUE_STOPPED;
dws->busy = 0;
tasklet_init(&dws->pump_transfers,
pump_transfers, (unsigned long)dws);
INIT_WORK(&dws->pump_messages, pump_messages);
dws->workqueue = create_singlethread_workqueue(
dev_name(dws->master->dev.parent));
if (dws->workqueue == NULL)
return -EBUSY;
return 0;
}
static int start_queue(struct dw_spi *dws)
{
unsigned long flags;
spin_lock_irqsave(&dws->lock, flags);
if (dws->run == QUEUE_RUNNING || dws->busy) {
spin_unlock_irqrestore(&dws->lock, flags);
return -EBUSY;
}
dws->run = QUEUE_RUNNING;
dws->cur_msg = NULL;
dws->cur_transfer = NULL;
dws->cur_chip = NULL;
dws->prev_chip = NULL;
spin_unlock_irqrestore(&dws->lock, flags);
queue_work(dws->workqueue, &dws->pump_messages);
return 0;
}
static int stop_queue(struct dw_spi *dws)
{
unsigned long flags;
unsigned limit = 50;
int status = 0;
spin_lock_irqsave(&dws->lock, flags);
dws->run = QUEUE_STOPPED;
while ((!list_empty(&dws->queue) || dws->busy) && limit--) {
spin_unlock_irqrestore(&dws->lock, flags);
msleep(10);
spin_lock_irqsave(&dws->lock, flags);
}
if (!list_empty(&dws->queue) || dws->busy)
status = -EBUSY;
spin_unlock_irqrestore(&dws->lock, flags);
return status;
}
static int destroy_queue(struct dw_spi *dws)
{
int status;
status = stop_queue(dws);
if (status != 0)
return status;
destroy_workqueue(dws->workqueue);
return 0;
} }
/* Restart the controller, disable all interrupts, clean rx fifo */ /* Restart the controller, disable all interrupts, clean rx fifo */
...@@ -794,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -794,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->bus_num = dws->bus_num; master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs; master->num_chipselect = dws->num_cs;
master->setup = dw_spi_setup; master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer; master->transfer_one_message = dw_spi_transfer_one_message;
master->max_speed_hz = dws->max_freq; master->max_speed_hz = dws->max_freq;
/* Basic HW init */ /* Basic HW init */
...@@ -808,33 +675,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -808,33 +675,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
} }
} }
/* Initial and start queue */ tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws);
ret = init_queue(dws);
if (ret) {
dev_err(&master->dev, "problem initializing queue\n");
goto err_diable_hw;
}
ret = start_queue(dws);
if (ret) {
dev_err(&master->dev, "problem starting queue\n");
goto err_diable_hw;
}
spi_master_set_devdata(master, dws); spi_master_set_devdata(master, dws);
ret = devm_spi_register_master(dev, master); ret = devm_spi_register_master(dev, master);
if (ret) { if (ret) {
dev_err(&master->dev, "problem registering spi master\n"); dev_err(&master->dev, "problem registering spi master\n");
goto err_queue_alloc; goto err_dma_exit;
} }
mrst_spi_debugfs_init(dws); mrst_spi_debugfs_init(dws);
return 0; return 0;
err_queue_alloc: err_dma_exit:
destroy_queue(dws);
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
err_diable_hw:
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
err_free_master: err_free_master:
spi_master_put(master); spi_master_put(master);
...@@ -844,18 +699,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); ...@@ -844,18 +699,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host);
void dw_spi_remove_host(struct dw_spi *dws) void dw_spi_remove_host(struct dw_spi *dws)
{ {
int status = 0;
if (!dws) if (!dws)
return; return;
mrst_spi_debugfs_remove(dws); mrst_spi_debugfs_remove(dws);
/* Remove the queue */
status = destroy_queue(dws);
if (status != 0)
dev_err(&dws->master->dev,
"dw_spi_remove: workqueue will not complete, message memory not freed\n");
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
...@@ -868,7 +715,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) ...@@ -868,7 +715,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
{ {
int ret = 0; int ret = 0;
ret = stop_queue(dws); ret = spi_master_suspend(dws->master);
if (ret) if (ret)
return ret; return ret;
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
...@@ -882,7 +729,7 @@ int dw_spi_resume_host(struct dw_spi *dws) ...@@ -882,7 +729,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
int ret; int ret;
spi_hw_init(dws); spi_hw_init(dws);
ret = start_queue(dws); ret = spi_master_resume(dws->master);
if (ret) if (ret)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
return ret; return ret;
......
...@@ -104,14 +104,6 @@ struct dw_spi { ...@@ -104,14 +104,6 @@ struct dw_spi {
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
/* Driver message queue */
struct workqueue_struct *workqueue;
struct work_struct pump_messages;
spinlock_t lock;
struct list_head queue;
int busy;
int run;
/* Message Transfer pump */ /* Message Transfer pump */
struct tasklet_struct pump_transfers; struct tasklet_struct pump_transfers;
......
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