Beispiel #1
0
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";
}
Beispiel #2
0
/*
 * Real startup routine, powers up the hardware and sets up
 * the SCC. Returns a delay in ms where you need to wait before
 * actually using the port, this is typically the internal modem
 * powerup delay. This routine expect the lock to be taken.
 */
static int __pmz_startup(struct uart_pmac_port *uap)
{
	int pwr_delay = 0;

	memset(&uap->curregs, 0, sizeof(uap->curregs));

	/* Power up the SCC & underlying hardware (modem/irda) */
	pwr_delay = pmz_set_scc_power(uap, 1);

	/* Nice buggy HW ... */
	pmz_fix_zero_bug_scc(uap);

	/* Reset the channel */
	uap->curregs[R9] = 0;
	write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
	zssync(uap);
	udelay(10);
	write_zsreg(uap, 9, 0);
	zssync(uap);

	/* Clear the interrupt registers */
	write_zsreg(uap, R1, 0);
	write_zsreg(uap, R0, ERR_RES);
	write_zsreg(uap, R0, ERR_RES);
	write_zsreg(uap, R0, RES_H_IUS);
	write_zsreg(uap, R0, RES_H_IUS);

	/* Setup some valid baud rate */
	uap->curregs[R4] = X16CLK | SB1;
	uap->curregs[R3] = Rx8;
	uap->curregs[R5] = Tx8 | RTS;
	if (!ZS_IS_IRDA(uap))
		uap->curregs[R5] |= DTR;
	uap->curregs[R12] = 0;
	uap->curregs[R13] = 0;
	uap->curregs[R14] = BRENAB;

	/* Clear handshaking, enable BREAK interrupts */
	uap->curregs[R15] = BRKIE;

	/* Master interrupt enable */
	uap->curregs[R9] |= NV | MIE;

	pmz_load_zsregs(uap, uap->curregs);

	/* Enable receiver and transmitter.  */
	write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE);
	write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE);

	/* Remember status for DCD/CTS changes */
	uap->prev_status = read_zsreg(uap, R0);


	return pwr_delay;
}
Beispiel #3
0
static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
			      struct ktermios *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 ktermios));

	/* 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);
	}
	uart_update_timeout(port, termios->c_cflag, baud);

	pmz_debug("pmz: set_termios() done.\n");
}
Beispiel #4
0
/* 
 * Enable modem status change interrupts
 * The port lock is held.
 */
static void pmz_enable_ms(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned char new_reg;

	if (ZS_IS_IRDA(uap) || uap->node == NULL)
		return;
	new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
	if (new_reg != uap->curregs[R15]) {
		uap->curregs[R15] = new_reg;

		if (ZS_IS_ASLEEP(uap))
			return;
		/* NOTE: Not subject to 'transmitter active' rule.  */ 
		write_zsreg(uap, R15, uap->curregs[R15]);
	}
}
Beispiel #5
0
/* 
 * Set Modem Control (RTS & DTR) bits
 * The port lock is held and interrupts are disabled.
 * Note: Shall we really filter out RTS on external ports or
 * should that be dealt at higher level only ?
 */
static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned char set_bits, clear_bits;

        /* Do nothing for irda for now... */
	if (ZS_IS_IRDA(uap))
		return;
	/* We get called during boot with a port not up yet */
	if (ZS_IS_ASLEEP(uap) ||
	    !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
		return;

	set_bits = clear_bits = 0;

	if (ZS_IS_INTMODEM(uap)) {
		if (mctrl & TIOCM_RTS)
			set_bits |= RTS;
		else
			clear_bits |= RTS;
	}
	if (mctrl & TIOCM_DTR)
		set_bits |= DTR;
	else
		clear_bits |= DTR;

	/* NOTE: Not subject to 'transmitter active' rule.  */ 
	uap->curregs[R5] |= set_bits;
	uap->curregs[R5] &= ~clear_bits;
	if (ZS_IS_ASLEEP(uap))
		return;
	write_zsreg(uap, R5, uap->curregs[R5]);
	pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
		  set_bits, clear_bits, uap->curregs[R5]);
	zssync(uap);
}
Beispiel #6
0
/*
 * This is the "normal" startup routine, using the above one
 * wrapped with the lock and doing a schedule delay
 */
