aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2009-08-14 05:59:05 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-08-15 10:36:29 -0400
commitc7c8c78fdf6e9bd65d8ee879115dc2cd5d9fd0dc (patch)
tree91f59159fed1c22277c72e2529317561778657b9
parentdf1e0520f9434b5b771c854a13dd928727d8673a (diff)
ARM: 5667/3: U300 SSP/SPI board setup and test
This adds a U300 board configuration for the PL022 SSP/SPI PrimeCell driver recently merged to the 2.6.31-rc series. Further it adds a dummy loopback SPI chip that can be used for testing the SPI functionality on a running system using the loopback mode of PL022. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-u300/Kconfig12
-rw-r--r--arch/arm/mach-u300/Makefile2
-rw-r--r--arch/arm/mach-u300/core.c6
-rw-r--r--arch/arm/mach-u300/dummyspichip.c290
-rw-r--r--arch/arm/mach-u300/spi.c124
-rw-r--r--arch/arm/mach-u300/spi.h26
6 files changed, 460 insertions, 0 deletions
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index 337b9aabce49..801b21e7f677 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -81,6 +81,18 @@ config MACH_U300_SEMI_IS_SHARED
81 Memory Interface) from both from access and application 81 Memory Interface) from both from access and application
82 side. 82 side.
83 83
84config MACH_U300_SPIDUMMY
85 bool "SSP/SPI dummy chip"
86 select SPI
87 select SPI_MASTER
88 select SPI_PL022
89 help
90 This creates a small kernel module that creates a dummy
91 SPI device to be used for loopback tests. Regularly used
92 to test reference designs. If you're not testing SPI,
93 you don't need it. Selecting this will activate the
94 SPI framework and ARM PL022 support.
95
84comment "All the settings below must match the bootloader's settings" 96comment "All the settings below must match the bootloader's settings"
85 97
86config MACH_U300_ACCESS_MEM_SIZE 98config MACH_U300_ACCESS_MEM_SIZE
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 24950e0df4b4..4941f89ea798 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -9,3 +9,5 @@ obj- :=
9 9
10obj-$(CONFIG_ARCH_U300) += u300.o 10obj-$(CONFIG_ARCH_U300) += u300.o
11obj-$(CONFIG_MMC) += mmc.o 11obj-$(CONFIG_MMC) += mmc.o
12obj-$(CONFIG_SPI_PL022) += spi.o
13obj-$(CONFIG_MACH_U300_SPIDUMMY) += dummyspichip.o
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 89b3ccf35e1b..38d08a1c25d0 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -32,6 +32,7 @@
32 32
33#include "clock.h" 33#include "clock.h"
34#include "mmc.h" 34#include "mmc.h"
35#include "spi.h"
35 36
36/* 37/*
37 * Static I/O mappings that are needed for booting the U300 platforms. The 38 * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -611,6 +612,8 @@ void __init u300_init_devices(void)
611 /* Wait for the PLL208 to lock if not locked in yet */ 612 /* Wait for the PLL208 to lock if not locked in yet */
612 while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) & 613 while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
613 U300_SYSCON_CSR_PLL208_LOCK_IND)); 614 U300_SYSCON_CSR_PLL208_LOCK_IND));
615 /* Initialize SPI device with some board specifics */
616 u300_spi_init(&pl022_device);
614 617
615 /* Register the AMBA devices in the AMBA bus abstraction layer */ 618 /* Register the AMBA devices in the AMBA bus abstraction layer */
616 u300_clock_primecells(); 619 u300_clock_primecells();
@@ -622,6 +625,9 @@ void __init u300_init_devices(void)
622 625
623 u300_assign_physmem(); 626 u300_assign_physmem();
624 627
628 /* Register subdevices on the SPI bus */
629 u300_spi_register_board_devices();
630
625 /* Register the platform devices */ 631 /* Register the platform devices */
626 platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); 632 platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
627 633
diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c
new file mode 100644
index 000000000000..962f9de454de
--- /dev/null
+++ b/arch/arm/mach-u300/dummyspichip.c
@@ -0,0 +1,290 @@
1/*
2 * arch/arm/mach-u300/dummyspichip.c
3 *
4 * Copyright (C) 2007-2009 ST-Ericsson AB
5 * License terms: GNU General Public License (GPL) version 2
6 * This is a dummy loopback SPI "chip" used for testing SPI.
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
8 */
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/device.h>
13#include <linux/err.h>
14#include <linux/sysfs.h>
15#include <linux/mutex.h>
16#include <linux/spi/spi.h>
17#include <linux/dma-mapping.h>
18/*
19 * WARNING! Do not include this pl022-specific controller header
20 * for any generic driver. It is only done in this dummy chip
21 * because we alter the chip configuration in order to test some
22 * different settings on the loopback device. Normal chip configs
23 * shall be STATIC and not altered by the driver!
24 */
25#include <linux/amba/pl022.h>
26
27struct dummy {
28 struct device *dev;
29 struct mutex lock;
30};
31
32#define DMA_TEST_SIZE 2048
33
34/* When we cat /sys/bus/spi/devices/spi0.0/looptest this will be triggered */
35static ssize_t dummy_looptest(struct device *dev,
36 struct device_attribute *attr, char *buf)
37{
38 struct spi_device *spi = to_spi_device(dev);
39 struct dummy *p_dummy = dev_get_drvdata(&spi->dev);
40
41 /*
42 * WARNING! Do not dereference the chip-specific data in any normal
43 * driver for a chip. It is usually STATIC and shall not be read
44 * or written to. Your chip driver should NOT depend on fields in this
45 * struct, this is just used here to alter the behaviour of the chip
46 * in order to perform tests.
47 */
48 struct pl022_config_chip *chip_info = spi->controller_data;
49 int status;
50 u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD,
51 0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05,
52 0xF0, 0x0D};
53 u8 rxbuf[14];
54 u8 *bigtxbuf_virtual;
55 u8 *bigrxbuf_virtual;
56
57 if (mutex_lock_interruptible(&p_dummy->lock))
58 return -ERESTARTSYS;
59
60 bigtxbuf_virtual = kmalloc(DMA_TEST_SIZE, GFP_KERNEL);
61 if (bigtxbuf_virtual == NULL) {
62 status = -ENOMEM;
63 goto out;
64 }
65 bigrxbuf_virtual = kmalloc(DMA_TEST_SIZE, GFP_KERNEL);
66
67 /* Fill TXBUF with some happy pattern */
68 memset(bigtxbuf_virtual, 0xAA, DMA_TEST_SIZE);
69
70 /*
71 * Force chip to 8 bit mode
72 * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
73 */
74 chip_info->data_size = SSP_DATA_BITS_8;
75 /* You should NOT DO THIS EITHER */
76 spi->master->setup(spi);
77
78 /* Now run the tests for 8bit mode */
79 pr_info("Simple test 1: write 0xAA byte, read back garbage byte "
80 "in 8bit mode\n");
81 status = spi_w8r8(spi, 0xAA);
82 if (status < 0)
83 pr_warning("Siple test 1: FAILURE: spi_write_then_read "
84 "failed with status %d\n", status);
85 else
86 pr_info("Simple test 1: SUCCESS!\n");
87
88 pr_info("Simple test 2: write 8 bytes, read back 8 bytes garbage "
89 "in 8bit mode (full FIFO)\n");
90 status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
91 if (status < 0)
92 pr_warning("Simple test 2: FAILURE: spi_write_then_read() "
93 "failed with status %d\n", status);
94 else
95 pr_info("Simple test 2: SUCCESS!\n");
96
97 pr_info("Simple test 3: write 14 bytes, read back 14 bytes garbage "
98 "in 8bit mode (see if we overflow FIFO)\n");
99 status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
100 if (status < 0)
101 pr_warning("Simple test 3: FAILURE: failed with status %d "
102 "(probably FIFO overrun)\n", status);
103 else
104 pr_info("Simple test 3: SUCCESS!\n");
105
106 pr_info("Simple test 4: write 8 bytes with spi_write(), read 8 "
107 "bytes garbage with spi_read() in 8bit mode\n");
108 status = spi_write(spi, &txbuf[0], 8);
109 if (status < 0)
110 pr_warning("Simple test 4 step 1: FAILURE: spi_write() "
111 "failed with status %d\n", status);
112 else
113 pr_info("Simple test 4 step 1: SUCCESS!\n");
114 status = spi_read(spi, &rxbuf[0], 8);
115 if (status < 0)
116 pr_warning("Simple test 4 step 2: FAILURE: spi_read() "
117 "failed with status %d\n", status);
118 else
119 pr_info("Simple test 4 step 2: SUCCESS!\n");
120
121 pr_info("Simple test 5: write 14 bytes with spi_write(), read "
122 "14 bytes garbage with spi_read() in 8bit mode\n");
123 status = spi_write(spi, &txbuf[0], 14);
124 if (status < 0)
125 pr_warning("Simple test 5 step 1: FAILURE: spi_write() "
126 "failed with status %d (probably FIFO overrun)\n",
127 status);
128 else
129 pr_info("Simple test 5 step 1: SUCCESS!\n");
130 status = spi_read(spi, &rxbuf[0], 14);
131 if (status < 0)
132 pr_warning("Simple test 5 step 2: FAILURE: spi_read() "
133 "failed with status %d (probably FIFO overrun)\n",
134 status);
135 else
136 pr_info("Simple test 5: SUCCESS!\n");
137
138 pr_info("Simple test 6: write %d bytes with spi_write(), "
139 "read %d bytes garbage with spi_read() in 8bit mode\n",
140 DMA_TEST_SIZE, DMA_TEST_SIZE);
141 status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
142 if (status < 0)
143 pr_warning("Simple test 6 step 1: FAILURE: spi_write() "
144 "failed with status %d (probably FIFO overrun)\n",
145 status);
146 else
147 pr_info("Simple test 6 step 1: SUCCESS!\n");
148 status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
149 if (status < 0)
150 pr_warning("Simple test 6 step 2: FAILURE: spi_read() "
151 "failed with status %d (probably FIFO overrun)\n",
152 status);
153 else
154 pr_info("Simple test 6: SUCCESS!\n");
155
156
157 /*
158 * Force chip to 16 bit mode
159 * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
160 */
161 chip_info->data_size = SSP_DATA_BITS_16;
162 /* You should NOT DO THIS EITHER */
163 spi->master->setup(spi);
164
165 pr_info("Simple test 7: write 0xAA byte, read back garbage byte "
166 "in 16bit bus mode\n");
167 status = spi_w8r8(spi, 0xAA);
168 if (status == -EIO)
169 pr_info("Simple test 7: SUCCESS! (expected failure with "
170 "status EIO)\n");
171 else if (status < 0)
172 pr_warning("Siple test 7: FAILURE: spi_write_then_read "
173 "failed with status %d\n", status);
174 else
175 pr_warning("Siple test 7: FAILURE: spi_write_then_read "
176 "succeeded but it was expected to fail!\n");
177
178 pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage "
179 "in 16bit mode (full FIFO)\n");
180 status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
181 if (status < 0)
182 pr_warning("Simple test 8: FAILURE: spi_write_then_read() "
183 "failed with status %d\n", status);
184 else
185 pr_info("Simple test 8: SUCCESS!\n");
186
187 pr_info("Simple test 9: write 14 bytes, read back 14 bytes garbage "
188 "in 16bit mode (see if we overflow FIFO)\n");
189 status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
190 if (status < 0)
191 pr_warning("Simple test 9: FAILURE: failed with status %d "
192 "(probably FIFO overrun)\n", status);
193 else
194 pr_info("Simple test 9: SUCCESS!\n");
195
196 pr_info("Simple test 10: write %d bytes with spi_write(), "
197 "read %d bytes garbage with spi_read() in 16bit mode\n",
198 DMA_TEST_SIZE, DMA_TEST_SIZE);
199 status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
200 if (status < 0)
201 pr_warning("Simple test 10 step 1: FAILURE: spi_write() "
202 "failed with status %d (probably FIFO overrun)\n",
203 status);
204 else
205 pr_info("Simple test 10 step 1: SUCCESS!\n");
206
207 status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
208 if (status < 0)
209 pr_warning("Simple test 10 step 2: FAILURE: spi_read() "
210 "failed with status %d (probably FIFO overrun)\n",
211 status);
212 else
213 pr_info("Simple test 10: SUCCESS!\n");
214
215 status = sprintf(buf, "loop test complete\n");
216 kfree(bigrxbuf_virtual);
217 kfree(bigtxbuf_virtual);
218 out:
219 mutex_unlock(&p_dummy->lock);
220 return status;
221}
222
223static DEVICE_ATTR(looptest, S_IRUGO, dummy_looptest, NULL);
224
225static int __devinit pl022_dummy_probe(struct spi_device *spi)
226{
227 struct dummy *p_dummy;
228 int status;
229
230 dev_info(&spi->dev, "probing dummy SPI device\n");
231
232 p_dummy = kzalloc(sizeof *p_dummy, GFP_KERNEL);
233 if (!p_dummy)
234 return -ENOMEM;
235
236 dev_set_drvdata(&spi->dev, p_dummy);
237 mutex_init(&p_dummy->lock);
238
239 /* sysfs hook */
240 status = device_create_file(&spi->dev, &dev_attr_looptest);
241 if (status) {
242 dev_dbg(&spi->dev, "device_create_file looptest failure.\n");
243 goto out_dev_create_looptest_failed;
244 }
245
246 return 0;
247
248out_dev_create_looptest_failed:
249 dev_set_drvdata(&spi->dev, NULL);
250 kfree(p_dummy);
251 return status;
252}
253
254static int __devexit pl022_dummy_remove(struct spi_device *spi)
255{
256 struct dummy *p_dummy = dev_get_drvdata(&spi->dev);
257
258 dev_info(&spi->dev, "removing dummy SPI device\n");
259 device_remove_file(&spi->dev, &dev_attr_looptest);
260 dev_set_drvdata(&spi->dev, NULL);
261 kfree(p_dummy);
262
263 return 0;
264}
265
266static struct spi_driver pl022_dummy_driver = {
267 .driver = {
268 .name = "spi-dummy",
269 .owner = THIS_MODULE,
270 },
271 .probe = pl022_dummy_probe,
272 .remove = __devexit_p(pl022_dummy_remove),
273};
274
275static int __init pl022_init_dummy(void)
276{
277 return spi_register_driver(&pl022_dummy_driver);
278}
279
280static void __exit pl022_exit_dummy(void)
281{
282 spi_unregister_driver(&pl022_dummy_driver);
283}
284
285module_init(pl022_init_dummy);
286module_exit(pl022_exit_dummy);
287
288MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
289MODULE_DESCRIPTION("PL022 SSP/SPI DUMMY Linux driver");
290MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
new file mode 100644
index 000000000000..307d007ea7f3
--- /dev/null
+++ b/arch/arm/mach-u300/spi.c
@@ -0,0 +1,124 @@
1/*
2 * arch/arm/mach-u300/spi.c
3 *
4 * Copyright (C) 2009 ST-Ericsson AB
5 * License terms: GNU General Public License (GPL) version 2
6 *
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
8 */
9#include <linux/device.h>
10#include <linux/amba/bus.h>
11#include <linux/spi/spi.h>
12#include <linux/amba/pl022.h>
13#include <linux/err.h>
14#include "padmux.h"
15
16/*
17 * The following is for the actual devices on the SSP/SPI bus
18 */
19#ifdef CONFIG_MACH_U300_SPIDUMMY
20static void select_dummy_chip(u32 chipselect)
21{
22 pr_debug("CORE: %s called with CS=0x%x (%s)\n",
23 __func__,
24 chipselect,
25 chipselect ? "unselect chip" : "select chip");
26 /*
27 * Here you would write the chip select value to the GPIO pins if
28 * this was a real chip (but this is a loopback dummy).
29 */
30}
31
32struct pl022_config_chip dummy_chip_info = {
33 /* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */
34 .lbm = LOOPBACK_ENABLED,
35 /*
36 * available POLLING_TRANSFER and INTERRUPT_TRANSFER,
37 * DMA_TRANSFER does not work
38 */
39 .com_mode = INTERRUPT_TRANSFER,
40 .iface = SSP_INTERFACE_MOTOROLA_SPI,
41 /* We can only act as master but SSP_SLAVE is possible in theory */
42 .hierarchy = SSP_MASTER,
43 /* 0 = drive TX even as slave, 1 = do not drive TX as slave */
44 .slave_tx_disable = 0,
45 /* LSB first */
46 .endian_tx = SSP_TX_LSB,
47 .endian_rx = SSP_RX_LSB,
48 .data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */
49 .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
50 .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
51 .clk_phase = SSP_CLK_FALLING_EDGE,
52 .clk_pol = SSP_CLK_POL_IDLE_LOW,
53 .ctrl_len = SSP_BITS_12,
54 .wait_state = SSP_MWIRE_WAIT_ZERO,
55 .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
56 /*
57 * This is where you insert a call to a function to enable CS
58 * (usually GPIO) for a certain chip.
59 */
60 .cs_control = select_dummy_chip,
61};
62#endif
63
64static struct spi_board_info u300_spi_devices[] = {
65#ifdef CONFIG_MACH_U300_SPIDUMMY
66 {
67 /* A dummy chip used for loopback tests */
68 .modalias = "spi-dummy",
69 /* Really dummy, pass in additional chip config here */
70 .platform_data = NULL,
71 /* This defines how the controller shall handle the device */
72 .controller_data = &dummy_chip_info,
73 /* .irq - no external IRQ routed from this device */
74 .max_speed_hz = 1000000,
75 .bus_num = 0, /* Only one bus on this chip */
76 .chip_select = 0,
77 /* Means SPI_CS_HIGH, change if e.g low CS */
78 .mode = 0,
79 },
80#endif
81};
82
83static struct pl022_ssp_controller ssp_platform_data = {
84 /* If you have several SPI buses this varies, we have only bus 0 */
85 .bus_id = 0,
86 /* Set this to 1 when we think we got DMA working */
87 .enable_dma = 0,
88 /*
89 * On the APP CPU GPIO 4, 5 and 6 are connected as generic
90 * chip selects for SPI. (Same on U330, U335 and U365.)
91 * TODO: make sure the GPIO driver can select these properly
92 * and do padmuxing accordingly too.
93 */
94 .num_chipselect = 3,
95};
96
97
98void __init u300_spi_init(struct amba_device *adev)
99{
100 struct pmx *pmx;
101
102 adev->dev.platform_data = &ssp_platform_data;
103 /*
104 * Setup padmuxing for SPI. Since this must always be
105 * compiled into the kernel, pmx is never released.
106 */
107 pmx = pmx_get(&adev->dev, U300_APP_PMX_SPI_SETTING);
108
109 if (IS_ERR(pmx))
110 dev_warn(&adev->dev, "Could not get padmux handle\n");
111 else {
112 int ret;
113
114 ret = pmx_activate(&adev->dev, pmx);
115 if (IS_ERR_VALUE(ret))
116 dev_warn(&adev->dev, "Could not activate padmuxing\n");
117 }
118
119}
120void __init u300_spi_register_board_devices(void)
121{
122 /* Register any SPI devices */
123 spi_register_board_info(u300_spi_devices, ARRAY_SIZE(u300_spi_devices));
124}
diff --git a/arch/arm/mach-u300/spi.h b/arch/arm/mach-u300/spi.h
new file mode 100644
index 000000000000..bd3d867e240f
--- /dev/null
+++ b/arch/arm/mach-u300/spi.h
@@ -0,0 +1,26 @@
1/*
2 * arch/arm/mach-u300/spi.h
3 *
4 * Copyright (C) 2009 ST-Ericsson AB
5 * License terms: GNU General Public License (GPL) version 2
6 *
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
8 */
9#ifndef SPI_H
10#define SPI_H
11#include <linux/amba/bus.h>
12
13#ifdef CONFIG_SPI_PL022
14void __init u300_spi_init(struct amba_device *adev);
15void __init u300_spi_register_board_devices(void);
16#else
17/* Compile out SPI support if PL022 is not selected */
18static inline void __init u300_spi_init(struct amba_device *adev)
19{
20}
21static inline void __init u300_spi_register_board_devices(void)
22{
23}
24#endif
25
26#endif