diff options
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 154 |
1 files changed, 63 insertions, 91 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 6ee59001d61..61477567423 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -99,12 +99,6 @@ struct sci_port { #endif struct notifier_block freq_transition; - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE - unsigned short saved_smr; - unsigned short saved_fcr; - unsigned char saved_brr; -#endif }; /* Function prototypes */ @@ -202,9 +196,9 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x60, 8 }, [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, + [SCFDR] = sci_reg_invalid, + [SCTFDR] = { 0x38, 16 }, + [SCRFDR] = { 0x3c, 16 }, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, }, @@ -491,7 +485,7 @@ static int sci_txfill(struct uart_port *port) reg = sci_getreg(port, SCTFDR); if (reg->size) - return serial_port_in(port, SCTFDR) & 0xff; + return serial_port_in(port, SCTFDR) & ((port->fifosize << 1) - 1); reg = sci_getreg(port, SCFDR); if (reg->size) @@ -511,7 +505,7 @@ static int sci_rxfill(struct uart_port *port) reg = sci_getreg(port, SCRFDR); if (reg->size) - return serial_port_in(port, SCRFDR) & 0xff; + return serial_port_in(port, SCRFDR) & ((port->fifosize << 1) - 1); reg = sci_getreg(port, SCFDR); if (reg->size) @@ -1132,7 +1126,7 @@ static const char *sci_gpio_str(unsigned int index) return sci_gpio_names[index]; } -static void __devinit sci_init_gpios(struct sci_port *port) +static void sci_init_gpios(struct sci_port *port) { struct uart_port *up = &port->port; int i; @@ -1749,22 +1743,21 @@ static inline void sci_free_dma(struct uart_port *port) static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + unsigned long flags; int ret; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - pm_runtime_put_noidle(port->dev); - - sci_port_enable(s); - ret = sci_request_irq(s); if (unlikely(ret < 0)) return ret; sci_request_dma(port); + spin_lock_irqsave(&port->lock, flags); sci_start_tx(port); sci_start_rx(port); + spin_unlock_irqrestore(&port->lock, flags); return 0; } @@ -1772,18 +1765,17 @@ static int sci_startup(struct uart_port *port) static void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + unsigned long flags; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); sci_free_dma(port); sci_free_irq(s); - - sci_port_disable(s); - - pm_runtime_get_noresume(port->dev); } static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, @@ -1829,7 +1821,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, { struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; - unsigned int baud, smr_val, max_baud; + unsigned int baud, smr_val, max_baud, cks; int t = -1; /* @@ -1863,21 +1855,18 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); - serial_port_out(port, SCSMR, smr_val); - - dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, - s->cfg->scscr); + for (cks = 0; t >= 256 && cks <= 3; cks++) + t >>= 2; - if (t > 0) { - if (t >= 256) { - serial_port_out(port, SCSMR, (serial_port_in(port, SCSMR) & ~3) | 1); - t >>= 2; - } else - serial_port_out(port, SCSMR, serial_port_in(port, SCSMR) & ~3); + dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n", + __func__, smr_val, cks, t, s->cfg->scscr); + if (t >= 0) { + serial_port_out(port, SCSMR, (smr_val & ~3) | cks); serial_port_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ - } + } else + serial_port_out(port, SCSMR, smr_val); sci_init_pins(port, termios->c_cflag); @@ -1932,6 +1921,21 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_port_disable(s); } +static void sci_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct sci_port *sci_port = to_sci_port(port); + + switch (state) { + case 3: + sci_port_disable(sci_port); + break; + default: + sci_port_enable(sci_port); + break; + } +} + static const char *sci_type(struct uart_port *port) { switch (port->type) { @@ -2053,6 +2057,7 @@ static struct uart_ops sci_uart_ops = { .startup = sci_startup, .shutdown = sci_shutdown, .set_termios = sci_set_termios, + .pm = sci_pm, .type = sci_type, .release_port = sci_release_port, .request_port = sci_request_port, @@ -2064,7 +2069,7 @@ static struct uart_ops sci_uart_ops = { #endif }; -static int __devinit sci_init_single(struct platform_device *dev, +static int sci_init_single(struct platform_device *dev, struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p) @@ -2121,8 +2126,6 @@ static int __devinit sci_init_single(struct platform_device *dev, sci_init_gpios(sci_port); - pm_runtime_irq_safe(&dev->dev); - pm_runtime_get_noresume(&dev->dev); pm_runtime_enable(&dev->dev); } @@ -2206,9 +2209,21 @@ static void serial_console_write(struct console *co, const char *s, { struct sci_port *sci_port = &sci_ports[co->index]; struct uart_port *port = &sci_port->port; - unsigned short bits; + unsigned short bits, ctrl; + unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&port->lock); + else + spin_lock(&port->lock); - sci_port_enable(sci_port); + /* first save the SCSCR then disable the interrupts */ + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, sci_port->cfg->scscr); uart_console_write(port, s, count, serial_console_putchar); @@ -2217,10 +2232,15 @@ static void serial_console_write(struct console *co, const char *s, while ((serial_port_in(port, SCxSR) & bits) != bits) cpu_relax(); - sci_port_disable(sci_port); + /* restore the SCSCR */ + serial_port_out(port, SCSCR, ctrl); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); } -static int __devinit serial_console_setup(struct console *co, char *options) +static int serial_console_setup(struct console *co, char *options) { struct sci_port *sci_port; struct uart_port *port; @@ -2249,13 +2269,9 @@ static int __devinit serial_console_setup(struct console *co, char *options) if (unlikely(ret != 0)) return ret; - sci_port_enable(sci_port); - if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - sci_port_disable(sci_port); - return uart_set_options(port, co, baud, parity, bits, flow); } @@ -2278,7 +2294,7 @@ static struct console early_serial_console = { static char early_serial_buf[32]; -static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +static int sci_probe_earlyprintk(struct platform_device *pdev) { struct plat_sci_port *cfg = pdev->dev.platform_data; @@ -2298,57 +2314,15 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) return 0; } -#define uart_console(port) ((port)->cons->index == (port)->line) - -static int sci_runtime_suspend(struct device *dev) -{ - struct sci_port *sci_port = dev_get_drvdata(dev); - struct uart_port *port = &sci_port->port; - - if (uart_console(port)) { - struct plat_sci_reg *reg; - - sci_port->saved_smr = serial_port_in(port, SCSMR); - sci_port->saved_brr = serial_port_in(port, SCBRR); - - reg = sci_getreg(port, SCFCR); - if (reg->size) - sci_port->saved_fcr = serial_port_in(port, SCFCR); - else - sci_port->saved_fcr = 0; - } - return 0; -} - -static int sci_runtime_resume(struct device *dev) -{ - struct sci_port *sci_port = dev_get_drvdata(dev); - struct uart_port *port = &sci_port->port; - - if (uart_console(port)) { - sci_reset(port); - serial_port_out(port, SCSMR, sci_port->saved_smr); - serial_port_out(port, SCBRR, sci_port->saved_brr); - - if (sci_port->saved_fcr) - serial_port_out(port, SCFCR, sci_port->saved_fcr); - - serial_port_out(port, SCSCR, sci_port->cfg->scscr); - } - return 0; -} - #define SCI_CONSOLE (&serial_console) #else -static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +static inline int sci_probe_earlyprintk(struct platform_device *pdev) { return -EINVAL; } #define SCI_CONSOLE NULL -#define sci_runtime_suspend NULL -#define sci_runtime_resume NULL #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -2379,7 +2353,7 @@ static int sci_remove(struct platform_device *dev) return 0; } -static int __devinit sci_probe_single(struct platform_device *dev, +static int sci_probe_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p, struct sci_port *sciport) @@ -2409,7 +2383,7 @@ static int __devinit sci_probe_single(struct platform_device *dev, return 0; } -static int __devinit sci_probe(struct platform_device *dev) +static int sci_probe(struct platform_device *dev) { struct plat_sci_port *p = dev->dev.platform_data; struct sci_port *sp = &sci_ports[dev->id]; @@ -2466,8 +2440,6 @@ static int sci_resume(struct device *dev) } static const struct dev_pm_ops sci_dev_pm_ops = { - .runtime_suspend = sci_runtime_suspend, - .runtime_resume = sci_runtime_resume, .suspend = sci_suspend, .resume = sci_resume, }; |