diff options
author | Bryan Wu <bryan.wu@analog.com> | 2007-12-05 02:45:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-12-05 12:21:19 -0500 |
commit | 131b17d42de6194fa960132c1f62c29923c4f20c (patch) | |
tree | 7606b689e111820328ff5c88a57192adce02cec2 /drivers/spi | |
parent | c24b2602af88db4489c6c3fb4b2a8e47fb15769b (diff) |
spi: initial BF54x SPI support
Initial BF54x SPI support
- support BF54x SPI0
- clean up some code (whitespace etc)
- will support multiports in the future
- start using portmux calls
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi_bfin5xx.c | 139 |
1 files changed, 69 insertions, 70 deletions
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 2ef11bb70b2e..805f03bb5ef9 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -1,17 +1,20 @@ | |||
1 | /* | 1 | /* |
2 | * File: drivers/spi/bfin5xx_spi.c | 2 | * File: drivers/spi/bfin5xx_spi.c |
3 | * Based on: N/A | 3 | * Maintainer: |
4 | * Author: Luke Yang (Analog Devices Inc.) | 4 | * Bryan Wu <bryan.wu@analog.com> |
5 | * Original Author: | ||
6 | * Luke Yang (Analog Devices Inc.) | ||
5 | * | 7 | * |
6 | * Created: March. 10th 2006 | 8 | * Created: March. 10th 2006 |
7 | * Description: SPI controller driver for Blackfin 5xx | 9 | * Description: SPI controller driver for Blackfin BF5xx |
8 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | 10 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ |
9 | * | 11 | * |
10 | * Modified: | 12 | * Modified: |
11 | * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) | 13 | * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) |
12 | * 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) | ||
13 | * | 16 | * |
14 | * Copyright 2004-2006 Analog Devices Inc. | 17 | * Copyright 2004-2007 Analog Devices Inc. |
15 | * | 18 | * |
16 | * This program is free software ; you can redistribute it and/or modify | 19 | * This program is free software ; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 20 | * it under the terms of the GNU General Public License as published by |
@@ -31,27 +34,27 @@ | |||
31 | 34 | ||
32 | #include <linux/init.h> | 35 | #include <linux/init.h> |
33 | #include <linux/module.h> | 36 | #include <linux/module.h> |
37 | #include <linux/delay.h> | ||
34 | #include <linux/device.h> | 38 | #include <linux/device.h> |
39 | #include <linux/io.h> | ||
35 | #include <linux/ioport.h> | 40 | #include <linux/ioport.h> |
41 | #include <linux/irq.h> | ||
36 | #include <linux/errno.h> | 42 | #include <linux/errno.h> |
37 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
38 | #include <linux/platform_device.h> | 44 | #include <linux/platform_device.h> |
39 | #include <linux/dma-mapping.h> | 45 | #include <linux/dma-mapping.h> |
40 | #include <linux/spi/spi.h> | 46 | #include <linux/spi/spi.h> |
41 | #include <linux/workqueue.h> | 47 | #include <linux/workqueue.h> |
42 | #include <linux/delay.h> | ||
43 | 48 | ||
44 | #include <asm/io.h> | ||
45 | #include <asm/irq.h> | ||
46 | #include <asm/delay.h> | ||
47 | #include <asm/dma.h> | 49 | #include <asm/dma.h> |
48 | 50 | #include <asm/portmux.h> | |
49 | #include <asm/bfin5xx_spi.h> | 51 | #include <asm/bfin5xx_spi.h> |
50 | 52 | ||
51 | MODULE_AUTHOR("Luke Yang"); | 53 | MODULE_AUTHOR("Bryan Wu, Luke Yang"); |
52 | MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller"); | 54 | MODULE_DESCRIPTION("Blackfin BF5xx SPI Contoller Driver"); |
53 | MODULE_LICENSE("GPL"); | 55 | MODULE_LICENSE("GPL"); |
54 | 56 | ||
57 | #define DRV_NAME "bfin-spi-master" | ||
55 | #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) | 58 | #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) |
56 | 59 | ||
57 | #define DEFINE_SPI_REG(reg, off) \ | 60 | #define DEFINE_SPI_REG(reg, off) \ |
@@ -124,6 +127,7 @@ struct chip_data { | |||
124 | u16 flag; | 127 | u16 flag; |
125 | 128 | ||
126 | u8 chip_select_num; | 129 | u8 chip_select_num; |
130 | u8 chip_select_requested; | ||
127 | u8 n_bytes; | 131 | u8 n_bytes; |
128 | u8 width; /* 0 or 1 */ | 132 | u8 width; /* 0 or 1 */ |
129 | u8 enable_dma; | 133 | u8 enable_dma; |
@@ -188,53 +192,37 @@ static void restore_state(struct driver_data *drv_data) | |||
188 | bfin_spi_disable(drv_data); | 192 | bfin_spi_disable(drv_data); |
189 | dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); | 193 | dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); |
190 | 194 | ||
191 | #if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537) | 195 | if (!chip->chip_select_requested) { |
192 | dev_dbg(&drv_data->pdev->dev, | ||
193 | "chip select number is %d\n", chip->chip_select_num); | ||
194 | |||
195 | switch (chip->chip_select_num) { | ||
196 | case 1: | ||
197 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00); | ||
198 | SSYNC(); | ||
199 | break; | ||
200 | 196 | ||
201 | case 2: | 197 | dev_dbg(&drv_data->pdev->dev, |
202 | case 3: | 198 | "chip select number is %d\n", chip->chip_select_num); |
203 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI); | ||
204 | SSYNC(); | ||
205 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); | ||
206 | SSYNC(); | ||
207 | break; | ||
208 | |||
209 | case 4: | ||
210 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI); | ||
211 | SSYNC(); | ||
212 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840); | ||
213 | SSYNC(); | ||
214 | break; | ||
215 | |||
216 | case 5: | ||
217 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI); | ||
218 | SSYNC(); | ||
219 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820); | ||
220 | SSYNC(); | ||
221 | break; | ||
222 | 199 | ||
223 | case 6: | 200 | switch (chip->chip_select_num) { |
224 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI); | 201 | case 1: |
225 | SSYNC(); | 202 | peripheral_request(P_SPI0_SSEL1, DRV_NAME); |
226 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810); | 203 | break; |
227 | SSYNC(); | 204 | case 2: |
228 | break; | 205 | peripheral_request(P_SPI0_SSEL2, DRV_NAME); |
206 | break; | ||
207 | case 3: | ||
208 | peripheral_request(P_SPI0_SSEL3, DRV_NAME); | ||
209 | break; | ||
210 | case 4: | ||
211 | peripheral_request(P_SPI0_SSEL4, DRV_NAME); | ||
212 | break; | ||
213 | case 5: | ||
214 | peripheral_request(P_SPI0_SSEL5, DRV_NAME); | ||
215 | break; | ||
216 | case 6: | ||
217 | peripheral_request(P_SPI0_SSEL6, DRV_NAME); | ||
218 | break; | ||
219 | case 7: | ||
220 | peripheral_request(P_SPI0_SSEL7, DRV_NAME); | ||
221 | break; | ||
222 | } | ||
229 | 223 | ||
230 | case 7: | 224 | chip->chip_select_requested = 1; |
231 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI); | ||
232 | SSYNC(); | ||
233 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); | ||
234 | SSYNC(); | ||
235 | break; | ||
236 | } | 225 | } |
237 | #endif | ||
238 | 226 | ||
239 | /* Load the registers */ | 227 | /* Load the registers */ |
240 | write_CTRL(chip->ctl_reg); | 228 | write_CTRL(chip->ctl_reg); |
@@ -277,7 +265,7 @@ static void null_reader(struct driver_data *drv_data) | |||
277 | 265 | ||
278 | static void u8_writer(struct driver_data *drv_data) | 266 | static void u8_writer(struct driver_data *drv_data) |
279 | { | 267 | { |
280 | dev_dbg(&drv_data->pdev->dev, | 268 | dev_dbg(&drv_data->pdev->dev, |
281 | "cr8-s is 0x%x\n", read_STAT()); | 269 | "cr8-s is 0x%x\n", read_STAT()); |
282 | while (drv_data->tx < drv_data->tx_end) { | 270 | while (drv_data->tx < drv_data->tx_end) { |
283 | write_TDBR(*(u8 *) (drv_data->tx)); | 271 | write_TDBR(*(u8 *) (drv_data->tx)); |
@@ -316,7 +304,7 @@ static void u8_cs_chg_writer(struct driver_data *drv_data) | |||
316 | 304 | ||
317 | static void u8_reader(struct driver_data *drv_data) | 305 | static void u8_reader(struct driver_data *drv_data) |
318 | { | 306 | { |
319 | dev_dbg(&drv_data->pdev->dev, | 307 | dev_dbg(&drv_data->pdev->dev, |
320 | "cr-8 is 0x%x\n", read_STAT()); | 308 | "cr-8 is 0x%x\n", read_STAT()); |
321 | 309 | ||
322 | /* clear TDBR buffer before read(else it will be shifted out) */ | 310 | /* clear TDBR buffer before read(else it will be shifted out) */ |
@@ -403,7 +391,7 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data) | |||
403 | 391 | ||
404 | static void u16_writer(struct driver_data *drv_data) | 392 | static void u16_writer(struct driver_data *drv_data) |
405 | { | 393 | { |
406 | dev_dbg(&drv_data->pdev->dev, | 394 | dev_dbg(&drv_data->pdev->dev, |
407 | "cr16 is 0x%x\n", read_STAT()); | 395 | "cr16 is 0x%x\n", read_STAT()); |
408 | 396 | ||
409 | while (drv_data->tx < drv_data->tx_end) { | 397 | while (drv_data->tx < drv_data->tx_end) { |
@@ -700,9 +688,9 @@ static void pump_transfers(unsigned long data) | |||
700 | drv_data->write = drv_data->tx ? chip->write : null_writer; | 688 | drv_data->write = drv_data->tx ? chip->write : null_writer; |
701 | drv_data->read = drv_data->rx ? chip->read : null_reader; | 689 | drv_data->read = drv_data->rx ? chip->read : null_reader; |
702 | drv_data->duplex = chip->duplex ? chip->duplex : null_writer; | 690 | drv_data->duplex = chip->duplex ? chip->duplex : null_writer; |
703 | dev_dbg(&drv_data->pdev->dev, | 691 | dev_dbg(&drv_data->pdev->dev, "transfer: ", |
704 | "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n", | 692 | "drv_data->write is %p, chip->write is %p, null_wr is %p\n", |
705 | drv_data->write, chip->write, null_writer); | 693 | drv_data->write, chip->write, null_writer); |
706 | 694 | ||
707 | /* speed and width has been set on per message */ | 695 | /* speed and width has been set on per message */ |
708 | message->state = RUNNING_STATE; | 696 | message->state = RUNNING_STATE; |
@@ -816,7 +804,7 @@ static void pump_transfers(unsigned long data) | |||
816 | /* full duplex mode */ | 804 | /* full duplex mode */ |
817 | BUG_ON((drv_data->tx_end - drv_data->tx) != | 805 | BUG_ON((drv_data->tx_end - drv_data->tx) != |
818 | (drv_data->rx_end - drv_data->rx)); | 806 | (drv_data->rx_end - drv_data->rx)); |
819 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); | 807 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); |
820 | cr |= CFG_SPI_WRITE | (width << 8) | | 808 | cr |= CFG_SPI_WRITE | (width << 8) | |
821 | (CFG_SPI_ENABLE << 14); | 809 | (CFG_SPI_ENABLE << 14); |
822 | dev_dbg(&drv_data->pdev->dev, | 810 | dev_dbg(&drv_data->pdev->dev, |
@@ -834,7 +822,7 @@ static void pump_transfers(unsigned long data) | |||
834 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); | 822 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); |
835 | cr |= CFG_SPI_WRITE | (width << 8) | | 823 | cr |= CFG_SPI_WRITE | (width << 8) | |
836 | (CFG_SPI_ENABLE << 14); | 824 | (CFG_SPI_ENABLE << 14); |
837 | dev_dbg(&drv_data->pdev->dev, | 825 | dev_dbg(&drv_data->pdev->dev, |
838 | "IO write: cr is 0x%x\n", cr); | 826 | "IO write: cr is 0x%x\n", cr); |
839 | 827 | ||
840 | write_CTRL(cr); | 828 | write_CTRL(cr); |
@@ -849,7 +837,7 @@ static void pump_transfers(unsigned long data) | |||
849 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); | 837 | cr = (read_CTRL() & (~BIT_CTL_TIMOD)); |
850 | cr |= CFG_SPI_READ | (width << 8) | | 838 | cr |= CFG_SPI_READ | (width << 8) | |
851 | (CFG_SPI_ENABLE << 14); | 839 | (CFG_SPI_ENABLE << 14); |
852 | dev_dbg(&drv_data->pdev->dev, | 840 | dev_dbg(&drv_data->pdev->dev, |
853 | "IO read: cr is 0x%x\n", cr); | 841 | "IO read: cr is 0x%x\n", cr); |
854 | 842 | ||
855 | write_CTRL(cr); | 843 | write_CTRL(cr); |
@@ -861,7 +849,7 @@ static void pump_transfers(unsigned long data) | |||
861 | } | 849 | } |
862 | 850 | ||
863 | if (!tranf_success) { | 851 | if (!tranf_success) { |
864 | dev_dbg(&drv_data->pdev->dev, | 852 | dev_dbg(&drv_data->pdev->dev, |
865 | "IO write error!\n"); | 853 | "IO write error!\n"); |
866 | message->state = ERROR_STATE; | 854 | message->state = ERROR_STATE; |
867 | } else { | 855 | } else { |
@@ -881,9 +869,11 @@ static void pump_transfers(unsigned long data) | |||
881 | /* pop a msg from queue and kick off real transfer */ | 869 | /* pop a msg from queue and kick off real transfer */ |
882 | static void pump_messages(struct work_struct *work) | 870 | static void pump_messages(struct work_struct *work) |
883 | { | 871 | { |
884 | struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages); | 872 | struct driver_data *drv_data; |
885 | unsigned long flags; | 873 | unsigned long flags; |
886 | 874 | ||
875 | drv_data = container_of(work, struct driver_data, pump_messages); | ||
876 | |||
887 | /* Lock queue and check for queue work */ | 877 | /* Lock queue and check for queue work */ |
888 | spin_lock_irqsave(&drv_data->lock, flags); | 878 | spin_lock_irqsave(&drv_data->lock, flags); |
889 | if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { | 879 | if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { |
@@ -916,8 +906,8 @@ static void pump_messages(struct work_struct *work) | |||
916 | "got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n", | 906 | "got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n", |
917 | drv_data->cur_chip->baud, drv_data->cur_chip->flag, | 907 | drv_data->cur_chip->baud, drv_data->cur_chip->flag, |
918 | drv_data->cur_chip->ctl_reg); | 908 | drv_data->cur_chip->ctl_reg); |
919 | 909 | ||
920 | dev_dbg(&drv_data->pdev->dev, | 910 | dev_dbg(&drv_data->pdev->dev, |
921 | "the first transfer len is %d\n", | 911 | "the first transfer len is %d\n", |
922 | drv_data->cur_transfer->len); | 912 | drv_data->cur_transfer->len); |
923 | 913 | ||
@@ -1193,6 +1183,15 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) | |||
1193 | dev_err(&pdev->dev, "can not alloc spi_master\n"); | 1183 | dev_err(&pdev->dev, "can not alloc spi_master\n"); |
1194 | return -ENOMEM; | 1184 | return -ENOMEM; |
1195 | } | 1185 | } |
1186 | |||
1187 | if (peripheral_request(P_SPI0_SCK, DRV_NAME) || | ||
1188 | peripheral_request(P_SPI0_MISO, DRV_NAME) || | ||
1189 | peripheral_request(P_SPI0_MOSI, DRV_NAME)) { | ||
1190 | |||
1191 | dev_err(&pdev->dev, ": Requesting Peripherals failed\n"); | ||
1192 | goto out_error_queue_alloc; | ||
1193 | } | ||
1194 | |||
1196 | drv_data = spi_master_get_devdata(master); | 1195 | drv_data = spi_master_get_devdata(master); |
1197 | drv_data->master = master; | 1196 | drv_data->master = master; |
1198 | drv_data->master_info = platform_info; | 1197 | drv_data->master_info = platform_info; |