/* * Control the transmission of a break signal */ static void atmel_break_ctl(struct uart_port *port, int break_state) { if (break_state != 0) UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ else UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ }
static int __init at91_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */ port = uart_get_console(at91_ports, AT91_NR_UART, co); /* * Enable the serial console, in-case bootloader did not do it. */ at91_sys_write(AT91_PMC_PCER, 1 << port->irq); /* enable clock */ UART_PUT_IDR(port, -1); /* disable interrupts */ UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else at91_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow); }
/* * Set state of the modem control output lines */ static void at91_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; /* * Errata #39: RTS0 is not internally connected to PA21. We need to drive * the pin manually. */ if (port->mapbase == AT91_VA_BASE_US0) { if (mctrl & TIOCM_RTS) at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0); else at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0); } if (mctrl & TIOCM_RTS) control |= AT91_US_RTSEN; else control |= AT91_US_RTSDIS; if (mctrl & TIOCM_DTR) control |= AT91_US_DTREN; else control |= AT91_US_DTRDIS; UART_PUT_CR(port,control); }
static int pl010_startup(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; /* * Allocate the IRQ */ retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port); if (retval) return retval; /* * initialise the old status of the modem signals */ uap->old_status = UART_GET_FR(port) & UART01x_FR_MODEM_ANY; /* * Finally, enable interrupts */ UART_PUT_CR(port, UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE); return 0; }
/* * Interrupt handler */ static irqreturn_t atmel_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; unsigned int status, pending, pass_counter = 0; status = UART_GET_CSR(port); pending = status & UART_GET_IMR(port); while (pending) { /* PDC receive */ if (pending & ATMEL_US_ENDRX) atmel_pdc_endrx(port); if (pending & ATMEL_US_TIMEOUT) atmel_pdc_timeout(port); if (atmel_port->use_dma_rx && pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | ATMEL_US_FRAME | ATMEL_US_PARE)) atmel_pdc_rxerr(port, pending); /* Interrupt receive */ if (pending & ATMEL_US_RXRDY) atmel_rx_chars(port); else if (pending & ATMEL_US_RXBRK) { /* * End of break detected. If it came along * with a character, atmel_rx_chars will * handle it. */ UART_PUT_CR(port, ATMEL_US_RSTSTA); UART_PUT_IDR(port, ATMEL_US_RXBRK); atmel_port->break_active = 0; } // TODO: All reads to CSR will clear these interrupts! if (pending & ATMEL_US_RIIC) port->icount.rng++; if (pending & ATMEL_US_DSRIC) port->icount.dsr++; if (pending & ATMEL_US_DCDIC) uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); if (pending & ATMEL_US_CTSIC) uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) wake_up_interruptible(&port->info->delta_msr_wait); /* PDC transmit */ if (pending & ATMEL_US_ENDTX) atmel_pdc_endtx(port); if (pending & ATMEL_US_TXBUFE) atmel_pdc_txbufe(port); /* Interrupt transmit */ if (pending & ATMEL_US_TXRDY) atmel_tx_chars(port); if (pass_counter++ > ATMEL_ISR_PASS_LIMIT) break; status = UART_GET_CSR(port); pending = status & UART_GET_IMR(port); } return IRQ_HANDLED; }
static void ambauart_enable_ms(struct uart_port *port) { unsigned int cr; cr = UART_GET_CR(port); cr |= AMBA_UARTCR_MSIE; UART_PUT_CR(port, cr); }
static void ambauart_stop_rx(struct uart_port *port) { unsigned int cr; cr = UART_GET_CR(port); cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); UART_PUT_CR(port, cr); }
static void ambauart_stop_tx(struct uart_port *port, u_int from_tty) { unsigned int cr; cr = UART_GET_CR(port); cr &= ~AMBA_UARTCR_TIE; UART_PUT_CR(port, cr); }
static void pl010_start_tx(struct uart_port *port) { unsigned int cr; cr = UART_GET_CR(port); cr |= UART010_CR_TIE; UART_PUT_CR(port, cr); }
static void pl010_stop_rx(struct uart_port *port) { unsigned int cr; cr = UART_GET_CR(port); cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); UART_PUT_CR(port, cr); }
static void pl010_enable_ms(struct uart_port *port) { unsigned int cr; cr = UART_GET_CR(port); cr |= UART010_CR_MSIE; UART_PUT_CR(port, cr); }
static void pl010_stop_tx(struct uart_port *port, unsigned int tty_stop) { unsigned int cr; cr = UART_GET_CR(port); cr &= ~UART010_CR_TIE; UART_PUT_CR(port, cr); }
static void ambauart_start_tx(struct uart_port *port, unsigned int tty_start) { unsigned int cr; cr = UART_GET_CR(port); cr |= AMBA_UARTCR_TIE; UART_PUT_CR(port, cr); }
static void ambauart_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty) { if (nonempty) { unsigned int cr; cr = UART_GET_CR(port); cr |= AMBA_UARTCR_TIE; UART_PUT_CR(port, cr); } }
/* * Perform initialization and enable port for reception */ static int atmel_startup(struct uart_port *port) { struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; int retval; /* * Ensure that no interrupts are enabled otherwise when * request_irq() is called we could get stuck trying to * handle an unexpected interrupt */ UART_PUT_IDR(port, -1); /* * Allocate the IRQ */ retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port); if (retval) { printk("atmel_serial: atmel_startup - Can't get irq\n"); return retval; } /* * If there is a specific "open" function (to register * control line interrupts) */ if (atmel_open_hook) { retval = atmel_open_hook(port); if (retval) { free_irq(port->irq, port); return retval; } } /* * Finally, enable the serial port */ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */ UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */ return 0; }
/* * Characters received (called from interrupt handler) */ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; status = UART_GET_CSR(port) & port->read_status_mask; while (status & (AT91_US_RXRDY)) { ch = UART_GET_CHAR(port); port->icount.rx++; flg = TTY_NORMAL; /* * note that the error handling code is * out of the main execution path */ if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE))) { UART_PUT_CR(port, AT91_US_RSTSTA); /* clear error */ if (status & (AT91_US_PARE)) port->icount.parity++; if (status & (AT91_US_FRAME)) port->icount.frame++; if (status & (AT91_US_OVRE)) port->icount.overrun++; if (status & AT91_US_PARE) flg = TTY_PARITY; else if (status & AT91_US_FRAME) flg = TTY_FRAME; if (status & AT91_US_OVRE) { /* * overrun does *not* affect the character * we read from the FIFO */ tty_insert_flip_char(tty, ch, flg); ch = 0; flg = TTY_OVERRUN; } #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; tty_insert_flip_char(tty, ch, flg); ignore_char: status = UART_GET_CSR(port) & port->read_status_mask; } tty_flip_buffer_push(tty); }
/* * Perform initialization and enable port for reception */ static int at91_startup(struct uart_port *port) { int retval; /* * Ensure that no interrupts are enabled otherwise when * request_irq() is called we could get stuck trying to * handle an unexpected interrupt */ UART_PUT_IDR(port, -1); /* * Allocate the IRQ */ retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", port); if (retval) { printk("at91_serial: at91_startup - Can't get irq\n"); return retval; } /* * If there is a specific "open" function (to register * control line interrupts) */ if (at91_open) { retval = at91_open(port); if (retval) { free_irq(port->irq, port); return retval; } } port->read_status_mask = AT91_US_RXRDY | AT91_US_TXRDY | AT91_US_OVRE | AT91_US_FRAME | AT91_US_PARE | AT91_US_RXBRK; /* * Finally, enable the serial port */ UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); /* enable xmit & rcvr */ UART_PUT_IER(port, AT91_US_RXRDY); /* do receive only */ return 0; }
/* * Characters received (called from interrupt handler) */ static void atmel_rx_chars(struct uart_port *port) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; status = UART_GET_CSR(port); while (status & ATMEL_US_RXRDY) { ch = UART_GET_CHAR(port); port->icount.rx++; flg = TTY_NORMAL; /* * note that the error handling code is * out of the main execution path */ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ if (status & ATMEL_US_RXBRK) { status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } if (status & ATMEL_US_PARE) port->icount.parity++; if (status & ATMEL_US_FRAME) port->icount.frame++; if (status & ATMEL_US_OVRE) port->icount.overrun++; status &= port->read_status_mask; if (status & ATMEL_US_RXBRK) flg = TTY_BREAK; else if (status & ATMEL_US_PARE) flg = TTY_PARITY; else if (status & ATMEL_US_FRAME) flg = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); ignore_char: status = UART_GET_CSR(port); } tty_flip_buffer_push(tty); }
static int __init atmel_console_setup(struct console *co, char *options) { struct uart_port *port = &atmel_ports[co->index].uart; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; if (port->membase == 0) /* Port not initialized yet - delay setup */ return -ENODEV; UART_PUT_IDR(port, -1); /* disable interrupts */ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else atmel_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow); }
static void pl010_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = &amba_ports[co->index].port; unsigned int status, old_cr; int i; /* * First save the CR then disable the interrupts */ old_cr = UART_GET_CR(port); UART_PUT_CR(port, UART01x_CR_UARTEN); /* * Now, do each character */ for (i = 0; i < count; i++) { do { status = UART_GET_FR(port); } while (!UART_TX_READY(status)); UART_PUT_CHAR(port, s[i]); if (s[i] == '\n') { do { status = UART_GET_FR(port); } while (!UART_TX_READY(status)); UART_PUT_CHAR(port, '\r'); } } /* * Finally, wait for transmitter to become empty * and restore the TCR */ do { status = UART_GET_FR(port); } while (status & UART01x_FR_BUSY); UART_PUT_CR(port, old_cr); }
static void pl010_shutdown(struct uart_port *port) { /* * Free the interrupt */ free_irq(port->irq, port); /* * disable all interrupts, disable the port */ UART_PUT_CR(port, 0); /* disable break condition and fifos */ UART_PUT_LCRH(port, UART_GET_LCRH(port) & ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN)); }
/* * Deal with parity, framing and overrun errors. */ static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) { /* clear error */ UART_PUT_CR(port, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK) { status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ port->icount.brk++; } if (status & ATMEL_US_PARE) port->icount.parity++; if (status & ATMEL_US_FRAME) port->icount.frame++; if (status & ATMEL_US_OVRE) port->icount.overrun++; }
static void ambauart_shutdown(struct uart_port *port, struct uart_info *info) { /* * Free the interrupt */ free_irq(port->irq, info); /* * disable all interrupts, disable the port */ UART_PUT_CR(port, 0); /* disable break condition and fifos */ UART_PUT_LCRH(port, UART_GET_LCRH(port) & ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); }
/* * Disable the port */ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; /* * Ensure everything is stopped. */ atmel_stop_rx(port); atmel_stop_tx(port); /* * Shut-down the DMA. */ if (atmel_port->use_dma_rx) { int i; for (i = 0; i < 2; i++) { struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; dma_unmap_single(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE); kfree(pdc->buf); } } if (atmel_port->use_dma_tx) { struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; dma_unmap_single(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE); } /* * Disable all interrupts, port and break condition. */ UART_PUT_CR(port, ATMEL_US_RSTSTA); UART_PUT_IDR(port, -1); /* * Free the interrupt */ free_irq(port->irq, port); /* * If there is a specific "close" function (to unregister * control line interrupts) */ if (atmel_close_hook) atmel_close_hook(port); }
/* * Disable the port */ static void at91_shutdown(struct uart_port *port) { /* * Disable all interrupts, port and break condition. */ UART_PUT_CR(port, AT91_US_RSTSTA); UART_PUT_IDR(port, -1); /* * Free the interrupt */ free_irq(port->irq, port); /* * If there is a specific "close" function (to unregister * control line interrupts) */ if (at91_close) at91_close(port); }
/* * Interrupt handler */ static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct uart_port *port = dev_id; unsigned int status, pending, pass_counter = 0; status = UART_GET_CSR(port); pending = status & port->read_status_mask; if (pending) { do { if (pending & AT91_US_RXRDY) at91_rx_chars(port, regs); /* Clear the relevent break bits */ if (pending & AT91_US_RXBRK) { UART_PUT_CR(port, AT91_US_RSTSTA); port->icount.brk++; uart_handle_break(port); } // TODO: All reads to CSR will clear these interrupts! if (pending & AT91_US_RIIC) port->icount.rng++; if (pending & AT91_US_DSRIC) port->icount.dsr++; if (pending & AT91_US_DCDIC) uart_handle_dcd_change(port, !(status & AT91_US_DCD)); if (pending & AT91_US_CTSIC) uart_handle_cts_change(port, !(status & AT91_US_CTS)); if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC)) wake_up_interruptible(&port->info->delta_msr_wait); if (pending & AT91_US_TXRDY) at91_tx_chars(port); if (pass_counter++ > AT91_ISR_PASS_LIMIT) break; status = UART_GET_CSR(port); pending = status & port->read_status_mask; } while (pending); } return IRQ_HANDLED; }
/* * Set state of the modem control output lines */ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; unsigned int mode; #ifdef CONFIG_ARCH_AT91RM9200 if (cpu_is_at91rm9200()) { /* * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. * We need to drive the pin manually. */ if (port->mapbase == AT91RM9200_BASE_US0) { if (mctrl & TIOCM_RTS) at91_set_gpio_value(AT91_PIN_PA21, 0); else at91_set_gpio_value(AT91_PIN_PA21, 1); } } #endif if (mctrl & TIOCM_RTS) control |= ATMEL_US_RTSEN; else control |= ATMEL_US_RTSDIS; if (mctrl & TIOCM_DTR) control |= ATMEL_US_DTREN; else control |= ATMEL_US_DTRDIS; UART_PUT_CR(port, control); /* Local loopback mode? */ mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; if (mctrl & TIOCM_LOOP) mode |= ATMEL_US_CHMODE_LOC_LOOP; else mode |= ATMEL_US_CHMODE_NORMAL; UART_PUT_MR(port, mode); }
/* * Receive data via the PDC. At least one byte was received, but the * buffer was not full when the inter-character timeout expired. */ static void atmel_pdc_timeout(struct uart_port *port) { struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; struct tty_struct *tty = port->info->tty; struct atmel_dma_buffer *pdc = PDC_RX_BUF(atmel_port); /* unsigned */ int ofs, count; ofs = UART_GET_RPR(port) - pdc->dma_addr; /* current DMA adress */ count = ofs - pdc->ofs; if (likely(count > 0)) { dma_sync_single_for_cpu(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE); tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); tty_flip_buffer_push(tty); pdc->ofs = ofs; port->icount.rx += count; } /* reset the UART timeout */ UART_PUT_CR(port, ATMEL_US_STTTO); }
static int ambauart_startup(struct uart_port *port, struct uart_info *info) { int retval; /* * Allocate the IRQ */ retval = request_irq(port->irq, ambauart_int, 0, "amba", info); if (retval) return retval; /* * initialise the old status of the modem signals */ info->drv_old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY; /* * Finally, enable interrupts */ UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); return 0; }
static void pl010_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) { unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { case CS5: lcr_h = UART01x_LCRH_WLEN_5; break; case CS6: lcr_h = UART01x_LCRH_WLEN_6; break; case CS7: lcr_h = UART01x_LCRH_WLEN_7; break; default: // CS8 lcr_h = UART01x_LCRH_WLEN_8; break; } if (termios->c_cflag & CSTOPB) lcr_h |= UART01x_LCRH_STP2; if (termios->c_cflag & PARENB) { lcr_h |= UART01x_LCRH_PEN; if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; } if (port->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; spin_lock_irqsave(&port->lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); port->read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UART01x_RSR_BE; /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & IGNBRK) { port->ignore_status_mask |= UART01x_RSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART01x_RSR_OE; } /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= UART_DUMMY_RSR_RX; /* first, disable everything */ old_cr = UART_GET_CR(port) & ~UART010_CR_MSIE; if (UART_ENABLE_MS(port, termios->c_cflag)) old_cr |= UART010_CR_MSIE; UART_PUT_CR(port, 0); /* Set baud rate */ quot -= 1; UART_PUT_LCRM(port, ((quot & 0xf00) >> 8)); UART_PUT_LCRL(port, (quot & 0xff)); /* * ----------v----------v----------v----------v----- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L * ----------^----------^----------^----------^----- */ UART_PUT_LCRH(port, lcr_h); UART_PUT_CR(port, old_cr); spin_unlock_irqrestore(&port->lock, flags); }