aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig3
-rw-r--r--drivers/spi/at25.c7
-rw-r--r--drivers/spi/atmel_spi.c4
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c77
-rw-r--r--drivers/spi/omap2_mcspi.c6
-rw-r--r--drivers/spi/pxa2xx_spi.c141
-rw-r--r--drivers/spi/spi.c53
-rw-r--r--drivers/spi/spi_bfin5xx.c866
-rw-r--r--drivers/spi/spi_bitbang.c5
-rw-r--r--drivers/spi/spi_imx.c2
-rw-r--r--drivers/spi/spi_mpc83xx.c6
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c21
-rw-r--r--drivers/spi/spi_txx9.c40
-rw-r--r--drivers/spi/spidev.c6
-rw-r--r--drivers/spi/tle62x0.c5
15 files changed, 661 insertions, 581 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a77ede598d3..aaaea81e412 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -61,7 +61,7 @@ config SPI_ATMEL
config SPI_BFIN
tristate "SPI controller driver for ADI Blackfin5xx"
- depends on SPI_MASTER && BFIN
+ depends on SPI_MASTER && BLACKFIN
help
This is the SPI controller master driver for Blackfin 5xx processor.
@@ -153,6 +153,7 @@ config SPI_OMAP24XX
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
+ select PXA_SSP
help
This enables using a PXA2xx SSP port as a SPI master controller.
The driver can be configured to use any SSP port and additional
diff --git a/drivers/spi/at25.c b/drivers/spi/at25.c
index e007833cca5..290dbe99647 100644
--- a/drivers/spi/at25.c
+++ b/drivers/spi/at25.c
@@ -21,6 +21,13 @@
#include <linux/spi/eeprom.h>
+/*
+ * NOTE: this is an *EEPROM* driver. The vagaries of product naming
+ * mean that some AT25 products are EEPROMs, and others are FLASH.
+ * Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver,
+ * not this one!
+ */
+
struct at25_data {
struct spi_device *spi;
struct mutex lock;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 0d342dcdd30..ff10808183a 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -195,8 +195,8 @@ static void atmel_spi_next_xfer(struct spi_master *master,
xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
- spi_writel(as, TCR, len);
spi_writel(as, RCR, len);
+ spi_writel(as, TCR, len);
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
@@ -497,7 +497,7 @@ static int atmel_spi_setup(struct spi_device *spi)
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
if (!spi->controller_state) {
- ret = gpio_request(npcs_pin, "spi_npcs");
+ ret = gpio_request(npcs_pin, spi->dev.bus_id);
if (ret)
return ret;
spi->controller_state = (void *)npcs_pin;
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 7051e6c5edc..253ed5682a6 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -330,75 +330,13 @@ static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
{
- struct mpc52xx_cdm __iomem *cdm;
- struct mpc52xx_gpio __iomem *gpio;
struct mpc52xx_psc __iomem *psc = mps->psc;
- u32 ul;
u32 mclken_div;
int ret = 0;
-#if defined(CONFIG_PPC_MERGE)
- cdm = mpc52xx_find_and_map("mpc5200-cdm");
- gpio = mpc52xx_find_and_map("mpc5200-gpio");
-#else
- cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
- gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
-#endif
- if (!cdm || !gpio) {
- printk(KERN_ERR "Error mapping CDM/GPIO\n");
- ret = -EFAULT;
- goto unmap_regs;
- }
-
/* default sysclk is 512MHz */
- mclken_div = 0x8000 |
- (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
-
- switch (psc_id) {
- case 1:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFFFF8;
- ul |= 0x00000006;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc1, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000020;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 2:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFFF8F;
- ul |= 0x00000060;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc2, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000040;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 3:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFF0FF;
- ul |= 0x00000600;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc3, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000080;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 6:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFF8FFFFF;
- ul |= 0x00700000;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc6, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000010;
- out_be32(&cdm->clk_enables, ul);
- break;
- default:
- ret = -EINVAL;
- goto unmap_regs;
- }
+ mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK;
+ mpc52xx_set_psc_clkdiv(psc_id, mclken_div);
/* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
@@ -422,12 +360,6 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
mps->bits_per_word = 8;
-unmap_regs:
- if (cdm)
- iounmap(cdm);
- if (gpio)
- iounmap(gpio);
-
return ret;
}
@@ -623,8 +555,9 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
}
static struct of_device_id mpc52xx_psc_spi_of_match[] = {
- { .type = "spi", .compatible = "mpc5200-psc-spi", },
- {},
+ { .compatible = "fsl,mpc5200-psc-spi", },
+ { .compatible = "mpc5200-psc-spi", }, /* old */
+ {}
};
MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 3cdab131c4a..ea61724ae22 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
tx = xfer->tx_buf;
do {
+ c -= 1;
if (tx != NULL) {
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
word_len, *(rx - 1));
#endif
}
- c -= 1;
} while (c);
} else if (word_len <= 16) {
u16 *rx;
@@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
+ c -= 2;
if (tx != NULL) {
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
word_len, *(rx - 1));
#endif
}
- c -= 2;
} while (c);
} else if (word_len <= 32) {
u32 *rx;
@@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
+ c -= 4;
if (tx != NULL) {
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
word_len, *(rx - 1));
#endif
}
- c -= 4;
} while (c);
}
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 5f3d808cbc2..eb817b8eb02 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -27,6 +27,7 @@
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
+#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -36,10 +37,12 @@
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-ssp.h>
+#include <asm/arch/ssp.h>
#include <asm/arch/pxa2xx_spi.h>
MODULE_AUTHOR("Stephen Street");
-MODULE_DESCRIPTION("PXA2xx SSP SPI Contoller");
+MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
MODULE_LICENSE("GPL");
#define MAX_BUSES 3
@@ -80,6 +83,9 @@ struct driver_data {
/* Driver model hookup */
struct platform_device *pdev;
+ /* SSP Info */
+ struct ssp_device *ssp;
+
/* SPI framework hookup */
enum pxa_ssp_type ssp_type;
struct spi_master *master;
@@ -778,6 +784,16 @@ int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
return retval;
}
+static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
+{
+ unsigned long ssp_clk = clk_get_rate(ssp->clk);
+
+ if (ssp->type == PXA25x_SSP)
+ return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
+ else
+ return ((ssp_clk / rate - 1) & 0xfff) << 8;
+}
+
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
@@ -785,6 +801,7 @@ static void pump_transfers(unsigned long data)
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL;
+ struct ssp_device *ssp = drv_data->ssp;
void *reg = drv_data->ioaddr;
u32 clk_div = 0;
u8 bits = 0;
@@ -866,12 +883,7 @@ static void pump_transfers(unsigned long data)
if (transfer->bits_per_word)
bits = transfer->bits_per_word;
- if (reg == SSP1_VIRT)
- clk_div = SSP1_SerClkDiv(speed);
- else if (reg == SSP2_VIRT)
- clk_div = SSP2_SerClkDiv(speed);
- else if (reg == SSP3_VIRT)
- clk_div = SSP3_SerClkDiv(speed);
+ clk_div = ssp_get_clk_div(ssp, speed);
if (bits <= 8) {
drv_data->n_bytes = 1;
@@ -1074,6 +1086,7 @@ static int setup(struct spi_device *spi)
struct pxa2xx_spi_chip *chip_info = NULL;
struct chip_data *chip;
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct ssp_device *ssp = drv_data->ssp;
unsigned int clk_div;
if (!spi->bits_per_word)
@@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi)
}
}
- if (drv_data->ioaddr == SSP1_VIRT)
- clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
- else if (drv_data->ioaddr == SSP2_VIRT)
- clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
- else if (drv_data->ioaddr == SSP3_VIRT)
- clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
- else
- {
- dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
- drv_data->ioaddr);
- return -ENODEV;
- }
+ clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
chip->speed_hz = spi->max_speed_hz;
chip->cr0 = clk_div
@@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi)
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP)
- dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+ dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
spi->bits_per_word,
- (CLOCK_SPEED_HZ)
+ clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
spi->mode & 0x3);
else
- dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+ dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
spi->bits_per_word,
- (CLOCK_SPEED_HZ/2)
+ clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
spi->mode & 0x3);
@@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
struct pxa2xx_spi_master *platform_info;
struct spi_master *master;
struct driver_data *drv_data = 0;
- struct resource *memory_resource;
- int irq;
+ struct ssp_device *ssp;
int status = 0;
platform_info = dev->platform_data;
- if (platform_info->ssp_type == SSP_UNDEFINED) {
- dev_err(&pdev->dev, "undefined SSP\n");
+ ssp = ssp_request(pdev->id, pdev->name);
+ if (ssp == NULL) {
+ dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
return -ENODEV;
}
@@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) {
dev_err(&pdev->dev, "can not alloc spi_master\n");
+ ssp_free(ssp);
return -ENOMEM;
}
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
drv_data->master_info = platform_info;
drv_data->pdev = pdev;
+ drv_data->ssp = ssp;
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
@@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
master->setup = setup;
master->transfer = transfer;
- drv_data->ssp_type = platform_info->ssp_type;
+ drv_data->ssp_type = ssp->type;
drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
sizeof(struct driver_data)), 8);
- /* Setup register addresses */
- memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!memory_resource) {
- dev_err(&pdev->dev, "memory resources not defined\n");
- status = -ENODEV;
- goto out_error_master_alloc;
- }
-
- drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
- drv_data->ssdr_physical = memory_resource->start + 0x00000010;
- if (platform_info->ssp_type == PXA25x_SSP) {
+ drv_data->ioaddr = ssp->mmio_base;
+ drv_data->ssdr_physical = ssp->phys_base + SSDR;
+ if (ssp->type == PXA25x_SSP) {
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
drv_data->dma_cr1 = 0;
drv_data->clear_sr = SSSR_ROR;
@@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
}
- /* Attach to IRQ */
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "irq resource not defined\n");
- status = -ENODEV;
- goto out_error_master_alloc;
- }
-
- status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
+ status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
if (status < 0) {
dev_err(&pdev->dev, "can not get IRQ\n");
goto out_error_master_alloc;
@@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
goto out_error_dma_alloc;
}
- if (drv_data->ioaddr == SSP1_VIRT) {
- DRCMRRXSSDR = DRCMR_MAPVLD
- | drv_data->rx_channel;
- DRCMRTXSSDR = DRCMR_MAPVLD
- | drv_data->tx_channel;
- } else if (drv_data->ioaddr == SSP2_VIRT) {
- DRCMRRXSS2DR = DRCMR_MAPVLD
- | drv_data->rx_channel;
- DRCMRTXSS2DR = DRCMR_MAPVLD
- | drv_data->tx_channel;
- } else if (drv_data->ioaddr == SSP3_VIRT) {
- DRCMRRXSS3DR = DRCMR_MAPVLD
- | drv_data->rx_channel;
- DRCMRTXSS3DR = DRCMR_MAPVLD
- | drv_data->tx_channel;
- } else {
- dev_err(dev, "bad SSP type\n");
- goto out_error_dma_alloc;
- }
+ DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
+ DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
}
/* Enable SOC clock */
- pxa_set_cken(platform_info->clock_enable, 1);
+ clk_enable(ssp->clk);
/* Load default SSP configuration */
write_SSCR0(0, drv_data->ioaddr);
@@ -1479,7 +1450,7 @@ out_error_queue_alloc:
destroy_queue(drv_data);
out_error_clock_enabled:
- pxa_set_cken(platform_info->clock_enable, 0);
+ clk_disable(ssp->clk);
out_error_dma_alloc:
if (drv_data->tx_channel != -1)
@@ -1488,17 +1459,18 @@ out_error_dma_alloc:
pxa_free_dma(drv_data->rx_channel);
out_error_irq_alloc:
- free_irq(irq, drv_data);
+ free_irq(ssp->irq, drv_data);
out_error_master_alloc:
spi_master_put(master);
+ ssp_free(ssp);
return status;
}
static int pxa2xx_spi_remove(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
- int irq;
+ struct ssp_device *ssp = drv_data->ssp;
int status = 0;
if (!drv_data)
@@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
/* Disable the SSP at the peripheral and SOC level */
write_SSCR0(0, drv_data->ioaddr);
- pxa_set_cken(drv_data->master_info->clock_enable, 0);
+ clk_disable(ssp->clk);
/* Release DMA */
if (drv_data->master_info->enable_dma) {
- if (drv_data->ioaddr == SSP1_VIRT) {
- DRCMRRXSSDR = 0;
- DRCMRTXSSDR = 0;
- } else if (drv_data->ioaddr == SSP2_VIRT) {
- DRCMRRXSS2DR = 0;
- DRCMRTXSS2DR = 0;
- } else if (drv_data->ioaddr == SSP3_VIRT) {
- DRCMRRXSS3DR = 0;
- DRCMRTXSS3DR = 0;
- }
+ DRCMR(ssp->drcmr_rx) = 0;
+ DRCMR(ssp->drcmr_tx) = 0;
pxa_free_dma(drv_data->tx_channel);
pxa_free_dma(drv_data->rx_channel);
}
/* Release IRQ */
- irq = platform_get_irq(pdev, 0);
- if (irq >= 0)
- free_irq(irq, drv_data);
+ free_irq(ssp->irq, drv_data);
+
+ /* Release SSP */
+ ssp_free(ssp);
/* Disconnect from the SPI framework */
spi_unregister_master(drv_data->master);
@@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message)
static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct ssp_device *ssp = drv_data->ssp;
int status = 0;
/* Check all childern for current power state */
@@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
if (status != 0)
return status;
write_SSCR0(0, drv_data->ioaddr);
- pxa_set_cken(drv_data->master_info->clock_enable, 0);
+ clk_disable(ssp->clk);
return 0;
}
@@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
static int pxa2xx_spi_resume(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct ssp_device *ssp = drv_data->ssp;
int status = 0;
/* Enable the SSP clock */
- pxa_set_cken(drv_data->master_info->clock_enable, 1);
+ clk_disable(ssp->clk);
/* Start the queue running */
status = start_queue(drv_data);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 89769ce16f8..682a6a48fec 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -457,10 +457,11 @@ done:
EXPORT_SYMBOL_GPL(spi_register_master);
-static int __unregister(struct device *dev, void *unused)
+static int __unregister(struct device *dev, void *master_dev)
{
/* note: before about 2.6.14-rc1 this would corrupt memory: */
- spi_unregister_device(to_spi_device(dev));
+ if (dev != master_dev)
+ spi_unregister_device(to_spi_device(dev));
return 0;
}
@@ -478,11 +479,21 @@ void spi_unregister_master(struct spi_master *master)
{
int dummy;
- dummy = device_for_each_child(master->dev.parent, NULL, __unregister);
+ dummy = device_for_each_child(master->dev.parent, &master->dev,
+ __unregister);
device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
+static int __spi_master_match(struct device *dev, void *data)
+{
+ struct spi_master *m;
+ u16 *bus_num = data;
+
+ m = container_of(dev, struct spi_master, dev);
+ return m->bus_num == *bus_num;
+}
+
/**
* spi_busnum_to_master - look up master associated with bus_num
* @bus_num: the master's bus number
@@ -497,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
{
struct device *dev;
struct spi_master *master = NULL;
- struct spi_master *m;
-
- down(&spi_master_class.sem);
- list_for_each_entry(dev, &spi_master_class.children, node) {
- m = container_of(dev, struct spi_master, dev);
- if (m->bus_num == bus_num) {
- master = spi_master_get(m);
- break;
- }
- }
- up(&spi_master_class.sem);
+
+ dev = class_find_device(&spi_master_class, &bus_num,
+ __spi_master_match);
+ if (dev)
+ master = container_of(dev, struct spi_master, dev);
+ /* reference got in class_find_device */
return master;
}
EXPORT_SYMBOL_GPL(spi_busnum_to_master);
@@ -539,10 +545,7 @@ static void spi_complete(void *arg)
* Also, the caller is guaranteeing that the memory associated with the
* message will not be freed before this call returns.
*
- * The return value is a negative error code if the message could not be
- * submitted, else zero. When the value is zero, then message->status is
- * also defined; it's the completion code for the transfer, either zero
- * or a negative error code from the controller driver.
+ * It returns zero on success, else a negative error code.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
@@ -552,8 +555,10 @@ int spi_sync(struct spi_device *spi, struct spi_message *message)
message->complete = spi_complete;
message->context = &done;
status = spi_async(spi, message);
- if (status == 0)
+ if (status == 0) {
wait_for_completion(&done);
+ status = message->status;
+ }
message->context = NULL;
return status;
}
@@ -587,7 +592,7 @@ int spi_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx)
{
- static DECLARE_MUTEX(lock);
+ static DEFINE_MUTEX(lock);
int status;
struct spi_message message;
@@ -613,7 +618,7 @@ int spi_write_then_read(struct spi_device *spi,
}
/* ... unless someone else is using the pre-allocated buffer */
- if (down_trylock(&lock)) {
+ if (!mutex_trylock(&lock)) {
local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!local_buf)
return -ENOMEM;
@@ -626,13 +631,11 @@ int spi_write_then_read(struct spi_device *spi,
/* do the i/o */
status = spi_sync(spi, &message);
- if (status == 0) {
+ if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
- status = message.status;
- }
if (x[0].tx_buf == buf)
- up(&lock);
+ mutex_unlock(&lock);
else
kfree(local_buf);
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 2ef11bb70b2..7ef39a6e8c0 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1,17 +1,22 @@
/*
- * File: drivers/spi/bfin5xx_spi.c
- * Based on: N/A
- * Author: Luke Yang (Analog Devices Inc.)
+ * File: drivers/spi/bfin5xx_spi.c
+ * Maintainer:
+ * Bryan Wu <bryan.wu@analog.com>
+ * Original Author:
+ * Luke Yang (Analog Devices Inc.)
*
- * Created: March. 10th 2006
- * Description: SPI controller driver for Blackfin 5xx
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ * Created: March. 10th 2006
+ * Description: SPI controller driver for Blackfin BF5xx
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* Modified:
* March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
* August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
+ * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
+ * July 30, 2007 add platfrom_resource interface to support multi-port
+ * SPI controller (Bryan Wu)
*
- * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright 2004-2007 Analog Devices Inc.
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,50 +36,39 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
#include <asm/dma.h>
-
+#include <asm/portmux.h>
#include <asm/bfin5xx_spi.h>
-MODULE_AUTHOR("Luke Yang");
-MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller");
-MODULE_LICENSE("GPL");
+#define DRV_NAME "bfin-spi"
+#define DRV_AUTHOR "Bryan Wu, Luke Yang"
+#define DRV_DESC "Blackfin BF5xx on-chip SPI Controller Driver"
+#define DRV_VERSION "1.0"
-#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
-#define DEFINE_SPI_REG(reg, off) \
-static inline u16 read_##reg(void) \
- { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \
-static inline void write_##reg(u16 v) \
- {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\
- SSYNC();}
+#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07) == 0)
-DEFINE_SPI_REG(CTRL, 0x00)
-DEFINE_SPI_REG(FLAG, 0x04)
-DEFINE_SPI_REG(STAT, 0x08)
-DEFINE_SPI_REG(TDBR, 0x0C)
-DEFINE_SPI_REG(RDBR, 0x10)
-DEFINE_SPI_REG(BAUD, 0x14)
-DEFINE_SPI_REG(SHAW, 0x18)
-#define START_STATE ((void*)0)
-#define RUNNING_STATE ((void*)1)
-#define DONE_STATE ((void*)2)
-#define ERROR_STATE ((void*)-1)
-#define QUEUE_RUNNING 0
-#define QUEUE_STOPPED 1
-int dma_requested;
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+#define QUEUE_RUNNING 0
+#define QUEUE_STOPPED 1
struct driver_data {
/* Driver model hookup */
@@ -83,6 +77,12 @@ struct driver_data {
/* SPI framework hookup */
struct spi_master *master;
+ /* Regs base of SPI controller */
+ void __iomem *regs_base;
+
+ /* Pin request list */
+ u16 *pin_req;
+
/* BFIN hookup */
struct bfin5xx_spi_master *master_info;
@@ -107,12 +107,18 @@ struct driver_data {
void *tx_end;
void *rx;
void *rx_end;
+
+ /* DMA stuffs */
+ int dma_channel;
int dma_mapped;
+ int dma_requested;
dma_addr_t rx_dma;
dma_addr_t tx_dma;
+
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes;
+ int cs_change;
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
@@ -129,28 +135,40 @@ struct chip_data {
u8 enable_dma;
u8 bits_per_word; /* 8 or 16 */
u8 cs_change_per_word;
- u8 cs_chg_udelay;
+ u16 cs_chg_udelay; /* Some devices require > 255usec delay */
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
};
+#define DEFINE_SPI_REG(reg, off) \
+static inline u16 read_##reg(struct driver_data *drv_data) \
+ { return bfin_read16(drv_data->regs_base + off); } \
+static inline void write_##reg(struct driver_data *drv_data, u16 v) \
+ { bfin_write16(drv_data->regs_base + off, v); }
+
+DEFINE_SPI_REG(CTRL, 0x00)
+DEFINE_SPI_REG(FLAG, 0x04)
+DEFINE_SPI_REG(STAT, 0x08)
+DEFINE_SPI_REG(TDBR, 0x0C)
+DEFINE_SPI_REG(RDBR, 0x10)
+DEFINE_SPI_REG(BAUD, 0x14)
+DEFINE_SPI_REG(SHAW, 0x18)
+
static void bfin_spi_enable(struct driver_data *drv_data)
{
u16 cr;
- cr = read_CTRL();
- write_CTRL(cr | BIT_CTL_ENABLE);
- SSYNC();
+ cr = read_CTRL(drv_data);
+ write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
}
static void bfin_spi_disable(struct driver_data *drv_data)
{
u16 cr;
- cr = read_CTRL();
- write_CTRL(cr & (~BIT_CTL_ENABLE));
- SSYNC();
+ cr = read_CTRL(drv_data);
+ write_CTRL(drv_data, (cr & (~BIT_CTL_ENABLE)));
}
/* Caculate the SPI_BAUD register value based on input HZ */
@@ -170,83 +188,71 @@ static int flush(struct driver_data *drv_data)
unsigned long limit = loops_per_jiffy << 1;
/* wait for stop and clear stat */
- while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
- continue;
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--)
+ cpu_relax();
- write_STAT(BIT_STAT_CLR);
+ write_STAT(drv_data, BIT_STAT_CLR);
return limit;
}
+/* Chip select operation functions for cs_change flag */
+static void cs_active(struct driver_data *drv_data, struct chip_data *chip)
+{
+ u16 flag = read_FLAG(drv_data);
+
+ flag |= chip->flag;
+ flag &= ~(chip->flag << 8);
+
+ write_FLAG(drv_data, flag);
+}
+
+static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
+{
+ u16 flag = read_FLAG(drv_data);
+
+ flag |= (chip->flag << 8);
+
+ write_FLAG(drv_data, flag);
+
+ /* Move delay here for consistency */
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+}
+
+#define MAX_SPI_SSEL 7
+
/* stop controller and re-config current chip*/
-static void restore_state(struct driver_data *drv_data)
+static int restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ int ret = 0;
/* Clear status and disable clock */
- write_STAT(BIT_STAT_CLR);
+ write_STAT(drv_data, BIT_STAT_CLR);
bfin_spi_disable(drv_data);
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
-#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537)
- dev_dbg(&drv_data->pdev->dev,
- "chip select number is %d\n", chip->chip_select_num);
-
- switch (chip->chip_select_num) {
- case 1:
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00);
- SSYNC();
- break;
-
- case 2:
- case 3:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
- SSYNC();
- break;
-
- case 4:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840);
- SSYNC();
- break;
+ /* Load the registers */
+ write_CTRL(drv_data, chip->ctl_reg);
+ write_BAUD(drv_data, chip->baud);
- case 5:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820);
- SSYNC();
- break;
+ bfin_spi_enable(drv_data);
+ cs_active(drv_data, chip);
- case 6:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810);
- SSYNC();
- break;
+ if (ret)
+ dev_dbg(&drv_data->pdev->dev,
+ ": request chip select number %d failed\n",
+ chip->chip_select_num);
- case 7:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
- SSYNC();
- break;
- }
-#endif
-
- /* Load the registers */
- write_CTRL(chip->ctl_reg);
- write_BAUD(chip->baud);
- write_FLAG(chip->flag);
+ return ret;
}
/* used to kick off transfer in rx mode */
-static unsigned short dummy_read(void)
+static unsigned short dummy_read(struct driver_data *drv_data)
{
unsigned short tmp;
- tmp = read_RDBR();
+ tmp = read_RDBR(drv_data);
return tmp;
}
@@ -255,9 +261,9 @@ static void null_writer(struct driver_data *drv_data)
u8 n_bytes = drv_data->n_bytes;
while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(0);
- while ((read_STAT() & BIT_STAT_TXS))
- continue;
+ write_TDBR(drv_data, 0);
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
+ cpu_relax();
drv_data->tx += n_bytes;
}
}
@@ -265,75 +271,78 @@ static void null_writer(struct driver_data *drv_data)
static void null_reader(struct driver_data *drv_data)
{
u8 n_bytes = drv_data->n_bytes;
- dummy_read();
+ dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- dummy_read();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ dummy_read(drv_data);
drv_data->rx += n_bytes;
}
}
static void u8_writer(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
- "cr8-s is 0x%x\n", read_STAT());
+ dev_dbg(&drv_data->pdev->dev,
+ "cr8-s is 0x%x\n", read_STAT(drv_data));
+
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(*(u8 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
- continue;
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
++drv_data->tx;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}
static void u8_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- write_TDBR(*(u8 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ cs_active(drv_data, chip);
+
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
+
+ cs_deactive(drv_data, chip);
+
++drv_data->tx;
}
- write_FLAG(0xFF00);
- SSYNC();
}
static void u8_reader(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
- "cr-8 is 0x%x\n", read_STAT());
+ dev_dbg(&drv_data->pdev->dev,
+ "cr-8 is 0x%x\n", read_STAT(drv_data));
+
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
/* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);
- dummy_read();
+ dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end - 1) {
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
}
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u8 *) (drv_data->rx) = read_SHAW();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
++drv_data->rx;
}
@@ -341,36 +350,47 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- while (drv_data->rx < drv_data->rx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- read_RDBR(); /* kick off */
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- *(u8 *) (drv_data->rx) = read_SHAW();
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(drv_data, 0xFFFF);
+
+ cs_active(drv_data, chip);
+ dummy_read(drv_data);
+
+ while (drv_data->rx < drv_data->rx_end - 1) {
+ cs_deactive(drv_data, chip);
+
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ cs_active(drv_data, chip);
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
}
- write_FLAG(0xFF00);
- SSYNC();
+ cs_deactive(drv_data, chip);
+
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
+ ++drv_data->rx;
}
static void u8_duplex(struct driver_data *drv_data)
{
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
- write_TDBR(*(u8 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
++drv_data->tx;
}
@@ -380,83 +400,89 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
while (drv_data->rx < drv_data->rx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- write_TDBR(*(u8 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ cs_active(drv_data, chip);
+
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+
+ cs_deactive(drv_data, chip);
+
++drv_data->rx;
++drv_data->tx;
}
- write_FLAG(0xFF00);
- SSYNC();
}
static void u16_writer(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
- "cr16 is 0x%x\n", read_STAT());
+ dev_dbg(&drv_data->pdev->dev,
+ "cr16 is 0x%x\n", read_STAT(drv_data));
+
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(*(u16 *) (drv_data->tx));
- while ((read_STAT() & BIT_STAT_TXS))
- continue;
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
+ cpu_relax();
drv_data->tx += 2;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}
static void u16_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- write_TDBR(*(u16 *) (drv_data->tx));
- while ((read_STAT() & BIT_STAT_TXS))
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ cs_active(drv_data, chip);
+
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
+ cpu_relax();
+
+ cs_deactive(drv_data, chip);
+
drv_data->tx += 2;
}
- write_FLAG(0xFF00);
- SSYNC();
}
static void u16_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
- "cr-16 is 0x%x\n", read_STAT());
- dummy_read();
+ "cr-16 is 0x%x\n", read_STAT(drv_data));
+
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(drv_data, 0xFFFF);
+
+ dummy_read(drv_data);
while (drv_data->rx < (drv_data->rx_end - 2)) {
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
}
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u16 *) (drv_data->rx) = read_SHAW();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
drv_data->rx += 2;
}
@@ -464,36 +490,47 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- while (drv_data->rx < drv_data->rx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- read_RDBR(); /* kick off */
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- *(u16 *) (drv_data->rx) = read_SHAW();
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(drv_data, 0xFFFF);
+
+ cs_active(drv_data, chip);
+ dummy_read(drv_data);
+
+ while (drv_data->rx < drv_data->rx_end - 2) {
+ cs_deactive(drv_data, chip);
+
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ cs_active(drv_data, chip);
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
}
- write_FLAG(0xFF00);
- SSYNC();
+ cs_deactive(drv_data, chip);
+
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
+ drv_data->rx += 2;
}
static void u16_duplex(struct driver_data *drv_data)
{
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(*(u16 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
drv_data->tx += 2;
}
@@ -503,25 +540,25 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
- SSYNC();
-
- write_TDBR(*(u16 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
- write_FLAG(0xFF00 | chip->flag);
- SSYNC();
- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
+ cs_active(drv_data, chip);
+
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
+ cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+
+ cs_deactive(drv_data, chip);
+
drv_data->rx += 2;
drv_data->tx += 2;
}
- write_FLAG(0xFF00);
- SSYNC();
}
/* test if ther is more transfer to be done */
@@ -546,6 +583,7 @@ static void *next_transfer(struct driver_data *drv_data)
*/
static void giveback(struct driver_data *drv_data)
{
+ struct chip_data *chip = drv_data->cur_chip;
struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@@ -565,10 +603,13 @@ static void giveback(struct driver_data *drv_data)
/* disable chip select signal. And not stop spi in autobuffer mode */
if (drv_data->tx_dma != 0xFFFF) {
- write_FLAG(0xFF00);
+ cs_deactive(drv_data, chip);
bfin_spi_disable(drv_data);
}
+ if (!drv_data->cs_change)
+ cs_deactive(drv_data, chip);
+
if (msg->complete)
msg->complete(msg->context);
}
@@ -576,14 +617,15 @@ static void giveback(struct driver_data *drv_data)
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct chip_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
- clear_dma_irqstat(CH_SPI);
+ clear_dma_irqstat(drv_data->dma_channel);
/* Wait for DMA to complete */
- while (get_dma_curr_irqstat(CH_SPI) & DMA_RUN)
- continue;
+ while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN)
+ cpu_relax();
/*
* wait for the last transaction shifted out. HRM states:
@@ -592,18 +634,19 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
* register until it goes low for 2 successive reads
*/
if (drv_data->tx != NULL) {
- while ((bfin_read_SPI_STAT() & TXS) ||
- (bfin_read_SPI_STAT() & TXS))
- continue;
+ while ((read_STAT(drv_data) & TXS) ||
+ (read_STAT(drv_data) & TXS))
+ cpu_relax();
}
- while (!(bfin_read_SPI_STAT() & SPIF))
- continue;
-
- bfin_spi_disable(drv_data);
+ while (!(read_STAT(drv_data) & SPIF))
+ cpu_relax();
msg->actual_length += drv_data->len_in_bytes;
+ if (drv_data->cs_change)
+ cs_deactive(drv_data, chip);
+
/* Move to next transfer */
msg->state = next_transfer(drv_data);
@@ -613,8 +656,8 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
/* free the irq handler before next transfer */
dev_dbg(&drv_data->pdev->dev,
"disable dma channel irq%d\n",
- CH_SPI);
- dma_disable_irq(CH_SPI);
+ drv_data->dma_channel);
+ dma_disable_irq(drv_data->dma_channel);
return IRQ_HANDLED;
}
@@ -690,31 +733,67 @@ static void pump_transfers(unsigned long data)
drv_data->rx_dma = transfer->rx_dma;
drv_data->tx_dma = transfer->tx_dma;
drv_data->len_in_bytes = transfer->len;
+ drv_data->cs_change = transfer->cs_change;
+
+ /* Bits per word setup */
+ switch (transfer->bits_per_word) {
+ case 8:
+ drv_data->n_bytes = 1;
+ width = CFG_SPI_WORDSIZE8;
+ drv_data->read = chip->cs_change_per_word ?
+ u8_cs_chg_reader : u8_reader;
+ drv_data->write = chip->cs_change_per_word ?
+ u8_cs_chg_writer : u8_writer;
+ drv_data->duplex = chip->cs_change_per_word ?
+ u8_cs_chg_duplex : u8_duplex;
+ break;
+
+ case 16:
+ drv_data->n_bytes = 2;
+ width = CFG_SPI_WORDSIZE16;
+ drv_data->read = chip->cs_change_per_word ?
+ u16_cs_chg_reader : u16_reader;
+ drv_data->write = chip->cs_change_per_word ?
+ u16_cs_chg_writer : u16_writer;
+ drv_data->duplex = chip->cs_change_per_word ?
+ u16_cs_chg_duplex : u16_duplex;
+ break;
+
+ default:
+ /* No change, the same as default setting */
+ drv_data->n_bytes = chip->n_bytes;
+ width = chip->width;
+ drv_data->write = drv_data->tx ? chip->write : null_writer;
+ drv_data->read = drv_data->rx ? chip->read : null_reader;
+ drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+ break;
+ }
+ cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
+ cr |= (width << 8);
+ write_CTRL(drv_data, cr);
- width = chip->width;
if (width == CFG_SPI_WORDSIZE16) {
drv_data->len = (transfer->len) >> 1;
} else {
drv_data->len = transfer->len;
}
- drv_data->write = drv_data->tx ? chip->write : null_writer;
- drv_data->read = drv_data->rx ? chip->read : null_reader;
- drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
- dev_dbg(&drv_data->pdev->dev,
- "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
- drv_data->write, chip->write, null_writer);
+ dev_dbg(&drv_data->pdev->dev, "transfer: ",
+ "drv_data->write is %p, chip->write is %p, null_wr is %p\n",
+ drv_data->write, chip->write, null_writer);
/* speed and width has been set on per message */
message->state = RUNNING_STATE;
dma_config = 0;
- /* restore spi status for each spi transfer */
- if (transfer->speed_hz) {
- write_BAUD(hz_to_spi_baud(transfer->speed_hz));
- } else {
- write_BAUD(chip->baud);
- }
- write_FLAG(chip->flag);
+ /* Speed setup (surely valid because already checked) */
+ if (transfer->speed_hz)
+ write_BAUD(drv_data, hz_to_spi_baud(transfer->speed_hz));
+ else
+ write_BAUD(drv_data, chip->baud);
+
+ write_STAT(drv_data, BIT_STAT_CLR);
+ cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
+ cs_active(drv_data, chip);
dev_dbg(&drv_data->pdev->dev,
"now pumping a transfer: width is %d, len is %d\n",
@@ -727,25 +806,25 @@ static void pump_transfers(unsigned long data)
*/
if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
- write_STAT(BIT_STAT_CLR);
- disable_dma(CH_SPI);
- clear_dma_irqstat(CH_SPI);
+ disable_dma(drv_data->dma_channel);
+ clear_dma_irqstat(drv_data->dma_channel);
bfin_spi_disable(drv_data);
/* config dma channel */
dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
if (width == CFG_SPI_WORDSIZE16) {
- set_dma_x_count(CH_SPI, drv_data->len);
- set_dma_x_modify(CH_SPI, 2);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);
+ set_dma_x_modify(drv_data->dma_channel, 2);
dma_width = WDSIZE_16;
} else {
- set_dma_x_count(CH_SPI, drv_data->len);
- set_dma_x_modify(CH_SPI, 1);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);
+ set_dma_x_modify(drv_data->dma_channel, 1);
dma_width = WDSIZE_8;
}
- /* set transfer width,direction. And enable spi */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
+ /* poll for SPI completion before start */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
/* dirty hack for autobuffer DMA mode */
if (drv_data->tx_dma == 0xFFFF) {
@@ -755,13 +834,18 @@ static void pump_transfers(unsigned long data)
/* no irq in autobuffer mode */
dma_config =
(DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
- enable_dma(CH_SPI);
- write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14));
-
- /* just return here, there can only be one transfer in this mode */
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
+ (unsigned long)drv_data->tx);
+ enable_dma(drv_data->dma_channel);
+
+ /* start SPI transfer */
+ write_CTRL(drv_data,
+ (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
+
+ /* just return here, there can only be one transfer
+ * in this mode
+ */
message->status = 0;
giveback(drv_data);
return;
@@ -772,58 +856,51 @@ static void pump_transfers(unsigned long data)
/* set transfer mode, and enable SPI */
dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");
- /* disable SPI before write to TDBR */
- write_CTRL(cr & ~BIT_CTL_ENABLE);
-
/* clear tx reg soformer data is not shifted out */
- write_TDBR(0xFF);
+ write_TDBR(drv_data, 0xFFFF);
- set_dma_x_count(CH_SPI, drv_data->len);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);
/* start dma */
- dma_enable_irq(CH_SPI);
+ dma_enable_irq(drv_data->dma_channel);
dma_config = (WNR | RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx);
- enable_dma(CH_SPI);
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
+ (unsigned long)drv_data->rx);
+ enable_dma(drv_data->dma_channel);
+
+ /* start SPI transfer */
+ write_CTRL(drv_data,
+ (cr | CFG_SPI_DMAREAD | BIT_CTL_ENABLE));
- cr |=
- CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
- 14);
- /* set transfer mode, and enable SPI */
- write_CTRL(cr);
} else if (drv_data->tx != NULL) {
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
/* start dma */
- dma_enable_irq(CH_SPI);
+ dma_enable_irq(drv_data->dma_channel);
dma_config = (RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
- enable_dma(CH_SPI);
-
- write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14));
-
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
+ (unsigned long)drv_data->tx);
+ enable_dma(drv_data->dma_channel);
+
+ /* start SPI transfer */
+ write_CTRL(drv_data,
+ (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
}
} else {
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- write_STAT(BIT_STAT_CLR);
-
if (drv_data->tx != NULL && drv_data->rx != NULL) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_WRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14);
dev_dbg(&drv_data->pdev->dev,
"IO duplex: cr is 0x%x\n", cr);
- write_CTRL(cr);
- SSYNC();
+ /* set SPI transfer mode */
+ write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
drv_data->duplex(drv_data);
@@ -831,14 +908,11 @@ static void pump_transfers(unsigned long data)
tranf_success = 0;
} else if (drv_data->tx != NULL) {
/* write only half duplex */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_WRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14);
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO write: cr is 0x%x\n", cr);
- write_CTRL(cr);
- SSYNC();
+ /* set SPI transfer mode */
+ write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
drv_data->write(drv_data);
@@ -846,14 +920,11 @@ static void pump_transfers(unsigned long data)
tranf_success = 0;
} else if (drv_data->rx != NULL) {
/* read only half duplex */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_READ | (width << 8) |
- (CFG_SPI_ENABLE << 14);
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO read: cr is 0x%x\n", cr);
- write_CTRL(cr);
- SSYNC();
+ /* set SPI transfer mode */
+ write_CTRL(drv_data, (cr | CFG_SPI_READ));
drv_data->read(drv_data);
if (drv_data->rx != drv_data->rx_end)
@@ -861,7 +932,7 @@ static void pump_transfers(unsigned long data)
}
if (!tranf_success) {
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO write error!\n");
message->state = ERROR_STATE;
} else {
@@ -881,9 +952,11 @@ static void pump_transfers(unsigned long data)
/* pop a msg from queue and kick off real transfer */
static void pump_messages(struct work_struct *work)
{
- struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages);
+ struct driver_data *drv_data;
unsigned long flags;
+ drv_data = container_of(work, struct driver_data, pump_messages);
+
/* Lock queue and check for queue work */
spin_lock_irqsave(&drv_data->lock, flags);
if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
@@ -902,6 +975,14 @@ static void pump_messages(struct work_struct *work)
/* Extract head of queue */
drv_data->cur_msg = list_entry(drv_data->queue.next,
struct spi_message, queue);
+
+ /* Setup the SSP using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ if (restore_state(drv_data)) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ };
+
list_del_init(&drv_data->cur_msg->queue);
/* Initial message state */
@@ -909,15 +990,12 @@ static void pump_messages(struct work_struct *work)
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
struct spi_transfer, transfer_list);
- /* Setup the SSP using the per chip configuration */
- drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- restore_state(drv_data);
+ dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
+ "state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
+ drv_data->cur_chip->baud, drv_data->cur_chip->flag,
+ drv_data->cur_chip->ctl_reg);
+
dev_dbg(&drv_data->pdev->dev,
- "got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
- drv_data->cur_chip->baud, drv_data->cur_chip->flag,
- drv_data->cur_chip->ctl_reg);
-
- dev_dbg(&drv_data->pdev->dev,
"the first transfer len is %d\n",
drv_data->cur_transfer->len);
@@ -959,6 +1037,22 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
return 0;
}
+#define MAX_SPI_SSEL 7
+
+static u16 ssel[3][MAX_SPI_SSEL] = {
+ {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+ P_SPI0_SSEL4, P_SPI0_SSEL5,
+ P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+ {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+ P_SPI1_SSEL4, P_SPI1_SSEL5,
+ P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+ {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+ P_SPI2_SSEL4, P_SPI2_SSEL5,
+ P_SPI2_SSEL6, P_SPI2_SSEL7},
+};
+
/* first setup for new devices */
static int setup(struct spi_device *spi)
{
@@ -993,6 +1087,18 @@ static int setup(struct spi_device *spi)
/* chip_info isn't always needed */
if (chip_info) {
+ /* Make sure people stop trying to set fields via ctl_reg
+ * when they should actually be using common SPI framework.
+ * Currently we let through: WOM EMISO PSSE GM SZ TIMOD.
+ * Not sure if a user actually needs/uses any of these,
+ * but let's assume (for now) they do.
+ */
+ if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) {
+ dev_err(&spi->dev, "do not set bits in ctl_reg "
+ "that the SPI framework manages\n");
+ return -EINVAL;
+ }
+
chip->enable_dma = chip_info->enable_dma != 0
&& drv_data->master_info->enable_dma;
chip->ctl_reg = chip_info->ctl_reg;
@@ -1015,20 +1121,20 @@ static int setup(struct spi_device *spi)
* if any one SPI chip is registered and wants DMA, request the
* DMA channel for it
*/
- if (chip->enable_dma && !dma_requested) {
+ if (chip->enable_dma && !drv_data->dma_requested) {
/* register dma irq handler */
- if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) {
+ if (request_dma(drv_data->dma_channel, "BF53x_SPI_DMA") < 0) {
dev_dbg(&spi->dev,
"Unable to request BlackFin SPI DMA channel\n");
return -ENODEV;
}
- if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data)
- < 0) {
+ if (set_dma_callback(drv_data->dma_channel,
+ (void *)dma_irq_handler, drv_data) < 0) {
dev_dbg(&spi->dev, "Unable to set dma callback\n");
return -EPERM;
}
- dma_disable_irq(CH_SPI);
- dma_requested = 1;
+ dma_disable_irq(drv_data->dma_channel);
+ drv_data->dma_requested = 1;
}
/*
@@ -1077,6 +1183,14 @@ static int setup(struct spi_device *spi)
spi_set_ctldata(spi, chip);
+ dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
+ if ((chip->chip_select_num > 0)
+ && (chip->chip_select_num <= spi->master->num_chipselect))
+ peripheral_request(ssel[spi->master->bus_num]
+ [chip->chip_select_num-1], DRV_NAME);
+
+ cs_deactive(drv_data, chip);
+
return 0;
}
@@ -1088,6 +1202,11 @@ static void cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
+ if ((chip->chip_select_num > 0)
+ && (chip->chip_select_num <= spi->master->num_chipselect))
+ peripheral_free(ssel[spi->master->bus_num]
+ [chip->chip_select_num-1]);
+
kfree(chip);
}
@@ -1183,6 +1302,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
struct bfin5xx_spi_master *platform_info;
struct spi_master *master;
struct driver_data *drv_data = 0;
+ struct resource *res;
int status = 0;
platform_info = dev->platform_data;
@@ -1193,10 +1313,12 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can not alloc spi_master\n");
return -ENOMEM;
}
+
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
drv_data->master_info = platform_info;
drv_data->pdev = pdev;
+ drv_data->pin_req = platform_info->pin_req;
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
@@ -1204,15 +1326,38 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
master->setup = setup;
master->transfer = transfer;
+ /* Find and map our resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "Cannot get IORESOURCE_MEM\n");
+ status = -ENOENT;
+ goto out_error_get_res;
+ }
+
+ drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
+ if (drv_data->regs_base == NULL) {
+ dev_err(dev, "Cannot map IO\n");
+ status = -ENXIO;
+ goto out_error_ioremap;
+ }
+
+ drv_data->dma_channel = platform_get_irq(pdev, 0);
+ if (drv_data->dma_channel < 0) {
+ dev_err(dev, "No DMA channel specified\n");
+ status = -ENOENT;
+ goto out_error_no_dma_ch;
+ }
+
/* Initial and start queue */
status = init_queue(drv_data);
if (status != 0) {
- dev_err(&pdev->dev, "problem initializing queue\n");
+ dev_err(dev, "problem initializing queue\n");
goto out_error_queue_alloc;
}
+
status = start_queue(drv_data);
if (status != 0) {
- dev_err(&pdev->dev, "problem starting queue\n");
+ dev_err(dev, "problem starting queue\n");
goto out_error_queue_alloc;
}
@@ -1220,15 +1365,30 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drv_data);
status = spi_register_master(master);
if (status != 0) {
- dev_err(&pdev->dev, "problem registering spi master\n");
+ dev_err(dev, "problem registering spi master\n");
goto out_error_queue_alloc;
}
- dev_dbg(&pdev->dev, "controller probe successfully\n");
+
+ status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
+ if (status != 0) {
+ dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
+ goto out_error;
+ }
+
+ dev_info(dev, "%s, Version %s, regs_base@%p, dma channel@%d\n",
+ DRV_DESC, DRV_VERSION, drv_data->regs_base,
+ drv_data->dma_channel);
return status;
- out_error_queue_alloc:
+out_error_queue_alloc:
destroy_queue(drv_data);
+out_error_no_dma_ch:
+ iounmap((void *) drv_data->regs_base);
+out_error_ioremap:
+out_error_get_res:
+out_error:
spi_master_put(master);
+
return status;
}
@@ -1251,13 +1411,15 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
/* Release DMA */
if (drv_data->master_info->enable_dma) {
- if (dma_channel_active(CH_SPI))
- free_dma(CH_SPI);
+ if (dma_channel_active(drv_data->dma_channel))
+ free_dma(drv_data->dma_channel);
}
/* Disconnect from the SPI framework */
spi_unregister_master(drv_data->master);
+ peripheral_free_list(drv_data->pin_req);
+
/* Prevent double remove */
platform_set_drvdata(pdev, NULL);
@@ -1305,7 +1467,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */
static struct platform_driver bfin5xx_spi_driver = {
.driver = {
- .name = "bfin-spi-master",
+ .name = DRV_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin5xx_spi_suspend,
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 81639c6be1c..f7f8580edad 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -184,6 +184,7 @@ int spi_bitbang_setup(struct spi_device *spi)
struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang;
int retval;
+ unsigned long flags;
bitbang = spi_master_get_devdata(spi->master);
@@ -222,12 +223,12 @@ int spi_bitbang_setup(struct spi_device *spi)
*/
/* deselect chip (low or high) */
- spin_lock(&bitbang->lock);
+ spin_lock_irqsave(&bitbang->lock, flags);
if (!bitbang->busy) {
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(cs->nsecs);
}
- spin_unlock(&bitbang->lock);
+ spin_unlock_irqrestore(&bitbang->lock, flags);
return 0;
}
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 7686ba34430..2cd8573fb09 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1758,5 +1758,5 @@ static void __exit spi_imx_exit(void)
module_exit(spi_imx_exit);
MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
-MODULE_DESCRIPTION("iMX SPI Contoller Driver");
+MODULE_DESCRIPTION("iMX SPI Controller Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 4580b9cf625..04f7cd9fc26 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -436,11 +436,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->qe_mode = pdata->qe_mode;
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
-
- if (mpc83xx_spi->qe_mode)
- mpc83xx_spi->spibrg = pdata->sysclk / 2;
- else
- mpc83xx_spi->spibrg = pdata->sysclk;
+ mpc83xx_spi->spibrg = pdata->sysclk;
mpc83xx_spi->rx_shift = 0;
mpc83xx_spi->tx_shift = 0;
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index 0fa25e2e80f..109d82c1abc 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -96,6 +96,7 @@ static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
static int s3c2410_spigpio_probe(struct platform_device *dev)
{
+ struct s3c2410_spigpio_info *info;
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
@@ -113,10 +114,11 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp);
/* copy in the plkatform data */
- sp->info = dev->dev.platform_data;
+ info = sp->info = dev->dev.platform_data;
/* setup spi bitbang adaptor */
sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.master->bus_num = info->bus_num;
sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
@@ -124,13 +126,18 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
sp->bitbang.txrx_word[SPI_MODE_2] = s3c2410_spigpio_txrx_mode2;
sp->bitbang.txrx_word[SPI_MODE_3] = s3c2410_spigpio_txrx_mode3;
- /* set state of spi pins */
- s3c2410_gpio_setpin(sp->info->pin_clk, 0);
- s3c2410_gpio_setpin(sp->info->pin_mosi, 0);
+ /* set state of spi pins, always assume that the clock is
+ * available, but do check the MOSI and MISO. */
+ s3c2410_gpio_setpin(info->pin_clk, 0);
+ s3c2410_gpio_cfgpin(info->pin_clk, S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(sp->info->pin_clk, S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(sp->info->pin_mosi, S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(sp->info->pin_miso, S3C2410_GPIO_INPUT);
+ if (info->pin_mosi < S3C2410_GPH10) {
+ s3c2410_gpio_setpin(info->pin_mosi, 0);
+ s3c2410_gpio_cfgpin(info->pin_mosi, S3C2410_GPIO_OUTPUT);
+ }
+
+ if (info->pin_miso != S3C2410_GPA0 && info->pin_miso < S3C2410_GPH10)
+ s3c2410_gpio_cfgpin(info->pin_miso, S3C2410_GPIO_INPUT);
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index cc5094f37dd..363ac8e6882 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -24,6 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/io.h>
#include <asm/gpio.h>
@@ -74,7 +75,6 @@ struct txx9spi {
struct list_head queue;
wait_queue_head_t waitq;
void __iomem *membase;
- int irq;
int baseclk;
struct clk *clk;
u32 max_speed_hz, min_speed_hz;
@@ -350,12 +350,12 @@ static int __init txx9spi_probe(struct platform_device *dev)
struct resource *res;
int ret = -ENODEV;
u32 mcr;
+ int irq;
master = spi_alloc_master(&dev->dev, sizeof(*c));
if (!master)
return ret;
c = spi_master_get_devdata(master);
- c->irq = -1;
platform_set_drvdata(dev, master);
INIT_WORK(&c->work, txx9spi_work);
@@ -381,32 +381,36 @@ static int __init txx9spi_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
- goto exit;
- c->membase = ioremap(res->start, res->end - res->start + 1);
+ goto exit_busy;
+ if (!devm_request_mem_region(&dev->dev,
+ res->start, res->end - res->start + 1,
+ "spi_txx9"))
+ goto exit_busy;
+ c->membase = devm_ioremap(&dev->dev,
+ res->start, res->end - res->start + 1);
if (!c->membase)
- goto exit;
+ goto exit_busy;
/* enter config mode */
mcr = txx9spi_rd(c, TXx9_SPMCR);
mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
- c->irq = platform_get_irq(dev, 0);
- if (c->irq < 0)
- goto exit;
- ret = request_irq(c->irq, txx9spi_interrupt, 0, dev->name, c);
- if (ret) {
- c->irq = -1;
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0)
+ goto exit_busy;
+ ret = devm_request_irq(&dev->dev, irq, txx9spi_interrupt, 0,
+ "spi_txx9", c);
+ if (ret)
goto exit;
- }
c->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
if (!c->workqueue)
- goto exit;
+ goto exit_busy;
c->last_chipselect = -1;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
- (unsigned long long)res->start, c->irq,
+ (unsigned long long)res->start, irq,
(c->baseclk + 500000) / 1000000);
master->bus_num = dev->id;
@@ -418,13 +422,11 @@ static int __init txx9spi_probe(struct platform_device *dev)
if (ret)
goto exit;
return 0;
+exit_busy:
+ ret = -EBUSY;
exit:
if (c->workqueue)
destroy_workqueue(c->workqueue);
- if (c->irq >= 0)
- free_irq(c->irq, c);
- if (c->membase)
- iounmap(c->membase);
if (c->clk) {
clk_disable(c->clk);
clk_put(c->clk);
@@ -442,8 +444,6 @@ static int __exit txx9spi_remove(struct platform_device *dev)
spi_unregister_master(master);
platform_set_drvdata(dev, NULL);
destroy_workqueue(c->workqueue);
- free_irq(c->irq, c);
- iounmap(c->membase);
clk_disable(c->clk);
clk_put(c->clk);
spi_master_put(master);
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index c55459c592b..b3518ca9f04 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -184,14 +184,14 @@ static int spidev_message(struct spidev_data *spidev,
if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
- (ptrdiff_t) u_tmp->rx_buf,
+ (uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
if (copy_from_user(buf, (const u8 __user *)
- (ptrdiff_t) u_tmp->tx_buf,
+ (uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
@@ -224,7 +224,7 @@ static int spidev_message(struct spidev_data *spidev,
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
if (__copy_to_user((u8 __user *)
- (ptrdiff_t) u_tmp->rx_buf, buf,
+ (uintptr_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
diff --git a/drivers/spi/tle62x0.c b/drivers/spi/tle62x0.c
index 6da58ca48b3..455991fbe28 100644
--- a/drivers/spi/tle62x0.c
+++ b/drivers/spi/tle62x0.c
@@ -107,8 +107,11 @@ static ssize_t tle62x0_status_show(struct device *dev,
mutex_lock(&st->lock);
ret = tle62x0_read(st);
-
dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
fault <<= 8;