summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/sh-sci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r--drivers/tty/serial/sh-sci.c154
1 files changed, 63 insertions, 91 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 6ee59001d61d..61477567423f 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,
};