📄 pmac_zilog.c
字号:
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 + -