📄 at91_tl16c554.c
字号:
}/* * Perform initialization and enable port for reception */static int tl16c554_startup(struct uart_port *port){ int retval=0; // DPRINTK("\n\\rtl16c554_startup!\n\r"); /* * If there is a specific "open" function (to register * control line interrupts) */ if (tl16c554_open) { retval = tl16c554_open(port); if (retval) { return retval; } } port->read_status_mask = TL16C554_US_RXRDY | TL16C554_US_THRE | TL16C554_US_TEMT | TL16C554_US_OVRE | TL16C554_US_PARE | TL16C554_US_FRAME | TL16C554_US_BREAKI; /* * Finally, clear and enable interrupts */ //设置波特率 UART_PUT_IDR (port, -1); UART_PUT_BRGR(port,QUTO_DEFAULT); UART_PUT_LCR (port,LCR_CONFIG_DEFAULT); UART_PUT_MCR (port,MCR_CONFIG_DEFAULT); UART_PUT_IER(port, TL16C554_RX_FULL); UART_PUT_FCR(port, TL16C554_EN); return 0;}/* * Disable the port */static void tl16c554_shutdown(struct uart_port *port){ int status; // DPRINTK("\n\\rtl16c554_shutdown!\n\r"); if (tl16c554_close) tl16c554_close(port); /* * Clear all Err status and Disable all interrupts. */ status = UART_GET_LSR(port); UART_PUT_IDR(port, -1); /* disable the tl16c554 */ UART_PUT_FCR(port, TL16C554_DIS);}static struct uart_ops tl16c554_pops; /* forward declaration *//* * Change the port parameters */static void tl16c554_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot){ unsigned long flags; unsigned int mode,imr; //DPRINTK("\n\\rtl16c554_change_speed!\n\r"); /* Get current mode register */ mode = UART_GET_LCR(port) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR); /* byte size */ switch (cflag & CSIZE) { case CS5: mode |= TL16C554_US_CHRL_5_BITS; break; case CS6: mode |= TL16C554_US_CHRL_6_BITS; break; case CS7: mode |= TL16C554_US_CHRL_7_BITS; break; default: mode |= TL16C554_US_CHRL_8_BITS; break; } /* stop bits */ if (cflag & CSTOPB) mode |= TL16C554_US_NBSTOP_2_BIT; /* parity */ if (cflag & PARENB) { if (cflag & PARODD) mode |= TL16C554_US_PAR_ODD; else if(cflag & PARENB) mode |= TL16C554_US_PAR_EVEN; } else mode |= TL16C554_US_PAR_NONE; port->read_status_mask |= TL16C554_US_OVRE; if (iflag & INPCK) port->read_status_mask |= TL16C554_US_FRAME | TL16C554_US_PARE; if (iflag & (BRKINT | PARMRK)) port->read_status_mask |= TL16C554_US_BREAKI; /* * Characters to ignore */ port->ignore_status_mask = 0; if (iflag & IGNPAR) port->ignore_status_mask |= (TL16C554_US_FRAME | TL16C554_US_PARE); if (iflag & IGNBRK) { port->ignore_status_mask |= TL16C554_US_BREAKI; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (iflag & IGNPAR) port->ignore_status_mask |= TL16C554_US_OVRE; } // TODO: Ignore all characters if CREAD is set. /* first, disable interrupts and drain transmitter */ local_irq_save(flags); imr = UART_GET_IER(port); /* get interrupt status */ UART_PUT_IDR(port, -1); /* disable all interrupts */ local_irq_restore(flags); //while (!(UART_GET_LSR(port) & TL16C554_US_TEMT)) //{ barrier(); } /* disable the tl16c554 */ UART_PUT_FCR(port, TL16C554_DIS); /* set the parity, stop bits and data size */ UART_PUT_LCR(port, mode); /* set the baud rate */ UART_PUT_BRGR(port, quot); /* restore interrupts */ UART_PUT_IER(port, imr); UART_PUT_FCR(port, TL16C554_EN); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, cflag)) tl16c554_pops.enable_ms(port); // DPRINTK("\n\\rexit tl16c554_change_speed!\n\r");}/* * Return string describing the specified port */static const char *tl16c554_type(struct uart_port *port){ return port->type == PORT_AT91RM9200 ? "TL16C554_SERIAL" : NULL;}/* * Release the memory region(s) being used by 'port'. */static void tl16c554_release_port(struct uart_port *port){ }/* * Request the memory region(s) being used by 'port'. */static int tl16c554_request_port(struct uart_port *port){ return 0;}/* * Configure/autoconfigure the port. */static void tl16c554_config_port(struct uart_port *port, int flags){ if (flags & UART_CONFIG_TYPE) { port->type = PORT_AT91RM9200; }}/* * Verify the new serial_struct (for TIOCSSERIAL). */static int tl16c554_verify_port(struct uart_port *port, struct serial_struct *ser){ int ret = 0; return ret;}static struct uart_ops tl16c554_pops = { tx_empty: tl16c554_tx_empty, set_mctrl: tl16c554_set_mctrl, get_mctrl: tl16c554_get_mctrl, stop_tx: tl16c554_stop_tx, start_tx: tl16c554_start_tx, stop_rx: tl16c554_stop_rx, enable_ms: tl16c554_enable_ms, break_ctl: tl16c554_break_ctl, startup: tl16c554_startup, shutdown: tl16c554_shutdown, change_speed: tl16c554_change_speed, type: tl16c554_type, release_port: tl16c554_release_port, request_port: tl16c554_request_port, config_port: tl16c554_config_port, verify_port: tl16c554_verify_port,};/* * Setup ports. */void __init tl16c554_register_uart(int idx, int port){ DPRINTK("\n\\rtl16c554_register_uart!\n\r"); if ((idx < 0) || (idx >= TL16C554_NR_UART)) { printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx); return; } switch (port) { case 5: tl16c554_ports[idx].membase = (void *) TL16C554_VA_BASE_ADDR5; tl16c554_ports[idx].mapbase = TL16C554_BASE_ADDR_USA5; tl16c554_ports[idx].irq = TL16C554_PIO5; break; case 6: tl16c554_ports[idx].membase = (void *) TL16C554_VA_BASE_ADDR6; tl16c554_ports[idx].mapbase = TL16C554_BASE_ADDR_USB6; tl16c554_ports[idx].irq = TL16C554_PIO6; break; case 7: tl16c554_ports[idx].membase = (void *) TL16C554_VA_BASE_ADDR7; tl16c554_ports[idx].mapbase = TL16C554_BASE_ADDR_USC7; tl16c554_ports[idx].irq = TL16C554_PIO7; break; case 8: tl16c554_ports[idx].membase = (void *) TL16C554_VA_BASE_ADDR8; tl16c554_ports[idx].mapbase = TL16C554_BASE_ADDR_USD8; tl16c554_ports[idx].irq = TL16C554_PIO8; break; default: printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port); }}void __init tl16c554_init_ports(void){ static int first_in = 1; int i; DPRINTK("\n\\rtl16c554_init_ports!\n\r"); if (!first_in) return; first_in = 0; for (i = 0; i < TL16C554_NR_UART; i++) { tl16c554_ports[i].iotype = SERIAL_IO_MEM; tl16c554_ports[i].flags = ASYNC_BOOT_AUTOCONF; tl16c554_ports[i].uartclk = TL16C554_CLOCK; tl16c554_ports[i].ops = &tl16c554_pops; tl16c554_ports[i].fifosize = 1; tl16c554_ports[i].line = i+5; if (tl16c554_serialmap[i] >= 0) tl16c554_register_uart(i, tl16c554_serialmap[i]); }}extern struct uart_driver at91_reg ;static int __init at91_tl16c554_init(void){ int i,retval; DPRINTK("\n\\rat91_tl16c554_init!\n\r"); AT91_SYS->PIOC_PDR |= 0x2000; AT91_SYS->PIOC_ASR |= 0x2000; AT91_SYS->EBI_SMC2_CSR[7] = 0x11003183; //addr iomap if(!request_mem_region(TL16C554_BASE_ADDR_USA5,VA_SIZE,"tl16c554_serial_A")) { printk("tl16c554_serial: can't request mem for serial_a\n"); return -EBUSY; } TL16C554_VA_BASE_ADDR5 = (unsigned long)ioremap(TL16C554_BASE_ADDR_USA5,VA_SIZE); if(!request_mem_region(TL16C554_BASE_ADDR_USB6,VA_SIZE,"tl16c554_serial_B")) { printk("tl16c554_serial: can't request mem for serial_b\n"); return -EBUSY; } TL16C554_VA_BASE_ADDR6 = (unsigned long)ioremap(TL16C554_BASE_ADDR_USB6,VA_SIZE); if(!request_mem_region(TL16C554_BASE_ADDR_USC7,VA_SIZE,"tl16c554_serial_A")) { printk("tl16c554_serial: can't request mem for serial_c\n"); return -EBUSY; } TL16C554_VA_BASE_ADDR7 = (unsigned long)ioremap(TL16C554_BASE_ADDR_USC7,VA_SIZE); if(!request_mem_region(TL16C554_BASE_ADDR_USD8,VA_SIZE,"tl16c554_serial_A")) { printk("tl16c554_serial: can't request mem for serial_d\n"); return -EBUSY; } TL16C554_VA_BASE_ADDR8 = (unsigned long)ioremap(TL16C554_BASE_ADDR_USD8,VA_SIZE); //GPIO config //AT91_SYS->PIOA_PER |= 0x1; //AT91_SYS->PIOA_ODR |= 0x1; AT91_SYS->AIC_IDCR |= 0x1<< AT91C_ID_PIOA; //Disable interrupt AT91_SYS->AIC_ICCR |= 0x1<< AT91C_ID_PIOA; AT91_SYS->PIOA_PER |= (TL16C554_PIO5 | TL16C554_PIO6 | TL16C554_PIO7 | TL16C554_PIO8) ; //Enable peripheral control of the pin PIOA3 AT91_SYS->PIOA_ODR |= (TL16C554_PIO5 | TL16C554_PIO6 | TL16C554_PIO7 | TL16C554_PIO8); //Assign the I/O PIOA3 to the Peripheral B functiom AT91_SYS->PIOA_IFER |= (TL16C554_PIO5 | TL16C554_PIO6 | TL16C554_PIO7 | TL16C554_PIO8); AT91_SYS->PIOA_IER |= (TL16C554_PIO5 | TL16C554_PIO6 | TL16C554_PIO7 | TL16C554_PIO8); AT91_SYS->PMC_PCER |= 0x1<< AT91C_ID_PIOA;// enable clock */ //init the tc16c554 uart tl16c554_init_ports(); for (i = 0; i < TL16C554_NR_UART; i++) { if (tl16c554_serialmap[i] >= 0) uart_add_one_port(&at91_reg, &tl16c554_ports[i]); } DPRINTK("\n\rtl16c554_serial request irq!\n\r"); //request irq retval = request_irq(AT91C_ID_PIOA, tl16c554_interrupt, SA_INTERRUPT, "tl16c554_serial", NULL); if (retval) { printk("tl16c554_serial: - Can't get irq\n"); return retval; } DPRINTK("\n\rtl16c554_serial request irq succeed!\n\r"); AT91_SYS->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_PRIOR_LOWEST|AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE ; //enable the irq retval = AT91_SYS->PIOA_ISR ; AT91_SYS->AIC_IECR |= 0x1<< AT91C_ID_PIOA; DPRINTK("\n\rtl16c554_serial succeed!\n\r"); return 0;}static void __exit at91_tl16c554_exit(void){ int i; free_irq(AT91C_ID_PIOA,NULL); for (i = 0; i < TL16C554_NR_UART; i++) { if (tl16c554_serialmap[i] >= 0) uart_remove_one_port(&at91_reg, &tl16c554_ports[i]); } iounmap((void*)TL16C554_VA_BASE_ADDR5); iounmap((void*)TL16C554_VA_BASE_ADDR6); iounmap((void*)TL16C554_VA_BASE_ADDR7); iounmap((void*)TL16C554_VA_BASE_ADDR8); release_mem_region(TL16C554_BASE_ADDR_USA5,VA_SIZE); release_mem_region(TL16C554_BASE_ADDR_USB6,VA_SIZE); release_mem_region(TL16C554_BASE_ADDR_USC7,VA_SIZE); release_mem_region(TL16C554_BASE_ADDR_USD8,VA_SIZE);}module_init(at91_tl16c554_init);module_exit(at91_tl16c554_exit);EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Wujh@hyesco.com");MODULE_DESCRIPTION("AT91 tl16c554 serial port driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -