add preliminary support for Storm SL3512 based devices, not ready yet
[openwrt/openwrt.git] / target / linux / storm / patches / 1021-serial.patch
1 Index: linux-2.6.23.16/drivers/serial/it8712.c
2 ===================================================================
3 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4 +++ linux-2.6.23.16/drivers/serial/it8712.c 2008-03-15 17:59:53.568330991 +0200
5 @@ -0,0 +1,858 @@
6 +/*
7 + * linux/drivers/char/serial_uart00.c
8 + *
9 + * Driver for UART00 serial ports
10 + *
11 + * Based on drivers/char/serial_amba.c, by ARM Limited &
12 + * Deep Blue Solutions Ltd.
13 + * Copyright 2001 Altera Corporation
14 + *
15 + * This program is free software; you can redistribute it and/or modify
16 + * it under the terms of the GNU General Public License as published by
17 + * the Free Software Foundation; either version 2 of the License, or
18 + * (at your option) any later version.
19 + *
20 + * This program is distributed in the hope that it will be useful,
21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 + * GNU General Public License for more details.
24 + *
25 + * You should have received a copy of the GNU General Public License
26 + * along with this program; if not, write to the Free Software
27 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 + *
29 + * $Id: it8712.c,v 1.2 2006/06/06 06:36:04 middle Exp $
30 + *
31 + */
32 +#include <linux/module.h>
33 +#include <linux/tty.h>
34 +#include <linux/ioport.h>
35 +#include <linux/init.h>
36 +#include <linux/serial.h>
37 +#include <linux/console.h>
38 +#include <linux/sysrq.h>
39 +#include <asm/hardware.h>
40 +#include <asm/system.h>
41 +#include <asm/io.h>
42 +#include <asm/irq.h>
43 +#include <asm/uaccess.h>
44 +#include <asm/bitops.h>
45 +#include <asm/sizes.h>
46 +
47 +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
48 +#define SUPPORT_SYSRQ
49 +#endif
50 +
51 +#include <linux/serial_core.h>
52 +#include <asm/arch/sl2312.h>
53 +#include <asm/arch/int_ctrl.h>
54 +#include <asm/arch/it8712.h>
55 +#include "it8712.h"
56 +
57 +//#define DEBUG 1
58 +#define UART_NR 1
59 +
60 +#define SERIAL_IT8712_NAME "ttySI"
61 +#define SERIAL_IT8712_MAJOR 204
62 +#define SERIAL_IT8712_MINOR 41 /* Temporary - will change in future */
63 +#define SERIAL_IT8712_NR UART_NR
64 +#define UART_PORT_SIZE 0x50
65 +#define LPC_HOST_CONTINUE_MODE 0x00000040
66 +
67 +#define IT8712_NO_PORTS UART_NR
68 +#define IT8712_ISR_PASS_LIMIT 256
69 +
70 +#define LPC_BUS_CTRL *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
71 +#define LPC_BUS_STATUS *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
72 +#define LPC_SERIAL_IRQ_CTRL *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 8))
73 +#define LPC_SERIAL_IRQ_STATUS *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x0c))
74 +#define LPC_SERIAL_IRQ_TRITYPE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x10))
75 +#define LPC_SERIAL_IRQ_POLARITY *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x14))
76 +#define LPC_SERIAL_IRQ_ENABLE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x18))
77 +
78 +
79 +
80 +
81 +/*
82 + * Access macros for the SL2312 UARTs
83 + */
84 +#define UART_GET_INT_STATUS(p) (inb(((p)->membase+UART_IIR)) & 0x0F) // interrupt identification
85 +#define UART_PUT_IER(p, c) outb(c,((p)->membase+UART_IER)) // interrupt enable
86 +#define UART_GET_IER(p) inb(((p)->membase+UART_IER))
87 +#define UART_PUT_CHAR(p, c) outb(c,((p)->membase+UART_TX)) // transmitter holding
88 +#define UART_GET_CHAR(p) inb(((p)->membase+UART_RX)) // receive buffer
89 +#define UART_GET_LSR(p) inb(((p)->membase+UART_LSR)) // line status
90 +#define UART_GET_MSR(p) inb(((p)->membase+UART_MSR)) // modem status
91 +#define UART_GET_MCR(p) inb(((p)->membase+UART_MCR)) // modem control
92 +#define UART_PUT_MCR(p, c) outb(c,((p)->membase+UART_MCR))
93 +#define UART_GET_LCR(p) inb(((p)->membase+UART_LCR)) // mode control
94 +#define UART_PUT_LCR(p, c) outb(c,((p)->membase+UART_LCR))
95 +#define UART_PUT_FCR(p, c) outb(c,((p)->membase+UART_FCR)) // fifo control
96 +#define UART_GET_DIV_HI(p) inb(((p)->membase+UART_DLM))
97 +#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
98 +#define UART_GET_DIV_LO(p) inb(((p)->membase+UART_DLL))
99 +#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
100 +#define UART_PUT_MDR(p, c) outb(c,UART_MDR((p)->membase))
101 +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
102 +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
103 +
104 +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
105 +{
106 + unsigned int reg;
107 +
108 + //printk("it8712 stop tx : \n");
109 + reg = UART_GET_IER(port);
110 + reg &= ~(UART_IER_THRI);
111 + UART_PUT_IER(port, reg);
112 +}
113 +
114 +static void it8712_stop_rx(struct uart_port *port)
115 +{
116 + unsigned int reg;
117 +
118 + //printk("it8712 stop rx : \n");
119 + reg = UART_GET_IER(port);
120 + reg &= ~(UART_IER_RDI);
121 + UART_PUT_IER(port, reg);
122 +
123 +}
124 +
125 +static void it8712_enable_ms(struct uart_port *port)
126 +{
127 + unsigned int reg;
128 +
129 + //printk("it8712 enable ms : \n");
130 +
131 + reg = UART_GET_IER(port);
132 + reg |= (UART_IER_MSI);
133 + UART_PUT_IER(port, reg);
134 +
135 +}
136 +
137 +static void it8712_rx_chars(struct uart_port *port, struct pt_regs *regs)
138 +{
139 + struct tty_struct *tty = port->info->tty;
140 + unsigned int status, mask, ch, flg, ignored = 0;
141 +
142 + // printk("it8712_rx_chars : \n");
143 + status = UART_GET_LSR(port);
144 + while (UART_RX_DATA(status)) {
145 +
146 + /*
147 + * We need to read rds before reading the
148 + * character from the fifo
149 + */
150 + ch = UART_GET_CHAR(port);
151 + port->icount.rx++;
152 +
153 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
154 + goto ignore_char;
155 +
156 + flg = TTY_NORMAL;
157 +
158 + /*
159 + * Note that the error handling code is
160 + * out of the main execution path
161 + */
162 +
163 + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
164 + goto handle_error;
165 + if (uart_handle_sysrq_char(port, ch, regs))
166 + goto ignore_char;
167 +
168 + error_return:
169 + *tty->flip.flag_buf_ptr++ = flg;
170 + *tty->flip.char_buf_ptr++ = ch;
171 + tty->flip.count++;
172 + ignore_char:
173 + status = UART_GET_LSR(port);
174 + } // end of while
175 +out:
176 + tty_flip_buffer_push(tty);
177 + return;
178 +
179 +handle_error:
180 + if (status & UART_LSR_BI) {
181 + status &= ~(UART_LSR_FE);
182 + port->icount.brk++;
183 +
184 +#ifdef SUPPORT_SYSRQ
185 + if (uart_handle_break(port))
186 + goto ignore_char;
187 +#endif
188 + } else if (status & UART_LSR_PE)
189 + port->icount.parity++;
190 + else if (status & UART_LSR_FE)
191 + port->icount.frame++;
192 +
193 + if (status & UART_LSR_OE)
194 + port->icount.overrun++;
195 +
196 + if (status & port->ignore_status_mask) {
197 + if (++ignored > 100)
198 + goto out;
199 + goto ignore_char;
200 + }
201 +
202 + mask = status & port->read_status_mask;
203 +
204 + if (mask & UART_LSR_BI)
205 + flg = TTY_BREAK;
206 + else if (mask & UART_LSR_PE)
207 + flg = TTY_PARITY;
208 + else if (mask & UART_LSR_FE)
209 + flg = TTY_FRAME;
210 +
211 + if (status & UART_LSR_OE) {
212 + /*
213 + * CHECK: does overrun affect the current character?
214 + * ASSUMPTION: it does not.
215 + */
216 + *tty->flip.flag_buf_ptr++ = flg;
217 + *tty->flip.char_buf_ptr++ = ch;
218 + tty->flip.count++;
219 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
220 + goto ignore_char;
221 + ch = 0;
222 + flg = TTY_OVERRUN;
223 + }
224 +#ifdef SUPPORT_SYSRQ
225 + port->sysrq = 0;
226 +#endif
227 + goto error_return;
228 +}
229 +
230 +static void it8712_tx_chars(struct uart_port *port)
231 +{
232 + struct circ_buf *xmit = &port->info->xmit;
233 + int count;
234 +
235 + if (port->x_char) {
236 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
237 + UART_PUT_CHAR(port, port->x_char);
238 + port->icount.tx++;
239 + port->x_char = 0;
240 +
241 + return;
242 + }
243 + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
244 + it8712_stop_tx(port, 0);
245 + return;
246 + }
247 +
248 + count = port->fifosize >> 1;
249 + do {
250 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
251 + UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
252 + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
253 + port->icount.tx++;
254 + if (uart_circ_empty(xmit))
255 + break;
256 + } while (--count > 0);
257 +
258 + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
259 + uart_write_wakeup(port);
260 +
261 + if (uart_circ_empty(xmit))
262 + it8712_stop_tx(port, 0);
263 +}
264 +
265 +static void it8712_start_tx(struct uart_port *port, unsigned int tty_start)
266 +{
267 + unsigned int reg;
268 +
269 + //printk("it8712 start tx : \n");
270 + reg = UART_GET_IER(port);
271 + reg |= (UART_IER_THRI);
272 + UART_PUT_IER(port, reg);
273 + it8712_tx_chars(port);
274 +}
275 +
276 +static void it8712_modem_status(struct uart_port *port)
277 +{
278 + unsigned int status;
279 +
280 +// printk("it8712 modem status : \n");
281 +
282 + status = UART_GET_MSR(port);
283 +
284 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
285 + UART_MSR_TERI | UART_MSR_DDCD)))
286 + return;
287 +
288 + if (status & UART_MSR_DDCD)
289 + uart_handle_dcd_change(port, status & UART_MSR_DCD);
290 +
291 + if (status & UART_MSR_DDSR)
292 + port->icount.dsr++;
293 +
294 + if (status & UART_MSR_DCTS)
295 + uart_handle_cts_change(port, status & UART_MSR_CTS);
296 +
297 + wake_up_interruptible(&port->info->delta_msr_wait);
298 +
299 +}
300 +
301 +static irqreturn_t it8712_int(int irq, void *dev_id, struct pt_regs *regs)
302 +{
303 + struct uart_port *port = dev_id;
304 + unsigned int status, pass_counter = 0, data;
305 +
306 +
307 + data = LPC_SERIAL_IRQ_STATUS;
308 + if((data&0x10)==0x10)
309 + {
310 + status = UART_GET_INT_STATUS(port);
311 + do {
312 +// printk("it8712_int: status %x \n", status);
313 + switch(status)
314 + {
315 + case UART_IIR_RDI:
316 + case UART_IIR_RLSI:
317 + case UART_IIR_RCTO:
318 + it8712_rx_chars(port, regs);
319 + break;
320 + case UART_IIR_THRI:
321 + it8712_tx_chars(port);
322 + break;
323 + case UART_IIR_MSI:
324 + it8712_modem_status(port);
325 + break;
326 + default:
327 + break;
328 + }
329 + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
330 + break;
331 +
332 + status = UART_GET_INT_STATUS(port);
333 + } while (status);
334 + }
335 +
336 + status = 0;
337 + status |= (IRQ_LPC_MASK);
338 + *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = status;
339 +
340 + //cnt=0;
341 + //do{
342 + // data = LPC_SERIAL_IRQ_STATUS;
343 + LPC_SERIAL_IRQ_STATUS = data;
344 + // cnt++;
345 + //}while(data);
346 + //if(cnt>2)
347 + // printf("it8712_uart_Isr clear LPC_SERIAL_IRQ_STATUS %x \n", cnt);
348 + return IRQ_HANDLED;
349 +}
350 +
351 +static u_int it8712_tx_empty(struct uart_port *port)
352 +{
353 +// printk("it8712 tx empty : \n");
354 +
355 + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
356 +}
357 +
358 +static u_int it8712_get_mctrl(struct uart_port *port)
359 +{
360 + unsigned int result = 0;
361 + unsigned int status;
362 +
363 +// printk("it8712 get mctrl : \n");
364 +
365 + status = UART_GET_MSR(port);
366 + if (status & UART_MSR_DCD)
367 + result |= TIOCM_CAR;
368 + if (status & UART_MSR_DSR)
369 + result |= TIOCM_DSR;
370 + if (status & UART_MSR_CTS)
371 + result |= TIOCM_CTS;
372 + if (status & UART_MSR_RI)
373 + result |= TIOCM_RI;
374 +
375 + return result;
376 +}
377 +
378 +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
379 +{
380 +}
381 +
382 +static void it8712_break_ctl(struct uart_port *port, int break_state)
383 +{
384 + unsigned int lcr;
385 +
386 +// printk("it8712 break ctl : \n");
387 +
388 + lcr = UART_GET_LCR(port);
389 + if (break_state == -1)
390 + lcr |= UART_LCR_SBC;
391 + else
392 + lcr &= ~UART_LCR_SBC;
393 + UART_PUT_LCR(port, lcr);
394 +}
395 +
396 +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
397 +{
398 + u_int quot;
399 +
400 + /* Special case: B0 rate */
401 + if (!baud)
402 + baud = 9600;
403 +
404 + quot = (port->uartclk/(16 * baud)) ;
405 +
406 + return quot;
407 +}
408 +static void it8712_set_termios(struct uart_port *port, struct termios *termios,
409 + struct termios *old)
410 +{
411 + unsigned int uart_mc, old_ier, baud, quot;
412 + unsigned long flags;
413 +
414 + termios->c_cflag |= CREAD;
415 + termios->c_cflag |= CLOCAL;
416 +#ifdef DEBUG
417 + printk("it8712_set_cflag(0x%x) called\n", cflag);
418 +#endif
419 + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
420 + quot = uart_get_divisor(port, baud);
421 +
422 + /* byte size and parity */
423 + switch (termios->c_cflag & CSIZE) {
424 + case CS5:
425 + uart_mc = UART_LCR_WLEN5;
426 + break;
427 + case CS6:
428 + uart_mc = UART_LCR_WLEN6;
429 + break;
430 + case CS7:
431 + uart_mc = UART_LCR_WLEN7;
432 + break;
433 + default: // CS8
434 + uart_mc = UART_LCR_WLEN8;
435 + break;
436 + }
437 +
438 + if (termios->c_cflag & CSTOPB)
439 + uart_mc|= UART_LCR_STOP;
440 + if (termios->c_cflag & PARENB) {
441 + uart_mc |= UART_LCR_EVEN;
442 + if (!(termios->c_cflag & PARODD))
443 + uart_mc |= UART_LCR_ODD;
444 + }
445 +
446 + spin_lock_irqsave(&port->lock, flags);
447 + /*
448 + * Update the per-port timeout
449 + */
450 + uart_update_timeout(port, termios->c_cflag, baud);
451 + port->read_status_mask = UART_LSR_OE;
452 + if (termios->c_iflag & INPCK)
453 + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
454 + if (termios->c_iflag & (BRKINT | PARMRK))
455 + port->read_status_mask |= UART_LSR_BI;
456 +
457 + /*
458 + * Characters to ignore
459 + */
460 + port->ignore_status_mask = 0;
461 + if (termios->c_iflag & IGNPAR)
462 + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
463 + if (termios->c_iflag & IGNBRK) {
464 + port->ignore_status_mask |= UART_LSR_BI;
465 + /*
466 + * If we're ignoring parity and break indicators,
467 + * ignore overruns to (for real raw support).
468 + */
469 + if (termios->c_iflag & IGNPAR)
470 + port->ignore_status_mask |= UART_LSR_OE;
471 + }
472 +
473 + old_ier = UART_GET_IER(port);
474 +
475 + if(UART_ENABLE_MS(port, termios->c_cflag))
476 + old_ier |= UART_IER_MSI;
477 +
478 + /* Set baud rate */
479 + quot = quot / 13;
480 + UART_PUT_LCR(port, UART_LCR_DLAB);
481 + UART_PUT_DIV_LO(port, (quot & 0xff));
482 + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
483 +
484 + UART_PUT_LCR(port, uart_mc);
485 +// UART_PUT_LCR(port, 0x07); // ???? it is wired
486 + UART_PUT_MCR(port, 0x08);
487 + UART_PUT_FCR(port, 0x01);
488 + UART_PUT_IER(port, 0x07);
489 +
490 + spin_unlock_irqrestore(&port->lock, flags);
491 +}
492 +
493 +static int it8712_startup(struct uart_port *port)
494 +{
495 + int retval, i;
496 + unsigned int regs;
497 +
498 + //printk("it8712 startup : \n");
499 +
500 + /*
501 + * Use iobase to store a pointer to info. We need this to start a
502 + * transmission as the tranmittr interrupt is only generated on
503 + * the transition to the idle state
504 + */
505 +
506 + // regs = 0;
507 + // regs |= (IRQ_LPC_MASK);
508 + // *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
509 +
510 + /*
511 + * Allocate the IRQ
512 + */
513 + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", port);
514 + if (retval)
515 + return retval;
516 +
517 + //printk("Init LPC int...........\n");
518 + /* setup interrupt controller */
519 + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
520 + regs &= ~(IRQ_LPC_MASK);
521 + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
522 + regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
523 + regs &= ~(IRQ_LPC_MASK);
524 + *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
525 + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_LPC_MASK);
526 +
527 + LPC_SERIAL_IRQ_POLARITY = 0x10; //0x10; //0x02;
528 + LPC_SERIAL_IRQ_TRITYPE = 0x10; //0x10;//
529 + LPC_SERIAL_IRQ_ENABLE = 0x10;
530 +
531 + LPC_BUS_CTRL = 0xc0;
532 + LPC_SERIAL_IRQ_CTRL = 0xc0;
533 + for(i=0;i<1000;i++) ;
534 + LPC_SERIAL_IRQ_CTRL = 0x80;
535 + /*
536 + * Finally, enable interrupts. Use the TII interrupt to minimise
537 + * the number of interrupts generated. If higher performance is
538 + * needed, consider using the TI interrupt with a suitable FIFO
539 + * threshold
540 + */
541 + //UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
542 + UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI|UART_IER_RLSI));//middle
543 +
544 + return 0;
545 +}
546 +
547 +static void it8712_shutdown(struct uart_port *port)
548 +{
549 + //printk("it8712 shutdown : \n");
550 +
551 + /*
552 + * disable all interrupts, disable the port
553 + */
554 + UART_PUT_IER(port, 0x0);
555 +
556 + /* disable break condition and fifos */
557 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
558 +
559 + /*
560 + * Free the interrupt
561 + */
562 + free_irq(port->irq, port);
563 +}
564 +
565 +static const char *it8712_type(struct uart_port *port)
566 +{
567 + return port->type == PORT_IT8712 ? "IT8712" : NULL;
568 +}
569 +
570 +/*
571 + * Release the memory region(s) being used by 'port'
572 + */
573 +static void it8712_release_port(struct uart_port *port)
574 +{
575 +// printk("it8712 release port : \n");
576 +
577 + release_mem_region(port->mapbase, UART_PORT_SIZE);
578 +}
579 +
580 +/*
581 + * Request the memory region(s) being used by 'port'
582 + */
583 +static int it8712_request_port(struct uart_port *port)
584 +{
585 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
586 + "serial_it8712") != NULL ? 0 : -EBUSY;
587 +}
588 +
589 +/*
590 + * Configure/autoconfigure the port.
591 + */
592 +static void it8712_config_port(struct uart_port *port, int flags)
593 +{
594 +
595 + if (flags & UART_CONFIG_TYPE) {
596 + if (it8712_request_port(port) == 0)
597 + port->type = PORT_IT8712;
598 + }
599 +}
600 +
601 +/*
602 + * verify the new serial_struct (for TIOCSSERIAL).
603 + */
604 +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
605 +{
606 + int ret = 0;
607 +
608 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
609 + ret = -EINVAL;
610 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
611 + ret = -EINVAL;
612 + if (ser->baud_base < 9600)
613 + ret = -EINVAL;
614 + return ret;
615 +}
616 +
617 +static struct uart_ops it8712_pops = {
618 + .tx_empty = it8712_tx_empty,
619 + .set_mctrl = it8712_set_mctrl_null,
620 + .get_mctrl = it8712_get_mctrl,
621 + .stop_tx = it8712_stop_tx,
622 + .start_tx = it8712_start_tx,
623 + .stop_rx = it8712_stop_rx,
624 + .enable_ms = it8712_enable_ms,
625 + .break_ctl = it8712_break_ctl,
626 + .startup = it8712_startup,
627 + .shutdown = it8712_shutdown,
628 + .set_termios = it8712_set_termios,
629 + .type = it8712_type,
630 + .release_port = it8712_release_port,
631 + .request_port = it8712_request_port,
632 + .config_port = it8712_config_port,
633 + .verify_port = it8712_verify_port,
634 +};
635 +
636 +#ifdef CONFIG_ARCH_SL2312
637 +
638 +static struct uart_port it8712_ports[UART_NR] = {
639 + {
640 + membase: (void *)0,
641 + mapbase: 0,
642 + iotype: SERIAL_IO_MEM,
643 + irq: 0,
644 + uartclk: UART_CLK/2,
645 + fifosize: 16,
646 + ops: &it8712_pops,
647 + flags: ASYNC_BOOT_AUTOCONF,
648 + }
649 +};
650 +
651 +#endif
652 +
653 +#ifdef CONFIG_SERIAL_IT8712_CONSOLE
654 +#ifdef used_and_not_const_char_pointer
655 +static int it8712_console_read(struct uart_port *port, char *s, u_int count)
656 +{
657 + unsigned int status;
658 + int c;
659 +#ifdef DEBUG
660 + printk("it8712_console_read() called\n");
661 +#endif
662 +
663 + c = 0;
664 + while (c < count) {
665 + status = UART_GET_LSR(port);
666 + if (UART_RX_DATA(status)) {
667 + *s++ = UART_GET_CHAR(port);
668 + c++;
669 + } else {
670 + // nothing more to get, return
671 + return c;
672 + }
673 + }
674 + // return the count
675 + return c;
676 +}
677 +#endif
678 +static void it8712_console_write(struct console *co, const char *s, unsigned count)
679 +{
680 +#ifdef CONFIG_ARCH_SL2312
681 + struct uart_port *port = it8712_ports + co->index;
682 + unsigned int status, old_ies;
683 + int i;
684 +
685 + /*
686 + * First save the CR then disable the interrupts
687 + */
688 + old_ies = UART_GET_IER(port);
689 + //if(old_ies!=7)
690 + //{
691 + //
692 + // printk("old_ies = %x\n",old_ies);
693 + // old_ies = 7;
694 + //}
695 + UART_PUT_IER(port,0x0);
696 +
697 + /*
698 + * Now, do each character
699 + */
700 + for (i = 0; i < count; i++) {
701 + do {
702 + status = UART_GET_LSR(port);
703 + } while (!UART_TX_READY(status));
704 + UART_PUT_CHAR(port, s[i]);
705 + if (s[i] == '\n') {
706 + do {
707 + status = UART_GET_LSR(port);
708 + } while (!UART_TX_READY(status));
709 + UART_PUT_CHAR(port, '\r');
710 + }
711 + }
712 +
713 + /*
714 + * Finally, wait for transmitter to become empty
715 + * and restore the IES
716 + */
717 + do {
718 + status = UART_GET_LSR(port);
719 + } while (!(status&UART_LSR_THRE));
720 + UART_PUT_IER(port, old_ies);
721 +#endif
722 +}
723 +
724 +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
725 +{
726 + //printk("it8712 console get options : \n");
727 +
728 + u_int uart_mc, quot;
729 + uart_mc= UART_GET_MCR(port);
730 +
731 + *parity = 'n';
732 + if (uart_mc & UART_LCR_PARITY) {
733 + if (uart_mc & UART_LCR_EVEN)
734 + *parity = 'e';
735 + else
736 + *parity = 'o';
737 + }
738 +
739 + switch (uart_mc & UART_LCR_MSK){
740 +
741 + case UART_LCR_WLEN5:
742 + *bits = 5;
743 + break;
744 + case UART_LCR_WLEN6:
745 + *bits = 6;
746 + break;
747 + case UART_LCR_WLEN7:
748 + *bits = 7;
749 + break;
750 + case UART_LCR_WLEN8:
751 + *bits = 8;
752 + break;
753 + }
754 + UART_PUT_MCR(port,UART_LCR_DLAB);
755 + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
756 + UART_PUT_MCR(port,uart_mc);
757 + *baud = (port->uartclk / (16 *quot));
758 +}
759 +
760 +static int __init it8712_console_setup(struct console *co, char *options)
761 +{
762 + struct uart_port *port;
763 + int baud = 38400;
764 + int bits = 8;
765 + int parity = 'n';
766 + int flow= 'n';
767 + int base;//, irq;
768 + int i ;
769 +
770 + printk("it8712 console setup : \n");
771 +
772 + LPCSetConfig(0, 0x02, 0x01);
773 + LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
774 + LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
775 + base = IT8712_IO_BASE;
776 + base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
777 + it8712_ports[0].mapbase = base;
778 + it8712_ports[0].membase = (void *)IO_ADDRESS(base);
779 + it8712_ports[0].irq = IRQ_LPC_OFFSET;
780 + // irq = LPCGetConfig(LDN_SERIAL1, 0x70);
781 + //it8712_ports[0].irq += irq;
782 +
783 + //printk("it8712 irq is %x \n", it8712_ports[0].irq);
784 +
785 + // setup LPC Host 'quiet mode'
786 + //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
787 + //for(i=0;i<1000;i++) ; // delay
788 + //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
789 + LPC_BUS_CTRL = 0xc0;
790 + LPC_SERIAL_IRQ_CTRL = 0xc0;
791 + for(i=0;i<1000;i++) ;
792 + LPC_SERIAL_IRQ_CTRL = 0x80;
793 +
794 +#ifdef CONFIG_ARCH_SL2312
795 + /*
796 + * Check whether an invalid uart number has been specified, and
797 + * if so, search for the first available port that does have
798 + * console support.
799 + */
800 + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
801 +#else
802 + return -ENODEV;
803 +#endif
804 +
805 + if (options)
806 + uart_parse_options(options, &baud, &parity, &bits, &flow);
807 + else
808 + it8712_console_get_options(port, &baud, &parity, &bits);
809 +
810 + return uart_set_options(port, co, baud, parity, bits, flow);
811 +}
812 +
813 +extern struct uart_driver it8712_reg;
814 +static struct console it8712_console = {
815 + .name = SERIAL_IT8712_NAME,
816 + .write = it8712_console_write,
817 + .device = uart_console_device,
818 + .setup = it8712_console_setup,
819 + .flags = CON_PRINTBUFFER,
820 + .index = 0,
821 + .data = &it8712_reg,
822 +};
823 +
824 +static int __init it8712_console_init(void)
825 +{
826 + register_console(&it8712_console);
827 + return 0;
828 +}
829 +
830 +console_initcall(it8712_console_init);
831 +
832 +#define IT8712_CONSOLE &it8712_console
833 +#else
834 +#define IT8712_CONSOLE NULL
835 +#endif
836 +
837 +static struct uart_driver it8712_reg = {
838 + .owner = NULL,
839 + .driver_name = SERIAL_IT8712_NAME,
840 + .dev_name = SERIAL_IT8712_NAME,
841 + .major = SERIAL_IT8712_MAJOR,
842 + .minor = SERIAL_IT8712_MINOR,
843 + .nr = UART_NR,
844 + .cons = IT8712_CONSOLE,
845 +};
846 +
847 +static int __init it8712_init(void)
848 +{
849 + int result;
850 + //printk("serial_it8712: it871212_init \n");
851 +
852 +
853 + result = uart_register_driver(&it8712_reg);
854 + if(result)
855 + return result;
856 + result = uart_add_one_port(&it8712_reg, &it8712_ports[0]);
857 +
858 + return result;
859 +
860 +}
861 +
862 +
863 +__initcall(it8712_init);
864 Index: linux-2.6.23.16/drivers/serial/it8712.h
865 ===================================================================
866 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
867 +++ linux-2.6.23.16/drivers/serial/it8712.h 2008-03-15 17:59:53.568330991 +0200
868 @@ -0,0 +1,135 @@
869 +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
870 +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
871 +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
872 +#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx
873 + * In: Fifo count
874 + * Out: Fifo custom trigger levels
875 + * XR16C85x only */
876 +
877 +#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
878 +#define UART_IER 1 /* Out: Interrupt Enable Register */
879 +#define UART_FCTR 1 /* (LCR=BF) Feature Control Register
880 + * XR16C85x only */
881 +
882 +#define UART_IIR 2 /* In: Interrupt ID Register */
883 +#define UART_FCR 2 /* Out: FIFO Control Register */
884 +#define UART_EFR 2 /* I/O: Extended Features Register */
885 + /* (DLAB=1, 16C660 only) */
886 +
887 +#define UART_LCR 3 /* Out: Line Control Register */
888 +#define UART_MCR 4 /* Out: Modem Control Register */
889 +#define UART_LSR 5 /* In: Line Status Register */
890 +#define UART_MSR 6 /* In: Modem Status Register */
891 +#define UART_SCR 7 /* I/O: Scratch Register */
892 +#define UART_EMSR 7 /* (LCR=BF) Extended Mode Select Register
893 + * FCTR bit 6 selects SCR or EMSR
894 + * XR16c85x only */
895 +
896 +/*
897 + * These are the definitions for the FIFO Control Register
898 + * (16650 only)
899 + */
900 +#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
901 +#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
902 +#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
903 +#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
904 +#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
905 +#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
906 +#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
907 +#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
908 +#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
909 +/* 16650 redefinitions */
910 +#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
911 +#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
912 +#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
913 +#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
914 +#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
915 +#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
916 +#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
917 +#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
918 +/* TI 16750 definitions */
919 +#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode */
920 +
921 +/*
922 + * These are the definitions for the Line Control Register
923 + *
924 + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
925 + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
926 + */
927 +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
928 +#define UART_LCR_SBC 0x40 /* Set break control */
929 +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
930 +#define UART_LCR_EPAR 0x10 /* Even parity select */
931 +#define UART_LCR_PARITY 0x08 /* Parity Enable */
932 +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
933 +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
934 +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
935 +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
936 +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
937 +#define UART_LCR_EVEN 0x18 /* Even parity */
938 +#define UART_LCR_ODD 0x08 /* Odd parity */
939 +#define UART_LCR_MSK 0x03
940 +/*
941 + * These are the definitions for the Line Status Register
942 + */
943 +#define UART_LSR_DE 0x80 /* FIFO Data Error */
944 +#define UART_LSR_TEMT 0x40 /* Transmitter empty */
945 +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
946 +#define UART_LSR_BI 0x10 /* Break interrupt indicator */
947 +#define UART_LSR_FE 0x08 /* Frame error indicator */
948 +#define UART_LSR_PE 0x04 /* Parity error indicator */
949 +#define UART_LSR_OE 0x02 /* Overrun error indicator */
950 +#define UART_LSR_DR 0x01 /* Receiver data ready */
951 +
952 +/*
953 + * These are the definitions for the Interrupt Identification Register
954 + */
955 +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
956 +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
957 +
958 +#define UART_IIR_MSI 0x00 /* Modem status interrupt */
959 +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
960 +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
961 +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
962 +#define UART_IIR_RCTO 0x0c /* Receiver character timeout interrupt */
963 +/*
964 + * These are the definitions for the Interrupt Enable Register
965 + */
966 +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
967 +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
968 +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
969 +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
970 +/*
971 + * Sleep mode for ST16650 and TI16750.
972 + * Note that for 16650, EFR-bit 4 must be selected as well.
973 + */
974 +#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
975 +
976 +/*
977 + * These are the definitions for the Modem Control Register
978 + */
979 +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
980 +#define UART_MCR_OUT2 0x08 /* Out2 complement */
981 +#define UART_MCR_OUT1 0x04 /* Out1 complement */
982 +#define UART_MCR_RTS 0x02 /* RTS complement */
983 +#define UART_MCR_DTR 0x01 /* DTR complement */
984 +
985 +/*
986 + * These are the definitions for the Modem Status Register
987 + */
988 +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
989 +#define UART_MSR_RI 0x40 /* Ring Indicator */
990 +#define UART_MSR_DSR 0x20 /* Data Set Ready */
991 +#define UART_MSR_CTS 0x10 /* Clear to Send */
992 +#define UART_MSR_DDCD 0x08 /* Delta DCD */
993 +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
994 +#define UART_MSR_DDSR 0x02 /* Delta DSR */
995 +#define UART_MSR_DCTS 0x01 /* Delta CTS */
996 +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
997 +
998 +#define UART_PARITY_NONE 0x00
999 +#define UART_PARITY_ODD 0x01
1000 +#define UART_PARITY_EVEN 0x02
1001 +
1002 +
1003 +
1004 Index: linux-2.6.23.16/drivers/serial/serial_it8712.c
1005 ===================================================================
1006 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1007 +++ linux-2.6.23.16/drivers/serial/serial_it8712.c 2008-03-15 17:59:53.568330991 +0200
1008 @@ -0,0 +1,876 @@
1009 +/*
1010 + * linux/drivers/char/serial_uart00.c
1011 + *
1012 + * Driver for UART00 serial ports
1013 + *
1014 + * Based on drivers/char/serial_amba.c, by ARM Limited &
1015 + * Deep Blue Solutions Ltd.
1016 + * Copyright 2001 Altera Corporation
1017 + *
1018 + * This program is free software; you can redistribute it and/or modify
1019 + * it under the terms of the GNU General Public License as published by
1020 + * the Free Software Foundation; either version 2 of the License, or
1021 + * (at your option) any later version.
1022 + *
1023 + * This program is distributed in the hope that it will be useful,
1024 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1025 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1026 + * GNU General Public License for more details.
1027 + *
1028 + * You should have received a copy of the GNU General Public License
1029 + * along with this program; if not, write to the Free Software
1030 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1031 + *
1032 + * $Id: serial_it8712.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
1033 + *
1034 + */
1035 +#include <linux/module.h>
1036 +
1037 +#include <linux/errno.h>
1038 +#include <linux/signal.h>
1039 +#include <linux/sched.h>
1040 +#include <linux/interrupt.h>
1041 +#include <linux/tty.h>
1042 +#include <linux/tty_flip.h>
1043 +#include <linux/major.h>
1044 +#include <linux/string.h>
1045 +#include <linux/fcntl.h>
1046 +#include <linux/ptrace.h>
1047 +#include <linux/ioport.h>
1048 +#include <linux/mm.h>
1049 +#include <linux/slab.h>
1050 +#include <linux/init.h>
1051 +#include <linux/circ_buf.h>
1052 +#include <linux/serial.h>
1053 +#include <linux/console.h>
1054 +#include <linux/sysrq.h>
1055 +
1056 +#include <asm/system.h>
1057 +#include <asm/io.h>
1058 +#include <asm/irq.h>
1059 +#include <asm/uaccess.h>
1060 +#include <asm/bitops.h>
1061 +#include <asm/sizes.h>
1062 +
1063 +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
1064 +#define SUPPORT_SYSRQ
1065 +#endif
1066 +
1067 +#include <linux/serial_core.h>
1068 +#include <asm/arch/sl2312.h>
1069 +#include <asm/arch/int_ctrl.h>
1070 +#include <asm/arch/it8712.h>
1071 +#include "serial_it8712.h"
1072 +
1073 +//#define DEBUG 1
1074 +#define UART_NR 1
1075 +
1076 +#define SERIAL_IT8712_NAME "ttySI"
1077 +#define SERIAL_IT8712_MAJOR 204
1078 +#define SERIAL_IT8712_MINOR 41 /* Temporary - will change in future */
1079 +#define SERIAL_IT8712_NR UART_NR
1080 +#define UART_PORT_SIZE 0x50
1081 +
1082 +#define CALLOUT_IT8712_NAME "cuaslI"
1083 +#define CALLOUT_IT8712_MAJOR 205
1084 +#define CALLOUT_IT8712_MINOR 41 /* Temporary - will change in future */
1085 +#define CALLOUT_IT8712_NR UART_NR
1086 +#define LPC_HOST_CONTINUE_MODE 0x00000040
1087 +
1088 +#define IT8712_NO_PORTS UART_NR
1089 +
1090 +static struct tty_driver normal, callout;
1091 +static struct tty_struct *it8712_table[UART_NR];
1092 +static struct termios *it8712_termios[UART_NR], *it8712_termios_locked[UART_NR];
1093 +static struct console it8712_console;
1094 +
1095 +#define IT8712_ISR_PASS_LIMIT 256
1096 +
1097 +/*
1098 + * Access macros for the SL2312 UARTs
1099 + */
1100 +#define UART_GET_INT_STATUS(p) (inb(((p)->membase+UART_IIR)) & 0x0F) // interrupt identification
1101 +#define UART_PUT_IER(p, c) outb(c,((p)->membase+UART_IER)) // interrupt enable
1102 +#define UART_GET_IER(p) inb(((p)->membase+UART_IER))
1103 +#define UART_PUT_CHAR(p, c) outb(c,((p)->membase+UART_TX)) // transmitter holding
1104 +#define UART_GET_CHAR(p) inb(((p)->membase+UART_RX)) // receive buffer
1105 +#define UART_GET_LSR(p) inb(((p)->membase+UART_LSR)) // line status
1106 +#define UART_GET_MSR(p) inb(((p)->membase+UART_MSR)) // modem status
1107 +#define UART_GET_MCR(p) inb(((p)->membase+UART_MCR)) // modem control
1108 +#define UART_PUT_MCR(p, c) outb(c,((p)->membase+UART_MCR))
1109 +#define UART_GET_LCR(p) inb(((p)->membase+UART_LCR)) // mode control
1110 +#define UART_PUT_LCR(p, c) outb(c,((p)->membase+UART_LCR))
1111 +#define UART_PUT_FCR(p, c) outb(c,((p)->membase+UART_FCR)) // fifo control
1112 +#define UART_GET_DIV_HI(p) inb(((p)->membase+UART_DLM))
1113 +#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
1114 +#define UART_GET_DIV_LO(p) inb(((p)->membase+UART_DLL))
1115 +#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
1116 +#define UART_PUT_MDR(p, c) outb(c,UART_MDR((p)->membase))
1117 +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
1118 +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
1119 +
1120 +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
1121 +{
1122 + unsigned int reg;
1123 +
1124 +// printk("it8712 stop tx : \n");
1125 + reg = UART_GET_IER(port);
1126 + reg &= ~(UART_IER_THRI);
1127 + UART_PUT_IER(port, reg);
1128 +}
1129 +
1130 +static void it8712_stop_rx(struct uart_port *port)
1131 +{
1132 + unsigned int reg;
1133 +
1134 +// printk("it8712 stop rx : \n");
1135 + reg = UART_GET_IER(port);
1136 + reg &= ~(UART_IER_RDI);
1137 + UART_PUT_IER(port, reg);
1138 +
1139 +}
1140 +
1141 +static void it8712_enable_ms(struct uart_port *port)
1142 +{
1143 + unsigned int reg;
1144 +
1145 +// printk("it8712 enable ms : \n");
1146 +
1147 + reg = UART_GET_IER(port);
1148 + reg |= (UART_IER_MSI);
1149 + UART_PUT_IER(port, reg);
1150 +
1151 +}
1152 +
1153 +static void
1154 +it8712_rx_chars(struct uart_info *info, struct pt_regs *regs)
1155 +{
1156 + struct tty_struct *tty = info->tty;
1157 + unsigned int status, mask, ch, flg, ignored = 0;
1158 + struct uart_port *port = info->port;
1159 +
1160 + // printk("it8712_rx_chars : \n");
1161 + status = UART_GET_LSR(port);
1162 + while (UART_RX_DATA(status)) {
1163 +
1164 + /*
1165 + * We need to read rds before reading the
1166 + * character from the fifo
1167 + */
1168 + ch = UART_GET_CHAR(port);
1169 + port->icount.rx++;
1170 +
1171 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
1172 + goto ignore_char;
1173 +
1174 + flg = TTY_NORMAL;
1175 +
1176 + /*
1177 + * Note that the error handling code is
1178 + * out of the main execution path
1179 + */
1180 +
1181 + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
1182 + goto handle_error;
1183 + if (uart_handle_sysrq_char(info, ch, regs))
1184 + goto ignore_char;
1185 +
1186 + error_return:
1187 + *tty->flip.flag_buf_ptr++ = flg;
1188 + *tty->flip.char_buf_ptr++ = ch;
1189 + tty->flip.count++;
1190 + ignore_char:
1191 + status = UART_GET_LSR(port);
1192 + } // end of while
1193 +out:
1194 + tty_flip_buffer_push(tty);
1195 + return;
1196 +
1197 +handle_error:
1198 + if (status & UART_LSR_BI) {
1199 + status &= ~(UART_LSR_FE);
1200 + port->icount.brk++;
1201 +
1202 +#ifdef SUPPORT_SYSRQ
1203 + if (uart_handle_break(info, &it8712_console))
1204 + goto ignore_char;
1205 +#endif
1206 + } else if (status & UART_LSR_PE)
1207 + port->icount.parity++;
1208 + else if (status & UART_LSR_FE)
1209 + port->icount.frame++;
1210 +
1211 + if (status & UART_LSR_OE)
1212 + port->icount.overrun++;
1213 +
1214 + if (status & port->ignore_status_mask) {
1215 + if (++ignored > 100)
1216 + goto out;
1217 + goto ignore_char;
1218 + }
1219 +
1220 + mask = status & port->read_status_mask;
1221 +
1222 + if (mask & UART_LSR_BI)
1223 + flg = TTY_BREAK;
1224 + else if (mask & UART_LSR_PE)
1225 + flg = TTY_PARITY;
1226 + else if (mask & UART_LSR_FE)
1227 + flg = TTY_FRAME;
1228 +
1229 + if (status & UART_LSR_OE) {
1230 + /*
1231 + * CHECK: does overrun affect the current character?
1232 + * ASSUMPTION: it does not.
1233 + */
1234 + *tty->flip.flag_buf_ptr++ = flg;
1235 + *tty->flip.char_buf_ptr++ = ch;
1236 + tty->flip.count++;
1237 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
1238 + goto ignore_char;
1239 + ch = 0;
1240 + flg = TTY_OVERRUN;
1241 + }
1242 +#ifdef SUPPORT_SYSRQ
1243 + info->sysrq = 0;
1244 +#endif
1245 + goto error_return;
1246 +}
1247 +
1248 +static void it8712_tx_chars(struct uart_info *info)
1249 +{
1250 + int count;
1251 + struct uart_port *port=info->port;
1252 +
1253 + if (port->x_char) {
1254 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
1255 + UART_PUT_CHAR(port, port->x_char);
1256 + port->icount.tx++;
1257 + port->x_char = 0;
1258 +
1259 + return;
1260 + }
1261 + if (info->xmit.head == info->xmit.tail
1262 + || info->tty->stopped
1263 + || info->tty->hw_stopped) {
1264 + it8712_stop_tx(info->port, 0);
1265 + return;
1266 + }
1267 +
1268 + count = port->fifosize >> 1;
1269 + do {
1270 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
1271 + UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
1272 + info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
1273 + port->icount.tx++;
1274 + if (info->xmit.head == info->xmit.tail)
1275 + break;
1276 + } while (--count > 0);
1277 +
1278 + if (CIRC_CNT(info->xmit.head,
1279 + info->xmit.tail,
1280 + UART_XMIT_SIZE) < WAKEUP_CHARS)
1281 + uart_event(info, EVT_WRITE_WAKEUP);
1282 +
1283 + if (info->xmit.head == info->xmit.tail)
1284 + it8712_stop_tx(info->port, 0);
1285 +}
1286 +
1287 +static void it8712_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
1288 +{
1289 + unsigned int reg;
1290 + struct uart_info *info=(struct uart_info*)(port->iobase);
1291 +
1292 +// printk("it8712 start tx : \n");
1293 + reg = UART_GET_IER(port);
1294 + reg |= (UART_IER_THRI);
1295 + UART_PUT_IER(port, reg);
1296 + it8712_tx_chars(info);
1297 +}
1298 +
1299 +static void it8712_modem_status(struct uart_info *info)
1300 +{
1301 + unsigned int status;
1302 + struct uart_icount *icount = &info->port->icount;
1303 +
1304 +// printk("it8712 modem status : \n");
1305 +
1306 + status = UART_GET_MSR(info->port);
1307 +
1308 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
1309 + UART_MSR_TERI | UART_MSR_DDCD)))
1310 + return;
1311 +
1312 + if (status & UART_MSR_DCD) {
1313 + icount->dcd++;
1314 +#ifdef CONFIG_HARD_PPS
1315 + if ((info->flags & ASYNC_HARDPPS_CD) &&
1316 + (status & UART_MSR_DCD_MSK))
1317 + hardpps();
1318 +#endif
1319 + if (info->flags & ASYNC_CHECK_CD) {
1320 + if (status & UART_MSR_DCD)
1321 + wake_up_interruptible(&info->open_wait);
1322 + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
1323 + (info->flags & ASYNC_CALLOUT_NOHUP))) {
1324 + if (info->tty)
1325 + tty_hangup(info->tty);
1326 + }
1327 + }
1328 + }
1329 +
1330 + if (status & UART_MSR_DDSR)
1331 + icount->dsr++;
1332 +
1333 + if (status & UART_MSR_DCTS) {
1334 + icount->cts++;
1335 +
1336 + if (info->flags & ASYNC_CTS_FLOW) {
1337 + status &= UART_MSR_CTS;
1338 +
1339 + if (info->tty->hw_stopped) {
1340 + if (status) {
1341 + info->tty->hw_stopped = 0;
1342 + info->ops->start_tx(info->port, 1, 0);
1343 + uart_event(info, EVT_WRITE_WAKEUP);
1344 + }
1345 + } else {
1346 + if (!status) {
1347 + info->tty->hw_stopped = 1;
1348 + info->ops->stop_tx(info->port, 0);
1349 + }
1350 + }
1351 + }
1352 + }
1353 + wake_up_interruptible(&info->delta_msr_wait);
1354 +
1355 +}
1356 +
1357 +static void it8712_int(int irq, void *dev_id, struct pt_regs *regs)
1358 +{
1359 + struct uart_info *info = dev_id;
1360 + unsigned int status, pass_counter = 0;
1361 +
1362 + status = UART_GET_INT_STATUS(info->port);
1363 + do {
1364 +// printk("it8712_int: status %x \n", status);
1365 + switch(status)
1366 + {
1367 + case UART_IIR_RDI:
1368 + case UART_IIR_RLSI:
1369 + case UART_IIR_RCTO:
1370 + it8712_rx_chars(info, regs);
1371 + break;
1372 + case UART_IIR_THRI:
1373 + it8712_tx_chars(info);
1374 + break;
1375 + case UART_IIR_MSI:
1376 + it8712_modem_status(info);
1377 + break;
1378 + default:
1379 + break;
1380 + }
1381 + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
1382 + break;
1383 +
1384 + status = UART_GET_INT_STATUS(info->port);
1385 + } while (status);
1386 +}
1387 +
1388 +static u_int it8712_tx_empty(struct uart_port *port)
1389 +{
1390 +// printk("it8712 tx empty : \n");
1391 +
1392 + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
1393 +}
1394 +
1395 +static u_int it8712_get_mctrl(struct uart_port *port)
1396 +{
1397 + unsigned int result = 0;
1398 + unsigned int status;
1399 +
1400 +// printk("it8712 get mctrl : \n");
1401 +
1402 + status = UART_GET_MSR(port);
1403 + if (status & UART_MSR_DCD)
1404 + result |= TIOCM_CAR;
1405 + if (status & UART_MSR_DSR)
1406 + result |= TIOCM_DSR;
1407 + if (status & UART_MSR_CTS)
1408 + result |= TIOCM_CTS;
1409 + if (status & UART_MSR_RI)
1410 + result |= TIOCM_RI;
1411 +
1412 + return result;
1413 +}
1414 +
1415 +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
1416 +{
1417 +}
1418 +
1419 +static void it8712_break_ctl(struct uart_port *port, int break_state)
1420 +{
1421 + unsigned int lcr;
1422 +
1423 +// printk("it8712 break ctl : \n");
1424 +
1425 + lcr = UART_GET_LCR(port);
1426 + if (break_state == -1)
1427 + lcr |= UART_LCR_SBC;
1428 + else
1429 + lcr &= ~UART_LCR_SBC;
1430 + UART_PUT_LCR(port, lcr);
1431 +}
1432 +
1433 +static inline u_int uart_calculate_quot(struct uart_info *info, u_int baud)
1434 +{
1435 + u_int quot;
1436 +
1437 + /* Special case: B0 rate */
1438 + if (!baud)
1439 + baud = 9600;
1440 +
1441 + quot = (info->port->uartclk/(16 * baud)) ;
1442 +
1443 + return quot;
1444 +}
1445 +static void it8712_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
1446 +{
1447 + u_int uart_mc=0, old_ier;
1448 + unsigned long flags;
1449 +
1450 +#ifdef DEBUG
1451 + printk("it8712_set_cflag(0x%x) called\n", cflag);
1452 +#endif
1453 +
1454 +
1455 + /* byte size and parity */
1456 + switch (cflag & CSIZE) {
1457 + case CS5: uart_mc = UART_LCR_WLEN5; break;
1458 + case CS6: uart_mc = UART_LCR_WLEN6; break;
1459 + case CS7: uart_mc = UART_LCR_WLEN7; break;
1460 + default: uart_mc = UART_LCR_WLEN8; break; // CS8
1461 + }
1462 + if (cflag & CSTOPB)
1463 + uart_mc|= UART_LCR_STOP;
1464 + if (cflag & PARENB) {
1465 + uart_mc |= UART_LCR_EVEN;
1466 + if (!(cflag & PARODD))
1467 + uart_mc |= UART_LCR_ODD;
1468 + }
1469 +
1470 + port->read_status_mask = UART_LSR_OE;
1471 + if (iflag & INPCK)
1472 + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
1473 + if (iflag & (BRKINT | PARMRK))
1474 + port->read_status_mask |= UART_LSR_BI;
1475 +
1476 + /*
1477 + * Characters to ignore
1478 + */
1479 + port->ignore_status_mask = 0;
1480 + if (iflag & IGNPAR)
1481 + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
1482 + if (iflag & IGNBRK) {
1483 + port->ignore_status_mask |= UART_LSR_BI;
1484 + /*
1485 + * If we're ignoring parity and break indicators,
1486 + * ignore overruns to (for real raw support).
1487 + */
1488 + if (iflag & IGNPAR)
1489 + port->ignore_status_mask |= UART_LSR_OE;
1490 + }
1491 +
1492 + /* first, disable everything */
1493 + save_flags(flags); cli();
1494 + old_ier = UART_GET_IER(port);
1495 +
1496 + if ((port->flags & ASYNC_HARDPPS_CD) ||
1497 + (cflag & CRTSCTS) || !(cflag & CLOCAL))
1498 + old_ier |= UART_IER_MSI;
1499 +
1500 + /* Set baud rate */
1501 + quot = quot / 13;
1502 + UART_PUT_LCR(port, UART_LCR_DLAB);
1503 + UART_PUT_DIV_LO(port, (quot & 0xff));
1504 + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
1505 +
1506 + UART_PUT_LCR(port, uart_mc);
1507 +// UART_PUT_LCR(port, 0x07); // ???? it is wired
1508 + UART_PUT_MCR(port, 0x08);
1509 + UART_PUT_FCR(port, 0x01);
1510 + UART_PUT_IER(port, 0x05);
1511 +
1512 + restore_flags(flags);
1513 +}
1514 +
1515 +static int it8712_startup(struct uart_port *port, struct uart_info *info)
1516 +{
1517 + int retval;
1518 + unsigned int regs;
1519 +
1520 +// printk("it8712 startup : \n");
1521 +
1522 + /*
1523 + * Use iobase to store a pointer to info. We need this to start a
1524 + * transmission as the tranmittr interrupt is only generated on
1525 + * the transition to the idle state
1526 + */
1527 +
1528 + port->iobase=(u_int)info;
1529 +
1530 + /*
1531 + * Allocate the IRQ
1532 + */
1533 + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", info);
1534 + if (retval)
1535 + return retval;
1536 +
1537 + /* setup interrupt controller */
1538 + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
1539 + regs |= (IRQ_SERIRQ0_MASK);
1540 + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
1541 + regs = *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
1542 + regs &= ~(IRQ_SERIRQ0_MASK);
1543 + *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
1544 + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_SERIRQ0_MASK);
1545 +
1546 + /*
1547 + * Finally, enable interrupts. Use the TII interrupt to minimise
1548 + * the number of interrupts generated. If higher performance is
1549 + * needed, consider using the TI interrupt with a suitable FIFO
1550 + * threshold
1551 + */
1552 + UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
1553 +
1554 + return 0;
1555 +}
1556 +
1557 +static void it8712_shutdown(struct uart_port *port, struct uart_info *info)
1558 +{
1559 +// printk("it8712 shutdown : \n");
1560 +
1561 + /*
1562 + * disable all interrupts, disable the port
1563 + */
1564 + UART_PUT_IER(port, 0x0);
1565 +
1566 + /* disable break condition and fifos */
1567 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
1568 +
1569 + /*
1570 + * Free the interrupt
1571 + */
1572 + free_irq(port->irq, info);
1573 +}
1574 +
1575 +static const char *it8712_type(struct uart_port *port)
1576 +{
1577 + return port->type == PORT_IT8712 ? "IT8712" : NULL;
1578 +}
1579 +
1580 +/*
1581 + * Release the memory region(s) being used by 'port'
1582 + */
1583 +static void it8712_release_port(struct uart_port *port)
1584 +{
1585 +// printk("it8712 release port : \n");
1586 +
1587 + release_mem_region(port->mapbase, UART_PORT_SIZE);
1588 +}
1589 +
1590 +/*
1591 + * Request the memory region(s) being used by 'port'
1592 + */
1593 +static int it8712_request_port(struct uart_port *port)
1594 +{
1595 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
1596 + "serial_it8712") != NULL ? 0 : -EBUSY;
1597 +}
1598 +
1599 +/*
1600 + * Configure/autoconfigure the port.
1601 + */
1602 +static void it8712_config_port(struct uart_port *port, int flags)
1603 +{
1604 +
1605 + if (flags & UART_CONFIG_TYPE) {
1606 + if (it8712_request_port(port) == 0)
1607 + port->type = PORT_IT8712;
1608 + }
1609 +}
1610 +
1611 +/*
1612 + * verify the new serial_struct (for TIOCSSERIAL).
1613 + */
1614 +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
1615 +{
1616 + int ret = 0;
1617 +
1618 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
1619 + ret = -EINVAL;
1620 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
1621 + ret = -EINVAL;
1622 + if (ser->baud_base < 9600)
1623 + ret = -EINVAL;
1624 + return ret;
1625 +}
1626 +
1627 +static struct uart_ops it8712_pops = {
1628 + tx_empty: it8712_tx_empty,
1629 + set_mctrl: it8712_set_mctrl_null,
1630 + get_mctrl: it8712_get_mctrl,
1631 + stop_tx: it8712_stop_tx,
1632 + start_tx: it8712_start_tx,
1633 + stop_rx: it8712_stop_rx,
1634 + enable_ms: it8712_enable_ms,
1635 + break_ctl: it8712_break_ctl,
1636 + startup: it8712_startup,
1637 + shutdown: it8712_shutdown,
1638 + change_speed: it8712_change_speed,
1639 + type: it8712_type,
1640 + release_port: it8712_release_port,
1641 + request_port: it8712_request_port,
1642 + config_port: it8712_config_port,
1643 + verify_port: it8712_verify_port,
1644 +};
1645 +
1646 +#ifdef CONFIG_ARCH_SL2312
1647 +
1648 +static struct uart_port it8712_ports[UART_NR] = {
1649 + {
1650 + membase: (void *)0,
1651 + mapbase: 0,
1652 + iotype: SERIAL_IO_MEM,
1653 + irq: 0,
1654 + uartclk: UART_CLK/2,
1655 + fifosize: 16,
1656 + ops: &it8712_pops,
1657 + flags: ASYNC_BOOT_AUTOCONF,
1658 + }
1659 +};
1660 +
1661 +#endif
1662 +
1663 +#ifdef CONFIG_SERIAL_IT8712_CONSOLE
1664 +#ifdef used_and_not_const_char_pointer
1665 +static int it8712_console_read(struct uart_port *port, char *s, u_int count)
1666 +{
1667 + unsigned int status;
1668 + int c;
1669 +#ifdef DEBUG
1670 + printk("it8712_console_read() called\n");
1671 +#endif
1672 +
1673 + c = 0;
1674 + while (c < count) {
1675 + status = UART_GET_LSR(port);
1676 + if (UART_RX_DATA(status)) {
1677 + *s++ = UART_GET_CHAR(port);
1678 + c++;
1679 + } else {
1680 + // nothing more to get, return
1681 + return c;
1682 + }
1683 + }
1684 + // return the count
1685 + return c;
1686 +}
1687 +#endif
1688 +static void it8712_console_write(struct console *co, const char *s, unsigned count)
1689 +{
1690 +#ifdef CONFIG_ARCH_SL2312
1691 + struct uart_port *port = it8712_ports + co->index;
1692 + unsigned int status, old_ies;
1693 + int i;
1694 +
1695 + /*
1696 + * First save the CR then disable the interrupts
1697 + */
1698 + old_ies = UART_GET_IER(port);
1699 + UART_PUT_IER(port,0x0);
1700 +
1701 + /*
1702 + * Now, do each character
1703 + */
1704 + for (i = 0; i < count; i++) {
1705 + do {
1706 + status = UART_GET_LSR(port);
1707 + } while (!UART_TX_READY(status));
1708 + UART_PUT_CHAR(port, s[i]);
1709 + if (s[i] == '\n') {
1710 + do {
1711 + status = UART_GET_LSR(port);
1712 + } while (!UART_TX_READY(status));
1713 + UART_PUT_CHAR(port, '\r');
1714 + }
1715 + }
1716 +
1717 + /*
1718 + * Finally, wait for transmitter to become empty
1719 + * and restore the IES
1720 + */
1721 + do {
1722 + status = UART_GET_LSR(port);
1723 + } while (!(status&UART_LSR_THRE));
1724 + UART_PUT_IER(port, old_ies);
1725 +#endif
1726 +}
1727 +
1728 +static kdev_t it8712_console_device(struct console *co)
1729 +{
1730 + return MKDEV(SERIAL_IT8712_MAJOR, SERIAL_IT8712_MINOR + co->index);
1731 +}
1732 +
1733 +static int it8712_console_wait_key(struct console *co)
1734 +{
1735 +#ifdef CONFIG_ARCH_SL2312
1736 + struct uart_port *port = (it8712_ports + co->index);
1737 + unsigned int status;
1738 +
1739 + do {
1740 + status = UART_GET_LSR(port);
1741 + } while (!UART_RX_DATA(status));
1742 + return UART_GET_CHAR(port);
1743 +#else
1744 + return 0;
1745 +#endif
1746 +}
1747 +
1748 +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
1749 +{
1750 + printk("it8712 console get options : \n");
1751 +
1752 + u_int uart_mc, quot;
1753 + uart_mc= UART_GET_MCR(port);
1754 +
1755 + *parity = 'n';
1756 + if (uart_mc & UART_LCR_PARITY) {
1757 + if (uart_mc & UART_LCR_EVEN)
1758 + *parity = 'e';
1759 + else
1760 + *parity = 'o';
1761 + }
1762 +
1763 + switch (uart_mc & UART_LCR_MSK){
1764 +
1765 + case UART_LCR_WLEN5:
1766 + *bits = 5;
1767 + break;
1768 + case UART_LCR_WLEN6:
1769 + *bits = 6;
1770 + break;
1771 + case UART_LCR_WLEN7:
1772 + *bits = 7;
1773 + break;
1774 + case UART_LCR_WLEN8:
1775 + *bits = 8;
1776 + break;
1777 + }
1778 + UART_PUT_MCR(port,UART_LCR_DLAB);
1779 + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
1780 + UART_PUT_MCR(port,uart_mc);
1781 + *baud = (port->uartclk / (16 *quot));
1782 +}
1783 +
1784 +static int __init it8712_console_setup(struct console *co, char *options)
1785 +{
1786 + struct uart_port *port;
1787 + int baud = 38400;
1788 + int bits = 8;
1789 + int parity = 'n';
1790 + int flow= 'n';
1791 + int base, irq;
1792 + int i ;
1793 +
1794 +// printk("it8712 console setup : \n");
1795 +
1796 + LPCSetConfig(0, 0x02, 0x01);
1797 + LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
1798 + LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
1799 + base = IT8712_IO_BASE;
1800 + base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
1801 + it8712_ports[0].mapbase = base;
1802 + it8712_ports[0].membase = IO_ADDRESS(base);
1803 + it8712_ports[0].irq = IRQ_SERIRQ0_OFFSET;
1804 + irq = LPCGetConfig(LDN_SERIAL1, 0x70);
1805 + it8712_ports[0].irq += irq;
1806 +
1807 + printk("it8712 irq is %x %x \n", it8712_ports[0].irq, irq);
1808 +
1809 + // setup LPC Host 'quiet mode'
1810 + *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
1811 + for(i=0;i<1000;i++) ; // delay
1812 + *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
1813 +
1814 +#ifdef CONFIG_ARCH_SL2312
1815 + /*
1816 + * Check whether an invalid uart number has been specified, and
1817 + * if so, search for the first available port that does have
1818 + * console support.
1819 + */
1820 + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
1821 +#else
1822 + return -ENODEV;
1823 +#endif
1824 +
1825 + if (options)
1826 + uart_parse_options(options, &baud, &parity, &bits, &flow);
1827 + else
1828 + it8712_console_get_options(port, &baud, &parity, &bits);
1829 +
1830 + return uart_set_options(port, co, baud, parity, bits, flow);
1831 +}
1832 +
1833 +static struct console it8712_console = {
1834 + name: SERIAL_IT8712_NAME,
1835 + write: it8712_console_write,
1836 +#ifdef used_and_not_const_char_pointer
1837 + read: it8712_console_read,
1838 +#endif
1839 + device: it8712_console_device,
1840 +// wait_key: it8712_console_wait_key,
1841 + setup: it8712_console_setup,
1842 + flags: (CON_PRINTBUFFER|CON_ENABLED),
1843 + index: -1,
1844 +};
1845 +
1846 +void __init it8712_console_init(void)
1847 +{
1848 + register_console(&it8712_console);
1849 +}
1850 +
1851 +#define IT8712_CONSOLE &it8712_console
1852 +#else
1853 +#define IT8712_CONSOLE NULL
1854 +#endif
1855 +
1856 +static struct uart_driver it8712_reg = {
1857 + owner: NULL,
1858 + normal_major: SERIAL_IT8712_MAJOR,
1859 + normal_name: SERIAL_IT8712_NAME,
1860 + normal_driver: &normal,
1861 + callout_major: CALLOUT_IT8712_MAJOR,
1862 + callout_name: CALLOUT_IT8712_NAME,
1863 + callout_driver: &callout,
1864 + table: it8712_table,
1865 + termios: it8712_termios,
1866 + termios_locked: it8712_termios_locked,
1867 + minor: SERIAL_IT8712_MINOR,
1868 + nr: UART_NR,
1869 +#ifdef CONFIG_ARCH_SL2312
1870 + port: it8712_ports,
1871 +#endif
1872 + state: NULL,
1873 + cons: IT8712_CONSOLE,
1874 +};
1875 +
1876 +static int __init it8712_init(void)
1877 +{
1878 +// printk("serial_it8712: it871212_init \n");
1879 +
1880 + return uart_register_driver(&it8712_reg);
1881 +}
1882 +
1883 +
1884 +__initcall(it8712_init);
1885 Index: linux-2.6.23.16/drivers/serial/serial_sl2312.c
1886 ===================================================================
1887 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1888 +++ linux-2.6.23.16/drivers/serial/serial_sl2312.c 2008-03-17 12:30:50.290536619 +0200
1889 @@ -0,0 +1,827 @@
1890 +/*
1891 + * linux/drivers/char/serial_uart00.c
1892 + *
1893 + * Driver for UART00 serial ports
1894 + *
1895 + * Based on drivers/char/serial_amba.c, by ARM Limited &
1896 + * Deep Blue Solutions Ltd.
1897 + * Copyright 2001 Altera Corporation
1898 + *
1899 + * This program is free software; you can redistribute it and/or modify
1900 + * it under the terms of the GNU General Public License as published by
1901 + * the Free Software Foundation; either version 2 of the License, or
1902 + * (at your option) any later version.
1903 + *
1904 + * This program is distributed in the hope that it will be useful,
1905 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1906 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1907 + * GNU General Public License for more details.
1908 + *
1909 + * You should have received a copy of the GNU General Public License
1910 + * along with this program; if not, write to the Free Software
1911 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1912 + *
1913 + * $Id: serial_sl2312.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
1914 + *
1915 + */
1916 +#include <linux/module.h>
1917 +
1918 +#include <linux/errno.h>
1919 +#include <linux/signal.h>
1920 +#include <linux/sched.h>
1921 +#include <linux/interrupt.h>
1922 +#include <linux/tty.h>
1923 +#include <linux/tty_flip.h>
1924 +#include <linux/major.h>
1925 +#include <linux/string.h>
1926 +#include <linux/fcntl.h>
1927 +#include <linux/ptrace.h>
1928 +#include <linux/ioport.h>
1929 +#include <linux/mm.h>
1930 +#include <linux/slab.h>
1931 +#include <linux/init.h>
1932 +#include <linux/circ_buf.h>
1933 +#include <linux/serial.h>
1934 +#include <linux/console.h>
1935 +#include <linux/sysrq.h>
1936 +#include <linux/serial_core.h>
1937 +
1938 +#include <asm/system.h>
1939 +#include <asm/hardware.h>
1940 +#include <asm/io.h>
1941 +#include <asm/irq.h>
1942 +#include <asm/uaccess.h>
1943 +#include <asm/bitops.h>
1944 +#include <asm/sizes.h>
1945 +#include <linux/spinlock.h>
1946 +#include <linux/irq.h>
1947 +
1948 +
1949 +#if defined(CONFIG_SERIAL_SL2312_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
1950 +#define SUPPORT_SYSRQ
1951 +#endif
1952 +
1953 +#include <asm/arch/sl2312.h>
1954 +#define UART_TYPE (volatile unsigned int*)
1955 +#include <asm/arch/uart.h>
1956 +#include <asm/arch/int_ctrl.h>
1957 +
1958 +// #define DEBUG 1
1959 +#define UART_NR 1
1960 +
1961 +
1962 +#define SERIAL_SL2312_NAME "ttySL"
1963 +#define SERIAL_SL2312_MAJOR 204
1964 +#define SERIAL_SL2312_MINOR 40 /* Temporary - will change in future */
1965 +#define SERIAL_SL2312_NR UART_NR
1966 +#define UART_PORT_SIZE 0x50
1967 +
1968 +#define SL2312_NO_PORTS UART_NR
1969 +#define SL2312_ISR_PASS_LIMIT 256
1970 +
1971 +/*
1972 + * Access macros for the SL2312 UARTs
1973 + */
1974 +#define UART_GET_INT_STATUS(p) (inl(UART_IIR((p)->membase)) & 0x0F) // interrupt identification
1975 +#define UART_PUT_IER(p, c) outl(c,UART_IER((p)->membase)) // interrupt enable
1976 +#define UART_GET_IER(p) inl(UART_IER((p)->membase))
1977 +#define UART_PUT_CHAR(p, c) outl(c,UART_THR((p)->membase)) // transmitter holding
1978 +#define UART_GET_CHAR(p) inl(UART_RBR((p)->membase)) // receive buffer
1979 +#define UART_GET_LSR(p) inl(UART_LSR((p)->membase)) // line status
1980 +#define UART_GET_MSR(p) inl(UART_MSR((p)->membase)) // modem status
1981 +#define UART_GET_MCR(p) inl(UART_MCR((p)->membase)) // modem control
1982 +#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase))
1983 +#define UART_GET_LCR(p) inl(UART_LCR((p)->membase)) // mode control
1984 +#define UART_PUT_LCR(p, c) outl(c,UART_LCR((p)->membase))
1985 +#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase))
1986 +#define UART_PUT_DIV_HI(p, c) outl(c,UART_DIV_HI((p)->membase))
1987 +#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase))
1988 +#define UART_PUT_DIV_LO(p, c) outl(c,UART_DIV_LO((p)->membase))
1989 +#define UART_PUT_MDR(p, c) outl(c,UART_MDR((p)->membase))
1990 +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
1991 +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
1992 +
1993 +
1994 +static void sl2312_stop_tx(struct uart_port *port)
1995 +{
1996 + unsigned int reg;
1997 +
1998 +// printk("sl2312 stop tx : \n");
1999 + reg = UART_GET_IER(port);
2000 + reg &= ~(UART_IER_TE);
2001 + UART_PUT_IER(port, reg);
2002 +}
2003 +
2004 +static void sl2312_stop_rx(struct uart_port *port)
2005 +{
2006 + unsigned int reg;
2007 +
2008 +// printk("sl2312 stop rx : \n");
2009 + reg = UART_GET_IER(port);
2010 + reg &= ~(UART_IER_DR);
2011 + UART_PUT_IER(port, reg);
2012 +
2013 +}
2014 +
2015 +static void sl2312_enable_ms(struct uart_port *port)
2016 +{
2017 + unsigned int reg;
2018 +
2019 +// printk("sl2312 enable ms : \n");
2020 +
2021 + reg = UART_GET_IER(port);
2022 + reg |= (UART_IER_MS);
2023 + UART_PUT_IER(port, reg);
2024 +
2025 +}
2026 +
2027 +static void
2028 +sl2312_rx_chars(struct uart_port *port)
2029 +{
2030 + struct tty_struct *tty = port->info->tty;
2031 + unsigned int status, mask, ch, flg, ignored = 0;
2032 +
2033 +
2034 + // printk("sl2312_rx_chars : \n");
2035 + status = UART_GET_LSR(port);
2036 + while (UART_RX_DATA(status)) {
2037 +
2038 + /*
2039 + * We need to read rds before reading the
2040 + * character from the fifo
2041 + */
2042 + ch = UART_GET_CHAR(port);
2043 + port->icount.rx++;
2044 +
2045 + //if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2046 + if (tty && !tty_buffer_request_room(tty, 1))
2047 + goto ignore_char;
2048 +
2049 + flg = TTY_NORMAL;
2050 +
2051 + /*
2052 + * Note that the error handling code is
2053 + * out of the main execution path
2054 + */
2055 +
2056 + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
2057 + goto handle_error;
2058 + if (uart_handle_sysrq_char(port, ch))
2059 + goto ignore_char;
2060 +
2061 + error_return:
2062 + //*tty->flip.flag_buf_ptr++ = flg;
2063 + //*tty->flip.char_buf_ptr++ = ch;
2064 + //tty->flip.count++;
2065 + tty_insert_flip_char(tty, ch, flg);
2066 + ignore_char:
2067 + status = UART_GET_LSR(port);
2068 + } // end of while
2069 +out:
2070 + tty_flip_buffer_push(tty);
2071 + return;
2072 +
2073 +handle_error:
2074 + if (status & UART_LSR_BI) {
2075 + status &= ~(UART_LSR_FE);
2076 + port->icount.brk++;
2077 +
2078 +#ifdef SUPPORT_SYSRQ
2079 + if (uart_handle_break(port))
2080 + goto ignore_char;
2081 +#endif
2082 + } else if (status & UART_LSR_PE)
2083 + port->icount.parity++;
2084 + else if (status & UART_LSR_FE)
2085 + port->icount.frame++;
2086 +
2087 + if (status & UART_LSR_OE)
2088 + port->icount.overrun++;
2089 +
2090 + if (status & port->ignore_status_mask) {
2091 + if (++ignored > 100)
2092 + goto out;
2093 + goto ignore_char;
2094 + }
2095 +
2096 + mask = status & port->read_status_mask;
2097 +
2098 + if (mask & UART_LSR_BI)
2099 + flg = TTY_BREAK;
2100 + else if (mask & UART_LSR_PE)
2101 + flg = TTY_PARITY;
2102 + else if (mask & UART_LSR_FE)
2103 + flg = TTY_FRAME;
2104 +
2105 + if (status & UART_LSR_OE) {
2106 + /*
2107 + * CHECK: does overrun affect the current character?
2108 + * ASSUMPTION: it does not.
2109 + */
2110 + //*tty->flip.flag_buf_ptr++ = flg;
2111 + //*tty->flip.char_buf_ptr++ = ch;
2112 + //tty->flip.count++;
2113 +
2114 + tty_insert_flip_char(tty, 0, TTY_BREAK);
2115 +
2116 + // if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2117 + if (tty_buffer_request_room(tty, 1))
2118 + goto ignore_char;
2119 + ch = 0;
2120 + flg = TTY_OVERRUN;
2121 + }
2122 +#ifdef SUPPORT_SYSRQ
2123 + port->sysrq = 0;
2124 +#endif
2125 + goto error_return;
2126 +}
2127 +
2128 +static void sl2312_tx_chars(struct uart_port *port)
2129 +{
2130 + struct circ_buf *xmit = &port->info->xmit;
2131 + int count;
2132 +
2133 +
2134 + if (port->x_char) {
2135 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
2136 + UART_PUT_CHAR(port, port->x_char);
2137 + port->icount.tx++;
2138 + port->x_char = 0;
2139 +
2140 + return;
2141 + }
2142 + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
2143 + sl2312_stop_tx(port);
2144 +
2145 + return;
2146 + }
2147 +
2148 + count = port->fifosize >> 1;
2149 + do {
2150 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
2151 + UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
2152 + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
2153 + port->icount.tx++;
2154 + if (uart_circ_empty(xmit))
2155 + break;
2156 + } while (--count > 0);
2157 +
2158 + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
2159 + uart_write_wakeup(port);
2160 +
2161 + if (uart_circ_empty(xmit))
2162 + sl2312_stop_tx(port);
2163 +
2164 +}
2165 +
2166 +static void sl2312_start_tx(struct uart_port *port)
2167 +{
2168 + unsigned int reg;
2169 +
2170 +// printk("sl2312 start tx : \n");
2171 + reg = UART_GET_IER(port);
2172 + reg |= (UART_IER_TE);
2173 + UART_PUT_IER(port, reg);
2174 +
2175 + sl2312_tx_chars(port);
2176 +}
2177 +
2178 +static void sl2312_modem_status(struct uart_port *port)
2179 +{
2180 + unsigned int status;
2181 +
2182 +// printk("it8712 modem status : \n");
2183 +
2184 + status = UART_GET_MSR(port);
2185 +
2186 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
2187 + UART_MSR_TERI | UART_MSR_DDCD)))
2188 + return;
2189 +
2190 + if (status & UART_MSR_DDCD)
2191 + uart_handle_dcd_change(port, status & UART_MSR_DCD);
2192 +
2193 + if (status & UART_MSR_DDSR)
2194 + port->icount.dsr++;
2195 +
2196 + if (status & UART_MSR_DCTS)
2197 + uart_handle_cts_change(port, status & UART_MSR_CTS);
2198 +
2199 + wake_up_interruptible(&port->info->delta_msr_wait);
2200 +
2201 +}
2202 +
2203 +static irqreturn_t sl2312_int(int irq, void *dev_id)
2204 +{
2205 + struct uart_port *port = dev_id;
2206 + unsigned int status, pass_counter = 0;
2207 +
2208 + status = UART_GET_INT_STATUS(port);
2209 + do {
2210 + switch(status)
2211 + {
2212 + case UART_IIR_DR:
2213 + case UART_IIR_RLS:
2214 + sl2312_rx_chars(port);
2215 + break;
2216 + case UART_IIR_TE:
2217 + sl2312_tx_chars(port);
2218 + break;
2219 + case UART_IIR_MODEM:
2220 + sl2312_modem_status(port);
2221 + break;
2222 + default:
2223 + break;
2224 + }
2225 + if (pass_counter++ > SL2312_ISR_PASS_LIMIT)
2226 + break;
2227 +
2228 + status = UART_GET_INT_STATUS(port);
2229 + } while (status);
2230 +
2231 + return IRQ_HANDLED;
2232 +}
2233 +
2234 +static u_int sl2312_tx_empty(struct uart_port *port)
2235 +{
2236 +// printk("sl2312 tx empty : \n");
2237 +
2238 + return ((UART_GET_LSR(port) & UART_LSR_TE)? TIOCSER_TEMT : 0);
2239 +}
2240 +
2241 +static u_int sl2312_get_mctrl(struct uart_port *port)
2242 +{
2243 + unsigned int result = 0;
2244 + unsigned int status;
2245 +
2246 +// printk("sl2312 get mctrl : \n");
2247 +
2248 + status = UART_GET_MSR(port);
2249 + if (status & UART_MSR_DCD)
2250 + result |= TIOCM_CAR;
2251 + if (status & UART_MSR_DSR)
2252 + result |= TIOCM_DSR;
2253 + if (status & UART_MSR_CTS)
2254 + result |= TIOCM_CTS;
2255 + if (status & UART_MSR_RI)
2256 + result |= TIOCM_RI;
2257 +
2258 + return result;
2259 +}
2260 +
2261 +static void sl2312_set_mctrl_null(struct uart_port *port, u_int mctrl)
2262 +{
2263 +}
2264 +
2265 +static void sl2312_break_ctl(struct uart_port *port, int break_state)
2266 +{
2267 + unsigned int lcr;
2268 +
2269 +// printk("sl2312 break ctl : \n");
2270 +
2271 + lcr = UART_GET_LCR(port);
2272 + if (break_state == -1)
2273 + lcr |= UART_LCR_SETBREAK;
2274 + else
2275 + lcr &= ~UART_LCR_SETBREAK;
2276 + UART_PUT_LCR(port, lcr);
2277 +}
2278 +
2279 +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
2280 +{
2281 + u_int quot;
2282 +
2283 + /* Special case: B0 rate */
2284 + if (!baud)
2285 + baud = 9600;
2286 +
2287 + quot = (port->uartclk / (16 * baud)-1) ;
2288 +
2289 + return quot;
2290 +}
2291 +
2292 +static void sl2312_set_termios(struct uart_port *port, struct ktermios *termios,
2293 + struct ktermios *old)
2294 +{
2295 + unsigned int uart_mc, old_ier, baud, quot;
2296 + unsigned long flags;
2297 +
2298 + termios->c_cflag |= CREAD;
2299 +#ifdef DEBUG
2300 + printk("it8712_set_cflag(0x%x) called\n", cflag);
2301 +#endif
2302 + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
2303 + quot = (port->uartclk / (16 * baud)) ;
2304 + //uart_get_divisor(port, baud);
2305 +
2306 + /* byte size and parity */
2307 + switch (termios->c_cflag & CSIZE) {
2308 + case CS5:
2309 + uart_mc = UART_LCR_LEN5;
2310 + break;
2311 + case CS6:
2312 + uart_mc = UART_LCR_LEN6;
2313 + break;
2314 + case CS7:
2315 + uart_mc = UART_LCR_LEN7;
2316 + break;
2317 + default: // CS8
2318 + uart_mc = UART_LCR_LEN8;
2319 + break;
2320 + }
2321 +
2322 + if (termios->c_cflag & CSTOPB)
2323 + uart_mc|= UART_LCR_STOP;
2324 + if (termios->c_cflag & PARENB) {
2325 + uart_mc |= UART_LCR_EVEN;
2326 + if (!(termios->c_cflag & PARODD))
2327 + uart_mc |= UART_LCR_ODD;
2328 + }
2329 +
2330 + spin_lock_irqsave(&port->lock, flags);
2331 + /*
2332 + * Update the per-port timeout
2333 + */
2334 + uart_update_timeout(port, termios->c_cflag, baud);
2335 + port->read_status_mask = UART_LSR_OE;
2336 + if (termios->c_iflag & INPCK)
2337 + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
2338 + if (termios->c_iflag & (BRKINT | PARMRK))
2339 + port->read_status_mask |= UART_LSR_BI;
2340 +
2341 + /*
2342 + * Characters to ignore
2343 + */
2344 + port->ignore_status_mask = 0;
2345 + if (termios->c_iflag & IGNPAR)
2346 + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
2347 + if (termios->c_iflag & IGNBRK) {
2348 + port->ignore_status_mask |= UART_LSR_BI;
2349 + /*
2350 + * If we're ignoring parity and break indicators,
2351 + * ignore overruns to (for real raw support).
2352 + */
2353 + if (termios->c_iflag & IGNPAR)
2354 + port->ignore_status_mask |= UART_LSR_OE;
2355 + }
2356 +
2357 + //save_flags(flags); cli();
2358 + old_ier = UART_GET_IER(port);
2359 +
2360 + if(UART_ENABLE_MS(port, termios->c_cflag))
2361 + old_ier |= UART_IER_MS;
2362 +
2363 + /* Set baud rate */
2364 + UART_PUT_LCR(port, UART_LCR_DLAB);
2365 + UART_PUT_DIV_LO(port, (quot & 0xff));
2366 + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
2367 +
2368 + UART_PUT_LCR(port, uart_mc);
2369 + UART_PUT_IER(port, old_ier);
2370 +
2371 + //restore_flags(flags);
2372 + spin_unlock_irqrestore(&port->lock, flags);
2373 +}
2374 +
2375 +
2376 +
2377 +static int sl2312_startup(struct uart_port *port)
2378 +{
2379 + int retval;
2380 + unsigned int regs;
2381 +
2382 +// printk("sl2312 startup : \n");
2383 +
2384 + /*
2385 + * Use iobase to store a pointer to info. We need this to start a
2386 + * transmission as the tranmittr interrupt is only generated on
2387 + * the transition to the idle state
2388 + */
2389 +
2390 + /*
2391 + * Allocate the IRQ
2392 + */
2393 + retval = request_irq(port->irq, sl2312_int, IRQF_DISABLED, "sl2312", port);
2394 + if (retval)
2395 + return retval;
2396 +
2397 + /* setup interrupt controller */
2398 + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
2399 + regs &= ~(IRQ_UART_MASK);
2400 + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
2401 + regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
2402 + regs &= ~(IRQ_UART_MASK);
2403 + *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
2404 + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_UART_MASK);
2405 +
2406 + /*
2407 + * Finally, enable interrupts. Use the TII interrupt to minimise
2408 + * the number of interrupts generated. If higher performance is
2409 + * needed, consider using the TI interrupt with a suitable FIFO
2410 + * threshold
2411 + */
2412 + UART_PUT_IER(port, (UART_IER_DR|UART_IER_TE));
2413 +
2414 + return 0;
2415 +}
2416 +
2417 +static void sl2312_shutdown(struct uart_port *port)
2418 +{
2419 +// printk("sl2312 shutdown : \n");
2420 +
2421 + /*
2422 + * disable all interrupts, disable the port
2423 + */
2424 + UART_PUT_IER(port, 0x0);
2425 +
2426 + /* disable break condition and fifos */
2427 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
2428 +
2429 + /*
2430 + * Free the interrupt
2431 + */
2432 + free_irq(port->irq, port);
2433 +}
2434 +
2435 +static const char *sl2312_type(struct uart_port *port)
2436 +{
2437 + return port->type == PORT_SL2312 ? "SL2312" : NULL;
2438 +}
2439 +
2440 +/*
2441 + * Release the memory region(s) being used by 'port'
2442 + */
2443 +static void sl2312_release_port(struct uart_port *port)
2444 +{
2445 +// printk("sl2312 release port : \n");
2446 +
2447 + release_mem_region(port->mapbase, UART_PORT_SIZE);
2448 +}
2449 +
2450 +/*
2451 + * Request the memory region(s) being used by 'port'
2452 + */
2453 +static int sl2312_request_port(struct uart_port *port)
2454 +{
2455 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
2456 + "serial_sl2312") != NULL ? 0 : -EBUSY;
2457 +}
2458 +
2459 +/*
2460 + * Configure/autoconfigure the port.
2461 + */
2462 +static void sl2312_config_port(struct uart_port *port, int flags)
2463 +{
2464 +
2465 + if (flags & UART_CONFIG_TYPE) {
2466 + if (sl2312_request_port(port) == 0)
2467 + port->type = PORT_SL2312;
2468 + }
2469 +}
2470 +
2471 +/*
2472 + * verify the new serial_struct (for TIOCSSERIAL).
2473 + */
2474 +static int sl2312_verify_port(struct uart_port *port, struct serial_struct *ser)
2475 +{
2476 + int ret = 0;
2477 +
2478 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
2479 + ret = -EINVAL;
2480 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
2481 + ret = -EINVAL;
2482 + if (ser->baud_base < 9600)
2483 + ret = -EINVAL;
2484 + return ret;
2485 +}
2486 +
2487 +static struct uart_ops sl2312_pops = {
2488 + .tx_empty =sl2312_tx_empty,
2489 + .set_mctrl =sl2312_set_mctrl_null,
2490 + .get_mctrl =sl2312_get_mctrl,
2491 + .stop_tx =sl2312_stop_tx,
2492 + .start_tx =sl2312_start_tx,
2493 + .stop_rx =sl2312_stop_rx,
2494 + .enable_ms =sl2312_enable_ms,
2495 + .break_ctl =sl2312_break_ctl,
2496 + .startup =sl2312_startup,
2497 + .shutdown =sl2312_shutdown,
2498 + .set_termios =sl2312_set_termios,
2499 + .type =sl2312_type,
2500 + .release_port =sl2312_release_port,
2501 + .request_port =sl2312_request_port,
2502 + .config_port =sl2312_config_port,
2503 + .verify_port =sl2312_verify_port,
2504 +};
2505 +
2506 +#ifdef CONFIG_ARCH_SL2312
2507 +
2508 +static struct uart_port sl2312_ports[UART_NR] = {
2509 + {
2510 + membase: (void *)IO_ADDRESS(SL2312_UART_BASE),
2511 + mapbase: SL2312_UART_BASE,
2512 + iotype: SERIAL_IO_MEM,
2513 + irq: IRQ_UART,
2514 + uartclk: UART_CLK,
2515 + fifosize: 16,
2516 + ops: &sl2312_pops,
2517 + flags: ASYNC_BOOT_AUTOCONF,
2518 + }
2519 +};
2520 +
2521 +#endif
2522 +
2523 +#ifdef CONFIG_SERIAL_SL2312_CONSOLE
2524 +#ifdef used_and_not_const_char_pointer
2525 +static int sl2312_console_read(struct uart_port *port, char *s, u_int count)
2526 +{
2527 + unsigned int status;
2528 + int c;
2529 +#ifdef DEBUG
2530 + printk("sl2312_console_read() called\n");
2531 +#endif
2532 +
2533 + c = 0;
2534 + while (c < count) {
2535 + status = UART_GET_LSR(port);
2536 + if (UART_RX_DATA(status)) {
2537 + *s++ = UART_GET_CHAR(port);
2538 + c++;
2539 + } else {
2540 + // nothing more to get, return
2541 + return c;
2542 + }
2543 + }
2544 + // return the count
2545 + return c;
2546 +}
2547 +#endif
2548 +static void sl2312_console_write(struct console *co, const char *s, unsigned count)
2549 +{
2550 +#ifdef CONFIG_ARCH_SL2312
2551 + struct uart_port *port = sl2312_ports + co->index;
2552 + unsigned int status, old_ies;
2553 + int i;
2554 +
2555 + /*
2556 + * First save the CR then disable the interrupts
2557 + */
2558 + old_ies = UART_GET_IER(port);
2559 + UART_PUT_IER(port,0x0);
2560 +
2561 + /*
2562 + * Now, do each character
2563 + */
2564 + for (i = 0; i < count; i++) {
2565 + do {
2566 + status = UART_GET_LSR(port);
2567 + } while (!UART_TX_READY(status));
2568 + UART_PUT_CHAR(port, s[i]);
2569 + if (s[i] == '\n') {
2570 + do {
2571 + status = UART_GET_LSR(port);
2572 + } while (!UART_TX_READY(status));
2573 + UART_PUT_CHAR(port, '\r');
2574 + }
2575 + }
2576 +
2577 + /*
2578 + * Finally, wait for transmitter to become empty
2579 + * and restore the IES
2580 + */
2581 + do {
2582 + status = UART_GET_LSR(port);
2583 + } while (!(status&UART_LSR_TE));
2584 + UART_PUT_IER(port, old_ies);
2585 +#endif
2586 +}
2587 +
2588 +#if 0
2589 +static void sl2312_console_device(struct console *co,int *index)
2590 +{
2591 +
2592 + struct uart_driver *p = co->data;
2593 + *index = co->index;
2594 + return p->tty_driver;
2595 +
2596 +}
2597 +#endif
2598 +
2599 +static void /*__init*/ sl2312_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
2600 +{
2601 +// printk("sl2312 console get options : \n");
2602 +
2603 + u_int uart_mc, quot;
2604 + uart_mc= UART_GET_MCR(port);
2605 +
2606 + *parity = 'n';
2607 + if (uart_mc & UART_LCR_PE) {
2608 + if (uart_mc & UART_LCR_EVEN)
2609 + *parity = 'e';
2610 + else
2611 + *parity = 'o';
2612 + }
2613 +
2614 + switch (uart_mc & UART_LCR_MSK){
2615 +
2616 + case UART_LCR_LEN5:
2617 + *bits = 5;
2618 + break;
2619 + case UART_LCR_LEN6:
2620 + *bits = 6;
2621 + break;
2622 + case UART_LCR_LEN7:
2623 + *bits = 7;
2624 + break;
2625 + case UART_LCR_LEN8:
2626 + *bits = 8;
2627 + break;
2628 + }
2629 + UART_PUT_MCR(port,UART_LCR_DLAB);
2630 + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
2631 + UART_PUT_MCR(port,uart_mc);
2632 + *baud = port->uartclk / (16 *quot );
2633 +}
2634 +
2635 +static int __init sl2312_console_setup(struct console *co, char *options)
2636 +{
2637 + struct uart_port *port;
2638 + int baud = 19200;
2639 + int bits = 8;
2640 + int parity = 'n';
2641 + int flow= 'n';
2642 +
2643 + printk("sl2312 console setup : \n");
2644 +
2645 +#ifdef CONFIG_ARCH_SL2312
2646 + /*
2647 + * Check whether an invalid uart number has been specified, and
2648 + * if so, search for the first available port that does have
2649 + * console support.
2650 + */
2651 + port = uart_get_console(sl2312_ports,SL2312_NO_PORTS,co);
2652 +#else
2653 + return -ENODEV;
2654 +#endif
2655 +
2656 + if (options)
2657 + uart_parse_options(options, &baud, &parity, &bits, &flow);
2658 + else
2659 + sl2312_console_get_options(port, &baud, &parity, &bits);
2660 +
2661 + return uart_set_options(port, co, baud, parity, bits, flow);
2662 +}
2663 +
2664 +extern struct uart_driver sl2312_reg;
2665 +static struct console sl2312_console = {
2666 + .name = SERIAL_SL2312_NAME,
2667 + .write = sl2312_console_write,
2668 + .device = uart_console_device,
2669 +// .device = sl2312_console_device,
2670 + .setup = sl2312_console_setup,
2671 +// .flags = (CON_PRINTBUFFER|CON_ENABLED),
2672 + .flags = CON_PRINTBUFFER,
2673 + .index = -1,
2674 + .data = &sl2312_reg,
2675 +};
2676 +
2677 +static int __init sl2312_console_init(void)
2678 +{
2679 + register_console(&sl2312_console);
2680 + return 0;
2681 +
2682 +}
2683 +
2684 +console_initcall(sl2312_console_init);
2685 +
2686 +#define SL2312_CONSOLE &sl2312_console
2687 +#else
2688 +#define SL2312_CONSOLE NULL
2689 +#endif
2690 +
2691 +// static
2692 +struct uart_driver sl2312_reg = {
2693 + .owner = NULL,
2694 + .driver_name = SERIAL_SL2312_NAME,
2695 + .dev_name = SERIAL_SL2312_NAME,
2696 + .major = SERIAL_SL2312_MAJOR,
2697 + .minor = SERIAL_SL2312_MINOR,
2698 + .nr = UART_NR,
2699 + .cons = SL2312_CONSOLE,
2700 +};
2701 +
2702 +static int __init sl2312_init(void)
2703 +{
2704 + int result;
2705 + //printk("serial_it8712: it871212_init \n");
2706 +
2707 + result = uart_register_driver(&sl2312_reg);
2708 + if(result)
2709 + return result;
2710 + result = uart_add_one_port(&sl2312_reg, &sl2312_ports[0]);
2711 +
2712 + return result;
2713 +}
2714 +
2715 +
2716 +__initcall(sl2312_init);
2717 Index: linux-2.6.23.16/include/linux/serial_core.h
2718 ===================================================================
2719 --- linux-2.6.23.16.orig/include/linux/serial_core.h 2008-03-15 17:59:22.566564448 +0200
2720 +++ linux-2.6.23.16/include/linux/serial_core.h 2008-03-15 17:59:53.568330991 +0200
2721 @@ -147,6 +147,10 @@
2722 #define PORT_SB1250_DUART 77
2723
2724
2725 +/* Storlink Soc */
2726 +#define PORT_SL2312 72
2727 +#define PORT_IT8712 73
2728 +
2729 #ifdef __KERNEL__
2730
2731 #include <linux/compiler.h>
2732 Index: linux-2.6.23.16/drivers/char/Makefile
2733 ===================================================================
2734 --- linux-2.6.23.16.orig/drivers/char/Makefile 2008-03-15 17:59:22.566564448 +0200
2735 +++ linux-2.6.23.16/drivers/char/Makefile 2008-03-17 12:19:43.252524398 +0200
2736 @@ -70,6 +70,16 @@
2737 obj-$(CONFIG_APPLICOM) += applicom.o
2738 obj-$(CONFIG_SONYPI) += sonypi.o
2739 obj-$(CONFIG_RTC) += rtc.o
2740 +
2741 +### for Storlink SoC ###
2742 +obj-$(CONFIG_SL2312_RTC) += sl2312_rtc.o
2743 +obj-$(CONFIG_IT8712_GPIO) += it8712_gpio.o
2744 +obj-$(CONFIG_GEMINI_GPIO) += gemini_gpio.o
2745 +obj-$(CONFIG_GEMINI_PWC) += gemini_pwr.o
2746 +obj-$(CONFIG_GEMINI_CIR) += gemini_cir.o
2747 +obj-$(CONFIG_GEMINI_I2S) += gemini_i2s.o
2748 +obj-$(CONFIG_SL2312_WATCHDOG) += sl2312_wd.o
2749 +
2750 obj-$(CONFIG_HPET) += hpet.o
2751 obj-$(CONFIG_GEN_RTC) += genrtc.o
2752 obj-$(CONFIG_EFI_RTC) += efirtc.o
2753 Index: linux-2.6.23.16/drivers/serial/Kconfig
2754 ===================================================================
2755 --- linux-2.6.23.16.orig/drivers/serial/Kconfig 2008-03-15 17:59:22.566564448 +0200
2756 +++ linux-2.6.23.16/drivers/serial/Kconfig 2008-03-15 17:59:53.568330991 +0200
2757 @@ -280,6 +280,56 @@
2758
2759 comment "Non-8250 serial port support"
2760
2761 +config SERIAL_SL2312
2762 + bool "SL2312 serial port (sl2312) support"
2763 + depends on ARCH_SL2312
2764 + select SERIAL_CORE
2765 + select SERIAL_SL2312_CONSOLE
2766 + help
2767 + Say Y here if you want to use the hard logic uart on SWORD. This
2768 + driver also supports soft logic implentations of this uart core.
2769 +
2770 +config SERIAL_SL2312_CONSOLE
2771 + bool "Support for console on SL2312 serial port"
2772 + depends on SERIAL_SL2312
2773 + select SERIAL_CORE_CONSOLE
2774 + help
2775 + Say Y here if you want to support a serial console on an SWORD
2776 + hard logic uart or uart00 IP core.
2777 +
2778 + Even if you say Y here, the currently visible virtual console
2779 + (/dev/tty0) will still be used as the system console by default, but
2780 + you can alter that using a kernel command line option such as
2781 + "console=ttySL0". (Try "man bootparam" or see the documentation of
2782 + your boot loader (lilo or loadlin) about how to pass options to the
2783 + kernel at boot time.)
2784 +
2785 +
2786 +config SERIAL_IT8712
2787 + bool "Sl2312 serial port(IT8712) support"
2788 + depends on ARM && ARCH_SL2312 && SL2312_LPC
2789 + select SERIAL_CORE
2790 + select SERIAL_IT8712_CONSOLE
2791 + help
2792 + Say Y here if you want to use the hard logic uart on Excalibur. This
2793 + driver also supports soft logic implentations of this uart core.
2794 +
2795 +config SERIAL_IT8712_CONSOLE
2796 + bool "Support for console on Sword serial port(IT8712)"
2797 + depends on SERIAL_IT8712
2798 + select SERIAL_CORE_CONSOLE
2799 + help
2800 + Say Y here if you want to support a serial console on an Excalibur
2801 + hard logic uart or uart00 IP core.
2802 +
2803 + Even if you say Y here, the currently visible virtual console
2804 + (/dev/tty0) will still be used as the system console by default, but
2805 + you can alter that using a kernel command line option such as
2806 + "console=ttySI0". (Try "man bootparam" or see the documentation of
2807 + your boot loader (lilo or loadlin) about how to pass options to the
2808 + kernel at boot time.)
2809 +
2810 +
2811 config SERIAL_AMBA_PL010
2812 tristate "ARM AMBA PL010 serial port support"
2813 depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
2814 Index: linux-2.6.23.16/drivers/serial/Makefile
2815 ===================================================================
2816 --- linux-2.6.23.16.orig/drivers/serial/Makefile 2008-03-15 17:59:22.566564448 +0200
2817 +++ linux-2.6.23.16/drivers/serial/Makefile 2008-03-15 17:59:53.568330991 +0200
2818 @@ -62,5 +62,7 @@
2819 obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
2820 obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
2821 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
2822 +obj-$(CONFIG_SERIAL_IT8712) += it8712.o
2823 +obj-$(CONFIG_SERIAL_SL2312) += serial_sl2312.o
2824 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
2825 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o