static int uart_clps711x_startup(struct uart_port *port) { struct clps711x_port *s = dev_get_drvdata(port->dev); int ret; s->tx_enabled[port->line] = 1; /* Allocate the IRQs */ ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx, 0, UART_CLPS711X_NAME " TX", port); if (ret) return ret; ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx, 0, UART_CLPS711X_NAME " RX", port); if (ret) { devm_free_irq(port->dev, TX_IRQ(port), port); return ret; } /* Disable break */ clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port)); /* Enable the port */ clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port)); return 0; }
static void clps711xuart_break_ctl(struct uart_port *port, int break_state) { unsigned int ubrlcr; ubrlcr = clps_readl(UBRLCR(port)); if (break_state == -1) ubrlcr |= UBRLCR_BREAK; else ubrlcr &= ~UBRLCR_BREAK; clps_writel(ubrlcr, UBRLCR(port)); }
static void clps711xuart_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; unsigned int ubrlcr; spin_lock_irqsave(&port->lock, flags); ubrlcr = clps_readl(UBRLCR(port)); if (break_state == -1) ubrlcr |= UBRLCR_BREAK; else ubrlcr &= ~UBRLCR_BREAK; clps_writel(ubrlcr, UBRLCR(port)); spin_unlock_irqrestore(&port->lock, flags); }
static void __init clps711xuart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { unsigned int ubrlcr, quot; ubrlcr = clps_readl(UBRLCR(port)); *parity = 'n'; if (ubrlcr & UBRLCR_PRTEN) { if (ubrlcr & UBRLCR_EVENPRT) *parity = 'e'; else *parity = 'o'; } if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) *bits = 7; else *bits = 8; quot = ubrlcr & UBRLCR_BAUD_MASK; *baud = port->uartclk / (16 * (quot + 1)); } }
static void clps711xuart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) { u_int ubrlcr; unsigned long flags; #if DEBUG printk("clps711xuart_change_speed(cflag=0x%x, iflag=0x%x, quot=%d) called\n", cflag, iflag, quot); #endif /* byte size and parity */ switch (cflag & CSIZE) { case CS5: ubrlcr = UBRLCR_WRDLEN5; break; case CS6: ubrlcr = UBRLCR_WRDLEN6; break; case CS7: ubrlcr = UBRLCR_WRDLEN7; break; default: ubrlcr = UBRLCR_WRDLEN8; break; // CS8 } if (cflag & CSTOPB) ubrlcr |= UBRLCR_XSTOP; if (cflag & PARENB) { ubrlcr |= UBRLCR_PRTEN; if (!(cflag & PARODD)) ubrlcr |= UBRLCR_EVENPRT; } if (port->fifosize > 1) ubrlcr |= UBRLCR_FIFOEN; port->read_status_mask = UARTDR_OVERR; if (iflag & INPCK) port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; // if (iflag & (BRKINT | PARMRK)) // port->read_status_mask |= AMBA_UARTRSR_BE; /* * Characters to ignore */ port->ignore_status_mask = 0; if (iflag & IGNPAR) port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; if (iflag & IGNBRK) { // port->ignore_status_mask |= AMBA_UARTRSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns to (for real raw support). */ if (iflag & IGNPAR) port->ignore_status_mask |= UARTDR_OVERR; } quot -= 1; /* first, disable everything */ save_flags(flags); cli(); clps_writel(ubrlcr | quot, UBRLCR(port)); restore_flags(flags); }
static void clps711xuart_shutdown(struct uart_port *port) { unsigned int ubrlcr, syscon; /* * Free the interrupt */ free_irq(TX_IRQ(port), port); /* TX interrupt */ free_irq(RX_IRQ(port), port); /* RX interrupt */ /* * disable the port */ syscon = clps_readl(SYSCON(port)); syscon &= ~SYSCON_UARTEN; clps_writel(syscon, SYSCON(port)); /* * disable break condition and fifos */ ubrlcr = clps_readl(UBRLCR(port)); ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); clps_writel(ubrlcr, UBRLCR(port)); }
static void clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int ubrlcr, baud, quot; unsigned long flags; /* * We don't implement CREAD. */ termios->c_cflag |= CREAD; /* * 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: ubrlcr = UBRLCR_WRDLEN5; break; case CS6: ubrlcr = UBRLCR_WRDLEN6; break; case CS7: ubrlcr = UBRLCR_WRDLEN7; break; default: // CS8 ubrlcr = UBRLCR_WRDLEN8; break; } if (termios->c_cflag & CSTOPB) ubrlcr |= UBRLCR_XSTOP; if (termios->c_cflag & PARENB) { ubrlcr |= UBRLCR_PRTEN; if (!(termios->c_cflag & PARODD)) ubrlcr |= UBRLCR_EVENPRT; } if (port->fifosize > 1) ubrlcr |= UBRLCR_FIFOEN; spin_lock_irqsave(&port->lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); port->read_status_mask = UARTDR_OVERR; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; if (termios->c_iflag & IGNBRK) { /* * If we're ignoring parity and break indicators, * ignore overruns to (for real raw support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UARTDR_OVERR; } quot -= 1; clps_writel(ubrlcr | quot, UBRLCR(port)); spin_unlock_irqrestore(&port->lock, flags); }
static void uart_clps711x_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int ubrlcr, baud, quot; unsigned long flags; /* Mask termios capabilities we don't support */ termios->c_cflag &= ~CMSPAR; termios->c_iflag &= ~(BRKINT | IGNBRK); /* Ask the core to calculate the divisor for us */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096, port->uartclk / 16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { case CS5: ubrlcr = UBRLCR_WRDLEN5; break; case CS6: ubrlcr = UBRLCR_WRDLEN6; break; case CS7: ubrlcr = UBRLCR_WRDLEN7; break; case CS8: default: ubrlcr = UBRLCR_WRDLEN8; break; } if (termios->c_cflag & CSTOPB) ubrlcr |= UBRLCR_XSTOP; if (termios->c_cflag & PARENB) { ubrlcr |= UBRLCR_PRTEN; if (!(termios->c_cflag & PARODD)) ubrlcr |= UBRLCR_EVENPRT; } /* Enable FIFO */ ubrlcr |= UBRLCR_FIFOEN; spin_lock_irqsave(&port->lock, flags); /* Set read status mask */ port->read_status_mask = UARTDR_OVERR; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; /* Set status ignore mask */ port->ignore_status_mask = 0; if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR | UARTDR_FRMERR; uart_update_timeout(port, termios->c_cflag, baud); clps_writel(ubrlcr | (quot - 1), UBRLCR(port)); spin_unlock_irqrestore(&port->lock, flags); }