static unsigned int sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) { unsigned int ch, rx_count = 0; struct tty_struct *tty; tty = tty_port_tty_get(&port->state->port); if (!tty) return -ENODEV; while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) & SIRFUART_FIFOEMPTY_MASK(port))) { ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ; if (unlikely(uart_handle_sysrq_char(port, ch))) continue; uart_insert_char(port, 0, 0, ch, TTY_NORMAL); rx_count++; if (rx_count >= max_rx_count) break; } port->icount.rx += rx_count; tty_flip_buffer_push(tty); tty_kref_put(tty); return rx_count; }
static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port) { unsigned long reg; reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS); if (reg & SIRFUART_FIFOEMPTY_MASK(port)) return TIOCSER_TEMT; else return 0; }
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) { unsigned long intr_status; unsigned long cts_status; unsigned long flag = TTY_NORMAL; struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id; struct uart_port *port = &sirfport->port; struct uart_state *state = port->state; struct circ_buf *xmit = &port->state->xmit; spin_lock(&port->lock); intr_status = rd_regl(port, SIRFUART_INT_STATUS); wr_regl(port, SIRFUART_INT_STATUS, intr_status); intr_status &= rd_regl(port, SIRFUART_INT_EN); if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) { if (intr_status & SIRFUART_RXD_BREAK) { if (uart_handle_break(port)) goto recv_char; uart_insert_char(port, intr_status, SIRFUART_RX_OFLOW, 0, TTY_BREAK); spin_unlock(&port->lock); return IRQ_HANDLED; } if (intr_status & SIRFUART_RX_OFLOW) port->icount.overrun++; if (intr_status & SIRFUART_FRM_ERR) { port->icount.frame++; flag = TTY_FRAME; } if (intr_status & SIRFUART_PARITY_ERR) flag = TTY_PARITY; wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET); wr_regl(port, SIRFUART_RX_FIFO_OP, 0); wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START); intr_status &= port->read_status_mask; uart_insert_char(port, intr_status, SIRFUART_RX_OFLOW_INT, 0, flag); } recv_char: if (intr_status & SIRFUART_CTS_INT_EN) { cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS); if (cts_status != 0) { uart_handle_cts_change(port, 1); } else { uart_handle_cts_change(port, 0); wake_up_interruptible(&state->port.delta_msr_wait); } } if (intr_status & SIRFUART_RX_IO_INT_EN) sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT); if (intr_status & SIRFUART_TX_INT_EN) { if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { spin_unlock(&port->lock); return IRQ_HANDLED; } else { sirfsoc_uart_pio_tx_chars(sirfport, SIRFSOC_UART_IO_TX_REASONABLE_CNT); if ((uart_circ_empty(xmit)) && (rd_regl(port, SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOEMPTY_MASK(port))) sirfsoc_uart_stop_tx(port); } } spin_unlock(&port->lock); return IRQ_HANDLED; }