pxa.c

来自「linux 内核源代码」· C语言 代码 · 共 865 行 · 第 1/2 页

C
865
字号
				  UART_FCR_CLEAR_XMIT);	serial_out(up, UART_FCR, 0);}static voidserial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,		       struct ktermios *old){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned char cval, fcr = 0;	unsigned long flags;	unsigned int baud, quot;	switch (termios->c_cflag & CSIZE) {	case CS5:		cval = UART_LCR_WLEN5;		break;	case CS6:		cval = UART_LCR_WLEN6;		break;	case CS7:		cval = UART_LCR_WLEN7;		break;	default:	case CS8:		cval = UART_LCR_WLEN8;		break;	}	if (termios->c_cflag & CSTOPB)		cval |= UART_LCR_STOP;	if (termios->c_cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(termios->c_cflag & PARODD))		cval |= UART_LCR_EPAR;	/*	 * 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);	if ((up->port.uartclk / quot) < (2400 * 16))		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;	else if ((up->port.uartclk / quot) < (230400 * 16))		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;	else		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;	/*	 * Ok, we're now changing the port state.  Do it with	 * interrupts disabled.	 */	spin_lock_irqsave(&up->port.lock, flags);	/*	 * Ensure the port will be enabled.	 * This is required especially for serial console.	 */	up->ier |= IER_UUE;	/*	 * Update the per-port timeout.	 */	uart_update_timeout(port, termios->c_cflag, baud);	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (termios->c_iflag & INPCK)		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (termios->c_iflag & (BRKINT | PARMRK))		up->port.read_status_mask |= UART_LSR_BI;	/*	 * Characters to ignore	 */	up->port.ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (termios->c_iflag & IGNBRK) {		up->port.ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too (for real raw support).		 */		if (termios->c_iflag & IGNPAR)			up->port.ignore_status_mask |= UART_LSR_OE;	}	/*	 * ignore all characters if CREAD is not set	 */	if ((termios->c_cflag & CREAD) == 0)		up->port.ignore_status_mask |= UART_LSR_DR;	/*	 * CTS flow control flag and modem status interrupts	 */	up->ier &= ~UART_IER_MSI;	if (UART_ENABLE_MS(&up->port, termios->c_cflag))		up->ier |= UART_IER_MSI;	serial_out(up, UART_IER, up->ier);	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */	serial_out(up, UART_LCR, cval);		/* reset DLAB */	up->lcr = cval;					/* Save LCR */	serial_pxa_set_mctrl(&up->port, up->port.mctrl);	serial_out(up, UART_FCR, fcr);	spin_unlock_irqrestore(&up->port.lock, flags);}static voidserial_pxa_pm(struct uart_port *port, unsigned int state,	      unsigned int oldstate){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	if (!state)		clk_enable(up->clk);	else		clk_disable(up->clk);}static void serial_pxa_release_port(struct uart_port *port){}static int serial_pxa_request_port(struct uart_port *port){	return 0;}static void serial_pxa_config_port(struct uart_port *port, int flags){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	up->port.type = PORT_PXA;}static intserial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser){	/* we don't want the core code to modify any port params */	return -EINVAL;}static const char *serial_pxa_type(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	return up->name;}static struct uart_pxa_port *serial_pxa_ports[4];static struct uart_driver serial_pxa_reg;#ifdef CONFIG_SERIAL_PXA_CONSOLE#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)/* *	Wait for transmitter & holding register to empty */static inline void wait_for_xmitr(struct uart_pxa_port *up){	unsigned int status, tmout = 10000;	/* Wait up to 10ms for the character(s) to be sent. */	do {		status = serial_in(up, UART_LSR);		if (status & UART_LSR_BI)			up->lsr_break_flag = UART_LSR_BI;		if (--tmout == 0)			break;		udelay(1);	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);	/* Wait up to 1s for flow control if necessary */	if (up->port.flags & UPF_CONS_FLOW) {		tmout = 1000000;		while (--tmout &&		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))			udelay(1);	}}static void serial_pxa_console_putchar(struct uart_port *port, int ch){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	wait_for_xmitr(up);	serial_out(up, UART_TX, ch);}/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * *	The console_lock must be held when we get here. */static voidserial_pxa_console_write(struct console *co, const char *s, unsigned int count){	struct uart_pxa_port *up = serial_pxa_ports[co->index];	unsigned int ier;	clk_enable(up->clk);	/*	 *	First save the IER then disable the interrupts	 */	ier = serial_in(up, UART_IER);	serial_out(up, UART_IER, UART_IER_UUE);	uart_console_write(&up->port, s, count, serial_pxa_console_putchar);	/*	 *	Finally, wait for transmitter to become empty	 *	and restore the IER	 */	wait_for_xmitr(up);	serial_out(up, UART_IER, ier);	clk_disable(up->clk);}static int __initserial_pxa_console_setup(struct console *co, char *options){	struct uart_pxa_port *up;	int baud = 9600;	int bits = 8;	int parity = 'n';	int flow = 'n';	if (co->index == -1 || co->index >= serial_pxa_reg.nr)		co->index = 0;	up = serial_pxa_ports[co->index];	if (!up)		return -ENODEV;	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(&up->port, co, baud, parity, bits, flow);}static struct console serial_pxa_console = {	.name		= "ttyS",	.write		= serial_pxa_console_write,	.device		= uart_console_device,	.setup		= serial_pxa_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,	.data		= &serial_pxa_reg,};#define PXA_CONSOLE	&serial_pxa_console#else#define PXA_CONSOLE	NULL#endifstruct uart_ops serial_pxa_pops = {	.tx_empty	= serial_pxa_tx_empty,	.set_mctrl	= serial_pxa_set_mctrl,	.get_mctrl	= serial_pxa_get_mctrl,	.stop_tx	= serial_pxa_stop_tx,	.start_tx	= serial_pxa_start_tx,	.stop_rx	= serial_pxa_stop_rx,	.enable_ms	= serial_pxa_enable_ms,	.break_ctl	= serial_pxa_break_ctl,	.startup	= serial_pxa_startup,	.shutdown	= serial_pxa_shutdown,	.set_termios	= serial_pxa_set_termios,	.pm		= serial_pxa_pm,	.type		= serial_pxa_type,	.release_port	= serial_pxa_release_port,	.request_port	= serial_pxa_request_port,	.config_port	= serial_pxa_config_port,	.verify_port	= serial_pxa_verify_port,};static struct uart_driver serial_pxa_reg = {	.owner		= THIS_MODULE,	.driver_name	= "PXA serial",	.dev_name	= "ttyS",	.major		= TTY_MAJOR,	.minor		= 64,	.nr		= 4,	.cons		= PXA_CONSOLE,};static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state){        struct uart_pxa_port *sport = platform_get_drvdata(dev);        if (sport)                uart_suspend_port(&serial_pxa_reg, &sport->port);        return 0;}static int serial_pxa_resume(struct platform_device *dev){        struct uart_pxa_port *sport = platform_get_drvdata(dev);        if (sport)                uart_resume_port(&serial_pxa_reg, &sport->port);        return 0;}static int serial_pxa_probe(struct platform_device *dev){	struct uart_pxa_port *sport;	struct resource *mmres, *irqres;	int ret;	mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);	irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);	if (!mmres || !irqres)		return -ENODEV;	sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);	if (!sport)		return -ENOMEM;	sport->clk = clk_get(&dev->dev, "UARTCLK");	if (IS_ERR(sport->clk)) {		ret = PTR_ERR(sport->clk);		goto err_free;	}	sport->port.type = PORT_PXA;	sport->port.iotype = UPIO_MEM;	sport->port.mapbase = mmres->start;	sport->port.irq = irqres->start;	sport->port.fifosize = 64;	sport->port.ops = &serial_pxa_pops;	sport->port.line = dev->id;	sport->port.dev = &dev->dev;	sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;	sport->port.uartclk = clk_get_rate(sport->clk);	/*	 * Is it worth keeping this?	 */	if (mmres->start == __PREG(FFUART))		sport->name = "FFUART";	else if (mmres->start == __PREG(BTUART))		sport->name = "BTUART";	else if (mmres->start == __PREG(STUART))		sport->name = "STUART";	else if (mmres->start == __PREG(HWUART))		sport->name = "HWUART";	else		sport->name = "???";	sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);	if (!sport->port.membase) {		ret = -ENOMEM;		goto err_clk;	}	serial_pxa_ports[dev->id] = sport;	uart_add_one_port(&serial_pxa_reg, &sport->port);	platform_set_drvdata(dev, sport);	return 0; err_clk:	clk_put(sport->clk); err_free:	kfree(sport);	return ret;}static int serial_pxa_remove(struct platform_device *dev){	struct uart_pxa_port *sport = platform_get_drvdata(dev);	platform_set_drvdata(dev, NULL);	uart_remove_one_port(&serial_pxa_reg, &sport->port);	clk_put(sport->clk);	kfree(sport);	return 0;}static struct platform_driver serial_pxa_driver = {        .probe          = serial_pxa_probe,        .remove         = serial_pxa_remove,	.suspend	= serial_pxa_suspend,	.resume		= serial_pxa_resume,	.driver		= {	        .name	= "pxa2xx-uart",	},};int __init serial_pxa_init(void){	int ret;	ret = uart_register_driver(&serial_pxa_reg);	if (ret != 0)		return ret;	ret = platform_driver_register(&serial_pxa_driver);	if (ret != 0)		uart_unregister_driver(&serial_pxa_reg);	return ret;}void __exit serial_pxa_exit(void){	platform_driver_unregister(&serial_pxa_driver);	uart_unregister_driver(&serial_pxa_reg);}module_init(serial_pxa_init);module_exit(serial_pxa_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?