static irqreturn_t sci_er_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; /* Handle errors */ if (port->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ sci_in(port, SCxSR); sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } else { #if defined(SCIF_ORER) if((sci_in(port, SCLSR) & SCIF_ORER) != 0) { struct tty_struct *tty = port->info->port.tty; sci_out(port, SCLSR, 0); tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_flip_buffer_push(tty); pr_debug("scif: overrun error\n"); } #endif sci_rx_interrupt(irq, ptr); } sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr); return IRQ_HANDLED; }
static inline int sci_handle_breaks(struct uart_port *port) { int copied = 0; unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->info->tty; struct sci_port *s = &sci_ports[port->line]; if (!s->break_flag && status & SCxSR_BRK(port)) { #if defined(CONFIG_CPU_SH3) /* Debounce break */ s->break_flag = 1; #endif /* Notify of BREAK */ if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; pr_debug("sci: BREAK detected\n"); } #if defined(SCIF_ORER) /* XXX: Handle SCIF overrun error */ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { sci_out(port, SCLSR, 0); if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { copied++; pr_debug("sci: overrun error\n"); } } #endif if (copied) tty_flip_buffer_push(tty); return copied; }
static int scif_rxfill(struct uart_port *port) { if (port->type == PORT_SCIFA) return sci_in(port, SCFDR) & SCIF_RFDC_MASK; else return sci_in(port, SCRFDR); }
static inline int scif_rxroom(struct uart_port *port) { if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ return sci_in(port, SCRFDR) & 0xff; else /* SCIF2 */ return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; }
void handle_error(void) { sci_in(&sh_sci, SCxSR); sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci)); sci_in(&sh_sci, SCLSR); sci_out(&sh_sci, SCLSR, 0x00); }
static void sci_transmit_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; unsigned int stopped = uart_tx_stopped(port); unsigned long flags; unsigned short status; unsigned short ctrl; int count, txroom; status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { local_irq_save(flags); ctrl = sci_in(port, SCSCR); if (uart_circ_empty(xmit)) { ctrl &= ~SCI_CTRL_FLAGS_TIE; } else { ctrl |= SCI_CTRL_FLAGS_TIE; } sci_out(port, SCSCR, ctrl); local_irq_restore(flags); return; } #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) { txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8); } else {
static void sci_setsignals(struct sci_port *port, int dtr, int rts) { /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ /* If you have signals for DTR and DCD, please implement here. */ #if defined(CONFIG_SH_SECUREEDGE5410) int flags; save_and_cli(flags); if (port == &sci_ports[1]) { /* port 1 only */ if (dtr == 0) SECUREEDGE_WRITE_IOPORT(0x0080, 0x0080); else if (dtr == 1) SECUREEDGE_WRITE_IOPORT(0x0000, 0x0080); if ((sci_in(port, SCFCR) & SCFCR_MCE) == 0) { if (rts) sci_out(port, SCSPTR, sci_in(port, SCSPTR) & ~0x40); else sci_out(port, SCSPTR, sci_in(port, SCSPTR) | 0x40); } } if (port == &sci_ports[0]) { /* port 0 only */ if (dtr == 0) SECUREEDGE_WRITE_IOPORT(0x0200, 0x0200); else if (dtr == 1) SECUREEDGE_WRITE_IOPORT(0x0000, 0x0200); if (rts == 0) SECUREEDGE_WRITE_IOPORT(0x0100, 0x0100); else if (rts == 1) SECUREEDGE_WRITE_IOPORT(0x0000, 0x0100); } restore_flags(flags); #endif }
static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; unsigned long flags; int t; baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); switch (baud) { case 0: t = -1; break; default: { #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) struct clk *clk = clk_get(NULL, "module_clk"); t = SCBRR_VALUE(baud, clk_get_rate(clk)); clk_put(clk); #else t = SCBRR_VALUE(baud); #endif } break; } spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); } while (!(status & SCxSR_TEND(port))); sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); #endif smr_val = sci_in(port, SCSMR) & 3; if ((termios->c_cflag & CSIZE) == CS7) smr_val |= 0x40; if (termios->c_cflag & PARENB) smr_val |= 0x20; if (termios->c_cflag & PARODD) smr_val |= 0x30; if (termios->c_cflag & CSTOPB) smr_val |= 0x08; uart_update_timeout(port, termios->c_cflag, baud); sci_out(port, SCSMR, smr_val); if (t > 0) { if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; } else {
/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void change_speed(struct sci_struct *sci) { unsigned cflag; unsigned int status; unsigned int smr_val; unsigned int ddr; unsigned int i,t; if (!sci->info->tty || !sci->info->tty->termios) return; cflag = sci->info->tty->termios->c_cflag; do status = sci_in(sci, SCI_SSR); while (!(status & SCI_SSR_TEND)); sci_out(sci, SCI_SCR, 0x00); /* TE=0, RE=0, CKE1=0 */ smr_val = sci_in(sci, SCI_SMR) & 3; if ((cflag & CSIZE) == CS7) smr_val |= 0x40; if (cflag & PARENB) smr_val |= 0x20; if (cflag & PARODD) smr_val |= 0x10; if (cflag & CSTOPB) smr_val |= 0x08; t=0; cflag = sci->info->tty->termios->c_cflag; i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 2) sci->info->tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } if (i == 15) { if ((sci->info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) i += 1; if ((sci->info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) i += 2; if ((sci->info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) t = sci->info->custom_divisor; } if (t==0) t=sci_baud_table[i]; if (t > 0) { if(t >= 256) { smr_val = (t >> 8) & 3; } sci_out(sci, SCI_BRR, t & 0xff); udelay(32*(1 << (t*2))*(t & 0xff)*CONFIG_CLK_FREQ); /* Wait one bit interval */ }
static int scif_rxfill(struct uart_port *port) { if ((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) { /* SCIF0/1*/ return sci_in(port, SCRFDR) & 0xff; } else { /* SCIF2 */ return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; } }
void serial_raw_putc(const char c) { while (1) { /* Tx fifo is empty */ if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci)) break; } sci_out(&sh_sci, SCxTDR, c); sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); }
/* Write a char */ static void kgdb_put_char(struct sci_port *port, char c) { unsigned short status; do status = sci_in(port, SCxSR); while (!(status & SCxSR_TDxE(port))); sci_out(port, SCxTDR, c); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); }
int serial_getc_check(void) { unsigned short status; status = sci_in(&sh_sci, SCxSR); if (status & SCIF_ERRORS) handle_error(); if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) handle_error(); return status & (SCIF_DR | SCxSR_RDxF(&sh_sci)); }
/* Get a char if there is one, else ret -1 */ static int kgdb_get_char(struct sci_port *port) { int c; if (kgdb_is_char_ready(port) == 0) c = -1; else { c = sci_in(port, SCxRDR); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } return c; }
static void scif_sercon_putc(int c) { while (((sci_in(&scif_port, SCFDR) & EPK_FIFO_BITS) >= EPK_FIFO_SIZE)) ; sci_in(&scif_port, SCxSR); sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40)); sci_out(&scif_port, SCxTDR, c); while ((sci_in(&scif_port, SCxSR) & 0x40) == 0) ; if (c == '\n') scif_sercon_putc('\r'); }
static inline int scif_txroom(struct uart_port *port) { if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); else /* SCIF2 */ return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); }
static _INLINE_ void transmit_chars(struct sci_struct *sci) { if (sci->info->x_char) { sci_outp(sci, SCI_TDR, sci->info->x_char); sci->info->x_char = 0; return; } if ((sci->info->xmit_cnt <= 0) || sci->info->tty->stopped) { sci_ctrl_reset(sci, SCI_SCR_TIE); return; } sci_outp(sci, SCI_TDR, sci->info->xmit_buf[sci->info->xmit_tail++]); sci->info->xmit_tail = sci->info->xmit_tail & (SERIAL_XMIT_SIZE-1); sci_outp(sci,SCI_SSR,sci_in(sci,SCI_SSR) & ~SCI_SSR_TDRE); sci->info->xmit_cnt--; if (sci->info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(sci, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif if (sci->info->xmit_cnt <= 0) { sci_ctrl_reset(sci, SCI_SCR_TIE); } }
static void put_char(struct uart_port *port, char c) { unsigned long flags; unsigned short status; spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); sci_out(port, SCxTDR, c); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); spin_unlock_irqrestore(&port->lock, flags); }
static void put_char(struct sci_port *port, char c) { unsigned long flags; unsigned short status; save_and_cli(flags); do status = sci_in(port, SCxSR); while (!(status & SCxSR_TDxE(port))); sci_out(port, SCxTDR, c); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); restore_flags(flags); }
/* Is the SCI ready, ie is there a char waiting? */ static int kgdb_is_char_ready(struct sci_port *port) { unsigned short status = sci_in(port, SCxSR); if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port))) kgdb_handle_error(port); return (status & SCxSR_RDxF(port)); }
static void sci_stop_rx(struct uart_port *port) { unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); sci_out(port, SCSCR, ctrl); }
static void sci_start_rx(struct uart_port *port, unsigned int tty_start) { unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; sci_out(port, SCSCR, ctrl); }
static void sci_stop_tx(struct uart_port *port) { unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); }
static int sh_serial_getc(void) { unsigned short status; char ch; while (!serial_getc_check()) ; ch = sci_in(&sh_sci, SCxRDR); status = sci_in(&sh_sci, SCxSR); sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci)); if (status & SCIF_ERRORS) handle_error(); if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) handle_error(); return ch; }
static int sci_getsignals(struct sci_port *port) { /* This routine is used for geting signals of: DTR, DCD, DSR, RI, and CTS/RTS */ #if defined(CONFIG_SH_SECUREEDGE5410) if (port == &sci_ports[1]) { /* port 1 only */ unsigned short s = SECUREEDGE_READ_IOPORT(); int rc = TIOCM_RTS|TIOCM_DSR|TIOCM_CTS; if ((sci_in(port, SCFCR) & SCFCR_MCE) == 0) { if (sci_in(port, SCSPTR) & 0x0040) rc &= ~TIOCM_RTS; if (sci_in(port, SCSPTR) & 0x0010) rc &= ~TIOCM_CTS; } if ((s & 0x0001) == 0) rc |= TIOCM_CAR; if ((SECUREEDGE_READ_IOPORT() & 0x0080) == 0) rc |= TIOCM_DTR; return(rc); } if (port == &sci_ports[0]) { /* port 0 only */ unsigned short s = SECUREEDGE_READ_IOPORT(); int rc = TIOCM_DSR; if ((s & 0x0010) == 0) rc |= TIOCM_CAR; if ((s & 0x0004) == 0) rc |= TIOCM_CTS; if ((SECUREEDGE_READ_IOPORT() & 0x0200) == 0) rc |= TIOCM_DTR; if ((SECUREEDGE_READ_IOPORT() & 0x0100) == 0) rc |= TIOCM_RTS; return(rc); } #endif return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR; }
static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; int t = -1; baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); if (likely(baud)) t = SCBRR_VALUE(baud, port->uartclk); do { status = sci_in(port, SCxSR); } while (!(status & SCxSR_TEND(port))); sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); #endif smr_val = sci_in(port, SCSMR) & 3; if ((termios->c_cflag & CSIZE) == CS7) smr_val |= 0x40; if (termios->c_cflag & PARENB) smr_val |= 0x20; if (termios->c_cflag & PARODD) smr_val |= 0x30; if (termios->c_cflag & CSTOPB) smr_val |= 0x08; uart_update_timeout(port, termios->c_cflag, baud); sci_out(port, SCSMR, smr_val); if (t > 0) { if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; } else {
static int get_char(struct uart_port *port) { unsigned long flags; unsigned short status; int c; spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { handle_error(port); continue; } } while (!(status & SCxSR_RDxF(port))); c = sci_in(port, SCxRDR); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); spin_unlock_irqrestore(&port->lock, flags); return c; }
static int get_char(struct sci_port *port) { unsigned long flags; unsigned short status; int c; save_and_cli(flags); do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { handle_error(port); continue; } } while (!(status & SCxSR_RDxF(port))); c = sci_in(port, SCxRDR); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); restore_flags(flags); return c; }
static int sh_serial_init(void) { sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); sci_out(&sh_sci, SCSMR, 0); sci_out(&sh_sci, SCSMR, 0); sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST); sci_in(&sh_sci, SCFCR); sci_out(&sh_sci, SCFCR, 0); serial_setbrg(); return 0; }
/* Breakpoint if there's a break sent on the serial port */ static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct sci_port *port = ptr; unsigned short status = sci_in(port, SCxSR); if (status & SCxSR_BRK(port)) { /* Break into the debugger if a break is detected */ BREAKPOINT(); /* Clear */ sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); } }