1/* arch/arm/mach-lh7a40x/ssp-cpld.c
2 *
3 *  Copyright (C) 2004,2005 Marc Singer
4 *
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.
8 *
9 * SSP/SPI driver for the CardEngine CPLD.
10 *
11 */
12
13/* NOTES
14   -----
15
16   o *** This driver is cribbed from the 7952x implementation.
17	 Some comments may not apply.
18
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.
23
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.
34
35 */
36
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>
46
47#include <asm/io.h>
48#include <asm/irq.h>
49#include <asm/hardware.h>
50
51#include <asm/arch/ssp.h>
52
53//#define TALK
54
55#if defined(TALK)
56#define PRINTK(f...)		printk (f)
57#else
58#define PRINTK(f...)		do {} while (0)
59#endif
60
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
73
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)
81
82#define T_SKH	1		/* Clock time high (us) */
83#define T_SKL	1		/* Clock time low (us) */
84#define T_CS	1		/* Minimum chip select low time (us)  */
85#define T_CSS	1		/* Minimum chip select setup time (us)  */
86#define T_DIS	1		/* Data setup time (us) */
87
88	 /* EEPROM SPI bits */
89#define P_START		(1<<9)
90#define P_WRITE		(1<<7)
91#define P_READ		(2<<7)
92#define P_ERASE		(3<<7)
93#define P_EWDS		(0<<7)
94#define P_WRAL		(0<<7)
95#define P_ERAL		(0<<7)
96#define P_EWEN		(0<<7)
97#define P_A_EWDS	(0<<5)
98#define P_A_WRAL	(1<<5)
99#define P_A_ERAL	(2<<5)
100#define P_A_EWEN	(3<<5)
101
102struct ssp_configuration {
103	int device;
104	int mode;
105	int speed;
106	int frame_size_write;
107	int frame_size_read;
108};
109
110static struct ssp_configuration ssp_configuration;
111static spinlock_t ssp_lock;
112
113static void enable_cs (void)
114{
115	switch (ssp_configuration.device) {
116	case DEVICE_EEPROM:
117		CPLD_SPI |= CPLD_SPI_CS_EEPROM;
118		break;
119	}
120	udelay (T_CSS);
121}
122
123static void disable_cs (void)
124{
125	switch (ssp_configuration.device) {
126	case DEVICE_EEPROM:
127		CPLD_SPI &= ~CPLD_SPI_CS_EEPROM;
128		break;
129	}
130	udelay (T_CS);
131}
132
133static void pulse_clock (void)
134{
135	CPLD_SPI |=  CPLD_SPI_SCLK;
136	udelay (T_SKH);
137	CPLD_SPI &= ~CPLD_SPI_SCLK;
138	udelay (T_SKL);
139}
140
141
142/* execute_spi_command
143
144   sends an spi command to a device.  It first sends cwrite bits from
145   v.  If cread is greater than zero it will read cread bits
146   (discarding the leading 0 bit) and return them.  If cread is less
147   than zero it will check for completetion status and return 0 on
148   success or -1 on timeout.  If cread is zero it does nothing other
149   than sending the command.
150
151   On the LPD7A400, we can only read or write multiples of 8 bits on
152   the codec and the touch screen device.  Here, we round up.
153
154*/
155
156static int execute_spi_command (int v, int cwrite, int cread)
157{
158	unsigned long l = 0;
159
160#if defined(CONFIG_MACH_LPD7A400)
161	/* The codec and touch devices cannot be bit-banged.  Instead,
162	 * the CPLD provides an eight-bit shift register and a crude
163	 * interface.  */
164	if (   ssp_configuration.device == DEVICE_CODEC
165	    || ssp_configuration.device == DEVICE_TOUCH) {
166		int select = 0;
167
168		PRINTK ("spi(%d %d.%d) 0x%04x",
169			ssp_configuration.device, cwrite, cread,
170			v);
171#if defined(TALK)
172		if (ssp_configuration.device == DEVICE_CODEC)
173			PRINTK (" 0x%03x -> %2d", v & 0x1ff, (v >> 9) & 0x7f);
174#endif
175		PRINTK ("\n");
176
177		if (ssp_configuration.device == DEVICE_CODEC)
178			select = CPLD_SPIC_CS_CODEC;
179		if (ssp_configuration.device == DEVICE_TOUCH)
180			select = CPLD_SPIC_CS_TOUCH;
181		if (cwrite) {
182			for (cwrite = (cwrite + 7)/8; cwrite-- > 0; ) {
183				CPLD_SPID = (v >> (8*cwrite)) & 0xff;
184				CPLD_SPIC = select | CPLD_SPIC_LOAD;
185				while (!(CPLD_SPIC & CPLD_SPIC_LOADED))
186					;
187				CPLD_SPIC = select;
188				while (!(CPLD_SPIC & CPLD_SPIC_DONE))
189					;
190			}
191			v = 0;
192		}
193		if (cread) {
194			mdelay (2);
195			v = 0;
196			for (cread = (cread + 7)/8; cread-- > 0;) {
197				CPLD_SPID = 0;
198				CPLD_SPIC = select | CPLD_SPIC_READ
199					| CPLD_SPIC_START;
200				while (!(CPLD_SPIC & CPLD_SPIC_LOADED))
201					;
202				CPLD_SPIC = select | CPLD_SPIC_READ;
203				while (!(CPLD_SPIC & CPLD_SPIC_DONE))
204					;
205				v = (v << 8) | CPLD_SPID;
206			}
207		}
208		return v;
209	}
210#endif
211
212	PRINTK ("spi(%d) 0x%04x -> 0x%x\r\n", ssp_configuration.device,
213		v & 0x1ff, (v >> 9) & 0x7f);
214
215	enable_cs ();
216
217	v <<= CPLD_SPI_TX_SHIFT; /* Correction for position of SPI_TX bit */
218	while (cwrite--) {
219		CPLD_SPI
220			= (CPLD_SPI & ~CPLD_SPI_TX)
221			| ((v >> cwrite) & CPLD_SPI_TX);
222		udelay (T_DIS);
223		pulse_clock ();
224	}
225
226	if (cread < 0) {
227		int delay = 10;
228		disable_cs ();
229		udelay (1);
230		enable_cs ();
231
232		l = -1;
233		do {
234			if (CPLD_SPI & CPLD_SPI_RX) {
235				l = 0;
236				break;
237			}
238		} while (udelay (1), --delay);
239	}
240	else
241	/* We pulse the clock before the data to skip the leading zero. */
242		while (cread-- > 0) {
243			pulse_clock ();
244			l = (l<<1)
245				| (((CPLD_SPI & CPLD_SPI_RX)
246				    >> CPLD_SPI_RX_SHIFT) & 0x1);
247		}
248
249	disable_cs ();
250	return l;
251}
252
253static int ssp_init (void)
254{
255	spin_lock_init (&ssp_lock);
256	memset (&ssp_configuration, 0, sizeof (ssp_configuration));
257	return 0;
258}
259
260
261/* ssp_chip_select
262
263   drops the chip select line for the CPLD shift-register controlled
264   devices.  It doesn't enable chip
265
266*/
267
268static void ssp_chip_select (int enable)
269{
270#if defined(CONFIG_MACH_LPD7A400)
271	int select;
272
273	if (ssp_configuration.device == DEVICE_CODEC)
274		select = CPLD_SPIC_CS_CODEC;
275	else if (ssp_configuration.device == DEVICE_TOUCH)
276		select = CPLD_SPIC_CS_TOUCH;
277	else
278		return;
279
280	if (enable)
281		CPLD_SPIC = select;
282	else
283		CPLD_SPIC = 0;
284#endif
285}
286
287static void ssp_acquire (void)
288{
289	spin_lock (&ssp_lock);
290}
291
292static void ssp_release (void)
293{
294	ssp_chip_select (0);	/* just in case */
295	spin_unlock (&ssp_lock);
296}
297
298static int ssp_configure (int device, int mode, int speed,
299			   int frame_size_write, int frame_size_read)
300{
301	ssp_configuration.device		= device;
302	ssp_configuration.mode			= mode;
303	ssp_configuration.speed			= speed;
304	ssp_configuration.frame_size_write	= frame_size_write;
305	ssp_configuration.frame_size_read	= frame_size_read;
306
307	return 0;
308}
309
310static int ssp_read (void)
311{
312	return execute_spi_command (0, 0, ssp_configuration.frame_size_read);
313}
314
315static int ssp_write (u16 data)
316{
317	execute_spi_command (data, ssp_configuration.frame_size_write, 0);
318	return 0;
319}
320
321static int ssp_write_read (u16 data)
322{
323	return execute_spi_command (data, ssp_configuration.frame_size_write,
324				    ssp_configuration.frame_size_read);
325}
326
327struct ssp_driver lh7a40x_cpld_ssp_driver = {
328	.init		= ssp_init,
329	.acquire	= ssp_acquire,
330	.release	= ssp_release,
331	.configure	= ssp_configure,
332	.chip_select	= ssp_chip_select,
333	.read		= ssp_read,
334	.write		= ssp_write,
335	.write_read	= ssp_write_read,
336};
337
338
339MODULE_AUTHOR("Marc Singer");
340MODULE_DESCRIPTION("LPD7A40X CPLD SPI driver");
341MODULE_LICENSE("GPL");
342