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

📄 pmac_zilog.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	uap->curregs[R5] &= ~SND_BRK;	pmz_maybe_update_regs(uap);	/* Shut the chip down */	pmz_set_scc_power(uap, 0);	spin_unlock_irqrestore(&port->lock, flags);	up(&pmz_irq_sem);	pmz_debug("pmz: shutdown() done.\n");}/* Shared by TTY driver and serial console setup.  The port lock is held * and local interrupts are disabled. */static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,			      unsigned int iflag, unsigned long baud){	int brg;	/* Switch to external clocking for IrDA high clock rates. That	 * code could be re-used for Midi interfaces with different	 * multipliers	 */	if (baud >= 115200 && ZS_IS_IRDA(uap)) {		uap->curregs[R4] = X1CLK;		uap->curregs[R11] = RCTRxCP | TCTRxCP;		uap->curregs[R14] = 0; /* BRG off */		uap->curregs[R12] = 0;		uap->curregs[R13] = 0;		uap->flags |= PMACZILOG_FLAG_IS_EXTCLK;	} else {		switch (baud) {		case ZS_CLOCK/16:	/* 230400 */			uap->curregs[R4] = X16CLK;			uap->curregs[R11] = 0;			uap->curregs[R14] = 0;			break;		case ZS_CLOCK/32:	/* 115200 */			uap->curregs[R4] = X32CLK;			uap->curregs[R11] = 0;			uap->curregs[R14] = 0;			break;		default:			uap->curregs[R4] = X16CLK;			uap->curregs[R11] = TCBR | RCBR;			brg = BPS_TO_BRG(baud, ZS_CLOCK / 16);			uap->curregs[R12] = (brg & 255);			uap->curregs[R13] = ((brg >> 8) & 255);			uap->curregs[R14] = BRENAB;		}		uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK;	}	/* Character size, stop bits, and parity. */	uap->curregs[3] &= ~RxN_MASK;	uap->curregs[5] &= ~TxN_MASK;	switch (cflag & CSIZE) {	case CS5:		uap->curregs[3] |= Rx5;		uap->curregs[5] |= Tx5;		uap->parity_mask = 0x1f;		break;	case CS6:		uap->curregs[3] |= Rx6;		uap->curregs[5] |= Tx6;		uap->parity_mask = 0x3f;		break;	case CS7:		uap->curregs[3] |= Rx7;		uap->curregs[5] |= Tx7;		uap->parity_mask = 0x7f;		break;	case CS8:	default:		uap->curregs[3] |= Rx8;		uap->curregs[5] |= Tx8;		uap->parity_mask = 0xff;		break;	};	uap->curregs[4] &= ~(SB_MASK);	if (cflag & CSTOPB)		uap->curregs[4] |= SB2;	else		uap->curregs[4] |= SB1;	if (cflag & PARENB)		uap->curregs[4] |= PAR_ENAB;	else		uap->curregs[4] &= ~PAR_ENAB;	if (!(cflag & PARODD))		uap->curregs[4] |= PAR_EVEN;	else		uap->curregs[4] &= ~PAR_EVEN;	uap->port.read_status_mask = Rx_OVR;	if (iflag & INPCK)		uap->port.read_status_mask |= CRC_ERR | PAR_ERR;	if (iflag & (BRKINT | PARMRK))		uap->port.read_status_mask |= BRK_ABRT;	uap->port.ignore_status_mask = 0;	if (iflag & IGNPAR)		uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR;	if (iflag & IGNBRK) {		uap->port.ignore_status_mask |= BRK_ABRT;		if (iflag & IGNPAR)			uap->port.ignore_status_mask |= Rx_OVR;	}	if ((cflag & CREAD) == 0)		uap->port.ignore_status_mask = 0xff;}/* * Set the irda codec on the imac to the specified baud rate. */static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud){	u8 cmdbyte;	int t, version;	switch (*baud) {	/* SIR modes */	case 2400:		cmdbyte = 0x53;		break;	case 4800:		cmdbyte = 0x52;		break;	case 9600:		cmdbyte = 0x51;		break;	case 19200:		cmdbyte = 0x50;		break;	case 38400:		cmdbyte = 0x4f;		break;	case 57600:		cmdbyte = 0x4e;		break;	case 115200:		cmdbyte = 0x4d;		break;	/* The FIR modes aren't really supported at this point, how	 * do we select the speed ? via the FCR on KeyLargo ?	 */	case 1152000:		cmdbyte = 0;		break;	case 4000000:		cmdbyte = 0;		break;	default: /* 9600 */		cmdbyte = 0x51;		*baud = 9600;		break;	}	/* Wait for transmitter to drain */	t = 10000;	while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0	       || (read_zsreg(uap, R1) & ALL_SNT) == 0) {		if (--t <= 0) {			dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n");			return;		}		udelay(10);	}	/* Drain the receiver too */	t = 100;	(void)read_zsdata(uap);	(void)read_zsdata(uap);	(void)read_zsdata(uap);	mdelay(10);	while (read_zsreg(uap, R0) & Rx_CH_AV) {		read_zsdata(uap);		mdelay(10);		if (--t <= 0) {			dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n");			return;		}	}	/* Switch to command mode */	uap->curregs[R5] |= DTR;	write_zsreg(uap, R5, uap->curregs[R5]);	zssync(uap);       	mdelay(1);	/* Switch SCC to 19200 */	pmz_convert_to_zs(uap, CS8, 0, 19200);			pmz_load_zsregs(uap, uap->curregs);       	mdelay(1);	/* Write get_version command byte */	write_zsdata(uap, 1);	t = 5000;	while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {		if (--t <= 0) {			dev_err(&uap->dev->ofdev.dev,				"irda_setup timed out on get_version byte\n");			goto out;		}		udelay(10);	}	version = read_zsdata(uap);	if (version < 4) {		dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n",			 version);		goto out;	}	/* Send speed mode */	write_zsdata(uap, cmdbyte);	t = 5000;	while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {		if (--t <= 0) {			dev_err(&uap->dev->ofdev.dev,				"irda_setup timed out on speed mode byte\n");			goto out;		}		udelay(10);	}	t = read_zsdata(uap);	if (t != cmdbyte)		dev_err(&uap->dev->ofdev.dev,			"irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);	dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n",		 *baud, version);	(void)read_zsdata(uap);	(void)read_zsdata(uap);	(void)read_zsdata(uap); out:	/* Switch back to data mode */	uap->curregs[R5] &= ~DTR;	write_zsreg(uap, R5, uap->curregs[R5]);	zssync(uap);	(void)read_zsdata(uap);	(void)read_zsdata(uap);	(void)read_zsdata(uap);}static void __pmz_set_termios(struct uart_port *port, struct termios *termios,			      struct termios *old){	struct uart_pmac_port *uap = to_pmz(port);	unsigned long baud;	pmz_debug("pmz: set_termios()\n");	if (ZS_IS_ASLEEP(uap))		return;	memcpy(&uap->termios_cache, termios, sizeof(struct termios));	/* XXX Check which revs of machines actually allow 1 and 4Mb speeds	 * on the IR dongle. Note that the IRTTY driver currently doesn't know	 * about the FIR mode and high speed modes. So these are unused. For	 * implementing proper support for these, we should probably add some	 * DMA as well, at least on the Rx side, which isn't a simple thing	 * at this point.	 */	if (ZS_IS_IRDA(uap)) {		/* Calc baud rate */		baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);		pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);		/* Cet the irda codec to the right rate */		pmz_irda_setup(uap, &baud);		/* Set final baud rate */		pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);		pmz_load_zsregs(uap, uap->curregs);		zssync(uap);	} else {		baud = uart_get_baud_rate(port, termios, old, 1200, 230400);		pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);		/* Make sure modem status interrupts are correctly configured */		if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {			uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;			uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;		} else {			uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);			uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;		}		/* Load registers to the chip */		pmz_maybe_update_regs(uap);	}	pmz_debug("pmz: set_termios() done.\n");}/* The port lock is not held.  */static void pmz_set_termios(struct uart_port *port, struct termios *termios,			    struct termios *old){	struct uart_pmac_port *uap = to_pmz(port);	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);		/* Disable IRQs on the port */	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);	write_zsreg(uap, R1, uap->curregs[R1]);	/* Setup new port configuration */	__pmz_set_termios(port, termios, old);	/* Re-enable IRQs on the port */	if (ZS_IS_OPEN(uap)) {		uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;		if (!ZS_IS_EXTCLK(uap))			uap->curregs[R1] |= EXT_INT_ENAB;		write_zsreg(uap, R1, uap->curregs[R1]);	}	spin_unlock_irqrestore(&port->lock, flags);}static const char *pmz_type(struct uart_port *port){	struct uart_pmac_port *uap = to_pmz(port);	if (ZS_IS_IRDA(uap))		return "Z85c30 ESCC - Infrared port";	else if (ZS_IS_INTMODEM(uap))		return "Z85c30 ESCC - Internal modem";	return "Z85c30 ESCC - Serial port";}/* We do not request/release mappings of the registers here, this * happens at early serial probe time. */static void pmz_release_port(struct uart_port *port){}static int pmz_request_port(struct uart_port *port){	return 0;}/* These do not need to do anything interesting either.  */static void pmz_config_port(struct uart_port *port, int flags){}/* We do not support letting the user mess with the divisor, IRQ, etc. */static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser){	return -EINVAL;}static struct uart_ops pmz_pops = {	.tx_empty	=	pmz_tx_empty,	.set_mctrl	=	pmz_set_mctrl,	.get_mctrl	=	pmz_get_mctrl,	.stop_tx	=	pmz_stop_tx,	.start_tx	=	pmz_start_tx,	.stop_rx	=	pmz_stop_rx,	.enable_ms	=	pmz_enable_ms,	.break_ctl	=	pmz_break_ctl,	.startup	=	pmz_startup,	.shutdown	=	pmz_shutdown,	.set_termios	=	pmz_set_termios,	.type		=	pmz_type,	.release_port	=	pmz_release_port,	.request_port	=	pmz_request_port,	.config_port	=	pmz_config_port,	.verify_port	=	pmz_verify_port,};/* * Setup one port structure after probing, HW is down at this point, * Unlike sunzilog, we don't need to pre-init the spinlock as we don't * register our console before uart_add_one_port() is called */static int __init pmz_init_port(struct uart_pmac_port *uap){	struct device_node *np = uap->node;	char *conn;	struct slot_names_prop {		int	count;		char	name[1];	} *slots;	int len;	/*	 * Request & map chip registers	 */	uap->port.mapbase = np->addrs[0].address;	uap->port.membase = ioremap(uap->port.mapbase, 0x1000);      	uap->control_reg = (volatile u8 *)uap->port.membase;	uap->data_reg = uap->control_reg + 0x10;		/*	 * Request & map DBDMA registers	 */#ifdef HAS_DBDMA	if (np->n_addrs >= 3 && np->n_intrs >= 3)		uap->flags |= PMACZILOG_FLAG_HAS_DMA;#endif		if (ZS_HAS_DMA(uap)) {		uap->tx_dma_regs = (volatile struct dbdma_regs *)			ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);		if (uap->tx_dma_regs == NULL) {				uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;			goto no_dma;		}		uap->rx_dma_regs = (volatile struct dbdma_regs *)			ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);		if (uap->rx_dma_regs == NULL) {				iounmap((void *)uap->tx_dma_regs);			uap->tx_dma_regs = NULL;			uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;			goto no_dma;		}		uap->tx_dma_irq = np->intrs[1].line;		uap->rx_dma_irq = np->intrs[2].line;	}no_dma:	/*	 * Detect port type	 */	if (device_is_compatible(np, "cobalt"))		uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;	conn = get_property(np, "AAPL,connector", &len);	if (conn && (strcmp(conn, "infrared") == 0))		uap->flags |= PMACZILOG_FLAG_IS_IRDA;	uap->port_type = PMAC_SCC_ASYNC;	/* 1999 Powerbook G3 has slot-names property instead */	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);	if (slots && slots->count > 0) {		if (strcmp(slots->name, "IrDA") == 0)			uap->flags |= PMACZILOG_FLAG_IS_IRDA;		else if (strcmp(slots->name, "Modem") == 0)			uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;	}	if (ZS_IS_IRDA(uap))		uap->port_type = PMAC_SCC_IRDA;	if (ZS_IS_INTMODEM(uap)) {		struct device_node* i2c_modem = find_devices("i2c-modem");		if (i2c_modem) {			char* mid = get_property(i2c_modem, "modem-id", NULL);			if (mid) switch(*mid) {			case 0x04 :			case 0x05 :			case 0x07 :			case 0x08 :			case 0x0b :			case 0x0c :				uap->port_type = PMAC_SCC_I2S1;			}			printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",				mid ? (*mid) : 0);		} else {			printk(KERN_INFO "pmac_zilog: serial modem detected\n");		}	}	/*	 * Init remaining bits of "port" structure	 */	uap->port.iotype = SERIAL_IO_MEM;	uap->port.irq = np->intrs[0].line;	uap->port.uartclk = ZS_CLOCK;	uap->port.fifosize = 1;	uap->port.ops = &pmz_pops;	uap->port.type = PORT_PMAC_ZILOG;	uap->port.flags = 0;	/* Setup some valid baud rate information in the register	 * shadows so we don't write crap there before baud rate is	 * first initialized.	 */	pmz_convert_to_zs(uap, CS8, 0, 9600);	return 0;}/* * Get rid of a port on module removal */static void pmz_dispose_port(struct uart_pmac_port *uap){	struct device_node *np;	np = uap->node;	iounmap((void *)uap->rx_dma_regs);	iounmap((void *)uap->tx_dma_regs);	iounmap((void *)uap->control_reg);	uap->node = NULL;	of_node_put(np);	memset(uap, 0, sizeof(struct uart_pmac_port));}

⌨️ 快捷键说明

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