summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-sirf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-sirf.c')
-rw-r--r--drivers/spi/spi-sirf.c116
1 files changed, 68 insertions, 48 deletions
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index e430689c3837..1a77ad52812f 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -22,7 +22,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+#define SIRFSOC_MAX_CMD_BYTES 4
+
struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
@@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
int word_width; /* in bytes */
+ /*
+ * if tx size is not more than 4 and rx size is NULL, use
+ * command model
+ */
+ bool tx_by_cmd;
+
int chipselect[0];
};
@@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
+ complete(&sspi->tx_done);
+ writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+ return IRQ_HANDLED;
+ }
+
/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ /*
+ * fill tx_buf into command register and wait for its completion
+ */
+ if (sspi->tx_by_cmd) {
+ u32 cmd;
+ memcpy(&cmd, sspi->tx, t->len);
+
+ if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
+ cmd = cpu_to_be32(cmd) >>
+ ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
+ if (sspi->word_width == 2 && t->len == 4 &&
+ (!(spi->mode & SPI_LSB_FIRST)))
+ cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
+
+ writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
+ writel(SIRFSOC_SPI_FRM_END_INT_EN,
+ sspi->base + SIRFSOC_SPI_INT_EN);
+ writel(SIRFSOC_SPI_CMD_TX_EN,
+ sspi->base + SIRFSOC_SPI_TX_RX_EN);
+
+ if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+ dev_err(&spi->dev, "transfer timeout\n");
+ return 0;
+ }
+
+ return t->len;
+ }
+
if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
@@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
sspi->rx_word = spi_sirfsoc_rx_word_u8;
sspi->tx_word = spi_sirfsoc_tx_word_u8;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- sspi->word_width = 1;
break;
case 12:
case 16:
@@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_word_u16;
sspi->tx_word = spi_sirfsoc_tx_word_u16;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- sspi->word_width = 2;
break;
case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
sspi->rx_word = spi_sirfsoc_rx_word_u32;
sspi->tx_word = spi_sirfsoc_tx_word_u32;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- sspi->word_width = 4;
break;
default:
BUG();
}
+ sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
+ txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+ rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+
if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
if (!(spi->mode & SPI_LSB_FIRST))
@@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
+ if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
+ regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
+ SIRFSOC_SPI_CMD_MODE);
+ sspi->tx_by_cmd = true;
+ } else {
+ regval &= ~SIRFSOC_SPI_CMD_MODE;
+ sspi->tx_by_cmd = false;
+ }
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
if (IS_DMA_VALID(t)) {
@@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int num_cs, cs_gpio, irq;
- u32 rx_dma_ch, tx_dma_ch;
- dma_cap_mask_t dma_cap_mask;
int i;
int ret;
@@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
goto err_cs;
}
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-rx-channel", &rx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get rx dma channel\n");
- goto err_cs;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-tx-channel", &tx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get tx dma channel\n");
- goto err_cs;
- }
-
master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
/* request DMA channels */
- dma_cap_zero(dma_cap_mask);
- dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
-
- sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)rx_dma_ch);
+ sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!sspi->rx_chan) {
dev_err(&pdev->dev, "can not allocate rx dma channel\n");
ret = -ENODEV;
goto free_master;
}
- sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)tx_dma_ch);
+ sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV;
@@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(sspi->clk);
return 0;
@@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
- return 0;
+ return spi_master_resume(master);
}
-
-static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
- .suspend = spi_sirfsoc_suspend,
- .resume = spi_sirfsoc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
+ spi_sirfsoc_resume);
+
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", },
@@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops,
-#endif
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,