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.
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
26 o The audio codec writes to the codec chip whenever playback
28 o The touchscreen driver writes to the ads chip every time it
30 o The audio codec must write 16 bits, but the touch chip writes
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>
49 #include <asm/hardware.h>
51 #include <asm/arch/ssp.h>
56 #define PRINTK(f...) printk (f)
58 #define PRINTK(f...) do {} while (0)
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 */
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) */
91 #define P_START (1<<9)
92 #define P_WRITE (1<<7)
94 #define P_ERASE (3<<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
{
108 int frame_size_write
;
112 static struct ssp_configuration ssp_configuration
;
113 static spinlock_t ssp_lock
;
115 static void enable_cs (void)
117 switch (ssp_configuration
.device
) {
119 CPLD_SPI
|= CPLD_SPI_CS_EEPROM
;
125 static void disable_cs (void)
127 switch (ssp_configuration
.device
) {
129 CPLD_SPI
&= ~CPLD_SPI_CS_EEPROM
;
135 static void pulse_clock (void)
137 CPLD_SPI
|= CPLD_SPI_SCLK
;
139 CPLD_SPI
&= ~CPLD_SPI_SCLK
;
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
)
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
166 if ( ssp_configuration
.device
== DEVICE_CODEC
167 || ssp_configuration
.device
== DEVICE_TOUCH
) {
170 PRINTK ("spi(%d %d.%d) 0x%04x",
171 ssp_configuration
.device
, cwrite
, cread
,
174 if (ssp_configuration
.device
== DEVICE_CODEC
)
175 PRINTK (" 0x%03x -> %2d", v
& 0x1ff, (v
>> 9) & 0x7f);
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
;
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
))
190 while (!(CPLD_SPIC
& CPLD_SPIC_DONE
))
196 mdelay (2); /* *** FIXME: required by ads7843? */
198 for (cread
= (cread
+ 7)/8; cread
-- > 0;) {
200 CPLD_SPIC
= select
| CPLD_SPIC_READ
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
;
214 PRINTK ("spi(%d) 0x%04x -> 0x%x\r\n", ssp_configuration
.device
,
215 v
& 0x1ff, (v
>> 9) & 0x7f);
219 v
<<= CPLD_SPI_TX_SHIFT
; /* Correction for position of SPI_TX bit */
222 = (CPLD_SPI
& ~CPLD_SPI_TX
)
223 | ((v
>> cwrite
) & CPLD_SPI_TX
);
236 if (CPLD_SPI
& CPLD_SPI_RX
) {
240 } while (udelay (1), --delay
);
243 /* We pulse the clock before the data to skip the leading zero. */
244 while (cread
-- > 0) {
247 | (((CPLD_SPI
& CPLD_SPI_RX
)
248 >> CPLD_SPI_RX_SHIFT
) & 0x1);
255 static int ssp_init (void)
257 spin_lock_init (&ssp_lock
);
258 memset (&ssp_configuration
, 0, sizeof (ssp_configuration
));
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)
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
;
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
;
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);
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
= {
331 .acquire
= ssp_acquire
,
332 .release
= ssp_release
,
333 .configure
= ssp_configure
,
334 .chip_select
= ssp_chip_select
,
337 .write_read
= ssp_write_read
,
341 MODULE_AUTHOR("Marc Singer");
342 MODULE_DESCRIPTION("LPD7A40X CPLD SPI driver");
343 MODULE_LICENSE("GPL");