diff options
Diffstat (limited to 'drivers/spi/spi_bfin5xx.c')
-rw-r--r-- | drivers/spi/spi_bfin5xx.c | 124 |
1 files changed, 83 insertions, 41 deletions
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 8e4ea8906dc7..a8311a83ae96 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -13,6 +13,8 @@ | |||
13 | * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) | 13 | * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) |
14 | * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang) | 14 | * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang) |
15 | * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu) | 15 | * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu) |
16 | * July 30, 2007 add platfrom_resource interface to support multi-port | ||
17 | * SPI controller (Bryan Wu) | ||
16 | * | 18 | * |
17 | * Copyright 2004-2007 Analog Devices Inc. | 19 | * Copyright 2004-2007 Analog Devices Inc. |
18 | * | 20 | * |
@@ -50,18 +52,25 @@ | |||
50 | #include <asm/portmux.h> | 52 | #include <asm/portmux.h> |
51 | #include <asm/bfin5xx_spi.h> | 53 | #include <asm/bfin5xx_spi.h> |
52 | 54 | ||
53 | MODULE_AUTHOR("Bryan Wu, Luke Yang"); | 55 | #define DRV_NAME "bfin-spi" |
54 | MODULE_DESCRIPTION("Blackfin BF5xx SPI Contoller Driver"); | 56 | #define DRV_AUTHOR "Bryan Wu, Luke Yang" |
57 | #define DRV_DESC "Blackfin BF5xx on-chip SPI Contoller Driver" | ||
58 | #define DRV_VERSION "1.0" | ||
59 | |||
60 | MODULE_AUTHOR(DRV_AUTHOR); | ||
61 | MODULE_DESCRIPTION(DRV_DESC); | ||
55 | MODULE_LICENSE("GPL"); | 62 | MODULE_LICENSE("GPL"); |
56 | 63 | ||
57 | #define DRV_NAME "bfin-spi-master" | ||
58 | #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) | 64 | #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) |
59 | 65 | ||
66 | static u32 spi_dma_ch; | ||
67 | static u32 spi_regs_base; | ||
68 | |||
60 | #define DEFINE_SPI_REG(reg, off) \ | 69 | #define DEFINE_SPI_REG(reg, off) \ |
61 | static inline u16 read_##reg(void) \ | 70 | static inline u16 read_##reg(void) \ |
62 | { return bfin_read16(SPI0_REGBASE + off); } \ | 71 | { return bfin_read16(spi_regs_base + off); } \ |
63 | static inline void write_##reg(u16 v) \ | 72 | static inline void write_##reg(u16 v) \ |
64 | {bfin_write16(SPI0_REGBASE + off, v); } | 73 | {bfin_write16(spi_regs_base + off, v); } |
65 | 74 | ||
66 | DEFINE_SPI_REG(CTRL, 0x00) | 75 | DEFINE_SPI_REG(CTRL, 0x00) |
67 | DEFINE_SPI_REG(FLAG, 0x04) | 76 | DEFINE_SPI_REG(FLAG, 0x04) |
@@ -573,10 +582,10 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
573 | struct chip_data *chip = drv_data->cur_chip; | 582 | struct chip_data *chip = drv_data->cur_chip; |
574 | 583 | ||
575 | dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n"); | 584 | dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n"); |
576 | clear_dma_irqstat(CH_SPI); | 585 | clear_dma_irqstat(spi_dma_ch); |
577 | 586 | ||
578 | /* Wait for DMA to complete */ | 587 | /* Wait for DMA to complete */ |
579 | while (get_dma_curr_irqstat(CH_SPI) & DMA_RUN) | 588 | while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN) |
580 | continue; | 589 | continue; |
581 | 590 | ||
582 | /* | 591 | /* |
@@ -586,12 +595,12 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
586 | * register until it goes low for 2 successive reads | 595 | * register until it goes low for 2 successive reads |
587 | */ | 596 | */ |
588 | if (drv_data->tx != NULL) { | 597 | if (drv_data->tx != NULL) { |
589 | while ((bfin_read_SPI_STAT() & TXS) || | 598 | while ((read_STAT() & TXS) || |
590 | (bfin_read_SPI_STAT() & TXS)) | 599 | (read_STAT() & TXS)) |
591 | continue; | 600 | continue; |
592 | } | 601 | } |
593 | 602 | ||
594 | while (!(bfin_read_SPI_STAT() & SPIF)) | 603 | while (!(read_STAT() & SPIF)) |
595 | continue; | 604 | continue; |
596 | 605 | ||
597 | bfin_spi_disable(drv_data); | 606 | bfin_spi_disable(drv_data); |
@@ -610,8 +619,8 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
610 | /* free the irq handler before next transfer */ | 619 | /* free the irq handler before next transfer */ |
611 | dev_dbg(&drv_data->pdev->dev, | 620 | dev_dbg(&drv_data->pdev->dev, |
612 | "disable dma channel irq%d\n", | 621 | "disable dma channel irq%d\n", |
613 | CH_SPI); | 622 | spi_dma_ch); |
614 | dma_disable_irq(CH_SPI); | 623 | dma_disable_irq(spi_dma_ch); |
615 | 624 | ||
616 | return IRQ_HANDLED; | 625 | return IRQ_HANDLED; |
617 | } | 626 | } |
@@ -726,19 +735,19 @@ static void pump_transfers(unsigned long data) | |||
726 | if (drv_data->cur_chip->enable_dma && drv_data->len > 6) { | 735 | if (drv_data->cur_chip->enable_dma && drv_data->len > 6) { |
727 | 736 | ||
728 | write_STAT(BIT_STAT_CLR); | 737 | write_STAT(BIT_STAT_CLR); |
729 | disable_dma(CH_SPI); | 738 | disable_dma(spi_dma_ch); |
730 | clear_dma_irqstat(CH_SPI); | 739 | clear_dma_irqstat(spi_dma_ch); |
731 | bfin_spi_disable(drv_data); | 740 | bfin_spi_disable(drv_data); |
732 | 741 | ||
733 | /* config dma channel */ | 742 | /* config dma channel */ |
734 | dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); | 743 | dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); |
735 | if (width == CFG_SPI_WORDSIZE16) { | 744 | if (width == CFG_SPI_WORDSIZE16) { |
736 | set_dma_x_count(CH_SPI, drv_data->len); | 745 | set_dma_x_count(spi_dma_ch, drv_data->len); |
737 | set_dma_x_modify(CH_SPI, 2); | 746 | set_dma_x_modify(spi_dma_ch, 2); |
738 | dma_width = WDSIZE_16; | 747 | dma_width = WDSIZE_16; |
739 | } else { | 748 | } else { |
740 | set_dma_x_count(CH_SPI, drv_data->len); | 749 | set_dma_x_count(spi_dma_ch, drv_data->len); |
741 | set_dma_x_modify(CH_SPI, 1); | 750 | set_dma_x_modify(spi_dma_ch, 1); |
742 | dma_width = WDSIZE_8; | 751 | dma_width = WDSIZE_8; |
743 | } | 752 | } |
744 | 753 | ||
@@ -753,9 +762,10 @@ static void pump_transfers(unsigned long data) | |||
753 | /* no irq in autobuffer mode */ | 762 | /* no irq in autobuffer mode */ |
754 | dma_config = | 763 | dma_config = |
755 | (DMAFLOW_AUTO | RESTART | dma_width | DI_EN); | 764 | (DMAFLOW_AUTO | RESTART | dma_width | DI_EN); |
756 | set_dma_config(CH_SPI, dma_config); | 765 | set_dma_config(spi_dma_ch, dma_config); |
757 | set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); | 766 | set_dma_start_addr(spi_dma_ch, |
758 | enable_dma(CH_SPI); | 767 | (unsigned long)drv_data->tx); |
768 | enable_dma(spi_dma_ch); | ||
759 | write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | | 769 | write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | |
760 | (CFG_SPI_ENABLE << 14)); | 770 | (CFG_SPI_ENABLE << 14)); |
761 | 771 | ||
@@ -776,14 +786,15 @@ static void pump_transfers(unsigned long data) | |||
776 | /* clear tx reg soformer data is not shifted out */ | 786 | /* clear tx reg soformer data is not shifted out */ |
777 | write_TDBR(0xFF); | 787 | write_TDBR(0xFF); |
778 | 788 | ||
779 | set_dma_x_count(CH_SPI, drv_data->len); | 789 | set_dma_x_count(spi_dma_ch, drv_data->len); |
780 | 790 | ||
781 | /* start dma */ | 791 | /* start dma */ |
782 | dma_enable_irq(CH_SPI); | 792 | dma_enable_irq(spi_dma_ch); |
783 | dma_config = (WNR | RESTART | dma_width | DI_EN); | 793 | dma_config = (WNR | RESTART | dma_width | DI_EN); |
784 | set_dma_config(CH_SPI, dma_config); | 794 | set_dma_config(spi_dma_ch, dma_config); |
785 | set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx); | 795 | set_dma_start_addr(spi_dma_ch, |
786 | enable_dma(CH_SPI); | 796 | (unsigned long)drv_data->rx); |
797 | enable_dma(spi_dma_ch); | ||
787 | 798 | ||
788 | cr |= | 799 | cr |= |
789 | CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE << | 800 | CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE << |
@@ -794,11 +805,12 @@ static void pump_transfers(unsigned long data) | |||
794 | dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); | 805 | dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); |
795 | 806 | ||
796 | /* start dma */ | 807 | /* start dma */ |
797 | dma_enable_irq(CH_SPI); | 808 | dma_enable_irq(spi_dma_ch); |
798 | dma_config = (RESTART | dma_width | DI_EN); | 809 | dma_config = (RESTART | dma_width | DI_EN); |
799 | set_dma_config(CH_SPI, dma_config); | 810 | set_dma_config(spi_dma_ch, dma_config); |
800 | set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); | 811 | set_dma_start_addr(spi_dma_ch, |
801 | enable_dma(CH_SPI); | 812 | (unsigned long)drv_data->tx); |
813 | enable_dma(spi_dma_ch); | ||
802 | 814 | ||
803 | write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | | 815 | write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | |
804 | (CFG_SPI_ENABLE << 14)); | 816 | (CFG_SPI_ENABLE << 14)); |
@@ -1034,17 +1046,17 @@ static int setup(struct spi_device *spi) | |||
1034 | */ | 1046 | */ |
1035 | if (chip->enable_dma && !dma_requested) { | 1047 | if (chip->enable_dma && !dma_requested) { |
1036 | /* register dma irq handler */ | 1048 | /* register dma irq handler */ |
1037 | if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) { | 1049 | if (request_dma(spi_dma_ch, "BF53x_SPI_DMA") < 0) { |
1038 | dev_dbg(&spi->dev, | 1050 | dev_dbg(&spi->dev, |
1039 | "Unable to request BlackFin SPI DMA channel\n"); | 1051 | "Unable to request BlackFin SPI DMA channel\n"); |
1040 | return -ENODEV; | 1052 | return -ENODEV; |
1041 | } | 1053 | } |
1042 | if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data) | 1054 | if (set_dma_callback(spi_dma_ch, (void *)dma_irq_handler, |
1043 | < 0) { | 1055 | drv_data) < 0) { |
1044 | dev_dbg(&spi->dev, "Unable to set dma callback\n"); | 1056 | dev_dbg(&spi->dev, "Unable to set dma callback\n"); |
1045 | return -EPERM; | 1057 | return -EPERM; |
1046 | } | 1058 | } |
1047 | dma_disable_irq(CH_SPI); | 1059 | dma_disable_irq(spi_dma_ch); |
1048 | dma_requested = 1; | 1060 | dma_requested = 1; |
1049 | } | 1061 | } |
1050 | 1062 | ||
@@ -1215,6 +1227,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) | |||
1215 | struct bfin5xx_spi_master *platform_info; | 1227 | struct bfin5xx_spi_master *platform_info; |
1216 | struct spi_master *master; | 1228 | struct spi_master *master; |
1217 | struct driver_data *drv_data = 0; | 1229 | struct driver_data *drv_data = 0; |
1230 | struct resource *res; | ||
1218 | int status = 0; | 1231 | int status = 0; |
1219 | 1232 | ||
1220 | platform_info = dev->platform_data; | 1233 | platform_info = dev->platform_data; |
@@ -1242,15 +1255,38 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) | |||
1242 | master->setup = setup; | 1255 | master->setup = setup; |
1243 | master->transfer = transfer; | 1256 | master->transfer = transfer; |
1244 | 1257 | ||
1258 | /* Find and map our resources */ | ||
1259 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1260 | if (res == NULL) { | ||
1261 | dev_err(dev, "Cannot get IORESOURCE_MEM\n"); | ||
1262 | status = -ENOENT; | ||
1263 | goto out_error_get_res; | ||
1264 | } | ||
1265 | |||
1266 | spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1); | ||
1267 | if (!spi_regs_base) { | ||
1268 | dev_err(dev, "Cannot map IO\n"); | ||
1269 | status = -ENXIO; | ||
1270 | goto out_error_ioremap; | ||
1271 | } | ||
1272 | |||
1273 | spi_dma_ch = platform_get_irq(pdev, 0); | ||
1274 | if (spi_dma_ch < 0) { | ||
1275 | dev_err(dev, "No DMA channel specified\n"); | ||
1276 | status = -ENOENT; | ||
1277 | goto out_error_no_dma_ch; | ||
1278 | } | ||
1279 | |||
1245 | /* Initial and start queue */ | 1280 | /* Initial and start queue */ |
1246 | status = init_queue(drv_data); | 1281 | status = init_queue(drv_data); |
1247 | if (status != 0) { | 1282 | if (status != 0) { |
1248 | dev_err(&pdev->dev, "problem initializing queue\n"); | 1283 | dev_err(dev, "problem initializing queue\n"); |
1249 | goto out_error_queue_alloc; | 1284 | goto out_error_queue_alloc; |
1250 | } | 1285 | } |
1286 | |||
1251 | status = start_queue(drv_data); | 1287 | status = start_queue(drv_data); |
1252 | if (status != 0) { | 1288 | if (status != 0) { |
1253 | dev_err(&pdev->dev, "problem starting queue\n"); | 1289 | dev_err(dev, "problem starting queue\n"); |
1254 | goto out_error_queue_alloc; | 1290 | goto out_error_queue_alloc; |
1255 | } | 1291 | } |
1256 | 1292 | ||
@@ -1258,14 +1294,20 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) | |||
1258 | platform_set_drvdata(pdev, drv_data); | 1294 | platform_set_drvdata(pdev, drv_data); |
1259 | status = spi_register_master(master); | 1295 | status = spi_register_master(master); |
1260 | if (status != 0) { | 1296 | if (status != 0) { |
1261 | dev_err(&pdev->dev, "problem registering spi master\n"); | 1297 | dev_err(dev, "problem registering spi master\n"); |
1262 | goto out_error_queue_alloc; | 1298 | goto out_error_queue_alloc; |
1263 | } | 1299 | } |
1264 | dev_dbg(&pdev->dev, "controller probe successfully\n"); | 1300 | |
1301 | dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n", | ||
1302 | DRV_DESC, DRV_VERSION, spi_regs_base); | ||
1265 | return status; | 1303 | return status; |
1266 | 1304 | ||
1267 | out_error_queue_alloc: | 1305 | out_error_queue_alloc: |
1268 | destroy_queue(drv_data); | 1306 | destroy_queue(drv_data); |
1307 | out_error_no_dma_ch: | ||
1308 | iounmap((void *) spi_regs_base); | ||
1309 | out_error_ioremap: | ||
1310 | out_error_get_res: | ||
1269 | out_error: | 1311 | out_error: |
1270 | spi_master_put(master); | 1312 | spi_master_put(master); |
1271 | 1313 | ||
@@ -1291,8 +1333,8 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev) | |||
1291 | 1333 | ||
1292 | /* Release DMA */ | 1334 | /* Release DMA */ |
1293 | if (drv_data->master_info->enable_dma) { | 1335 | if (drv_data->master_info->enable_dma) { |
1294 | if (dma_channel_active(CH_SPI)) | 1336 | if (dma_channel_active(spi_dma_ch)) |
1295 | free_dma(CH_SPI); | 1337 | free_dma(spi_dma_ch); |
1296 | } | 1338 | } |
1297 | 1339 | ||
1298 | /* Disconnect from the SPI framework */ | 1340 | /* Disconnect from the SPI framework */ |
@@ -1347,7 +1389,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev) | |||
1347 | MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */ | 1389 | MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */ |
1348 | static struct platform_driver bfin5xx_spi_driver = { | 1390 | static struct platform_driver bfin5xx_spi_driver = { |
1349 | .driver = { | 1391 | .driver = { |
1350 | .name = "bfin-spi-master", | 1392 | .name = DRV_NAME, |
1351 | .owner = THIS_MODULE, | 1393 | .owner = THIS_MODULE, |
1352 | }, | 1394 | }, |
1353 | .suspend = bfin5xx_spi_suspend, | 1395 | .suspend = bfin5xx_spi_suspend, |