diff options
Diffstat (limited to 'drivers/spi/spi-sirf.c')
-rw-r--r-- | drivers/spi/spi-sirf.c | 116 |
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, |