📄 ep93xx_amba.c
字号:
}static unsigned int csambauart_get_mctrl(struct uart_port *port){ unsigned int result = 0; unsigned int status; status = UART_GET_FR(port); if (status & AMBA_UARTFR_DCD) result |= TIOCM_CAR; if (status & AMBA_UARTFR_DSR) result |= TIOCM_DSR; if (status & AMBA_UARTFR_CTS) result |= TIOCM_CTS; return result;}static void csambauart_set_mctrl(struct uart_port *port, unsigned int mctrl){ struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int ctrl = 0; /* If there's no RTS and DTR for this UART, do nothing here */ if( (uap->rts_mask == 0) && (uap->dtr_mask == 0) ) return; if ((mctrl & TIOCM_RTS) == 0) ctrl |= uap->rts_mask; if ((mctrl & TIOCM_DTR) == 0) ctrl |= uap->dtr_mask; UART_PUT_MCR(ctrl, port);}static void csambauart_break_ctl(struct uart_port *port, int break_state){ unsigned long flags; unsigned int lcr_h; spin_lock_irqsave(&port->lock, flags); lcr_h = UART_GET_LCRH(port); if (break_state == -1) lcr_h |= AMBA_UARTLCR_H_BRK; else lcr_h &= ~AMBA_UARTLCR_H_BRK; UART_PUT_LCRH(port, lcr_h); spin_unlock_irqrestore(&port->lock, flags);}static int csambauart_startup(struct uart_port *port){ struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; csambauart_enable_clocks(port); /* * Allocate the IRQ */ retval = request_irq(port->irq, csambauart_int, 0, "amba", port); if (retval) return retval; /* * initialise the old status of the modem signals */ uap->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 csambauart_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) & ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); csambauart_disable_clocks( port );}static void csambauart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot){ unsigned int lcr_h, old_cr; unsigned long flags; /* * Before we change speed, check to see if this UART is currently in use. * If it is, wait for the fifo to empty out before changing speed. */ if( csambauart_is_port_enabled( port ) ) { do{ flags = UART_GET_FR(port); } while( flags & UARTFR_BUSY ); } else { csambauart_enable_clocks( port ); } #if DEBUG printk("ambauart_set_cflag(0x%x) called\n", cflag);#endif /* byte size and parity */ switch (cflag & CSIZE) { case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; break; case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; break; case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; break; default: // CS8 lcr_h = AMBA_UARTLCR_H_WLEN_8; break; } if (cflag & CSTOPB) lcr_h |= AMBA_UARTLCR_H_STP2; if (cflag & PARENB) { lcr_h |= AMBA_UARTLCR_H_PEN; if (!(cflag & PARODD)) lcr_h |= AMBA_UARTLCR_H_EPS; } if (port->fifosize > 1) lcr_h |= AMBA_UARTLCR_H_FEN; spin_lock_irqsave(&port->lock, flags); port->read_status_mask = AMBA_UARTRSR_OE; if (iflag & INPCK) port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; 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 |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; if (iflag & IGNBRK) { port->ignore_status_mask |= AMBA_UARTRSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (iflag & IGNPAR) port->ignore_status_mask |= AMBA_UARTRSR_OE; } /* * Ignore all characters if CREAD is not set. */ if ((cflag & CREAD) == 0) port->ignore_status_mask |= UART_DUMMY_RSR_RX; old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE; if (UART_ENABLE_MS(port, cflag)) old_cr |= AMBA_UARTCR_MSIE; UART_PUT_CR(port, 0); UART_PUT_LCRM(port, 0 ); UART_PUT_LCRL(port, 0 ); UART_PUT_LCRH(port, 0 ); UART_CLEAR_ECR(port); /* 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);}static const char *csambauart_type(struct uart_port *port){ return port->type == PORT_AMBA ? "AMBA" : NULL;}/* * Release the memory region(s) being used by 'port' */static void csambauart_release_port(struct uart_port *port){ release_mem_region(port->mapbase, UART_PORT_SIZE);}/* * Request the memory region(s) being used by 'port' */static int csambauart_request_port(struct uart_port *port){ return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba") != NULL ? 0 : -EBUSY;}/* * Configure/autoconfigure the port. */static void csambauart_config_port(struct uart_port *port, int flags){ if (flags & UART_CONFIG_TYPE) { port->type = PORT_AMBA; csambauart_request_port(port); }}/* * verify the new serial_struct (for TIOCSSERIAL). */static int csambauart_verify_port(struct uart_port *port, struct serial_struct *ser){ int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; if (ser->irq < 0 || ser->irq >= NR_IRQS) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; return ret;}static struct uart_ops amba_pops = { .tx_empty = csambauart_tx_empty, .set_mctrl = csambauart_set_mctrl, .get_mctrl = csambauart_get_mctrl, .stop_tx = csambauart_stop_tx, .start_tx = csambauart_start_tx, .stop_rx = csambauart_stop_rx, .enable_ms = csambauart_enable_ms, .break_ctl = csambauart_break_ctl, .startup = csambauart_startup, .shutdown = csambauart_shutdown, .change_speed = csambauart_change_speed, .type = csambauart_type, .release_port = csambauart_release_port, .request_port = csambauart_request_port, .config_port = csambauart_config_port, .verify_port = csambauart_verify_port,};static struct uart_amba_port amba_ports[UART_NR] = { { .port = { .membase = (void *)IO_ADDRESS(UART1_BASE), .mapbase = UART1_BASE, .iotype = SERIAL_IO_MEM, .irq = IRQ_UART1, .uartclk = 14745600, .fifosize = 8, .ops = &amba_pops, .flags = ASYNC_BOOT_AUTOCONF, .line = 0, }, .dtr_mask = 1 << 0, .rts_mask = 1 << 1, },#if !defined(CONFIG_EP93XX_IRDA) { .port = { .membase = (void *)IO_ADDRESS(UART2_BASE), .mapbase = UART2_BASE, .iotype = SERIAL_IO_MEM, .irq = IRQ_UART2, .uartclk = 14745600, .fifosize = 8, .ops = &amba_pops, .flags = ASYNC_BOOT_AUTOCONF, .line = 1, }, .dtr_mask = 0, .rts_mask = 0, },#endif { .port = { .membase = (void *)IO_ADDRESS(UART3_BASE), .mapbase = UART3_BASE, .iotype = SERIAL_IO_MEM, .irq = IRQ_UART3, .uartclk = 14745600, .fifosize = 8, .ops = &amba_pops, .flags = ASYNC_BOOT_AUTOCONF,#if !defined(CONFIG_EP93XX_IRDA) .line = 2,#else .line = 1,#endif }, .dtr_mask = 0, .rts_mask = 0, }};static struct uart_driver amba_reg = { .owner = THIS_MODULE, .normal_major = SERIAL_AMBA_MAJOR,#ifdef CONFIG_DEVFS_FS .normal_name = "ttyAM%d", .callout_name = "cuaam%d",#else .normal_name = "ttyAM", .callout_name = "cuaam",#endif .normal_driver = &normal, .callout_major = CALLOUT_AMBA_MAJOR, .callout_driver = &callout, .table = cs_amba_table, .termios = cs_amba_termios, .termios_locked = cs_amba_termios_locked, .minor = SERIAL_AMBA_MINOR, .nr = UART_NR, .cons = AMBA_CONSOLE,};static int __init csambauart_init(void){ int ret; ret = uart_register_driver(&amba_reg); if (ret == 0) { int i; for (i = 0; i < UART_NR; i++) uart_add_one_port(&amba_reg, &amba_ports[i].port); } return ret;}static void __exit csambauart_exit(void){ int i; for (i = 0; i < UART_NR; i++) uart_remove_one_port(&amba_reg, &amba_ports[i].port); uart_unregister_driver(&amba_reg);}module_init(csambauart_init);module_exit(csambauart_exit);EXPORT_NO_SYMBOLS;MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd/Cirrus Logic, Inc.");MODULE_DESCRIPTION("EP9312 ARM AMBA serial port driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -