x86: cpa self-test, WARN_ON()
[wrt350n-kernel.git] / arch / arm / mach-lh7a40x / ssp-cpld.c
bloba10830186dac94bd8dd5062386ba9c574cefca48
1 /* arch/arm/mach-lh7a40x/ssp-cpld.c
3 * Copyright (C) 2004,2005 Marc Singer
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
9 * SSP/SPI driver for the CardEngine CPLD.
13 /* NOTES
14 -----
16 o *** This driver is cribbed from the 7952x implementation.
17 Some comments may not apply.
19 o This driver contains sufficient logic to control either the
20 serial EEPROMs or the audio codec. It is included in the kernel
21 to support the codec. The EEPROMs are really the responsibility
22 of the boot loader and should probably be left alone.
24 o The code must be augmented to cope with multiple, simultaneous
25 clients.
26 o The audio codec writes to the codec chip whenever playback
27 starts.
28 o The touchscreen driver writes to the ads chip every time it
29 samples.
30 o The audio codec must write 16 bits, but the touch chip writes
31 are 8 bits long.
32 o We need to be able to keep these configurations separate while
33 simultaneously active.
37 #include <linux/module.h>
38 #include <linux/kernel.h>
39 //#include <linux/sched.h>
40 #include <linux/errno.h>
41 #include <linux/interrupt.h>
42 //#include <linux/ioport.h>
43 #include <linux/init.h>
44 #include <linux/delay.h>
45 #include <linux/spinlock.h>
47 #include <asm/io.h>
48 #include <asm/irq.h>
49 #include <asm/hardware.h>
51 #include <asm/arch/ssp.h>
53 //#define TALK
55 #if defined (TALK)
56 #define PRINTK(f...) printk (f)
57 #else
58 #define PRINTK(f...) do {} while (0)
59 #endif
61 #if defined (CONFIG_ARCH_LH7A400)
62 # define CPLD_SPID __REGP16(CPLD06_VIRT) /* SPI data */
63 # define CPLD_SPIC __REGP16(CPLD08_VIRT) /* SPI control */
64 # define CPLD_SPIC_CS_CODEC (1<<0)
65 # define CPLD_SPIC_CS_TOUCH (1<<1)
66 # define CPLD_SPIC_WRITE (0<<2)
67 # define CPLD_SPIC_READ (1<<2)
68 # define CPLD_SPIC_DONE (1<<3) /* r/o */
69 # define CPLD_SPIC_LOAD (1<<4)
70 # define CPLD_SPIC_START (1<<4)
71 # define CPLD_SPIC_LOADED (1<<5) /* r/o */
72 #endif
74 #define CPLD_SPI __REGP16(CPLD0A_VIRT) /* SPI operation */
75 #define CPLD_SPI_CS_EEPROM (1<<3)
76 #define CPLD_SPI_SCLK (1<<2)
77 #define CPLD_SPI_TX_SHIFT (1)
78 #define CPLD_SPI_TX (1<<CPLD_SPI_TX_SHIFT)
79 #define CPLD_SPI_RX_SHIFT (0)
80 #define CPLD_SPI_RX (1<<CPLD_SPI_RX_SHIFT)
82 /* *** FIXME: these timing values are substantially larger than the
83 *** chip requires. We may implement an nsleep () function. */
84 #define T_SKH 1 /* Clock time high (us) */
85 #define T_SKL 1 /* Clock time low (us) */
86 #define T_CS 1 /* Minimum chip select low time (us) */
87 #define T_CSS 1 /* Minimum chip select setup time (us) */
88 #define T_DIS 1 /* Data setup time (us) */
90 /* EEPROM SPI bits */
91 #define P_START (1<<9)
92 #define P_WRITE (1<<7)
93 #define P_READ (2<<7)
94 #define P_ERASE (3<<7)
95 #define P_EWDS (0<<7)
96 #define P_WRAL (0<<7)
97 #define P_ERAL (0<<7)
98 #define P_EWEN (0<<7)
99 #define P_A_EWDS (0<<5)
100 #define P_A_WRAL (1<<5)
101 #define P_A_ERAL (2<<5)
102 #define P_A_EWEN (3<<5)
104 struct ssp_configuration {
105 int device;
106 int mode;
107 int speed;
108 int frame_size_write;
109 int frame_size_read;
112 static struct ssp_configuration ssp_configuration;
113 static spinlock_t ssp_lock;
115 static void enable_cs (void)
117 switch (ssp_configuration.device) {
118 case DEVICE_EEPROM:
119 CPLD_SPI |= CPLD_SPI_CS_EEPROM;
120 break;
122 udelay (T_CSS);
125 static void disable_cs (void)
127 switch (ssp_configuration.device) {
128 case DEVICE_EEPROM:
129 CPLD_SPI &= ~CPLD_SPI_CS_EEPROM;
130 break;
132 udelay (T_CS);
135 static void pulse_clock (void)
137 CPLD_SPI |= CPLD_SPI_SCLK;
138 udelay (T_SKH);
139 CPLD_SPI &= ~CPLD_SPI_SCLK;
140 udelay (T_SKL);
144 /* execute_spi_command
146 sends an spi command to a device. It first sends cwrite bits from
147 v. If cread is greater than zero it will read cread bits
148 (discarding the leading 0 bit) and return them. If cread is less
149 than zero it will check for completetion status and return 0 on
150 success or -1 on timeout. If cread is zero it does nothing other
151 than sending the command.
153 On the LPD7A400, we can only read or write multiples of 8 bits on
154 the codec and the touch screen device. Here, we round up.
158 static int execute_spi_command (int v, int cwrite, int cread)
160 unsigned long l = 0;
162 #if defined (CONFIG_MACH_LPD7A400)
163 /* The codec and touch devices cannot be bit-banged. Instead,
164 * the CPLD provides an eight-bit shift register and a crude
165 * interface. */
166 if ( ssp_configuration.device == DEVICE_CODEC
167 || ssp_configuration.device == DEVICE_TOUCH) {
168 int select = 0;
170 PRINTK ("spi(%d %d.%d) 0x%04x",
171 ssp_configuration.device, cwrite, cread,
173 #if defined (TALK)
174 if (ssp_configuration.device == DEVICE_CODEC)
175 PRINTK (" 0x%03x -> %2d", v & 0x1ff, (v >> 9) & 0x7f);
176 #endif
177 PRINTK ("\n");
179 if (ssp_configuration.device == DEVICE_CODEC)
180 select = CPLD_SPIC_CS_CODEC;
181 if (ssp_configuration.device == DEVICE_TOUCH)
182 select = CPLD_SPIC_CS_TOUCH;
183 if (cwrite) {
184 for (cwrite = (cwrite + 7)/8; cwrite-- > 0; ) {
185 CPLD_SPID = (v >> (8*cwrite)) & 0xff;
186 CPLD_SPIC = select | CPLD_SPIC_LOAD;
187 while (!(CPLD_SPIC & CPLD_SPIC_LOADED))
189 CPLD_SPIC = select;
190 while (!(CPLD_SPIC & CPLD_SPIC_DONE))
193 v = 0;
195 if (cread) {
196 mdelay (2); /* *** FIXME: required by ads7843? */
197 v = 0;
198 for (cread = (cread + 7)/8; cread-- > 0;) {
199 CPLD_SPID = 0;
200 CPLD_SPIC = select | CPLD_SPIC_READ
201 | CPLD_SPIC_START;
202 while (!(CPLD_SPIC & CPLD_SPIC_LOADED))
204 CPLD_SPIC = select | CPLD_SPIC_READ;
205 while (!(CPLD_SPIC & CPLD_SPIC_DONE))
207 v = (v << 8) | CPLD_SPID;
210 return v;
212 #endif
214 PRINTK ("spi(%d) 0x%04x -> 0x%x\r\n", ssp_configuration.device,
215 v & 0x1ff, (v >> 9) & 0x7f);
217 enable_cs ();
219 v <<= CPLD_SPI_TX_SHIFT; /* Correction for position of SPI_TX bit */
220 while (cwrite--) {
221 CPLD_SPI
222 = (CPLD_SPI & ~CPLD_SPI_TX)
223 | ((v >> cwrite) & CPLD_SPI_TX);
224 udelay (T_DIS);
225 pulse_clock ();
228 if (cread < 0) {
229 int delay = 10;
230 disable_cs ();
231 udelay (1);
232 enable_cs ();
234 l = -1;
235 do {
236 if (CPLD_SPI & CPLD_SPI_RX) {
237 l = 0;
238 break;
240 } while (udelay (1), --delay);
242 else
243 /* We pulse the clock before the data to skip the leading zero. */
244 while (cread-- > 0) {
245 pulse_clock ();
246 l = (l<<1)
247 | (((CPLD_SPI & CPLD_SPI_RX)
248 >> CPLD_SPI_RX_SHIFT) & 0x1);
251 disable_cs ();
252 return l;
255 static int ssp_init (void)
257 spin_lock_init (&ssp_lock);
258 memset (&ssp_configuration, 0, sizeof (ssp_configuration));
259 return 0;
263 /* ssp_chip_select
265 drops the chip select line for the CPLD shift-register controlled
266 devices. It doesn't enable chip
270 static void ssp_chip_select (int enable)
272 #if defined (CONFIG_MACH_LPD7A400)
273 int select;
275 if (ssp_configuration.device == DEVICE_CODEC)
276 select = CPLD_SPIC_CS_CODEC;
277 else if (ssp_configuration.device == DEVICE_TOUCH)
278 select = CPLD_SPIC_CS_TOUCH;
279 else
280 return;
282 if (enable)
283 CPLD_SPIC = select;
284 else
285 CPLD_SPIC = 0;
286 #endif
289 static void ssp_acquire (void)
291 spin_lock (&ssp_lock);
294 static void ssp_release (void)
296 ssp_chip_select (0); /* just in case */
297 spin_unlock (&ssp_lock);
300 static int ssp_configure (int device, int mode, int speed,
301 int frame_size_write, int frame_size_read)
303 ssp_configuration.device = device;
304 ssp_configuration.mode = mode;
305 ssp_configuration.speed = speed;
306 ssp_configuration.frame_size_write = frame_size_write;
307 ssp_configuration.frame_size_read = frame_size_read;
309 return 0;
312 static int ssp_read (void)
314 return execute_spi_command (0, 0, ssp_configuration.frame_size_read);
317 static int ssp_write (u16 data)
319 execute_spi_command (data, ssp_configuration.frame_size_write, 0);
320 return 0;
323 static int ssp_write_read (u16 data)
325 return execute_spi_command (data, ssp_configuration.frame_size_write,
326 ssp_configuration.frame_size_read);
329 struct ssp_driver lh7a40x_cpld_ssp_driver = {
330 .init = ssp_init,
331 .acquire = ssp_acquire,
332 .release = ssp_release,
333 .configure = ssp_configure,
334 .chip_select = ssp_chip_select,
335 .read = ssp_read,
336 .write = ssp_write,
337 .write_read = ssp_write_read,
341 MODULE_AUTHOR("Marc Singer");
342 MODULE_DESCRIPTION("LPD7A40X CPLD SPI driver");
343 MODULE_LICENSE("GPL");