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 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,  }; |