1 Index: linux-2.6.23.17/drivers/serial/it8712.c
2 ===================================================================
4 +++ linux-2.6.23.17/drivers/serial/it8712.c
7 + * linux/drivers/char/serial_uart00.c
9 + * Driver for UART00 serial ports
11 + * Based on drivers/char/serial_amba.c, by ARM Limited &
12 + * Deep Blue Solutions Ltd.
13 + * Copyright 2001 Altera Corporation
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.
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.
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
29 + * $Id: it8712.c,v 1.2 2006/06/06 06:36:04 middle Exp $
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>
43 +#include <asm/uaccess.h>
44 +#include <asm/bitops.h>
45 +#include <asm/sizes.h>
47 +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
48 +#define SUPPORT_SYSRQ
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>
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
67 +#define IT8712_NO_PORTS UART_NR
68 +#define IT8712_ISR_PASS_LIMIT 256
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))
82 + * Access macros for the SL2312 UARTs
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)
104 +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
108 + //printk("it8712 stop tx : \n");
109 + reg = UART_GET_IER(port);
110 + reg &= ~(UART_IER_THRI);
111 + UART_PUT_IER(port, reg);
114 +static void it8712_stop_rx(struct uart_port *port)
118 + //printk("it8712 stop rx : \n");
119 + reg = UART_GET_IER(port);
120 + reg &= ~(UART_IER_RDI);
121 + UART_PUT_IER(port, reg);
125 +static void it8712_enable_ms(struct uart_port *port)
129 + //printk("it8712 enable ms : \n");
131 + reg = UART_GET_IER(port);
132 + reg |= (UART_IER_MSI);
133 + UART_PUT_IER(port, reg);
137 +static void it8712_rx_chars(struct uart_port *port, struct pt_regs *regs)
139 + struct tty_struct *tty = port->info->tty;
140 + unsigned int status, mask, ch, flg, ignored = 0;
142 + // printk("it8712_rx_chars : \n");
143 + status = UART_GET_LSR(port);
144 + while (UART_RX_DATA(status)) {
147 + * We need to read rds before reading the
148 + * character from the fifo
150 + ch = UART_GET_CHAR(port);
153 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
159 + * Note that the error handling code is
160 + * out of the main execution path
163 + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
165 + if (uart_handle_sysrq_char(port, ch, regs))
169 + *tty->flip.flag_buf_ptr++ = flg;
170 + *tty->flip.char_buf_ptr++ = ch;
173 + status = UART_GET_LSR(port);
176 + tty_flip_buffer_push(tty);
180 + if (status & UART_LSR_BI) {
181 + status &= ~(UART_LSR_FE);
182 + port->icount.brk++;
184 +#ifdef SUPPORT_SYSRQ
185 + if (uart_handle_break(port))
188 + } else if (status & UART_LSR_PE)
189 + port->icount.parity++;
190 + else if (status & UART_LSR_FE)
191 + port->icount.frame++;
193 + if (status & UART_LSR_OE)
194 + port->icount.overrun++;
196 + if (status & port->ignore_status_mask) {
197 + if (++ignored > 100)
202 + mask = status & port->read_status_mask;
204 + if (mask & UART_LSR_BI)
206 + else if (mask & UART_LSR_PE)
208 + else if (mask & UART_LSR_FE)
211 + if (status & UART_LSR_OE) {
213 + * CHECK: does overrun affect the current character?
214 + * ASSUMPTION: it does not.
216 + *tty->flip.flag_buf_ptr++ = flg;
217 + *tty->flip.char_buf_ptr++ = ch;
219 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
224 +#ifdef SUPPORT_SYSRQ
230 +static void it8712_tx_chars(struct uart_port *port)
232 + struct circ_buf *xmit = &port->info->xmit;
235 + if (port->x_char) {
236 + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
237 + UART_PUT_CHAR(port, port->x_char);
243 + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
244 + it8712_stop_tx(port, 0);
248 + count = port->fifosize >> 1;
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);
254 + if (uart_circ_empty(xmit))
256 + } while (--count > 0);
258 + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
259 + uart_write_wakeup(port);
261 + if (uart_circ_empty(xmit))
262 + it8712_stop_tx(port, 0);
265 +static void it8712_start_tx(struct uart_port *port, unsigned int tty_start)
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);
276 +static void it8712_modem_status(struct uart_port *port)
278 + unsigned int status;
280 +// printk("it8712 modem status : \n");
282 + status = UART_GET_MSR(port);
284 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
285 + UART_MSR_TERI | UART_MSR_DDCD)))
288 + if (status & UART_MSR_DDCD)
289 + uart_handle_dcd_change(port, status & UART_MSR_DCD);
291 + if (status & UART_MSR_DDSR)
292 + port->icount.dsr++;
294 + if (status & UART_MSR_DCTS)
295 + uart_handle_cts_change(port, status & UART_MSR_CTS);
297 + wake_up_interruptible(&port->info->delta_msr_wait);
301 +static irqreturn_t it8712_int(int irq, void *dev_id, struct pt_regs *regs)
303 + struct uart_port *port = dev_id;
304 + unsigned int status, pass_counter = 0, data;
307 + data = LPC_SERIAL_IRQ_STATUS;
308 + if((data&0x10)==0x10)
310 + status = UART_GET_INT_STATUS(port);
312 +// printk("it8712_int: status %x \n", status);
316 + case UART_IIR_RLSI:
317 + case UART_IIR_RCTO:
318 + it8712_rx_chars(port, regs);
320 + case UART_IIR_THRI:
321 + it8712_tx_chars(port);
324 + it8712_modem_status(port);
329 + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
332 + status = UART_GET_INT_STATUS(port);
337 + status |= (IRQ_LPC_MASK);
338 + *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = status;
342 + // data = LPC_SERIAL_IRQ_STATUS;
343 + LPC_SERIAL_IRQ_STATUS = data;
347 + // printf("it8712_uart_Isr clear LPC_SERIAL_IRQ_STATUS %x \n", cnt);
348 + return IRQ_HANDLED;
351 +static u_int it8712_tx_empty(struct uart_port *port)
353 +// printk("it8712 tx empty : \n");
355 + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
358 +static u_int it8712_get_mctrl(struct uart_port *port)
360 + unsigned int result = 0;
361 + unsigned int status;
363 +// printk("it8712 get mctrl : \n");
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;
378 +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
382 +static void it8712_break_ctl(struct uart_port *port, int break_state)
386 +// printk("it8712 break ctl : \n");
388 + lcr = UART_GET_LCR(port);
389 + if (break_state == -1)
390 + lcr |= UART_LCR_SBC;
392 + lcr &= ~UART_LCR_SBC;
393 + UART_PUT_LCR(port, lcr);
396 +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
400 + /* Special case: B0 rate */
404 + quot = (port->uartclk/(16 * baud)) ;
408 +static void it8712_set_termios(struct uart_port *port, struct termios *termios,
409 + struct termios *old)
411 + unsigned int uart_mc, old_ier, baud, quot;
412 + unsigned long flags;
414 + termios->c_cflag |= CREAD;
415 + termios->c_cflag |= CLOCAL;
417 + printk("it8712_set_cflag(0x%x) called\n", cflag);
419 + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
420 + quot = uart_get_divisor(port, baud);
422 + /* byte size and parity */
423 + switch (termios->c_cflag & CSIZE) {
425 + uart_mc = UART_LCR_WLEN5;
428 + uart_mc = UART_LCR_WLEN6;
431 + uart_mc = UART_LCR_WLEN7;
434 + uart_mc = UART_LCR_WLEN8;
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;
446 + spin_lock_irqsave(&port->lock, flags);
448 + * Update the per-port timeout
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;
458 + * Characters to ignore
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;
466 + * If we're ignoring parity and break indicators,
467 + * ignore overruns to (for real raw support).
469 + if (termios->c_iflag & IGNPAR)
470 + port->ignore_status_mask |= UART_LSR_OE;
473 + old_ier = UART_GET_IER(port);
475 + if(UART_ENABLE_MS(port, termios->c_cflag))
476 + old_ier |= UART_IER_MSI;
478 + /* Set baud rate */
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));
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);
490 + spin_unlock_irqrestore(&port->lock, flags);
493 +static int it8712_startup(struct uart_port *port)
498 + //printk("it8712 startup : \n");
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
507 + // regs |= (IRQ_LPC_MASK);
508 + // *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
513 + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", port);
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);
527 + LPC_SERIAL_IRQ_POLARITY = 0x10; //0x10; //0x02;
528 + LPC_SERIAL_IRQ_TRITYPE = 0x10; //0x10;//
529 + LPC_SERIAL_IRQ_ENABLE = 0x10;
531 + LPC_BUS_CTRL = 0xc0;
532 + LPC_SERIAL_IRQ_CTRL = 0xc0;
533 + for(i=0;i<1000;i++) ;
534 + LPC_SERIAL_IRQ_CTRL = 0x80;
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
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
547 +static void it8712_shutdown(struct uart_port *port)
549 + //printk("it8712 shutdown : \n");
552 + * disable all interrupts, disable the port
554 + UART_PUT_IER(port, 0x0);
556 + /* disable break condition and fifos */
557 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
560 + * Free the interrupt
562 + free_irq(port->irq, port);
565 +static const char *it8712_type(struct uart_port *port)
567 + return port->type == PORT_IT8712 ? "IT8712" : NULL;
571 + * Release the memory region(s) being used by 'port'
573 +static void it8712_release_port(struct uart_port *port)
575 +// printk("it8712 release port : \n");
577 + release_mem_region(port->mapbase, UART_PORT_SIZE);
581 + * Request the memory region(s) being used by 'port'
583 +static int it8712_request_port(struct uart_port *port)
585 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
586 + "serial_it8712") != NULL ? 0 : -EBUSY;
590 + * Configure/autoconfigure the port.
592 +static void it8712_config_port(struct uart_port *port, int flags)
595 + if (flags & UART_CONFIG_TYPE) {
596 + if (it8712_request_port(port) == 0)
597 + port->type = PORT_IT8712;
602 + * verify the new serial_struct (for TIOCSSERIAL).
604 +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
608 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
610 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
612 + if (ser->baud_base < 9600)
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,
636 +#ifdef CONFIG_ARCH_SL2312
638 +static struct uart_port it8712_ports[UART_NR] = {
640 + membase: (void *)0,
642 + iotype: SERIAL_IO_MEM,
644 + uartclk: UART_CLK/2,
647 + flags: ASYNC_BOOT_AUTOCONF,
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)
657 + unsigned int status;
660 + printk("it8712_console_read() called\n");
664 + while (c < count) {
665 + status = UART_GET_LSR(port);
666 + if (UART_RX_DATA(status)) {
667 + *s++ = UART_GET_CHAR(port);
670 + // nothing more to get, return
674 + // return the count
678 +static void it8712_console_write(struct console *co, const char *s, unsigned count)
680 +#ifdef CONFIG_ARCH_SL2312
681 + struct uart_port *port = it8712_ports + co->index;
682 + unsigned int status, old_ies;
686 + * First save the CR then disable the interrupts
688 + old_ies = UART_GET_IER(port);
692 + // printk("old_ies = %x\n",old_ies);
695 + UART_PUT_IER(port,0x0);
698 + * Now, do each character
700 + for (i = 0; i < count; i++) {
702 + status = UART_GET_LSR(port);
703 + } while (!UART_TX_READY(status));
704 + UART_PUT_CHAR(port, s[i]);
705 + if (s[i] == '\n') {
707 + status = UART_GET_LSR(port);
708 + } while (!UART_TX_READY(status));
709 + UART_PUT_CHAR(port, '\r');
714 + * Finally, wait for transmitter to become empty
715 + * and restore the IES
718 + status = UART_GET_LSR(port);
719 + } while (!(status&UART_LSR_THRE));
720 + UART_PUT_IER(port, old_ies);
724 +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
726 + //printk("it8712 console get options : \n");
728 + u_int uart_mc, quot;
729 + uart_mc= UART_GET_MCR(port);
732 + if (uart_mc & UART_LCR_PARITY) {
733 + if (uart_mc & UART_LCR_EVEN)
739 + switch (uart_mc & UART_LCR_MSK){
741 + case UART_LCR_WLEN5:
744 + case UART_LCR_WLEN6:
747 + case UART_LCR_WLEN7:
750 + case UART_LCR_WLEN8:
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));
760 +static int __init it8712_console_setup(struct console *co, char *options)
762 + struct uart_port *port;
770 + printk("it8712 console setup : \n");
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;
783 + //printk("it8712 irq is %x \n", it8712_ports[0].irq);
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;
794 +#ifdef CONFIG_ARCH_SL2312
796 + * Check whether an invalid uart number has been specified, and
797 + * if so, search for the first available port that does have
800 + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
806 + uart_parse_options(options, &baud, &parity, &bits, &flow);
808 + it8712_console_get_options(port, &baud, &parity, &bits);
810 + return uart_set_options(port, co, baud, parity, bits, flow);
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,
821 + .data = &it8712_reg,
824 +static int __init it8712_console_init(void)
826 + register_console(&it8712_console);
830 +console_initcall(it8712_console_init);
832 +#define IT8712_CONSOLE &it8712_console
834 +#define IT8712_CONSOLE NULL
837 +static struct uart_driver it8712_reg = {
839 + .driver_name = SERIAL_IT8712_NAME,
840 + .dev_name = SERIAL_IT8712_NAME,
841 + .major = SERIAL_IT8712_MAJOR,
842 + .minor = SERIAL_IT8712_MINOR,
844 + .cons = IT8712_CONSOLE,
847 +static int __init it8712_init(void)
850 + //printk("serial_it8712: it871212_init \n");
853 + result = uart_register_driver(&it8712_reg);
856 + result = uart_add_one_port(&it8712_reg, &it8712_ports[0]);
863 +__initcall(it8712_init);
864 Index: linux-2.6.23.17/drivers/serial/it8712.h
865 ===================================================================
867 +++ linux-2.6.23.17/drivers/serial/it8712.h
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
874 + * Out: Fifo custom trigger levels
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
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) */
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
897 + * These are the definitions for the FIFO Control Register
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 */
922 + * These are the definitions for the Line Control Register
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.
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
941 + * These are the definitions for the Line Status Register
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 */
953 + * These are the definitions for the Interrupt Identification Register
955 +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
956 +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
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 */
964 + * These are the definitions for the Interrupt Enable Register
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 */
971 + * Sleep mode for ST16650 and TI16750.
972 + * Note that for 16650, EFR-bit 4 must be selected as well.
974 +#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
977 + * These are the definitions for the Modem Control Register
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 */
986 + * These are the definitions for the Modem Status Register
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! */
998 +#define UART_PARITY_NONE 0x00
999 +#define UART_PARITY_ODD 0x01
1000 +#define UART_PARITY_EVEN 0x02
1004 Index: linux-2.6.23.17/drivers/serial/serial_it8712.c
1005 ===================================================================
1007 +++ linux-2.6.23.17/drivers/serial/serial_it8712.c
1010 + * linux/drivers/char/serial_uart00.c
1012 + * Driver for UART00 serial ports
1014 + * Based on drivers/char/serial_amba.c, by ARM Limited &
1015 + * Deep Blue Solutions Ltd.
1016 + * Copyright 2001 Altera Corporation
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.
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.
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
1032 + * $Id: serial_it8712.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
1035 +#include <linux/module.h>
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>
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>
1063 +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
1064 +#define SUPPORT_SYSRQ
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"
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
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
1088 +#define IT8712_NO_PORTS UART_NR
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;
1095 +#define IT8712_ISR_PASS_LIMIT 256
1098 + * Access macros for the SL2312 UARTs
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)
1120 +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
1124 +// printk("it8712 stop tx : \n");
1125 + reg = UART_GET_IER(port);
1126 + reg &= ~(UART_IER_THRI);
1127 + UART_PUT_IER(port, reg);
1130 +static void it8712_stop_rx(struct uart_port *port)
1134 +// printk("it8712 stop rx : \n");
1135 + reg = UART_GET_IER(port);
1136 + reg &= ~(UART_IER_RDI);
1137 + UART_PUT_IER(port, reg);
1141 +static void it8712_enable_ms(struct uart_port *port)
1145 +// printk("it8712 enable ms : \n");
1147 + reg = UART_GET_IER(port);
1148 + reg |= (UART_IER_MSI);
1149 + UART_PUT_IER(port, reg);
1154 +it8712_rx_chars(struct uart_info *info, struct pt_regs *regs)
1156 + struct tty_struct *tty = info->tty;
1157 + unsigned int status, mask, ch, flg, ignored = 0;
1158 + struct uart_port *port = info->port;
1160 + // printk("it8712_rx_chars : \n");
1161 + status = UART_GET_LSR(port);
1162 + while (UART_RX_DATA(status)) {
1165 + * We need to read rds before reading the
1166 + * character from the fifo
1168 + ch = UART_GET_CHAR(port);
1169 + port->icount.rx++;
1171 + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
1177 + * Note that the error handling code is
1178 + * out of the main execution path
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))
1187 + *tty->flip.flag_buf_ptr++ = flg;
1188 + *tty->flip.char_buf_ptr++ = ch;
1189 + tty->flip.count++;
1191 + status = UART_GET_LSR(port);
1194 + tty_flip_buffer_push(tty);
1198 + if (status & UART_LSR_BI) {
1199 + status &= ~(UART_LSR_FE);
1200 + port->icount.brk++;
1202 +#ifdef SUPPORT_SYSRQ
1203 + if (uart_handle_break(info, &it8712_console))
1206 + } else if (status & UART_LSR_PE)
1207 + port->icount.parity++;
1208 + else if (status & UART_LSR_FE)
1209 + port->icount.frame++;
1211 + if (status & UART_LSR_OE)
1212 + port->icount.overrun++;
1214 + if (status & port->ignore_status_mask) {
1215 + if (++ignored > 100)
1220 + mask = status & port->read_status_mask;
1222 + if (mask & UART_LSR_BI)
1224 + else if (mask & UART_LSR_PE)
1226 + else if (mask & UART_LSR_FE)
1229 + if (status & UART_LSR_OE) {
1231 + * CHECK: does overrun affect the current character?
1232 + * ASSUMPTION: it does not.
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)
1240 + flg = TTY_OVERRUN;
1242 +#ifdef SUPPORT_SYSRQ
1245 + goto error_return;
1248 +static void it8712_tx_chars(struct uart_info *info)
1251 + struct uart_port *port=info->port;
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++;
1261 + if (info->xmit.head == info->xmit.tail
1262 + || info->tty->stopped
1263 + || info->tty->hw_stopped) {
1264 + it8712_stop_tx(info->port, 0);
1268 + count = port->fifosize >> 1;
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)
1276 + } while (--count > 0);
1278 + if (CIRC_CNT(info->xmit.head,
1280 + UART_XMIT_SIZE) < WAKEUP_CHARS)
1281 + uart_event(info, EVT_WRITE_WAKEUP);
1283 + if (info->xmit.head == info->xmit.tail)
1284 + it8712_stop_tx(info->port, 0);
1287 +static void it8712_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
1290 + struct uart_info *info=(struct uart_info*)(port->iobase);
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);
1299 +static void it8712_modem_status(struct uart_info *info)
1301 + unsigned int status;
1302 + struct uart_icount *icount = &info->port->icount;
1304 +// printk("it8712 modem status : \n");
1306 + status = UART_GET_MSR(info->port);
1308 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
1309 + UART_MSR_TERI | UART_MSR_DDCD)))
1312 + if (status & UART_MSR_DCD) {
1314 +#ifdef CONFIG_HARD_PPS
1315 + if ((info->flags & ASYNC_HARDPPS_CD) &&
1316 + (status & UART_MSR_DCD_MSK))
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))) {
1325 + tty_hangup(info->tty);
1330 + if (status & UART_MSR_DDSR)
1333 + if (status & UART_MSR_DCTS) {
1336 + if (info->flags & ASYNC_CTS_FLOW) {
1337 + status &= UART_MSR_CTS;
1339 + if (info->tty->hw_stopped) {
1341 + info->tty->hw_stopped = 0;
1342 + info->ops->start_tx(info->port, 1, 0);
1343 + uart_event(info, EVT_WRITE_WAKEUP);
1347 + info->tty->hw_stopped = 1;
1348 + info->ops->stop_tx(info->port, 0);
1353 + wake_up_interruptible(&info->delta_msr_wait);
1357 +static void it8712_int(int irq, void *dev_id, struct pt_regs *regs)
1359 + struct uart_info *info = dev_id;
1360 + unsigned int status, pass_counter = 0;
1362 + status = UART_GET_INT_STATUS(info->port);
1364 +// printk("it8712_int: status %x \n", status);
1367 + case UART_IIR_RDI:
1368 + case UART_IIR_RLSI:
1369 + case UART_IIR_RCTO:
1370 + it8712_rx_chars(info, regs);
1372 + case UART_IIR_THRI:
1373 + it8712_tx_chars(info);
1375 + case UART_IIR_MSI:
1376 + it8712_modem_status(info);
1381 + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
1384 + status = UART_GET_INT_STATUS(info->port);
1388 +static u_int it8712_tx_empty(struct uart_port *port)
1390 +// printk("it8712 tx empty : \n");
1392 + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
1395 +static u_int it8712_get_mctrl(struct uart_port *port)
1397 + unsigned int result = 0;
1398 + unsigned int status;
1400 +// printk("it8712 get mctrl : \n");
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;
1415 +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
1419 +static void it8712_break_ctl(struct uart_port *port, int break_state)
1423 +// printk("it8712 break ctl : \n");
1425 + lcr = UART_GET_LCR(port);
1426 + if (break_state == -1)
1427 + lcr |= UART_LCR_SBC;
1429 + lcr &= ~UART_LCR_SBC;
1430 + UART_PUT_LCR(port, lcr);
1433 +static inline u_int uart_calculate_quot(struct uart_info *info, u_int baud)
1437 + /* Special case: B0 rate */
1441 + quot = (info->port->uartclk/(16 * baud)) ;
1445 +static void it8712_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
1447 + u_int uart_mc=0, old_ier;
1448 + unsigned long flags;
1451 + printk("it8712_set_cflag(0x%x) called\n", cflag);
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
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;
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;
1477 + * Characters to ignore
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;
1485 + * If we're ignoring parity and break indicators,
1486 + * ignore overruns to (for real raw support).
1488 + if (iflag & IGNPAR)
1489 + port->ignore_status_mask |= UART_LSR_OE;
1492 + /* first, disable everything */
1493 + save_flags(flags); cli();
1494 + old_ier = UART_GET_IER(port);
1496 + if ((port->flags & ASYNC_HARDPPS_CD) ||
1497 + (cflag & CRTSCTS) || !(cflag & CLOCAL))
1498 + old_ier |= UART_IER_MSI;
1500 + /* Set baud rate */
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));
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);
1512 + restore_flags(flags);
1515 +static int it8712_startup(struct uart_port *port, struct uart_info *info)
1518 + unsigned int regs;
1520 +// printk("it8712 startup : \n");
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
1528 + port->iobase=(u_int)info;
1531 + * Allocate the IRQ
1533 + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", info);
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);
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
1552 + UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
1557 +static void it8712_shutdown(struct uart_port *port, struct uart_info *info)
1559 +// printk("it8712 shutdown : \n");
1562 + * disable all interrupts, disable the port
1564 + UART_PUT_IER(port, 0x0);
1566 + /* disable break condition and fifos */
1567 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
1570 + * Free the interrupt
1572 + free_irq(port->irq, info);
1575 +static const char *it8712_type(struct uart_port *port)
1577 + return port->type == PORT_IT8712 ? "IT8712" : NULL;
1581 + * Release the memory region(s) being used by 'port'
1583 +static void it8712_release_port(struct uart_port *port)
1585 +// printk("it8712 release port : \n");
1587 + release_mem_region(port->mapbase, UART_PORT_SIZE);
1591 + * Request the memory region(s) being used by 'port'
1593 +static int it8712_request_port(struct uart_port *port)
1595 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
1596 + "serial_it8712") != NULL ? 0 : -EBUSY;
1600 + * Configure/autoconfigure the port.
1602 +static void it8712_config_port(struct uart_port *port, int flags)
1605 + if (flags & UART_CONFIG_TYPE) {
1606 + if (it8712_request_port(port) == 0)
1607 + port->type = PORT_IT8712;
1612 + * verify the new serial_struct (for TIOCSSERIAL).
1614 +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
1618 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
1620 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
1622 + if (ser->baud_base < 9600)
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,
1646 +#ifdef CONFIG_ARCH_SL2312
1648 +static struct uart_port it8712_ports[UART_NR] = {
1650 + membase: (void *)0,
1652 + iotype: SERIAL_IO_MEM,
1654 + uartclk: UART_CLK/2,
1656 + ops: &it8712_pops,
1657 + flags: ASYNC_BOOT_AUTOCONF,
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)
1667 + unsigned int status;
1670 + printk("it8712_console_read() called\n");
1674 + while (c < count) {
1675 + status = UART_GET_LSR(port);
1676 + if (UART_RX_DATA(status)) {
1677 + *s++ = UART_GET_CHAR(port);
1680 + // nothing more to get, return
1684 + // return the count
1688 +static void it8712_console_write(struct console *co, const char *s, unsigned count)
1690 +#ifdef CONFIG_ARCH_SL2312
1691 + struct uart_port *port = it8712_ports + co->index;
1692 + unsigned int status, old_ies;
1696 + * First save the CR then disable the interrupts
1698 + old_ies = UART_GET_IER(port);
1699 + UART_PUT_IER(port,0x0);
1702 + * Now, do each character
1704 + for (i = 0; i < count; i++) {
1706 + status = UART_GET_LSR(port);
1707 + } while (!UART_TX_READY(status));
1708 + UART_PUT_CHAR(port, s[i]);
1709 + if (s[i] == '\n') {
1711 + status = UART_GET_LSR(port);
1712 + } while (!UART_TX_READY(status));
1713 + UART_PUT_CHAR(port, '\r');
1718 + * Finally, wait for transmitter to become empty
1719 + * and restore the IES
1722 + status = UART_GET_LSR(port);
1723 + } while (!(status&UART_LSR_THRE));
1724 + UART_PUT_IER(port, old_ies);
1728 +static kdev_t it8712_console_device(struct console *co)
1730 + return MKDEV(SERIAL_IT8712_MAJOR, SERIAL_IT8712_MINOR + co->index);
1733 +static int it8712_console_wait_key(struct console *co)
1735 +#ifdef CONFIG_ARCH_SL2312
1736 + struct uart_port *port = (it8712_ports + co->index);
1737 + unsigned int status;
1740 + status = UART_GET_LSR(port);
1741 + } while (!UART_RX_DATA(status));
1742 + return UART_GET_CHAR(port);
1748 +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
1750 + printk("it8712 console get options : \n");
1752 + u_int uart_mc, quot;
1753 + uart_mc= UART_GET_MCR(port);
1756 + if (uart_mc & UART_LCR_PARITY) {
1757 + if (uart_mc & UART_LCR_EVEN)
1763 + switch (uart_mc & UART_LCR_MSK){
1765 + case UART_LCR_WLEN5:
1768 + case UART_LCR_WLEN6:
1771 + case UART_LCR_WLEN7:
1774 + case UART_LCR_WLEN8:
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));
1784 +static int __init it8712_console_setup(struct console *co, char *options)
1786 + struct uart_port *port;
1794 +// printk("it8712 console setup : \n");
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;
1807 + printk("it8712 irq is %x %x \n", it8712_ports[0].irq, irq);
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) ;
1814 +#ifdef CONFIG_ARCH_SL2312
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.
1820 + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
1826 + uart_parse_options(options, &baud, &parity, &bits, &flow);
1828 + it8712_console_get_options(port, &baud, &parity, &bits);
1830 + return uart_set_options(port, co, baud, parity, bits, flow);
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,
1839 + device: it8712_console_device,
1840 +// wait_key: it8712_console_wait_key,
1841 + setup: it8712_console_setup,
1842 + flags: (CON_PRINTBUFFER|CON_ENABLED),
1846 +void __init it8712_console_init(void)
1848 + register_console(&it8712_console);
1851 +#define IT8712_CONSOLE &it8712_console
1853 +#define IT8712_CONSOLE NULL
1856 +static struct uart_driver it8712_reg = {
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,
1869 +#ifdef CONFIG_ARCH_SL2312
1870 + port: it8712_ports,
1873 + cons: IT8712_CONSOLE,
1876 +static int __init it8712_init(void)
1878 +// printk("serial_it8712: it871212_init \n");
1880 + return uart_register_driver(&it8712_reg);
1884 +__initcall(it8712_init);
1885 Index: linux-2.6.23.17/drivers/serial/serial_sl2312.c
1886 ===================================================================
1888 +++ linux-2.6.23.17/drivers/serial/serial_sl2312.c
1891 + * linux/drivers/char/serial_uart00.c
1893 + * Driver for UART00 serial ports
1895 + * Based on drivers/char/serial_amba.c, by ARM Limited &
1896 + * Deep Blue Solutions Ltd.
1897 + * Copyright 2001 Altera Corporation
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.
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.
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
1913 + * $Id: serial_sl2312.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
1916 +#include <linux/module.h>
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>
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>
1949 +#if defined(CONFIG_SERIAL_SL2312_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
1950 +#define SUPPORT_SYSRQ
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>
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
1968 +#define SL2312_NO_PORTS UART_NR
1969 +#define SL2312_ISR_PASS_LIMIT 256
1972 + * Access macros for the SL2312 UARTs
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)
1994 +static void sl2312_stop_tx(struct uart_port *port)
1998 +// printk("sl2312 stop tx : \n");
1999 + reg = UART_GET_IER(port);
2000 + reg &= ~(UART_IER_TE);
2001 + UART_PUT_IER(port, reg);
2004 +static void sl2312_stop_rx(struct uart_port *port)
2008 +// printk("sl2312 stop rx : \n");
2009 + reg = UART_GET_IER(port);
2010 + reg &= ~(UART_IER_DR);
2011 + UART_PUT_IER(port, reg);
2015 +static void sl2312_enable_ms(struct uart_port *port)
2019 +// printk("sl2312 enable ms : \n");
2021 + reg = UART_GET_IER(port);
2022 + reg |= (UART_IER_MS);
2023 + UART_PUT_IER(port, reg);
2028 +sl2312_rx_chars(struct uart_port *port)
2030 + struct tty_struct *tty = port->info->tty;
2031 + unsigned int status, mask, ch, flg, ignored = 0;
2034 + // printk("sl2312_rx_chars : \n");
2035 + status = UART_GET_LSR(port);
2036 + while (UART_RX_DATA(status)) {
2039 + * We need to read rds before reading the
2040 + * character from the fifo
2042 + ch = UART_GET_CHAR(port);
2043 + port->icount.rx++;
2045 + //if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2046 + if (tty && !tty_buffer_request_room(tty, 1))
2052 + * Note that the error handling code is
2053 + * out of the main execution path
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))
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);
2067 + status = UART_GET_LSR(port);
2070 + tty_flip_buffer_push(tty);
2074 + if (status & UART_LSR_BI) {
2075 + status &= ~(UART_LSR_FE);
2076 + port->icount.brk++;
2078 +#ifdef SUPPORT_SYSRQ
2079 + if (uart_handle_break(port))
2082 + } else if (status & UART_LSR_PE)
2083 + port->icount.parity++;
2084 + else if (status & UART_LSR_FE)
2085 + port->icount.frame++;
2087 + if (status & UART_LSR_OE)
2088 + port->icount.overrun++;
2090 + if (status & port->ignore_status_mask) {
2091 + if (++ignored > 100)
2096 + mask = status & port->read_status_mask;
2098 + if (mask & UART_LSR_BI)
2100 + else if (mask & UART_LSR_PE)
2102 + else if (mask & UART_LSR_FE)
2105 + if (status & UART_LSR_OE) {
2107 + * CHECK: does overrun affect the current character?
2108 + * ASSUMPTION: it does not.
2110 + //*tty->flip.flag_buf_ptr++ = flg;
2111 + //*tty->flip.char_buf_ptr++ = ch;
2112 + //tty->flip.count++;
2114 + tty_insert_flip_char(tty, 0, TTY_BREAK);
2116 + // if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2117 + if (tty_buffer_request_room(tty, 1))
2120 + flg = TTY_OVERRUN;
2122 +#ifdef SUPPORT_SYSRQ
2125 + goto error_return;
2128 +static void sl2312_tx_chars(struct uart_port *port)
2130 + struct circ_buf *xmit = &port->info->xmit;
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++;
2142 + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
2143 + sl2312_stop_tx(port);
2148 + count = port->fifosize >> 1;
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))
2156 + } while (--count > 0);
2158 + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
2159 + uart_write_wakeup(port);
2161 + if (uart_circ_empty(xmit))
2162 + sl2312_stop_tx(port);
2166 +static void sl2312_start_tx(struct uart_port *port)
2170 +// printk("sl2312 start tx : \n");
2171 + reg = UART_GET_IER(port);
2172 + reg |= (UART_IER_TE);
2173 + UART_PUT_IER(port, reg);
2175 + sl2312_tx_chars(port);
2178 +static void sl2312_modem_status(struct uart_port *port)
2180 + unsigned int status;
2182 +// printk("it8712 modem status : \n");
2184 + status = UART_GET_MSR(port);
2186 + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
2187 + UART_MSR_TERI | UART_MSR_DDCD)))
2190 + if (status & UART_MSR_DDCD)
2191 + uart_handle_dcd_change(port, status & UART_MSR_DCD);
2193 + if (status & UART_MSR_DDSR)
2194 + port->icount.dsr++;
2196 + if (status & UART_MSR_DCTS)
2197 + uart_handle_cts_change(port, status & UART_MSR_CTS);
2199 + wake_up_interruptible(&port->info->delta_msr_wait);
2203 +static irqreturn_t sl2312_int(int irq, void *dev_id)
2205 + struct uart_port *port = dev_id;
2206 + unsigned int status, pass_counter = 0;
2208 + status = UART_GET_INT_STATUS(port);
2213 + case UART_IIR_RLS:
2214 + sl2312_rx_chars(port);
2217 + sl2312_tx_chars(port);
2219 + case UART_IIR_MODEM:
2220 + sl2312_modem_status(port);
2225 + if (pass_counter++ > SL2312_ISR_PASS_LIMIT)
2228 + status = UART_GET_INT_STATUS(port);
2231 + return IRQ_HANDLED;
2234 +static u_int sl2312_tx_empty(struct uart_port *port)
2236 +// printk("sl2312 tx empty : \n");
2238 + return ((UART_GET_LSR(port) & UART_LSR_TE)? TIOCSER_TEMT : 0);
2241 +static u_int sl2312_get_mctrl(struct uart_port *port)
2243 + unsigned int result = 0;
2244 + unsigned int status;
2246 +// printk("sl2312 get mctrl : \n");
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;
2261 +static void sl2312_set_mctrl_null(struct uart_port *port, u_int mctrl)
2265 +static void sl2312_break_ctl(struct uart_port *port, int break_state)
2269 +// printk("sl2312 break ctl : \n");
2271 + lcr = UART_GET_LCR(port);
2272 + if (break_state == -1)
2273 + lcr |= UART_LCR_SETBREAK;
2275 + lcr &= ~UART_LCR_SETBREAK;
2276 + UART_PUT_LCR(port, lcr);
2279 +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
2283 + /* Special case: B0 rate */
2287 + quot = (port->uartclk / (16 * baud)-1) ;
2292 +static void sl2312_set_termios(struct uart_port *port, struct ktermios *termios,
2293 + struct ktermios *old)
2295 + unsigned int uart_mc, old_ier, baud, quot;
2296 + unsigned long flags;
2298 + termios->c_cflag |= CREAD;
2300 + printk("it8712_set_cflag(0x%x) called\n", cflag);
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);
2306 + /* byte size and parity */
2307 + switch (termios->c_cflag & CSIZE) {
2309 + uart_mc = UART_LCR_LEN5;
2312 + uart_mc = UART_LCR_LEN6;
2315 + uart_mc = UART_LCR_LEN7;
2318 + uart_mc = UART_LCR_LEN8;
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;
2330 + spin_lock_irqsave(&port->lock, flags);
2332 + * Update the per-port timeout
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;
2342 + * Characters to ignore
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;
2350 + * If we're ignoring parity and break indicators,
2351 + * ignore overruns to (for real raw support).
2353 + if (termios->c_iflag & IGNPAR)
2354 + port->ignore_status_mask |= UART_LSR_OE;
2357 + //save_flags(flags); cli();
2358 + old_ier = UART_GET_IER(port);
2360 + if(UART_ENABLE_MS(port, termios->c_cflag))
2361 + old_ier |= UART_IER_MS;
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));
2368 + UART_PUT_LCR(port, uart_mc);
2369 + UART_PUT_IER(port, old_ier);
2371 + //restore_flags(flags);
2372 + spin_unlock_irqrestore(&port->lock, flags);
2377 +static int sl2312_startup(struct uart_port *port)
2380 + unsigned int regs;
2382 +// printk("sl2312 startup : \n");
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
2391 + * Allocate the IRQ
2393 + retval = request_irq(port->irq, sl2312_int, IRQF_DISABLED, "sl2312", port);
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);
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
2412 + UART_PUT_IER(port, (UART_IER_DR|UART_IER_TE));
2417 +static void sl2312_shutdown(struct uart_port *port)
2419 +// printk("sl2312 shutdown : \n");
2422 + * disable all interrupts, disable the port
2424 + UART_PUT_IER(port, 0x0);
2426 + /* disable break condition and fifos */
2427 +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
2430 + * Free the interrupt
2432 + free_irq(port->irq, port);
2435 +static const char *sl2312_type(struct uart_port *port)
2437 + return port->type == PORT_SL2312 ? "SL2312" : NULL;
2441 + * Release the memory region(s) being used by 'port'
2443 +static void sl2312_release_port(struct uart_port *port)
2445 +// printk("sl2312 release port : \n");
2447 + release_mem_region(port->mapbase, UART_PORT_SIZE);
2451 + * Request the memory region(s) being used by 'port'
2453 +static int sl2312_request_port(struct uart_port *port)
2455 + return request_mem_region(port->mapbase, UART_PORT_SIZE,
2456 + "serial_sl2312") != NULL ? 0 : -EBUSY;
2460 + * Configure/autoconfigure the port.
2462 +static void sl2312_config_port(struct uart_port *port, int flags)
2465 + if (flags & UART_CONFIG_TYPE) {
2466 + if (sl2312_request_port(port) == 0)
2467 + port->type = PORT_SL2312;
2472 + * verify the new serial_struct (for TIOCSSERIAL).
2474 +static int sl2312_verify_port(struct uart_port *port, struct serial_struct *ser)
2478 + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
2480 + if (ser->irq < 0 || ser->irq >= NR_IRQS)
2482 + if (ser->baud_base < 9600)
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,
2506 +#ifdef CONFIG_ARCH_SL2312
2508 +static struct uart_port sl2312_ports[UART_NR] = {
2510 + membase: (void *)IO_ADDRESS(SL2312_UART_BASE),
2511 + mapbase: SL2312_UART_BASE,
2512 + iotype: SERIAL_IO_MEM,
2514 + uartclk: UART_CLK,
2516 + ops: &sl2312_pops,
2517 + flags: ASYNC_BOOT_AUTOCONF,
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)
2527 + unsigned int status;
2530 + printk("sl2312_console_read() called\n");
2534 + while (c < count) {
2535 + status = UART_GET_LSR(port);
2536 + if (UART_RX_DATA(status)) {
2537 + *s++ = UART_GET_CHAR(port);
2540 + // nothing more to get, return
2544 + // return the count
2548 +static void sl2312_console_write(struct console *co, const char *s, unsigned count)
2550 +#ifdef CONFIG_ARCH_SL2312
2551 + struct uart_port *port = sl2312_ports + co->index;
2552 + unsigned int status, old_ies;
2556 + * First save the CR then disable the interrupts
2558 + old_ies = UART_GET_IER(port);
2559 + UART_PUT_IER(port,0x0);
2562 + * Now, do each character
2564 + for (i = 0; i < count; i++) {
2566 + status = UART_GET_LSR(port);
2567 + } while (!UART_TX_READY(status));
2568 + UART_PUT_CHAR(port, s[i]);
2569 + if (s[i] == '\n') {
2571 + status = UART_GET_LSR(port);
2572 + } while (!UART_TX_READY(status));
2573 + UART_PUT_CHAR(port, '\r');
2578 + * Finally, wait for transmitter to become empty
2579 + * and restore the IES
2582 + status = UART_GET_LSR(port);
2583 + } while (!(status&UART_LSR_TE));
2584 + UART_PUT_IER(port, old_ies);
2589 +static void sl2312_console_device(struct console *co,int *index)
2592 + struct uart_driver *p = co->data;
2593 + *index = co->index;
2594 + return p->tty_driver;
2599 +static void /*__init*/ sl2312_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
2601 +// printk("sl2312 console get options : \n");
2603 + u_int uart_mc, quot;
2604 + uart_mc= UART_GET_MCR(port);
2607 + if (uart_mc & UART_LCR_PE) {
2608 + if (uart_mc & UART_LCR_EVEN)
2614 + switch (uart_mc & UART_LCR_MSK){
2616 + case UART_LCR_LEN5:
2619 + case UART_LCR_LEN6:
2622 + case UART_LCR_LEN7:
2625 + case UART_LCR_LEN8:
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 );
2635 +static int __init sl2312_console_setup(struct console *co, char *options)
2637 + struct uart_port *port;
2643 + printk("sl2312 console setup : \n");
2645 +#ifdef CONFIG_ARCH_SL2312
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.
2651 + port = uart_get_console(sl2312_ports,SL2312_NO_PORTS,co);
2657 + uart_parse_options(options, &baud, &parity, &bits, &flow);
2659 + sl2312_console_get_options(port, &baud, &parity, &bits);
2661 + return uart_set_options(port, co, baud, parity, bits, flow);
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,
2674 + .data = &sl2312_reg,
2677 +static int __init sl2312_console_init(void)
2679 + register_console(&sl2312_console);
2684 +console_initcall(sl2312_console_init);
2686 +#define SL2312_CONSOLE &sl2312_console
2688 +#define SL2312_CONSOLE NULL
2692 +struct uart_driver sl2312_reg = {
2694 + .driver_name = SERIAL_SL2312_NAME,
2695 + .dev_name = SERIAL_SL2312_NAME,
2696 + .major = SERIAL_SL2312_MAJOR,
2697 + .minor = SERIAL_SL2312_MINOR,
2699 + .cons = SL2312_CONSOLE,
2702 +static int __init sl2312_init(void)
2705 + //printk("serial_it8712: it871212_init \n");
2707 + result = uart_register_driver(&sl2312_reg);
2710 + result = uart_add_one_port(&sl2312_reg, &sl2312_ports[0]);
2716 +__initcall(sl2312_init);
2717 Index: linux-2.6.23.17/include/linux/serial_core.h
2718 ===================================================================
2719 --- linux-2.6.23.17.orig/include/linux/serial_core.h
2720 +++ linux-2.6.23.17/include/linux/serial_core.h
2721 @@ -147,6 +147,10 @@
2722 #define PORT_SB1250_DUART 77
2726 +#define PORT_SL2312 72
2727 +#define PORT_IT8712 73
2731 #include <linux/compiler.h>
2732 Index: linux-2.6.23.17/drivers/char/Makefile
2733 ===================================================================
2734 --- linux-2.6.23.17.orig/drivers/char/Makefile
2735 +++ linux-2.6.23.17/drivers/char/Makefile
2736 @@ -70,6 +70,16 @@ obj-$(CONFIG_R3964) += n_r3964.o
2737 obj-$(CONFIG_APPLICOM) += applicom.o
2738 obj-$(CONFIG_SONYPI) += sonypi.o
2739 obj-$(CONFIG_RTC) += rtc.o
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
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.17/drivers/serial/Kconfig
2754 ===================================================================
2755 --- linux-2.6.23.17.orig/drivers/serial/Kconfig
2756 +++ linux-2.6.23.17/drivers/serial/Kconfig
2757 @@ -280,6 +280,56 @@ config SERIAL_8250_RM9K
2759 comment "Non-8250 serial port support"
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
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.
2770 +config SERIAL_SL2312_CONSOLE
2771 + bool "Support for console on SL2312 serial port"
2772 + depends on SERIAL_SL2312
2773 + select SERIAL_CORE_CONSOLE
2775 + Say Y here if you want to support a serial console on an SWORD
2776 + hard logic uart or uart00 IP core.
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.)
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
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.
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
2800 + Say Y here if you want to support a serial console on an Excalibur
2801 + hard logic uart or uart00 IP core.
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.)
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.17/drivers/serial/Makefile
2815 ===================================================================
2816 --- linux-2.6.23.17.orig/drivers/serial/Makefile
2817 +++ linux-2.6.23.17/drivers/serial/Makefile
2818 @@ -62,5 +62,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_se
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