Commit 19655dd0 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'spi/topic/img-spfi' into spi-next

parents e897f795 8c2c8c03
...@@ -14,6 +14,7 @@ Required properties: ...@@ -14,6 +14,7 @@ Required properties:
- dma-names: Must include the following entries: - dma-names: Must include the following entries:
- rx - rx
- tx - tx
- cs-gpios: Must specify the GPIOs used for chipselect lines.
- #address-cells: Must be 1. - #address-cells: Must be 1.
- #size-cells: Must be 0. - #size-cells: Must be 0.
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi) ...@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi)
spfi_writel(spfi, val, SPFI_CONTROL); spfi_writel(spfi, val, SPFI_CONTROL);
} }
static inline void spfi_stop(struct img_spfi *spfi)
{
u32 val;
val = spfi_readl(spfi, SPFI_CONTROL);
val &= ~SPFI_CONTROL_SPFI_EN;
spfi_writel(spfi, val, SPFI_CONTROL);
}
static inline void spfi_reset(struct img_spfi *spfi) static inline void spfi_reset(struct img_spfi *spfi)
{ {
spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
udelay(1);
spfi_writel(spfi, 0, SPFI_CONTROL); spfi_writel(spfi, 0, SPFI_CONTROL);
} }
static void spfi_flush_tx_fifo(struct img_spfi *spfi) static int spfi_wait_all_done(struct img_spfi *spfi)
{ {
unsigned long timeout = jiffies + msecs_to_jiffies(10); unsigned long timeout = jiffies + msecs_to_jiffies(50);
spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR);
while (time_before(jiffies, timeout)) { while (time_before(jiffies, timeout)) {
if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
SPFI_INTERRUPT_SDE)
return; if (status & SPFI_INTERRUPT_ALLDONETRIG) {
spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
SPFI_INTERRUPT_CLEAR);
return 0;
}
cpu_relax(); cpu_relax();
} }
dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n"); dev_err(spfi->dev, "Timed out waiting for transaction to complete\n");
spfi_reset(spfi); spfi_reset(spfi);
return -ETIMEDOUT;
} }
static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
...@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master,
const void *tx_buf = xfer->tx_buf; const void *tx_buf = xfer->tx_buf;
void *rx_buf = xfer->rx_buf; void *rx_buf = xfer->rx_buf;
unsigned long timeout; unsigned long timeout;
int ret;
if (tx_buf) if (tx_buf)
tx_bytes = xfer->len; tx_bytes = xfer->len;
...@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax(); cpu_relax();
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
if (rx_bytes > 0 || tx_bytes > 0) { if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n"); dev_err(spfi->dev, "PIO transfer timed out\n");
spfi_reset(spfi);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
if (tx_buf)
spfi_flush_tx_fifo(spfi);
spfi_stop(spfi);
return 0; return 0;
} }
...@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data) ...@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data)
struct img_spfi *spfi = data; struct img_spfi *spfi = data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&spfi->lock, flags); spfi_wait_all_done(spfi);
spin_lock_irqsave(&spfi->lock, flags);
spfi->rx_dma_busy = false; spfi->rx_dma_busy = false;
if (!spfi->tx_dma_busy) { if (!spfi->tx_dma_busy)
spfi_stop(spfi);
spi_finalize_current_transfer(spfi->master); spi_finalize_current_transfer(spfi->master);
}
spin_unlock_irqrestore(&spfi->lock, flags); spin_unlock_irqrestore(&spfi->lock, flags);
} }
...@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data) ...@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data)
struct img_spfi *spfi = data; struct img_spfi *spfi = data;
unsigned long flags; unsigned long flags;
spfi_flush_tx_fifo(spfi); spfi_wait_all_done(spfi);
spin_lock_irqsave(&spfi->lock, flags); spin_lock_irqsave(&spfi->lock, flags);
spfi->tx_dma_busy = false; spfi->tx_dma_busy = false;
if (!spfi->rx_dma_busy) { if (!spfi->rx_dma_busy)
spfi_stop(spfi);
spi_finalize_current_transfer(spfi->master); spi_finalize_current_transfer(spfi->master);
}
spin_unlock_irqrestore(&spfi->lock, flags); spin_unlock_irqrestore(&spfi->lock, flags);
} }
...@@ -397,6 +387,75 @@ static int img_spfi_start_dma(struct spi_master *master, ...@@ -397,6 +387,75 @@ static int img_spfi_start_dma(struct spi_master *master,
return -EIO; return -EIO;
} }
static void img_spfi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
unsigned long flags;
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave(&spfi->lock, flags);
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
spfi->tx_dma_busy = false;
spfi->rx_dma_busy = false;
dmaengine_terminate_all(spfi->tx_ch);
dmaengine_terminate_all(spfi->rx_ch);
}
spin_unlock_irqrestore(&spfi->lock, flags);
}
static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
if (msg->spi->mode & SPI_CPHA)
val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
if (msg->spi->mode & SPI_CPOL)
val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
spfi_writel(spfi, val, SPFI_PORT_STATE);
return 0;
}
static int img_spfi_unprepare(struct spi_master *master,
struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
spfi_reset(spfi);
return 0;
}
static int img_spfi_setup(struct spi_device *spi)
{
int ret;
ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
dev_name(&spi->dev));
if (ret)
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
spi->cs_gpio);
return ret;
}
static void img_spfi_cleanup(struct spi_device *spi)
{
gpio_free(spi->cs_gpio);
}
static void img_spfi_config(struct spi_master *master, struct spi_device *spi, static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
...@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, ...@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
SPFI_TRANSACTION);
val = spfi_readl(spfi, SPFI_CONTROL); val = spfi_readl(spfi, SPFI_CONTROL);
val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
if (xfer->tx_buf) if (xfer->tx_buf)
...@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, ...@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
else if (xfer->tx_nbits == SPI_NBITS_QUAD && else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
xfer->rx_nbits == SPI_NBITS_QUAD) xfer->rx_nbits == SPI_NBITS_QUAD)
val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
val &= ~SPFI_CONTROL_CONTINUE;
if (!xfer->cs_change && !list_is_last(&xfer->transfer_list,
&master->cur_msg->transfers))
val |= SPFI_CONTROL_CONTINUE;
spfi_writel(spfi, val, SPFI_CONTROL); spfi_writel(spfi, val, SPFI_CONTROL);
val = spfi_readl(spfi, SPFI_PORT_STATE);
if (spi->mode & SPI_CPHA)
val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
if (spi->mode & SPI_CPOL)
val |= SPFI_PORT_STATE_CK_POL(spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select);
spfi_writel(spfi, val, SPFI_PORT_STATE);
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
SPFI_TRANSACTION);
} }
static int img_spfi_transfer_one(struct spi_master *master, static int img_spfi_transfer_one(struct spi_master *master,
...@@ -455,8 +499,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -455,8 +499,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct img_spfi *spfi = spi_master_get_devdata(spi->master); struct img_spfi *spfi = spi_master_get_devdata(spi->master);
bool dma_reset = false;
unsigned long flags;
int ret; int ret;
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) { if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
...@@ -466,23 +508,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -466,23 +508,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return -EINVAL; return -EINVAL;
} }
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave(&spfi->lock, flags);
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
dev_err(spfi->dev, "SPI DMA still busy\n");
dma_reset = true;
}
spin_unlock_irqrestore(&spfi->lock, flags);
if (dma_reset) {
dmaengine_terminate_all(spfi->tx_ch);
dmaengine_terminate_all(spfi->rx_ch);
spfi_reset(spfi);
}
img_spfi_config(master, spi, xfer); img_spfi_config(master, spi, xfer);
if (master->can_dma && master->can_dma(master, spi, xfer)) if (master->can_dma && master->can_dma(master, spi, xfer))
ret = img_spfi_start_dma(master, spi, xfer); ret = img_spfi_start_dma(master, spi, xfer);
...@@ -492,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -492,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return ret; return ret;
} }
static void img_spfi_set_cs(struct spi_device *spi, bool enable)
{
struct img_spfi *spfi = spi_master_get_devdata(spi->master);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT);
val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
spfi_writel(spfi, val, SPFI_PORT_STATE);
}
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)
{ {
...@@ -591,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -591,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
master->num_chipselect = 5;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
master->set_cs = img_spfi_set_cs; master->setup = img_spfi_setup;
master->cleanup = img_spfi_cleanup;
master->transfer_one = img_spfi_transfer_one; master->transfer_one = img_spfi_transfer_one;
master->prepare_message = img_spfi_prepare;
master->unprepare_message = img_spfi_unprepare;
master->handle_err = img_spfi_handle_err;
spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx"); spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx");
spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx"); spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx");
......
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