📄 pmac_zilog.c
字号:
/* Disable all interrupts and BRK assertion. */ 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); mutex_unlock(&pmz_irq_mutex); 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 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");}/* The port lock is not held. */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 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; 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;}/* * 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -