xref: /rk3399_rockchip-uboot/drivers/input/pc_keyb.c (revision f743931f9b4d4e15c9bdfe726bef033ea1f1402c)
1 /***********************************************************************
2  *
3  * (C) Copyright 2004
4  * DENX Software Engineering
5  * Wolfgang Denk, wd@denx.de
6  * All rights reserved.
7  *
8  * PS/2 keyboard driver
9  *
10  * Originally from linux source (drivers/char/pc_keyb.c)
11  *
12  ***********************************************************************/
13 
14 #include <common.h>
15 
16 #ifdef CONFIG_PS2KBD
17 
18 #include <keyboard.h>
19 #include <pc_keyb.h>
20 
21 #undef KBG_DEBUG
22 
23 #ifdef KBG_DEBUG
24 #define	PRINTF(fmt,args...)	printf (fmt ,##args)
25 #else
26 #define PRINTF(fmt,args...)
27 #endif
28 
29 
30 /*
31  * This reads the keyboard status port, and does the
32  * appropriate action.
33  *
34  */
35 static unsigned char handle_kbd_event(void)
36 {
37 	unsigned char status = kbd_read_status();
38 	unsigned int work = 10000;
39 
40 	while ((--work > 0) && (status & KBD_STAT_OBF)) {
41 		unsigned char scancode;
42 
43 		scancode = kbd_read_input();
44 
45 		/* Error bytes must be ignored to make the
46 		   Synaptics touchpads compaq use work */
47 		/* Ignore error bytes */
48 		if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
49 			if (status & KBD_STAT_MOUSE_OBF)
50 				; /* not supported: handle_mouse_event(scancode); */
51 			else
52 				handle_scancode(scancode);
53 		}
54 		status = kbd_read_status();
55 	}
56 	if (!work)
57 		PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
58 	return status;
59 }
60 
61 
62 static int kbd_read_data(void)
63 {
64 	int val;
65 	unsigned char status;
66 
67 	val=-1;
68 	status = kbd_read_status();
69 	if (status & KBD_STAT_OBF) {
70 		val = kbd_read_input();
71 		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
72 			val = -2;
73 	}
74 	return val;
75 }
76 
77 static int kbd_wait_for_input(void)
78 {
79 	unsigned long timeout;
80 	int val;
81 
82 	timeout = KBD_TIMEOUT;
83 	val=kbd_read_data();
84 	while(val < 0) {
85 		if(timeout--==0)
86 			return -1;
87 		udelay(1000);
88 		val=kbd_read_data();
89 	}
90 	return val;
91 }
92 
93 
94 static int kb_wait(void)
95 {
96 	unsigned long timeout = KBC_TIMEOUT * 10;
97 
98 	do {
99 		unsigned char status = handle_kbd_event();
100 		if (!(status & KBD_STAT_IBF))
101 			return 0; /* ok */
102 		udelay(1000);
103 		timeout--;
104 	} while (timeout);
105 	return 1;
106 }
107 
108 static void kbd_write_command_w(int data)
109 {
110 	if(kb_wait())
111 		PRINTF("timeout in kbd_write_command_w\n");
112 	kbd_write_command(data);
113 }
114 
115 static void kbd_write_output_w(int data)
116 {
117 	if(kb_wait())
118 		PRINTF("timeout in kbd_write_output_w\n");
119 	kbd_write_output(data);
120 }
121 
122 static void kbd_send_data(unsigned char data)
123 {
124 	kbd_write_output_w(data);
125 	kbd_wait_for_input();
126 }
127 
128 
129 static char * kbd_initialize(void)
130 {
131 	int status;
132 
133 	/*
134 	 * Test the keyboard interface.
135 	 * This seems to be the only way to get it going.
136 	 * If the test is successful a x55 is placed in the input buffer.
137 	 */
138 	kbd_write_command_w(KBD_CCMD_SELF_TEST);
139 	if (kbd_wait_for_input() != 0x55)
140 		return "Kbd:   failed self test";
141 	/*
142 	 * Perform a keyboard interface test.  This causes the controller
143 	 * to test the keyboard clock and data lines.  The results of the
144 	 * test are placed in the input buffer.
145 	 */
146 	kbd_write_command_w(KBD_CCMD_KBD_TEST);
147 	if (kbd_wait_for_input() != 0x00)
148 		return "Kbd:   interface failed self test";
149 	/*
150 	 * Enable the keyboard by allowing the keyboard clock to run.
151 	 */
152 	kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
153 
154 	/*
155 	 * Reset keyboard. If the read times out
156 	 * then the assumption is that no keyboard is
157 	 * plugged into the machine.
158 	 * This defaults the keyboard to scan-code set 2.
159 	 *
160 	 * Set up to try again if the keyboard asks for RESEND.
161 	 */
162 	do {
163 		kbd_write_output_w(KBD_CMD_RESET);
164 		status = kbd_wait_for_input();
165 		if (status == KBD_REPLY_ACK)
166 			break;
167 		if (status != KBD_REPLY_RESEND) {
168 			PRINTF("status: %X\n",status);
169 			return "Kbd:   reset failed, no ACK";
170 		}
171 	} while (1);
172 	if (kbd_wait_for_input() != KBD_REPLY_POR)
173 		return "Kbd:   reset failed, no POR";
174 
175 	/*
176 	 * Set keyboard controller mode. During this, the keyboard should be
177 	 * in the disabled state.
178 	 *
179 	 * Set up to try again if the keyboard asks for RESEND.
180 	 */
181 	do {
182 		kbd_write_output_w(KBD_CMD_DISABLE);
183 		status = kbd_wait_for_input();
184 		if (status == KBD_REPLY_ACK)
185 			break;
186 		if (status != KBD_REPLY_RESEND)
187 			return "Kbd:   disable keyboard: no ACK";
188 	} while (1);
189 
190 	kbd_write_command_w(KBD_CCMD_WRITE_MODE);
191 	kbd_write_output_w(KBD_MODE_KBD_INT
192 			      | KBD_MODE_SYS
193 			      | KBD_MODE_DISABLE_MOUSE
194 			      | KBD_MODE_KCC);
195 
196 	/* AMCC powerpc portables need this to use scan-code set 1 -- Cort */
197 	kbd_write_command_w(KBD_CCMD_READ_MODE);
198 	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
199 		/*
200 		 * If the controller does not support conversion,
201 		 * Set the keyboard to scan-code set 1.
202 		 */
203 		kbd_write_output_w(0xF0);
204 		kbd_wait_for_input();
205 		kbd_write_output_w(0x01);
206 		kbd_wait_for_input();
207 	}
208 	kbd_write_output_w(KBD_CMD_ENABLE);
209 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
210 		return "Kbd:   enable keyboard: no ACK";
211 
212 	/*
213 	 * Finally, set the typematic rate to maximum.
214 	 */
215 	kbd_write_output_w(KBD_CMD_SET_RATE);
216 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
217 		return "Kbd:   Set rate: no ACK";
218 	kbd_write_output_w(0x00);
219 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
220 		return "Kbd:   Set rate: no ACK";
221 	return NULL;
222 }
223 
224 static void kbd_interrupt(void *dev_id)
225 {
226 	handle_kbd_event();
227 }
228 
229 /******************************************************************
230  * Init
231  ******************************************************************/
232 
233 int kbd_init_hw(void)
234 {
235 	char* result;
236 
237 	kbd_request_region();
238 
239 	result=kbd_initialize();
240 	if (result==NULL) {
241 		PRINTF("AT Keyboard initialized\n");
242 		kbd_request_irq(kbd_interrupt);
243 		return (1);
244 	} else {
245 		printf("%s\n",result);
246 		return (-1);
247 	}
248 }
249 
250 void pckbd_leds(unsigned char leds)
251 {
252 	kbd_send_data(KBD_CMD_SET_LEDS);
253 	kbd_send_data(leds);
254 }
255 
256 #endif /* CONFIG_PS2KBD */
257