⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
error_out3:	free_irq(sport->txirq, sport);error_out2:	free_irq(sport->rxirq, sport);error_out1:	return retval;}static void imx_shutdown(struct uart_port *port){	struct imx_port *sport = (struct imx_port *)port;	unsigned long temp;	/*	 * Stop our timer.	 */	del_timer_sync(&sport->timer);	/*	 * Free the interrupts	 */	free_irq(sport->rtsirq, sport);	free_irq(sport->txirq, sport);	free_irq(sport->rxirq, sport);	/*	 * Disable all interrupts, port and break condition.	 */	temp = readl(sport->port.membase + UCR1);	temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);	writel(temp, sport->port.membase + UCR1);}static voidimx_set_termios(struct uart_port *port, struct ktermios *termios,		   struct ktermios *old){	struct imx_port *sport = (struct imx_port *)port;	unsigned long flags;	unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;	/*	 * If we don't support modem control lines, don't allow	 * these to be set.	 */	if (0) {		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);		termios->c_cflag |= CLOCAL;	}	/*	 * We only support CS7 and CS8.	 */	while ((termios->c_cflag & CSIZE) != CS7 &&	       (termios->c_cflag & CSIZE) != CS8) {		termios->c_cflag &= ~CSIZE;		termios->c_cflag |= old_csize;		old_csize = CS8;	}	if ((termios->c_cflag & CSIZE) == CS8)		ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;	else		ucr2 = UCR2_SRST | UCR2_IRTS;	if (termios->c_cflag & CRTSCTS) {		if( sport->have_rtscts ) {			ucr2 &= ~UCR2_IRTS;			ucr2 |= UCR2_CTSC;		} else {			termios->c_cflag &= ~CRTSCTS;		}	}	if (termios->c_cflag & CSTOPB)		ucr2 |= UCR2_STPB;	if (termios->c_cflag & PARENB) {		ucr2 |= UCR2_PREN;		if (termios->c_cflag & PARODD)			ucr2 |= UCR2_PROE;	}	/*	 * 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);	spin_lock_irqsave(&sport->port.lock, flags);	sport->port.read_status_mask = 0;	if (termios->c_iflag & INPCK)		sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);	if (termios->c_iflag & (BRKINT | PARMRK))		sport->port.read_status_mask |= URXD_BRK;	/*	 * Characters to ignore	 */	sport->port.ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		sport->port.ignore_status_mask |= URXD_PRERR;	if (termios->c_iflag & IGNBRK) {		sport->port.ignore_status_mask |= URXD_BRK;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too (for real raw support).		 */		if (termios->c_iflag & IGNPAR)			sport->port.ignore_status_mask |= URXD_OVRRUN;	}	del_timer_sync(&sport->timer);	/*	 * Update the per-port timeout.	 */	uart_update_timeout(port, termios->c_cflag, baud);	/*	 * disable interrupts and drain transmitter	 */	old_ucr1 = readl(sport->port.membase + UCR1);	writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),			sport->port.membase + UCR1);	while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))		barrier();	/* then, disable everything */	old_txrxen = readl(sport->port.membase + UCR2);	writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),			sport->port.membase + UCR2);	old_txrxen &= (UCR2_TXEN | UCR2_RXEN);	/* set the baud rate. We assume uartclk = 16 MHz	 *	 * baud * 16   UBIR - 1	 * --------- = --------	 *  uartclk    UBMR - 1	 */	writel((baud / 100) - 1, sport->port.membase + UBIR);	writel(10000 - 1, sport->port.membase + UBMR);	writel(old_ucr1, sport->port.membase + UCR1);	/* set the parity, stop bits and data size */	writel(ucr2 | old_txrxen, sport->port.membase + UCR2);	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))		imx_enable_ms(&sport->port);	spin_unlock_irqrestore(&sport->port.lock, flags);}static const char *imx_type(struct uart_port *port){	struct imx_port *sport = (struct imx_port *)port;	return sport->port.type == PORT_IMX ? "IMX" : NULL;}/* * Release the memory region(s) being used by 'port'. */static void imx_release_port(struct uart_port *port){	struct imx_port *sport = (struct imx_port *)port;	release_mem_region(sport->port.mapbase, UART_PORT_SIZE);}/* * Request the memory region(s) being used by 'port'. */static int imx_request_port(struct uart_port *port){	struct imx_port *sport = (struct imx_port *)port;	return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,			"imx-uart") != NULL ? 0 : -EBUSY;}/* * Configure/autoconfigure the port. */static void imx_config_port(struct uart_port *port, int flags){	struct imx_port *sport = (struct imx_port *)port;	if (flags & UART_CONFIG_TYPE &&	    imx_request_port(&sport->port) == 0)		sport->port.type = PORT_IMX;}/* * Verify the new serial_struct (for TIOCSSERIAL). * The only change we allow are to the flags and type, and * even then only between PORT_IMX and PORT_UNKNOWN */static intimx_verify_port(struct uart_port *port, struct serial_struct *ser){	struct imx_port *sport = (struct imx_port *)port;	int ret = 0;	if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)		ret = -EINVAL;	if (sport->port.irq != ser->irq)		ret = -EINVAL;	if (ser->io_type != UPIO_MEM)		ret = -EINVAL;	if (sport->port.uartclk / 16 != ser->baud_base)		ret = -EINVAL;	if ((void *)sport->port.mapbase != ser->iomem_base)		ret = -EINVAL;	if (sport->port.iobase != ser->port)		ret = -EINVAL;	if (ser->hub6 != 0)		ret = -EINVAL;	return ret;}static struct uart_ops imx_pops = {	.tx_empty	= imx_tx_empty,	.set_mctrl	= imx_set_mctrl,	.get_mctrl	= imx_get_mctrl,	.stop_tx	= imx_stop_tx,	.start_tx	= imx_start_tx,	.stop_rx	= imx_stop_rx,	.enable_ms	= imx_enable_ms,	.break_ctl	= imx_break_ctl,	.startup	= imx_startup,	.shutdown	= imx_shutdown,	.set_termios	= imx_set_termios,	.type		= imx_type,	.release_port	= imx_release_port,	.request_port	= imx_request_port,	.config_port	= imx_config_port,	.verify_port	= imx_verify_port,};static struct imx_port imx_ports[] = {	{	.txirq  = UART1_MINT_TX,	.rxirq  = UART1_MINT_RX,	.rtsirq = UART1_MINT_RTS,	.port	= {		.type		= PORT_IMX,		.iotype		= UPIO_MEM,		.membase	= (void *)IMX_UART1_BASE,		.mapbase	= IMX_UART1_BASE, /* FIXME */		.irq		= UART1_MINT_RX,		.uartclk	= 16000000,		.fifosize	= 32,		.flags		= UPF_BOOT_AUTOCONF,		.ops		= &imx_pops,		.line		= 0,	},	}, {	.txirq  = UART2_MINT_TX,	.rxirq  = UART2_MINT_RX,	.rtsirq = UART2_MINT_RTS,	.port	= {		.type		= PORT_IMX,		.iotype		= UPIO_MEM,		.membase	= (void *)IMX_UART2_BASE,		.mapbase	= IMX_UART2_BASE, /* FIXME */		.irq		= UART2_MINT_RX,		.uartclk	= 16000000,		.fifosize	= 32,		.flags		= UPF_BOOT_AUTOCONF,		.ops		= &imx_pops,		.line		= 1,	},	}};/* * Setup the IMX serial ports. * Note also that we support "console=ttySMXx" where "x" is either 0 or 1. * Which serial port this ends up being depends on the machine you're * running this kernel on.  I'm not convinced that this is a good idea, * but that's the way it traditionally works. * */static void __init imx_init_ports(void){	static int first = 1;	int i;	if (!first)		return;	first = 0;	for (i = 0; i < ARRAY_SIZE(imx_ports); i++) {		init_timer(&imx_ports[i].timer);		imx_ports[i].timer.function = imx_timeout;		imx_ports[i].timer.data     = (unsigned long)&imx_ports[i];	}}#ifdef CONFIG_SERIAL_IMX_CONSOLEstatic void imx_console_putchar(struct uart_port *port, int ch){	struct imx_port *sport = (struct imx_port *)port;	while (readl(sport->port.membase + UTS) & UTS_TXFULL)		barrier();	writel(ch, sport->port.membase + URTX0);}/* * Interrupts are disabled on entering */static voidimx_console_write(struct console *co, const char *s, unsigned int count){	struct imx_port *sport = &imx_ports[co->index];	unsigned int old_ucr1, old_ucr2;	/*	 *	First, save UCR1/2 and then disable interrupts	 */	old_ucr1 = readl(sport->port.membase + UCR1);	old_ucr2 = readl(sport->port.membase + UCR2);	writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) &		~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),		sport->port.membase + UCR1);	writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);	uart_console_write(&sport->port, s, count, imx_console_putchar);	/*	 *	Finally, wait for transmitter to become empty	 *	and restore UCR1/2	 */	while (!(readl(sport->port.membase + USR2) & USR2_TXDC));	writel(old_ucr1, sport->port.membase + UCR1);	writel(old_ucr2, sport->port.membase + UCR2);}/* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. */static void __initimx_console_get_options(struct imx_port *sport, int *baud,			   int *parity, int *bits){	if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) {		/* ok, the port was enabled */		unsigned int ucr2, ubir,ubmr, uartclk;		unsigned int baud_raw;		unsigned int ucfr_rfdiv;		ucr2 = readl(sport->port.membase + UCR2);		*parity = 'n';		if (ucr2 & UCR2_PREN) {			if (ucr2 & UCR2_PROE)				*parity = 'o';			else				*parity = 'e';		}		if (ucr2 & UCR2_WS)			*bits = 8;		else			*bits = 7;		ubir = readl(sport->port.membase + UBIR) & 0xffff;		ubmr = readl(sport->port.membase + UBMR) & 0xffff;		ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;		if (ucfr_rfdiv == 6)			ucfr_rfdiv = 7;		else			ucfr_rfdiv = 6 - ucfr_rfdiv;		uartclk = imx_get_perclk1();		uartclk /= ucfr_rfdiv;		{	/*			 * The next code provides exact computation of			 *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))			 * without need of float support or long long division,			 * which would be required to prevent 32bit arithmetic overflow			 */			unsigned int mul = ubir + 1;			unsigned int div = 16 * (ubmr + 1);			unsigned int rem = uartclk % div;			baud_raw = (uartclk / div) * mul;			baud_raw += (rem * mul + div / 2) / div;			*baud = (baud_raw + 50) / 100 * 100;		}		if(*baud != baud_raw)			printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",				baud_raw, *baud);	}}static int __initimx_console_setup(struct console *co, char *options){	struct imx_port *sport;	int baud = 9600;	int bits = 8;	int parity = 'n';	int flow = 'n';	/*	 * Check whether an invalid uart number has been specified, and	 * if so, search for the first available port that does have	 * console support.	 */	if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))		co->index = 0;	sport = &imx_ports[co->index];	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	else		imx_console_get_options(sport, &baud, &parity, &bits);	imx_setup_ufcr(sport, 0);	return uart_set_options(&sport->port, co, baud, parity, bits, flow);}static struct uart_driver imx_reg;static struct console imx_console = {	.name		= "ttySMX",	.write		= imx_console_write,	.device		= uart_console_device,	.setup		= imx_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,	.data		= &imx_reg,};static int __init imx_rs_console_init(void){	imx_init_ports();	register_console(&imx_console);	return 0;}console_initcall(imx_rs_console_init);#define IMX_CONSOLE	&imx_console#else#define IMX_CONSOLE	NULL#endifstatic struct uart_driver imx_reg = {	.owner          = THIS_MODULE,	.driver_name    = DRIVER_NAME,	.dev_name       = "ttySMX",	.major          = SERIAL_IMX_MAJOR,	.minor          = MINOR_START,	.nr             = ARRAY_SIZE(imx_ports),	.cons           = IMX_CONSOLE,};static int serial_imx_suspend(struct platform_device *dev, pm_message_t state){        struct imx_port *sport = platform_get_drvdata(dev);        if (sport)                uart_suspend_port(&imx_reg, &sport->port);        return 0;}static int serial_imx_resume(struct platform_device *dev){        struct imx_port *sport = platform_get_drvdata(dev);        if (sport)                uart_resume_port(&imx_reg, &sport->port);        return 0;}static int serial_imx_probe(struct platform_device *dev){	struct imxuart_platform_data *pdata;	imx_ports[dev->id].port.dev = &dev->dev;	pdata = (struct imxuart_platform_data *)dev->dev.platform_data;	if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))		imx_ports[dev->id].have_rtscts = 1;	uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);	platform_set_drvdata(dev, &imx_ports[dev->id]);	return 0;}static int serial_imx_remove(struct platform_device *dev){	struct imx_port *sport = platform_get_drvdata(dev);	platform_set_drvdata(dev, NULL);	if (sport)		uart_remove_one_port(&imx_reg, &sport->port);	return 0;}static struct platform_driver serial_imx_driver = {        .probe          = serial_imx_probe,        .remove         = serial_imx_remove,	.suspend	= serial_imx_suspend,	.resume		= serial_imx_resume,	.driver		= {	        .name	= "imx-uart",	},};static int __init imx_serial_init(void){	int ret;	printk(KERN_INFO "Serial: IMX driver\n");	imx_init_ports();	ret = uart_register_driver(&imx_reg);	if (ret)		return ret;	ret = platform_driver_register(&serial_imx_driver);	if (ret != 0)		uart_unregister_driver(&imx_reg);	return 0;}static void __exit imx_serial_exit(void){	platform_driver_unregister(&serial_imx_driver);	uart_unregister_driver(&imx_reg);}module_init(imx_serial_init);module_exit(imx_serial_exit);MODULE_AUTHOR("Sascha Hauer");MODULE_DESCRIPTION("IMX generic serial port driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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