/* * 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) { /* Interrupt receive */ if (pending & ATMEL_US_RXRDY) atmel_rx_chars(port); // 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); /* 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; }
/* * 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; }
/* * Interrupts are disabled on entering */ static void atmel_console_write(struct console *co, const char *s, u_int count) { struct uart_port *port = &atmel_ports[co->index].uart; unsigned int status, imr; /* * First, save IMR and then disable interrupts */ imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); uart_console_write(port, s, count, atmel_console_putchar); /* * Finally, wait for transmitter to become empty * and restore IMR */ do { status = UART_GET_CSR(port); } while (!(status & ATMEL_US_TXRDY)); UART_PUT_IER(port, imr); /* set interrupts back the way they were */ }
/* * Interrupts are disabled on entering */ static void at91_console_write(struct console *co, const char *s, u_int count) { struct uart_port *port = at91_ports + co->index; unsigned int status, i, imr; /* * First, save IMR and then disable interrupts */ imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, AT91_US_RXRDY | AT91_US_TXRDY); /* * Now, do each character */ for (i = 0; i < count; i++) { do { status = UART_GET_CSR(port); } while (!(status & AT91_US_TXRDY)); UART_PUT_CHAR(port, s[i]); if (s[i] == '\n') { do { status = UART_GET_CSR(port); } while (!(status & AT91_US_TXRDY)); UART_PUT_CHAR(port, '\r'); } } /* * Finally, wait for transmitter to become empty * and restore IMR */ do { status = UART_GET_CSR(port); } while (!(status & AT91_US_TXRDY)); UART_PUT_IER(port, imr); /* set interrupts back the way they were */ }
/* * Change the port parameters */ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old) { struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; unsigned long flags; unsigned int mode, imr, quot, baud; /* Get current mode register */ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ quot /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; } /* byte size */ switch (termios->c_cflag & CSIZE) { case CS5: mode |= ATMEL_US_CHRL_5; break; case CS6: mode |= ATMEL_US_CHRL_6; break; case CS7: mode |= ATMEL_US_CHRL_7; break; default: mode |= ATMEL_US_CHRL_8; break; } /* stop bits */ if (termios->c_cflag & CSTOPB) mode |= ATMEL_US_NBSTOP_2; /* parity */ if (termios->c_cflag & PARENB) { if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_MARK; else mode |= ATMEL_US_PAR_SPACE; } else if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_ODD; else mode |= ATMEL_US_PAR_EVEN; } else mode |= ATMEL_US_PAR_NONE; spin_lock_irqsave(&port->lock, flags); port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= ATMEL_US_RXBRK; if (atmel_port->use_dma_rx) /* need to enable error interrupts */ UART_PUT_IER(port, port->read_status_mask); /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); if (termios->c_iflag & IGNBRK) { port->ignore_status_mask |= ATMEL_US_RXBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= ATMEL_US_OVRE; } // TODO: Ignore all characters if CREAD is set. /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); /* disable interrupts and drain transmitter */ imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, -1); /* disable all interrupts */ while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) cpu_relax(); /* disable receiver and transmitter */ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); /* set the parity, stop bits and data size */ UART_PUT_MR(port, mode); /* set the baud rate */ UART_PUT_BRGR(port, quot); UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* restore interrupts */ UART_PUT_IER(port, imr); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, termios->c_cflag)) port->ops->enable_ms(port); spin_unlock_irqrestore(&port->lock, flags); }