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"; }
/* * 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; }
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"); }
/* * 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]); } }
/* * 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); }
/* * 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; }
/* * 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; }
/* 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; }
/* * 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; }