xref: /OK3568_Linux_fs/u-boot/drivers/input/ps2ser.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /***********************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * (C) Copyright 2004-2009
4*4882a593Smuzhiyun  * DENX Software Engineering
5*4882a593Smuzhiyun  * Wolfgang Denk, wd@denx.de
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Simple 16550A serial driver
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Originally from linux source (drivers/char/ps2ser.c)
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Used by the PS/2 multiplexer driver (ps2mult.c)
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  ***********************************************************************/
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <common.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <asm/atomic.h>
19*4882a593Smuzhiyun #include <ps2mult.h>
20*4882a593Smuzhiyun /* This is needed for ns16550.h */
21*4882a593Smuzhiyun #ifndef CONFIG_SYS_NS16550_REG_SIZE
22*4882a593Smuzhiyun #define CONFIG_SYS_NS16550_REG_SIZE 1
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun #include <ns16550.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* #define	DEBUG */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define PS2SER_BAUD	57600
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #if CONFIG_PS2SERIAL == 1
33*4882a593Smuzhiyun #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
34*4882a593Smuzhiyun #elif CONFIG_PS2SERIAL == 2
35*4882a593Smuzhiyun #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
36*4882a593Smuzhiyun #else
37*4882a593Smuzhiyun #error CONFIG_PS2SERIAL must be in 1 ... 2
38*4882a593Smuzhiyun #endif
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static int	ps2ser_getc_hw(void);
41*4882a593Smuzhiyun static void	ps2ser_interrupt(void *dev_id);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun extern struct	serial_state rs_table[]; /* in serial.c */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun static u_char	ps2buf[PS2BUF_SIZE];
46*4882a593Smuzhiyun static atomic_t	ps2buf_cnt;
47*4882a593Smuzhiyun static int	ps2buf_in_idx;
48*4882a593Smuzhiyun static int	ps2buf_out_idx;
49*4882a593Smuzhiyun 
ps2ser_init(void)50*4882a593Smuzhiyun int ps2ser_init(void)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	NS16550_t com_port = (NS16550_t)COM_BASE;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	com_port->ier = 0x00;
55*4882a593Smuzhiyun 	com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1;
56*4882a593Smuzhiyun 	com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
57*4882a593Smuzhiyun 	com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
58*4882a593Smuzhiyun 	com_port->lcr = UART_LCR_8N1;
59*4882a593Smuzhiyun 	com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS);
60*4882a593Smuzhiyun 	com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return (0);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
ps2ser_putc(int chr)65*4882a593Smuzhiyun void ps2ser_putc(int chr)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	NS16550_t com_port = (NS16550_t)COM_BASE;
68*4882a593Smuzhiyun 	debug(">>>> 0x%02x\n", chr);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	while ((com_port->lsr & UART_LSR_THRE) == 0);
71*4882a593Smuzhiyun 	com_port->thr = chr;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
ps2ser_getc_hw(void)74*4882a593Smuzhiyun static int ps2ser_getc_hw(void)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	NS16550_t com_port = (NS16550_t)COM_BASE;
77*4882a593Smuzhiyun 	int res = -1;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (com_port->lsr & UART_LSR_DR) {
80*4882a593Smuzhiyun 		res = com_port->rbr;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return res;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
ps2ser_getc(void)86*4882a593Smuzhiyun int ps2ser_getc(void)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	volatile int chr;
89*4882a593Smuzhiyun 	int flags;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	debug("<< ");
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	flags = disable_interrupts();
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	do {
96*4882a593Smuzhiyun 		if (atomic_read(&ps2buf_cnt) != 0) {
97*4882a593Smuzhiyun 			chr = ps2buf[ps2buf_out_idx++];
98*4882a593Smuzhiyun 			ps2buf_out_idx &= (PS2BUF_SIZE - 1);
99*4882a593Smuzhiyun 			atomic_dec(&ps2buf_cnt);
100*4882a593Smuzhiyun 		} else {
101*4882a593Smuzhiyun 			chr = ps2ser_getc_hw();
102*4882a593Smuzhiyun 		}
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	while (chr < 0);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (flags)
107*4882a593Smuzhiyun 		enable_interrupts();
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	debug("0x%02x\n", chr);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return chr;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
ps2ser_check(void)114*4882a593Smuzhiyun int ps2ser_check(void)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	int flags;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	flags = disable_interrupts();
119*4882a593Smuzhiyun 	ps2ser_interrupt(NULL);
120*4882a593Smuzhiyun 	if (flags) enable_interrupts();
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return atomic_read(&ps2buf_cnt);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
ps2ser_interrupt(void * dev_id)125*4882a593Smuzhiyun static void ps2ser_interrupt(void *dev_id)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	NS16550_t com_port = (NS16550_t)COM_BASE;
128*4882a593Smuzhiyun 	int chr;
129*4882a593Smuzhiyun 	int status;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	do {
132*4882a593Smuzhiyun 		chr = ps2ser_getc_hw();
133*4882a593Smuzhiyun 		status = com_port->lsr;
134*4882a593Smuzhiyun 		if (chr < 0) continue;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
137*4882a593Smuzhiyun 			ps2buf[ps2buf_in_idx++] = chr;
138*4882a593Smuzhiyun 			ps2buf_in_idx &= (PS2BUF_SIZE - 1);
139*4882a593Smuzhiyun 			atomic_inc(&ps2buf_cnt);
140*4882a593Smuzhiyun 		} else {
141*4882a593Smuzhiyun 			printf ("ps2ser.c: buffer overflow\n");
142*4882a593Smuzhiyun 		}
143*4882a593Smuzhiyun 	} while (status & UART_LSR_DR);
144*4882a593Smuzhiyun 	if (atomic_read(&ps2buf_cnt)) {
145*4882a593Smuzhiyun 		ps2mult_callback(atomic_read(&ps2buf_cnt));
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun }
148