static int pmz_startup(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned long flags;
	int pwr_delay = 0;

	pmz_debug("pmz: startup()\n");

	if (ZS_IS_ASLEEP(uap))
		return -EAGAIN;
	if (uap->node == NULL)
		return -ENODEV;

	mutex_lock(&pmz_irq_mutex);

	uap->flags |= PMACZILOG_FLAG_IS_OPEN;

	/* A console is never powered down. Else, power up and
	 * initialize the chip
	 */
	if (!ZS_IS_CONS(uap)) {
		spin_lock_irqsave(&port->lock, flags);
		pwr_delay = __pmz_startup(uap);
		spin_unlock_irqrestore(&port->lock, flags);
	}	

	pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
	if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
		dev_err(&uap->dev->ofdev.dev,
			"Unable to register zs interrupt handler.\n");
		pmz_set_scc_power(uap, 0);
		mutex_unlock(&pmz_irq_mutex);
		return -ENXIO;
	}

	mutex_unlock(&pmz_irq_mutex);

	/* Right now, we deal with delay by blocking here, I'll be
	 * smarter later on
	 */
	if (pwr_delay != 0) {
		pmz_debug("pmz: delaying %d ms\n", pwr_delay);
		msleep(pwr_delay);
	}

	/* IrDA reset is done now */
	if (ZS_IS_IRDA(uap))
		pmz_irda_reset(uap);

	/* Enable interrupts emission from the chip */
	spin_lock_irqsave(&port->lock, flags);
	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);

	pmz_debug("pmz: startup() done.\n");

	return 0;
}
Beispiel #7
0
/*
 * 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;
	const char *conn;
	const struct slot_names_prop {
		int	count;
		char	name[1];
	} *slots;
	int len;
	struct resource r_ports, r_rxdma, r_txdma;

	/*
	 * Request & map chip registers
	 */
	if (of_address_to_resource(np, 0, &r_ports))
		return -ENODEV;
	uap->port.mapbase = r_ports.start;
	uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
      
	uap->control_reg = uap->port.membase;
	uap->data_reg = uap->control_reg + 0x10;
	
	/*
	 * Request & map DBDMA registers
	 */
#ifdef HAS_DBDMA
	if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
	    of_address_to_resource(np, 2, &r_rxdma) == 0)
		uap->flags |= PMACZILOG_FLAG_HAS_DMA;
#else
	memset(&r_txdma, 0, sizeof(struct resource));
	memset(&r_rxdma, 0, sizeof(struct resource));
#endif	
	if (ZS_HAS_DMA(uap)) {
		uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
		if (uap->tx_dma_regs == NULL) {	
			uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
			goto no_dma;
		}
		uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
		if (uap->rx_dma_regs == NULL) {	
			iounmap(uap->tx_dma_regs);
			uap->tx_dma_regs = NULL;
			uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
			goto no_dma;
		}
		uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
		uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
	}
no_dma:

	/*
	 * Detect port type
	 */
	if (of_device_is_compatible(np, "cobalt"))
		uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
	conn = of_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 = of_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 =
			of_find_node_by_name(NULL, "i2c-modem");
		if (i2c_modem) {
			const char* mid =
				of_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);
			of_node_put(i2c_modem);
		} else {
			printk(KERN_INFO "pmac_zilog: serial modem detected\n");
		}
	}

	/*
	 * Init remaining bits of "port" structure
	 */
	uap->port.iotype = UPIO_MEM;
	uap->port.irq = irq_of_parse_and_map(np, 0);
	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;
}
Beispiel #8
0
/* 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;
}
Beispiel #9
0
/*
 * 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;
}