Commit ba59a807 authored by Andrew Lunn's avatar Andrew Lunn Committed by Mark Brown

spi: Refactor spi-orion to use SPI framework queue.

Replace the deprecated master->transfer with transfer_one_message()
and allow the SPI subsystem handle all the queuing of messages.
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Acked-by: default avatarSebastian Hesselbarth <sebastian.hesselbarth@googlemail.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent d9875690
...@@ -36,12 +36,6 @@ ...@@ -36,12 +36,6 @@
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F #define ORION_SPI_CLK_PRESCALE_MASK 0x1F
struct orion_spi { struct orion_spi {
struct work_struct work;
/* Lock access to transfer list. */
spinlock_t lock;
struct list_head msg_queue;
struct spi_master *master; struct spi_master *master;
void __iomem *base; void __iomem *base;
unsigned int max_speed; unsigned int max_speed;
...@@ -49,8 +43,6 @@ struct orion_spi { ...@@ -49,8 +43,6 @@ struct orion_spi {
struct clk *clk; struct clk *clk;
}; };
static struct workqueue_struct *orion_spi_wq;
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
{ {
return orion_spi->base + reg; return orion_spi->base + reg;
...@@ -277,73 +269,78 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -277,73 +269,78 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
} }
static void orion_spi_work(struct work_struct *work) static int orion_spi_transfer_one_message(struct spi_master *master,
struct spi_message *m)
{ {
struct orion_spi *orion_spi = struct orion_spi *orion_spi = spi_master_get_devdata(master);
container_of(work, struct orion_spi, work); struct spi_device *spi = m->spi;
struct spi_transfer *t = NULL;
spin_lock_irq(&orion_spi->lock); int par_override = 0;
while (!list_empty(&orion_spi->msg_queue)) { int status = 0;
struct spi_message *m; int cs_active = 0;
struct spi_device *spi;
struct spi_transfer *t = NULL;
int par_override = 0;
int status = 0;
int cs_active = 0;
m = container_of(orion_spi->msg_queue.next, struct spi_message,
queue);
list_del_init(&m->queue); /* Load defaults */
spin_unlock_irq(&orion_spi->lock); status = orion_spi_setup_transfer(spi, NULL);
spi = m->spi; if (status < 0)
goto msg_done;
/* Load defaults */ list_for_each_entry(t, &m->transfers, transfer_list) {
status = orion_spi_setup_transfer(spi, NULL); /* make sure buffer length is even when working in 16
* bit mode*/
if ((t->bits_per_word == 16) && (t->len & 1)) {
dev_err(&spi->dev,
"message rejected : "
"odd data length %d while in 16 bit mode\n",
t->len);
status = -EIO;
goto msg_done;
}
if (status < 0) if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev,
"message rejected : "
"device min speed (%d Hz) exceeds "
"required transfer speed (%d Hz)\n",
orion_spi->min_speed, t->speed_hz);
status = -EIO;
goto msg_done; goto msg_done;
}
list_for_each_entry(t, &m->transfers, transfer_list) { if (par_override || t->speed_hz || t->bits_per_word) {
if (par_override || t->speed_hz || t->bits_per_word) { par_override = 1;
par_override = 1; status = orion_spi_setup_transfer(spi, t);
status = orion_spi_setup_transfer(spi, t); if (status < 0)
if (status < 0) break;
break; if (!t->speed_hz && !t->bits_per_word)
if (!t->speed_hz && !t->bits_per_word) par_override = 0;
par_override = 0;
}
if (!cs_active) {
orion_spi_set_cs(orion_spi, 1);
cs_active = 1;
}
if (t->len)
m->actual_length +=
orion_spi_write_read(spi, t);
if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change) {
orion_spi_set_cs(orion_spi, 0);
cs_active = 0;
}
} }
msg_done: if (!cs_active) {
if (cs_active) orion_spi_set_cs(orion_spi, 1);
orion_spi_set_cs(orion_spi, 0); cs_active = 1;
}
m->status = status; if (t->len)
m->complete(m->context); m->actual_length += orion_spi_write_read(spi, t);
spin_lock_irq(&orion_spi->lock); if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change) {
orion_spi_set_cs(orion_spi, 0);
cs_active = 0;
}
} }
spin_unlock_irq(&orion_spi->lock); msg_done:
if (cs_active)
orion_spi_set_cs(orion_spi, 0);
m->status = status;
spi_finalize_current_message(master);
return 0;
} }
static int __init orion_spi_reset(struct orion_spi *orion_spi) static int __init orion_spi_reset(struct orion_spi *orion_spi)
...@@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi) ...@@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi)
return 0; return 0;
} }
static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct orion_spi *orion_spi;
struct spi_transfer *t = NULL;
unsigned long flags;
m->actual_length = 0;
m->status = 0;
/* reject invalid messages and transfers */
if (list_empty(&m->transfers) || !m->complete)
return -EINVAL;
orion_spi = spi_master_get_devdata(spi->master);
list_for_each_entry(t, &m->transfers, transfer_list) {
unsigned int bits_per_word = spi->bits_per_word;
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
dev_err(&spi->dev,
"message rejected : "
"invalid transfer data buffers\n");
goto msg_rejected;
}
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
if ((bits_per_word != 8) && (bits_per_word != 16)) {
dev_err(&spi->dev,
"message rejected : "
"invalid transfer bits_per_word (%d bits)\n",
bits_per_word);
goto msg_rejected;
}
/*make sure buffer length is even when working in 16 bit mode*/
if ((t->bits_per_word == 16) && (t->len & 1)) {
dev_err(&spi->dev,
"message rejected : "
"odd data length (%d) while in 16 bit mode\n",
t->len);
goto msg_rejected;
}
if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev,
"message rejected : "
"device min speed (%d Hz) exceeds "
"required transfer speed (%d Hz)\n",
orion_spi->min_speed, t->speed_hz);
goto msg_rejected;
}
}
spin_lock_irqsave(&orion_spi->lock, flags);
list_add_tail(&m->queue, &orion_spi->msg_queue);
queue_work(orion_spi_wq, &orion_spi->work);
spin_unlock_irqrestore(&orion_spi->lock, flags);
return 0;
msg_rejected:
/* Message rejected and not queued */
m->status = -EINVAL;
if (m->complete)
m->complete(m->context);
return -EINVAL;
}
static int __init orion_spi_probe(struct platform_device *pdev) static int __init orion_spi_probe(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
...@@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) ...@@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
master->mode_bits = 0; master->mode_bits = 0;
master->setup = orion_spi_setup; master->setup = orion_spi_setup;
master->transfer = orion_spi_transfer; master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS; master->num_chipselect = ORION_NUM_CHIPSELECTS;
dev_set_drvdata(&pdev->dev, master); dev_set_drvdata(&pdev->dev, master);
...@@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev) ...@@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev)
} }
spi->base = ioremap(r->start, SZ_1K); spi->base = ioremap(r->start, SZ_1K);
INIT_WORK(&spi->work, orion_spi_work);
spin_lock_init(&spi->lock);
INIT_LIST_HEAD(&spi->msg_queue);
if (orion_spi_reset(spi) < 0) if (orion_spi_reset(spi) < 0)
goto out_rel_mem; goto out_rel_mem;
...@@ -536,14 +459,12 @@ static int __init orion_spi_probe(struct platform_device *pdev) ...@@ -536,14 +459,12 @@ static int __init orion_spi_probe(struct platform_device *pdev)
static int __exit orion_spi_remove(struct platform_device *pdev) static int __exit orion_spi_remove(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
struct orion_spi *spi;
struct resource *r; struct resource *r;
struct orion_spi *spi;
master = dev_get_drvdata(&pdev->dev); master = dev_get_drvdata(&pdev->dev);
spi = spi_master_get_devdata(master); spi = spi_master_get_devdata(master);
cancel_work_sync(&spi->work);
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
clk_put(spi->clk); clk_put(spi->clk);
...@@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = { ...@@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = {
static int __init orion_spi_init(void) static int __init orion_spi_init(void)
{ {
orion_spi_wq = create_singlethread_workqueue(
orion_spi_driver.driver.name);
if (orion_spi_wq == NULL)
return -ENOMEM;
return platform_driver_probe(&orion_spi_driver, orion_spi_probe); return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
} }
module_init(orion_spi_init); module_init(orion_spi_init);
static void __exit orion_spi_exit(void) static void __exit orion_spi_exit(void)
{ {
flush_workqueue(orion_spi_wq);
platform_driver_unregister(&orion_spi_driver); platform_driver_unregister(&orion_spi_driver);
destroy_workqueue(orion_spi_wq);
} }
module_exit(orion_spi_exit); module_exit(orion_spi_exit);
......
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