diff options
author | Paul Mundt <lethal@linux-sh.org> | 2012-01-09 02:12:55 (GMT) |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2012-01-09 02:12:55 (GMT) |
commit | ca371d2854d48c0c22e7aa031df182f96dc85820 (patch) | |
tree | 1c62be8b4da0bfc82fa7ffa1ad5b0e958266cbd1 /drivers/tty/serial | |
parent | 0d376945d0bc0a8f8e00861d506b10e42e8af372 (diff) | |
parent | a0e86bd4252519321b0d102dc4ed90557aa7bee9 (diff) | |
download | linux-fsl-qoriq-ca371d2854d48c0c22e7aa031df182f96dc85820.tar.xz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into sh-latest
Conflicts:
arch/arm/mach-shmobile/clock-sh73a0.c
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r-- | drivers/tty/serial/Kconfig | 2 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl010.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/pmac_zilog.c | 423 | ||||
-rw-r--r-- | drivers/tty/serial/pmac_zilog.h | 19 | ||||
-rw-r--r-- | drivers/tty/serial/ucc_uart.c | 3 |
6 files changed, 149 insertions, 302 deletions
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 925a1e5..95b21a6 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -808,7 +808,7 @@ config BFIN_UART3_CTSRTS config SERIAL_IMX bool "IMX serial port support" - depends on ARM && (ARCH_IMX || ARCH_MXC) + depends on ARCH_MXC select SERIAL_CORE select RATIONAL help diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index efdf92c..0d91a54 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -795,6 +795,8 @@ static struct amba_id pl010_ids[] = { { 0, 0 }, }; +MODULE_DEVICE_TABLE(amba, pl010_ids); + static struct amba_driver pl010_driver = { .drv = { .name = "uart-pl010", diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 00233af..6958594 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1994,6 +1994,8 @@ static struct amba_id pl011_ids[] = { { 0, 0 }, }; +MODULE_DEVICE_TABLE(amba, pl011_ids); + static struct amba_driver pl011_driver = { .drv = { .name = "uart-pl011", diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 5acd24a..e9c2dfe4 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -99,6 +99,9 @@ MODULE_LICENSE("GPL"); #define PMACZILOG_NAME "ttyPZ" #endif +#define pmz_debug(fmt, arg...) pr_debug("ttyPZ%d: " fmt, uap->port.line, ## arg) +#define pmz_error(fmt, arg...) pr_err("ttyPZ%d: " fmt, uap->port.line, ## arg) +#define pmz_info(fmt, arg...) pr_info("ttyPZ%d: " fmt, uap->port.line, ## arg) /* * For the sake of early serial console, we can do a pre-probe @@ -106,7 +109,6 @@ MODULE_LICENSE("GPL"); */ static struct uart_pmac_port pmz_ports[MAX_ZS_PORTS]; static int pmz_ports_count; -static DEFINE_MUTEX(pmz_irq_mutex); static struct uart_driver pmz_uart_reg = { .owner = THIS_MODULE, @@ -126,9 +128,6 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs) { int i; - if (ZS_IS_ASLEEP(uap)) - return; - /* Let pending transmits finish. */ for (i = 0; i < 1000; i++) { unsigned char stat = read_zsreg(uap, R1); @@ -216,32 +215,24 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap) } } +static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) +{ + if (enable) { + uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[1] |= EXT_INT_ENAB; + } else { + uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + } + write_zsreg(uap, R1, uap->curregs[1]); +} + static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) { struct tty_struct *tty = NULL; unsigned char ch, r1, drop, error, flag; int loops = 0; - /* The interrupt can be enabled when the port isn't open, typically - * that happens when using one port is open and the other closed (stale - * interrupt) or when one port is used as a console. - */ - if (!ZS_IS_OPEN(uap)) { - pmz_debug("pmz: draining input\n"); - /* Port is closed, drain input data */ - for (;;) { - if ((++loops) > 1000) - goto flood; - (void)read_zsreg(uap, R1); - write_zsreg(uap, R0, ERR_RES); - (void)read_zsdata(uap); - ch = read_zsreg(uap, R0); - if (!(ch & Rx_CH_AV)) - break; - } - return NULL; - } - /* Sanity check, make sure the old bug is no longer happening */ if (uap->port.state == NULL || uap->port.state->port.tty == NULL) { WARN_ON(1); @@ -339,9 +330,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) return tty; flood: - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - write_zsreg(uap, R1, uap->curregs[R1]); - zssync(uap); + pmz_interrupt_control(uap, 0); pmz_error("pmz: rx irq flood !\n"); return tty; } @@ -383,8 +372,6 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) { struct circ_buf *xmit; - if (ZS_IS_ASLEEP(uap)) - return; if (ZS_IS_CONS(uap)) { unsigned char status = read_zsreg(uap, R0); @@ -481,6 +468,10 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) /* Channel A */ tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + if (!ZS_IS_OPEN(uap_a)) { + pmz_debug("ChanA interrupt while open !\n"); + goto skip_a; + } write_zsreg(uap_a, R0, RES_H_IUS); zssync(uap_a); if (r3 & CHAEXT) @@ -491,16 +482,21 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) pmz_transmit_chars(uap_a); rc = IRQ_HANDLED; } + skip_a: spin_unlock(&uap_a->port.lock); if (tty != NULL) tty_flip_buffer_push(tty); - if (uap_b->node == NULL) + if (!uap_b) goto out; spin_lock(&uap_b->port.lock); tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + if (!ZS_IS_OPEN(uap_a)) { + pmz_debug("ChanB interrupt while open !\n"); + goto skip_b; + } write_zsreg(uap_b, R0, RES_H_IUS); zssync(uap_b); if (r3 & CHBEXT) @@ -511,14 +507,12 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) pmz_transmit_chars(uap_b); rc = IRQ_HANDLED; } + skip_b: spin_unlock(&uap_b->port.lock); if (tty != NULL) tty_flip_buffer_push(tty); out: -#ifdef DEBUG_HARD - pmz_debug("irq done.\n"); -#endif return rc; } @@ -543,12 +537,8 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap) */ static unsigned int pmz_tx_empty(struct uart_port *port) { - struct uart_pmac_port *uap = to_pmz(port); unsigned char status; - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return TIOCSER_TEMT; - status = pmz_peek_status(to_pmz(port)); if (status & Tx_BUF_EMP) return TIOCSER_TEMT; @@ -570,8 +560,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) 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))) + if (!(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap))) return; set_bits = clear_bits = 0; @@ -590,8 +579,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) /* 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]); @@ -609,9 +597,6 @@ static unsigned int pmz_get_mctrl(struct uart_port *port) unsigned char status; unsigned int ret; - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return 0; - status = read_zsreg(uap, R0); ret = 0; @@ -649,9 +634,6 @@ static void pmz_start_tx(struct uart_port *port) uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return; - status = read_zsreg(uap, R0); /* TX busy? Just wait for the TX done interrupt. */ @@ -690,9 +672,6 @@ static void pmz_stop_rx(struct uart_port *port) { struct uart_pmac_port *uap = to_pmz(port); - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return; - pmz_debug("pmz: stop_rx()()\n"); /* Disable all RX interrupts. */ @@ -711,14 +690,12 @@ 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) + if (ZS_IS_IRDA(uap)) 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]); } @@ -734,8 +711,6 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) unsigned char set_bits, clear_bits, new_reg; unsigned long flags; - if (uap->node == NULL) - return; set_bits = clear_bits = 0; if (break_state) @@ -748,12 +723,6 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != uap->curregs[R5]) { uap->curregs[R5] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - if (ZS_IS_ASLEEP(uap)) { - spin_unlock_irqrestore(&port->lock, flags); - return; - } write_zsreg(uap, R5, uap->curregs[R5]); } @@ -927,14 +896,21 @@ static int __pmz_startup(struct uart_pmac_port *uap) static void pmz_irda_reset(struct uart_pmac_port *uap) { + unsigned long flags; + + spin_lock_irqsave(&uap->port.lock, flags); uap->curregs[R5] |= DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - mdelay(110); + spin_unlock_irqrestore(&uap->port.lock, flags); + msleep(110); + + spin_lock_irqsave(&uap->port.lock, flags); uap->curregs[R5] &= ~DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - mdelay(10); + spin_unlock_irqrestore(&uap->port.lock, flags); + msleep(10); } /* @@ -949,13 +925,6 @@ static int pmz_startup(struct uart_port *port) 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 @@ -966,18 +935,14 @@ static int pmz_startup(struct uart_port *port) pwr_delay = __pmz_startup(uap); spin_unlock_irqrestore(&port->lock, flags); } - - pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; + sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line); if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, - "SCC", uap)) { + uap->irq_name, uap)) { pmz_error("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 */ @@ -990,12 +955,9 @@ static int pmz_startup(struct uart_port *port) if (ZS_IS_IRDA(uap)) pmz_irda_reset(uap); - /* Enable interrupts emission from the chip */ + /* Enable interrupt requests for the channel */ 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]); + pmz_interrupt_control(uap, 1); spin_unlock_irqrestore(&port->lock, flags); pmz_debug("pmz: startup() done.\n"); @@ -1010,49 +972,35 @@ static void pmz_shutdown(struct uart_port *port) pmz_debug("pmz: shutdown()\n"); - if (uap->node == NULL) - return; - - mutex_lock(&pmz_irq_mutex); - - /* Release interrupt handler */ - free_irq(uap->port.irq, uap); - spin_lock_irqsave(&port->lock, flags); - uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; + /* Disable interrupt requests for the channel */ + pmz_interrupt_control(uap, 0); - if (!ZS_IS_OPEN(uap->mate)) - pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; + if (!ZS_IS_CONS(uap)) { + /* Disable receiver and transmitter */ + uap->curregs[R3] &= ~RxENABLE; + uap->curregs[R5] &= ~TxENABLE; - /* Disable interrupts */ - if (!ZS_IS_ASLEEP(uap)) { - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - write_zsreg(uap, R1, uap->curregs[R1]); - zssync(uap); + /* Disable break assertion */ + uap->curregs[R5] &= ~SND_BRK; + pmz_maybe_update_regs(uap); } - if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) { - spin_unlock_irqrestore(&port->lock, flags); - mutex_unlock(&pmz_irq_mutex); - return; - } + spin_unlock_irqrestore(&port->lock, flags); + + /* Release interrupt handler */ + free_irq(uap->port.irq, uap); - /* Disable receiver and transmitter. */ - uap->curregs[R3] &= ~RxENABLE; - uap->curregs[R5] &= ~TxENABLE; + spin_lock_irqsave(&port->lock, flags); - /* Disable all interrupts and BRK assertion. */ - uap->curregs[R5] &= ~SND_BRK; - pmz_maybe_update_regs(uap); + uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; - /* Shut the chip down */ - pmz_set_scc_power(uap, 0); + if (!ZS_IS_CONS(uap)) + pmz_set_scc_power(uap, 0); /* Shut the chip down */ spin_unlock_irqrestore(&port->lock, flags); - mutex_unlock(&pmz_irq_mutex); - pmz_debug("pmz: shutdown() done.\n"); } @@ -1300,9 +1248,6 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, 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 @@ -1352,19 +1297,15 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, 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]); + pmz_interrupt_control(uap, 0); /* 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]); - } + if (ZS_IS_OPEN(uap)) + pmz_interrupt_control(uap, 1); + spin_unlock_irqrestore(&port->lock, flags); } @@ -1604,25 +1545,34 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) */ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) { + struct uart_pmac_port *uap; int i; /* Iterate the pmz_ports array to find a matching entry */ for (i = 0; i < MAX_ZS_PORTS; i++) - if (pmz_ports[i].node == mdev->ofdev.dev.of_node) { - struct uart_pmac_port *uap = &pmz_ports[i]; - - uap->dev = mdev; - dev_set_drvdata(&mdev->ofdev.dev, uap); - if (macio_request_resources(uap->dev, "pmac_zilog")) - printk(KERN_WARNING "%s: Failed to request resource" - ", port still active\n", - uap->node->name); - else - uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; - return 0; - } - return -ENODEV; + if (pmz_ports[i].node == mdev->ofdev.dev.of_node) + break; + if (i >= MAX_ZS_PORTS) + return -ENODEV; + + + uap = &pmz_ports[i]; + uap->dev = mdev; + uap->port.dev = &mdev->ofdev.dev; + dev_set_drvdata(&mdev->ofdev.dev, uap); + + /* We still activate the port even when failing to request resources + * to work around bugs in ancient Apple device-trees + */ + if (macio_request_resources(uap->dev, "pmac_zilog")) + printk(KERN_WARNING "%s: Failed to request resource" + ", port still active\n", + uap->node->name); + else + uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; + + return uart_add_one_port(&pmz_uart_reg, &uap->port); } /* @@ -1636,12 +1586,15 @@ static int pmz_detach(struct macio_dev *mdev) if (!uap) return -ENODEV; + uart_remove_one_port(&pmz_uart_reg, &uap->port); + if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) { macio_release_resources(uap->dev); uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED; } dev_set_drvdata(&mdev->ofdev.dev, NULL); uap->dev = NULL; + uap->port.dev = NULL; return 0; } @@ -1650,59 +1603,13 @@ static int pmz_detach(struct macio_dev *mdev) static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state; - unsigned long flags; if (uap == NULL) { printk("HRM... pmz_suspend with NULL uap\n"); return 0; } - if (pm_state.event == mdev->ofdev.dev.power.power_state.event) - return 0; - - pmz_debug("suspend, switching to state %d\n", pm_state.event); - - state = pmz_uart_reg.state + uap->port.line; - - mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); - - spin_lock_irqsave(&uap->port.lock, flags); - - if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { - /* Disable receiver and transmitter. */ - uap->curregs[R3] &= ~RxENABLE; - uap->curregs[R5] &= ~TxENABLE; - - /* Disable all interrupts and BRK assertion. */ - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - uap->curregs[R5] &= ~SND_BRK; - pmz_load_zsregs(uap, uap->curregs); - uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; - mb(); - } - - spin_unlock_irqrestore(&uap->port.lock, flags); - - if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate)) - if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { - pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; - disable_irq(uap->port.irq); - } - - if (ZS_IS_CONS(uap)) - uap->port.cons->flags &= ~CON_ENABLED; - - /* Shut the chip down */ - pmz_set_scc_power(uap, 0); - - mutex_unlock(&state->port.mutex); - mutex_unlock(&pmz_irq_mutex); - - pmz_debug("suspend, switching complete\n"); - - mdev->ofdev.dev.power.power_state = pm_state; + uart_suspend_port(&pmz_uart_reg, &uap->port); return 0; } @@ -1711,76 +1618,20 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) static int pmz_resume(struct macio_dev *mdev) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state; - unsigned long flags; - int pwr_delay = 0; if (uap == NULL) return 0; - if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON) - return 0; - - pmz_debug("resume, switching to state 0\n"); - - state = pmz_uart_reg.state + uap->port.line; - - mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); - - spin_lock_irqsave(&uap->port.lock, flags); - if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { - spin_unlock_irqrestore(&uap->port.lock, flags); - goto bail; - } - pwr_delay = __pmz_startup(uap); - - /* Take care of config that may have changed while asleep */ - __pmz_set_termios(&uap->port, &uap->termios_cache, NULL); - - if (ZS_IS_OPEN(uap)) { - /* Enable interrupts */ - 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(&uap->port.lock, flags); - - if (ZS_IS_CONS(uap)) - uap->port.cons->flags |= CON_ENABLED; - - /* Re-enable IRQ on the controller */ - if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { - pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; - enable_irq(uap->port.irq); - } - - bail: - mutex_unlock(&state->port.mutex); - 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); - } - - pmz_debug("resume, switching complete\n"); - - mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; + uart_resume_port(&pmz_uart_reg, &uap->port); return 0; } /* * Probe all ports in the system and build the ports array, we register - * with the serial layer at this point, the macio-type probing is only - * used later to "attach" to the sysfs tree so we get power management - * events + * with the serial layer later, so we get a proper struct device which + * allows the tty to attach properly. This is later than it used to be + * but the tty layer really wants it that way. */ static int __init pmz_probe(void) { @@ -1816,8 +1667,10 @@ static int __init pmz_probe(void) /* * Fill basic fields in the port structures */ - pmz_ports[count].mate = &pmz_ports[count+1]; - pmz_ports[count+1].mate = &pmz_ports[count]; + if (node_b != NULL) { + pmz_ports[count].mate = &pmz_ports[count+1]; + pmz_ports[count+1].mate = &pmz_ports[count]; + } pmz_ports[count].flags = PMACZILOG_FLAG_IS_CHANNEL_A; pmz_ports[count].node = node_a; pmz_ports[count+1].node = node_b; @@ -1855,8 +1708,8 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) struct resource *r_ports; int irq; - r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0); - irq = platform_get_irq(uap->node, 0); + r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(uap->pdev, 0); if (!r_ports || !irq) return -ENODEV; @@ -1885,19 +1738,19 @@ static int __init pmz_probe(void) pmz_ports_count = 0; - pmz_ports[0].mate = &pmz_ports[1]; pmz_ports[0].port.line = 0; pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A; - pmz_ports[0].node = &scc_a_pdev; + pmz_ports[0].pdev = &scc_a_pdev; err = pmz_init_port(&pmz_ports[0]); if (err) return err; pmz_ports_count++; + pmz_ports[0].mate = &pmz_ports[1]; pmz_ports[1].mate = &pmz_ports[0]; pmz_ports[1].port.line = 1; pmz_ports[1].flags = 0; - pmz_ports[1].node = &scc_b_pdev; + pmz_ports[1].pdev = &scc_b_pdev; err = pmz_init_port(&pmz_ports[1]); if (err) return err; @@ -1913,16 +1766,35 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) static int __init pmz_attach(struct platform_device *pdev) { + struct uart_pmac_port *uap; int i; + /* Iterate the pmz_ports array to find a matching entry */ for (i = 0; i < pmz_ports_count; i++) - if (pmz_ports[i].node == pdev) - return 0; - return -ENODEV; + if (pmz_ports[i].pdev == pdev) + break; + if (i >= pmz_ports_count) + return -ENODEV; + + uap = &pmz_ports[i]; + uap->port.dev = &pdev->dev; + platform_set_drvdata(pdev, uap); + + return uart_add_one_port(&pmz_uart_reg, &uap->port); } static int __exit pmz_detach(struct platform_device *pdev) { + struct uart_pmac_port *uap = platform_get_drvdata(pdev); + + if (!uap) + return -ENODEV; + + uart_remove_one_port(&pmz_uart_reg, &uap->port); + + platform_set_drvdata(pdev, NULL); + uap->port.dev = NULL; + return 0; } @@ -1954,38 +1826,13 @@ static struct console pmz_console = { */ static int __init pmz_register(void) { - int i, rc; - pmz_uart_reg.nr = pmz_ports_count; pmz_uart_reg.cons = PMACZILOG_CONSOLE; /* * Register this driver with the serial core */ - rc = uart_register_driver(&pmz_uart_reg); - if (rc) - return rc; - - /* - * Register each port with the serial core - */ - for (i = 0; i < pmz_ports_count; i++) { - struct uart_pmac_port *uport = &pmz_ports[i]; - /* NULL node may happen on wallstreet */ - if (uport->node != NULL) - rc = uart_add_one_port(&pmz_uart_reg, &uport->port); - if (rc) - goto err_out; - } - - return 0; -err_out: - while (i-- > 0) { - struct uart_pmac_port *uport = &pmz_ports[i]; - uart_remove_one_port(&pmz_uart_reg, &uport->port); - } - uart_unregister_driver(&pmz_uart_reg); - return rc; + return uart_register_driver(&pmz_uart_reg); } #ifdef CONFIG_PPC_PMAC @@ -2084,10 +1931,13 @@ static void __exit exit_pmz(void) for (i = 0; i < pmz_ports_count; i++) { struct uart_pmac_port *uport = &pmz_ports[i]; - if (uport->node != NULL) { - uart_remove_one_port(&pmz_uart_reg, &uport->port); +#ifdef CONFIG_PPC_PMAC + if (uport->node != NULL) pmz_dispose_port(uport); - } +#else + if (uport->pdev != NULL) + pmz_dispose_port(uport); +#endif } /* Unregister UART driver */ uart_unregister_driver(&pmz_uart_reg); @@ -2114,8 +1964,6 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c struct uart_pmac_port *uap = &pmz_ports[con->index]; unsigned long flags; - if (ZS_IS_ASLEEP(uap)) - return; spin_lock_irqsave(&uap->port.lock, flags); /* Turn of interrupts and enable the transmitter. */ @@ -2160,8 +2008,13 @@ static int __init pmz_console_setup(struct console *co, char *options) if (co->index >= pmz_ports_count) co->index = 0; uap = &pmz_ports[co->index]; +#ifdef CONFIG_PPC_PMAC if (uap->node == NULL) return -ENODEV; +#else + if (uap->pdev == NULL) + return -ENODEV; +#endif port = &uap->port; /* diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h index cbc34fb..3483242 100644 --- a/drivers/tty/serial/pmac_zilog.h +++ b/drivers/tty/serial/pmac_zilog.h @@ -1,16 +1,6 @@ #ifndef __PMAC_ZILOG_H__ #define __PMAC_ZILOG_H__ -#ifdef CONFIG_PPC_PMAC -#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg) -#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg) -#define pmz_info(fmt, arg...) dev_info(&uap->dev->ofdev.dev, fmt, ## arg) -#else -#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg) -#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg) -#define pmz_info(fmt, arg...) dev_info(&uap->node->dev, fmt, ## arg) -#endif - /* * At most 2 ESCCs with 2 ports each */ @@ -35,7 +25,7 @@ struct uart_pmac_port { */ struct device_node *node; #else - struct platform_device *node; + struct platform_device *pdev; #endif /* Port type as obtained from device tree (IRDA, modem, ...) */ @@ -50,14 +40,11 @@ struct uart_pmac_port { #define PMACZILOG_FLAG_REGS_HELD 0x00000010 #define PMACZILOG_FLAG_TX_STOPPED 0x00000020 #define PMACZILOG_FLAG_TX_ACTIVE 0x00000040 -#define PMACZILOG_FLAG_ENABLED 0x00000080 #define PMACZILOG_FLAG_IS_IRDA 0x00000100 #define PMACZILOG_FLAG_IS_INTMODEM 0x00000200 #define PMACZILOG_FLAG_HAS_DMA 0x00000400 #define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800 -#define PMACZILOG_FLAG_IS_ASLEEP 0x00001000 #define PMACZILOG_FLAG_IS_OPEN 0x00002000 -#define PMACZILOG_FLAG_IS_IRQ_ON 0x00004000 #define PMACZILOG_FLAG_IS_EXTCLK 0x00008000 #define PMACZILOG_FLAG_BREAK 0x00010000 @@ -74,6 +61,8 @@ struct uart_pmac_port { volatile struct dbdma_regs __iomem *rx_dma_regs; #endif + unsigned char irq_name[8]; + struct ktermios termios_cache; }; @@ -388,9 +377,7 @@ static inline void zssync(struct uart_pmac_port *port) #define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA) #define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM) #define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA) -#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP) #define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN) -#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON) #define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK) #endif /* __PMAC_ZILOG_H__ */ diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index cea8918..2ebe606 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -963,6 +963,9 @@ static void qe_uart_set_termios(struct uart_port *port, /* Do we really need a spinlock here? */ spin_lock_irqsave(&port->lock, flags); + /* Update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + out_be16(&uccp->upsmr, upsmr); if (soft_uart) { out_be16(&uccup->supsmr, supsmr); |