|
@@ -13,6 +13,8 @@
|
|
|
* 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-2007 Analog Devices Inc.
|
|
|
*
|
|
@@ -50,18 +52,25 @@
|
|
|
#include <asm/portmux.h>
|
|
|
#include <asm/bfin5xx_spi.h>
|
|
|
|
|
|
-MODULE_AUTHOR("Bryan Wu, Luke Yang");
|
|
|
-MODULE_DESCRIPTION("Blackfin BF5xx SPI Contoller Driver");
|
|
|
+#define DRV_NAME "bfin-spi"
|
|
|
+#define DRV_AUTHOR "Bryan Wu, Luke Yang"
|
|
|
+#define DRV_DESC "Blackfin BF5xx on-chip SPI Contoller Driver"
|
|
|
+#define DRV_VERSION "1.0"
|
|
|
+
|
|
|
+MODULE_AUTHOR(DRV_AUTHOR);
|
|
|
+MODULE_DESCRIPTION(DRV_DESC);
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
-#define DRV_NAME "bfin-spi-master"
|
|
|
#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
|
|
|
|
|
|
+static u32 spi_dma_ch;
|
|
|
+static u32 spi_regs_base;
|
|
|
+
|
|
|
#define DEFINE_SPI_REG(reg, off) \
|
|
|
static inline u16 read_##reg(void) \
|
|
|
- { return bfin_read16(SPI0_REGBASE + off); } \
|
|
|
+ { return bfin_read16(spi_regs_base + off); } \
|
|
|
static inline void write_##reg(u16 v) \
|
|
|
- {bfin_write16(SPI0_REGBASE + off, v); }
|
|
|
+ {bfin_write16(spi_regs_base + off, v); }
|
|
|
|
|
|
DEFINE_SPI_REG(CTRL, 0x00)
|
|
|
DEFINE_SPI_REG(FLAG, 0x04)
|
|
@@ -573,10 +582,10 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
|
|
|
struct chip_data *chip = drv_data->cur_chip;
|
|
|
|
|
|
dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
|
|
|
- clear_dma_irqstat(CH_SPI);
|
|
|
+ clear_dma_irqstat(spi_dma_ch);
|
|
|
|
|
|
/* Wait for DMA to complete */
|
|
|
- while (get_dma_curr_irqstat(CH_SPI) & DMA_RUN)
|
|
|
+ while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN)
|
|
|
continue;
|
|
|
|
|
|
/*
|
|
@@ -586,12 +595,12 @@ 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))
|
|
|
+ while ((read_STAT() & TXS) ||
|
|
|
+ (read_STAT() & TXS))
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- while (!(bfin_read_SPI_STAT() & SPIF))
|
|
|
+ while (!(read_STAT() & SPIF))
|
|
|
continue;
|
|
|
|
|
|
bfin_spi_disable(drv_data);
|
|
@@ -610,8 +619,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);
|
|
|
+ spi_dma_ch);
|
|
|
+ dma_disable_irq(spi_dma_ch);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
@@ -726,19 +735,19 @@ 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(spi_dma_ch);
|
|
|
+ clear_dma_irqstat(spi_dma_ch);
|
|
|
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(spi_dma_ch, drv_data->len);
|
|
|
+ set_dma_x_modify(spi_dma_ch, 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(spi_dma_ch, drv_data->len);
|
|
|
+ set_dma_x_modify(spi_dma_ch, 1);
|
|
|
dma_width = WDSIZE_8;
|
|
|
}
|
|
|
|
|
@@ -753,9 +762,10 @@ 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);
|
|
|
+ set_dma_config(spi_dma_ch, dma_config);
|
|
|
+ set_dma_start_addr(spi_dma_ch,
|
|
|
+ (unsigned long)drv_data->tx);
|
|
|
+ enable_dma(spi_dma_ch);
|
|
|
write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
|
|
|
(CFG_SPI_ENABLE << 14));
|
|
|
|
|
@@ -776,14 +786,15 @@ static void pump_transfers(unsigned long data)
|
|
|
/* clear tx reg soformer data is not shifted out */
|
|
|
write_TDBR(0xFF);
|
|
|
|
|
|
- set_dma_x_count(CH_SPI, drv_data->len);
|
|
|
+ set_dma_x_count(spi_dma_ch, drv_data->len);
|
|
|
|
|
|
/* start dma */
|
|
|
- dma_enable_irq(CH_SPI);
|
|
|
+ dma_enable_irq(spi_dma_ch);
|
|
|
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(spi_dma_ch, dma_config);
|
|
|
+ set_dma_start_addr(spi_dma_ch,
|
|
|
+ (unsigned long)drv_data->rx);
|
|
|
+ enable_dma(spi_dma_ch);
|
|
|
|
|
|
cr |=
|
|
|
CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
|
|
@@ -794,11 +805,12 @@ static void pump_transfers(unsigned long data)
|
|
|
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
|
|
|
|
|
|
/* start dma */
|
|
|
- dma_enable_irq(CH_SPI);
|
|
|
+ dma_enable_irq(spi_dma_ch);
|
|
|
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);
|
|
|
+ set_dma_config(spi_dma_ch, dma_config);
|
|
|
+ set_dma_start_addr(spi_dma_ch,
|
|
|
+ (unsigned long)drv_data->tx);
|
|
|
+ enable_dma(spi_dma_ch);
|
|
|
|
|
|
write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
|
|
|
(CFG_SPI_ENABLE << 14));
|
|
@@ -1034,17 +1046,17 @@ static int setup(struct spi_device *spi)
|
|
|
*/
|
|
|
if (chip->enable_dma && !dma_requested) {
|
|
|
/* register dma irq handler */
|
|
|
- if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) {
|
|
|
+ if (request_dma(spi_dma_ch, "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(spi_dma_ch, (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_disable_irq(spi_dma_ch);
|
|
|
dma_requested = 1;
|
|
|
}
|
|
|
|
|
@@ -1215,6 +1227,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;
|
|
@@ -1242,15 +1255,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;
|
|
|
+ }
|
|
|
+
|
|
|
+ spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
|
|
|
+ if (!spi_regs_base) {
|
|
|
+ dev_err(dev, "Cannot map IO\n");
|
|
|
+ status = -ENXIO;
|
|
|
+ goto out_error_ioremap;
|
|
|
+ }
|
|
|
+
|
|
|
+ spi_dma_ch = platform_get_irq(pdev, 0);
|
|
|
+ if (spi_dma_ch < 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;
|
|
|
}
|
|
|
|
|
@@ -1258,14 +1294,20 @@ 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");
|
|
|
+
|
|
|
+ dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
|
|
|
+ DRV_DESC, DRV_VERSION, spi_regs_base);
|
|
|
return status;
|
|
|
|
|
|
out_error_queue_alloc:
|
|
|
destroy_queue(drv_data);
|
|
|
+out_error_no_dma_ch:
|
|
|
+ iounmap((void *) spi_regs_base);
|
|
|
+out_error_ioremap:
|
|
|
+out_error_get_res:
|
|
|
out_error:
|
|
|
spi_master_put(master);
|
|
|
|
|
@@ -1291,8 +1333,8 @@ 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(spi_dma_ch))
|
|
|
+ free_dma(spi_dma_ch);
|
|
|
}
|
|
|
|
|
|
/* Disconnect from the SPI framework */
|
|
@@ -1347,7 +1389,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,
|