📄 mpc52xx_uart.c
字号:
/* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ if (tty->flip.count < (TTY_FLIPBUF_SIZE-1)) { tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } *tty->flip.flag_buf_ptr = TTY_OVERRUN; } /* Clear error condition */ out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT); } tty->flip.char_buf_ptr++; tty->flip.flag_buf_ptr++; tty->flip.count++; } tty_flip_buffer_push(tty); return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;}static inline intmpc52xx_uart_int_tx_chars(struct uart_port *port){ struct circ_buf *xmit = &port->info->xmit; /* Process out of band chars */ if (port->x_char) { out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char); port->icount.tx++; port->x_char = 0; return 1; } /* Nothing to do ? */ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { mpc52xx_uart_stop_tx(port,0); return 0; } /* Send chars */ while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) { out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) break; } /* Wake up */ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); /* Maybe we're done after all */ if (uart_circ_empty(xmit)) { mpc52xx_uart_stop_tx(port,0); return 0; } return 1;}static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs){ struct uart_port *port = (struct uart_port *) dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; unsigned short status; if ( irq != port->irq ) { printk( KERN_WARNING "mpc52xx_uart_int : " \ "Received wrong int %d. Waiting for %d\n", irq, port->irq); return IRQ_NONE; } spin_lock(&port->lock); /* While we have stuff to do, we continue */ do { /* If we don't find anything to do, we stop */ keepgoing = 0; /* Read status */ status = in_be16(&PSC(port)->mpc52xx_psc_isr); status &= port->read_status_mask; /* Do we need to receive chars ? */ /* For this RX interrupts must be on and some chars waiting */ if ( status & MPC52xx_PSC_IMR_RXRDY ) keepgoing |= mpc52xx_uart_int_rx_chars(port, regs); /* Do we need to send chars ? */ /* For this, TX must be ready and TX interrupt enabled */ if ( status & MPC52xx_PSC_IMR_TXRDY ) keepgoing |= mpc52xx_uart_int_tx_chars(port); /* Limit number of iteration */ if ( !(--pass) ) keepgoing = 0; } while (keepgoing); spin_unlock(&port->lock); return IRQ_HANDLED;}/* ======================================================================== *//* Console ( if applicable ) *//* ======================================================================== */#ifdef CONFIG_SERIAL_MPC52xx_CONSOLEstatic void __initmpc52xx_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits, int *flow){ struct mpc52xx_psc *psc = PSC(port); unsigned char mr1; /* Read the mode registers */ out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); mr1 = in_8(&psc->mode); /* CT{U,L}R are write-only ! */ *baud = __res.bi_baudrate ? __res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; /* Parse them */ switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { case MPC52xx_PSC_MODE_5_BITS: *bits = 5; break; case MPC52xx_PSC_MODE_6_BITS: *bits = 6; break; case MPC52xx_PSC_MODE_7_BITS: *bits = 7; break; case MPC52xx_PSC_MODE_8_BITS: default: *bits = 8; } if (mr1 & MPC52xx_PSC_MODE_PARNONE) *parity = 'n'; else *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';}static void mpc52xx_console_write(struct console *co, const char *s, unsigned int count){ struct uart_port *port = &mpc52xx_uart_ports[co->index]; struct mpc52xx_psc *psc = PSC(port); unsigned int i, j; /* Disable interrupts */ out_be16(&psc->mpc52xx_psc_imr, 0); /* Wait the TX buffer to be empty */ j = 5000000; /* Maximum wait */ while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && --j) udelay(1); /* Write all the chars */ for ( i=0 ; i<count ; i++ ) { /* Send the char */ out_8(&psc->mpc52xx_psc_buffer_8, *s); /* Line return handling */ if ( *s++ == '\n' ) out_8(&psc->mpc52xx_psc_buffer_8, '\r'); /* Wait the TX buffer to be empty */ j = 20000; /* Maximum wait */ while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && --j) udelay(1); } /* Restore interrupt state */ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);}static int __initmpc52xx_console_setup(struct console *co, char *options){ struct uart_port *port = &mpc52xx_uart_ports[co->index]; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM) return -EINVAL; /* Basic port init. Needed since we use some uart_??? func before * real init for early access */ port->lock = SPIN_LOCK_UNLOCKED; port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ port->ops = &mpc52xx_uart_ops; port->mapbase = MPC52xx_PSCx(co->index); /* We ioremap ourself */ port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc)); if (port->membase == NULL) { release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); return -EBUSY; } /* Setup the port parameters accoding to options */ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); return uart_set_options(port, co, baud, parity, bits, flow);}extern struct uart_driver mpc52xx_uart_driver;static struct console mpc52xx_console = { .name = "ttyS", .write = mpc52xx_console_write, .device = uart_console_device, .setup = mpc52xx_console_setup, .flags = CON_PRINTBUFFER, .index = -1, /* Specified on the cmdline (e.g. console=ttyS0 ) */ .data = &mpc52xx_uart_driver,}; static int __init mpc52xx_console_init(void){ register_console(&mpc52xx_console); return 0;}console_initcall(mpc52xx_console_init);#define MPC52xx_PSC_CONSOLE &mpc52xx_console#else#define MPC52xx_PSC_CONSOLE NULL#endif/* ======================================================================== *//* UART Driver *//* ======================================================================== */static struct uart_driver mpc52xx_uart_driver = { .owner = THIS_MODULE, .driver_name = "mpc52xx_psc_uart", .dev_name = "ttyS", .devfs_name = "ttyS", .major = TTY_MAJOR, .minor = 64, .nr = MPC52xx_PSC_MAXNUM, .cons = MPC52xx_PSC_CONSOLE,};/* ======================================================================== *//* OCP Driver *//* ======================================================================== */static int __devinitmpc52xx_uart_probe(struct ocp_device *ocp){ struct uart_port *port = NULL; int idx, ret; /* Get the corresponding port struct */ idx = ocp->def->index; if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM) return -EINVAL; port = &mpc52xx_uart_ports[idx]; /* Init the port structure */ port->lock = SPIN_LOCK_UNLOCKED; port->mapbase = ocp->def->paddr; port->irq = ocp->def->irq; port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ port->fifosize = 255; /* Should be 512 ! But it can't be */ /* stored in a unsigned char */ port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | ( uart_console(port) ? 0 : UPF_IOREMAP ); port->line = idx; port->ops = &mpc52xx_uart_ops; port->read_status_mask = 0; /* Requests the mem & irqs */ /* Unlike other serial drivers, we reserve the resources here, so we * can detect early if multiple drivers uses the same PSC. Special * care must be taken with the console PSC */ ret = request_irq( port->irq, mpc52xx_uart_int, SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port); if (ret) goto error; ret = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; if (ret) goto free_irq; /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); if (ret) goto release_mem; ocp_set_drvdata(ocp, (void*)port); return 0;free_irq: free_irq(port->irq, mpc52xx_uart_int);release_mem: release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));error: if (uart_console(port)) printk( "mpc52xx_uart.c: Error during resource alloction for " "the console port !!! Check that the console PSC is " "not used by another OCP driver !!!\n" ); return ret;}static voidmpc52xx_uart_remove(struct ocp_device *ocp){ struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); ocp_set_drvdata(ocp, NULL); if (port) { uart_remove_one_port(&mpc52xx_uart_driver, port); release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); free_irq(port->irq, mpc52xx_uart_int); }}#ifdef CONFIG_PMstatic intmpc52xx_uart_suspend(struct ocp_device *ocp, u32 state){ struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); uart_suspend_port(&mpc52xx_uart_driver, port); return 0;}static intmpc52xx_uart_resume(struct ocp_device *ocp){ struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); uart_resume_port(&mpc52xx_uart_driver, port); return 0;}#endifstatic struct ocp_device_id mpc52xx_uart_ids[] __devinitdata = { { .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_PSC_UART }, { .vendor = OCP_VENDOR_INVALID /* Terminating entry */ }};MODULE_DEVICE_TABLE(ocp, mpc52xx_uart_ids);static struct ocp_driver mpc52xx_uart_ocp_driver = { .name = "mpc52xx_psc_uart", .id_table = mpc52xx_uart_ids, .probe = mpc52xx_uart_probe, .remove = mpc52xx_uart_remove,#ifdef CONFIG_PM .suspend = mpc52xx_uart_suspend, .resume = mpc52xx_uart_resume,#endif};/* ======================================================================== *//* Module *//* ======================================================================== */static int __initmpc52xx_uart_init(void){ int ret; printk(KERN_INFO "Serial: MPC52xx PSC driver\n"); ret = uart_register_driver(&mpc52xx_uart_driver); if (ret) return ret; ret = ocp_register_driver(&mpc52xx_uart_ocp_driver); return ret;}static void __exitmpc52xx_uart_exit(void){ ocp_unregister_driver(&mpc52xx_uart_ocp_driver); uart_unregister_driver(&mpc52xx_uart_driver);}module_init(mpc52xx_uart_init);module_exit(mpc52xx_uart_exit);MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -