summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-altera.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-altera.c')
-rw-r--r--drivers/spi/spi-altera.c163
1 files changed, 59 insertions, 104 deletions
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index b95010e72452..a5adf0d868fc 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -45,10 +44,6 @@
#define ALTERA_SPI_CONTROL_SSO_MSK 0x400
struct altera_spi {
- /* bitbang has to be first */
- struct spi_bitbang bitbang;
- struct completion done;
-
void __iomem *base;
int irq;
int len;
@@ -66,59 +61,64 @@ static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
return spi_master_get_devdata(sdev->master);
}
-static void altera_spi_chipsel(struct spi_device *spi, int value)
+static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
{
struct altera_spi *hw = altera_spi_to_hw(spi);
- if (spi->mode & SPI_CS_HIGH) {
- switch (value) {
- case BITBANG_CS_INACTIVE:
- writel(1 << spi->chip_select,
- hw->base + ALTERA_SPI_SLAVE_SEL);
- hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
- writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
- break;
-
- case BITBANG_CS_ACTIVE:
- hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
- writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
- writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
- break;
- }
+ if (is_high) {
+ hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
+ writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
+ writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
} else {
- switch (value) {
- case BITBANG_CS_INACTIVE:
- hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
- writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
- break;
+ writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL);
+ hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
+ writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
+ }
+}
+
+static void altera_spi_tx_word(struct altera_spi *hw)
+{
+ unsigned int txd = 0;
- case BITBANG_CS_ACTIVE:
- writel(1 << spi->chip_select,
- hw->base + ALTERA_SPI_SLAVE_SEL);
- hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
- writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
+ if (hw->tx) {
+ switch (hw->bytes_per_word) {
+ case 1:
+ txd = hw->tx[hw->count];
+ break;
+ case 2:
+ txd = (hw->tx[hw->count * 2]
+ | (hw->tx[hw->count * 2 + 1] << 8));
break;
}
}
+
+ writel(txd, hw->base + ALTERA_SPI_TXDATA);
}
-static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
+static void altera_spi_rx_word(struct altera_spi *hw)
{
- if (hw->tx) {
+ unsigned int rxd;
+
+ rxd = readl(hw->base + ALTERA_SPI_RXDATA);
+ if (hw->rx) {
switch (hw->bytes_per_word) {
case 1:
- return hw->tx[count];
+ hw->rx[hw->count] = rxd;
+ break;
case 2:
- return (hw->tx[count * 2]
- | (hw->tx[count * 2 + 1] << 8));
+ hw->rx[hw->count * 2] = rxd;
+ hw->rx[hw->count * 2 + 1] = rxd >> 8;
+ break;
}
}
- return 0;
+
+ hw->count++;
}
-static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+static int altera_spi_txrx(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *t)
{
- struct altera_spi *hw = altera_spi_to_hw(spi);
+ struct altera_spi *hw = spi_master_get_devdata(master);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -132,67 +132,39 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
/* send the first byte */
- writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
-
- wait_for_completion(&hw->done);
- /* disable receive interrupt */
- hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
- writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
+ altera_spi_tx_word(hw);
} else {
while (hw->count < hw->len) {
- unsigned int rxd;
-
- writel(hw_txbyte(hw, hw->count),
- hw->base + ALTERA_SPI_TXDATA);
+ altera_spi_tx_word(hw);
while (!(readl(hw->base + ALTERA_SPI_STATUS) &
ALTERA_SPI_STATUS_RRDY_MSK))
cpu_relax();
- rxd = readl(hw->base + ALTERA_SPI_RXDATA);
- if (hw->rx) {
- switch (hw->bytes_per_word) {
- case 1:
- hw->rx[hw->count] = rxd;
- break;
- case 2:
- hw->rx[hw->count * 2] = rxd;
- hw->rx[hw->count * 2 + 1] = rxd >> 8;
- break;
- }
- }
-
- hw->count++;
+ altera_spi_rx_word(hw);
}
+ spi_finalize_current_transfer(master);
}
- return hw->count * hw->bytes_per_word;
+ return t->len;
}
static irqreturn_t altera_spi_irq(int irq, void *dev)
{
- struct altera_spi *hw = dev;
- unsigned int rxd;
+ struct spi_master *master = dev;
+ struct altera_spi *hw = spi_master_get_devdata(master);
- rxd = readl(hw->base + ALTERA_SPI_RXDATA);
- if (hw->rx) {
- switch (hw->bytes_per_word) {
- case 1:
- hw->rx[hw->count] = rxd;
- break;
- case 2:
- hw->rx[hw->count * 2] = rxd;
- hw->rx[hw->count * 2 + 1] = rxd >> 8;
- break;
- }
- }
+ altera_spi_rx_word(hw);
- hw->count++;
+ if (hw->count < hw->len) {
+ altera_spi_tx_word(hw);
+ } else {
+ /* disable receive interrupt */
+ hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
+ writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
- if (hw->count < hw->len)
- writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA);
- else
- complete(&hw->done);
+ spi_finalize_current_transfer(master);
+ }
return IRQ_HANDLED;
}
@@ -214,14 +186,10 @@ static int altera_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->dev.of_node = pdev->dev.of_node;
+ master->transfer_one = altera_spi_txrx;
+ master->set_cs = altera_spi_set_cs;
hw = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, hw);
-
- /* setup the state for the bitbang driver */
- hw->bitbang.master = master;
- hw->bitbang.chipselect = altera_spi_chipsel;
- hw->bitbang.txrx_bufs = altera_spi_txrx;
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -239,15 +207,13 @@ static int altera_spi_probe(struct platform_device *pdev)
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
- init_completion(&hw->done);
err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
- pdev->name, hw);
+ pdev->name, master);
if (err)
goto exit;
}
- /* register our spi controller */
- err = spi_bitbang_start(&hw->bitbang);
+ err = devm_spi_register_master(&pdev->dev, master);
if (err)
goto exit;
dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
@@ -258,16 +224,6 @@ exit:
return err;
}
-static int altera_spi_remove(struct platform_device *dev)
-{
- struct altera_spi *hw = platform_get_drvdata(dev);
- struct spi_master *master = hw->bitbang.master;
-
- spi_bitbang_stop(&hw->bitbang);
- spi_master_put(master);
- return 0;
-}
-
#ifdef CONFIG_OF
static const struct of_device_id altera_spi_match[] = {
{ .compatible = "ALTR,spi-1.0", },
@@ -279,7 +235,6 @@ MODULE_DEVICE_TABLE(of, altera_spi_match);
static struct platform_driver altera_spi_driver = {
.probe = altera_spi_probe,
- .remove = altera_spi_remove,
.driver = {
.name = DRV_NAME,
.pm = NULL,