diff options
Diffstat (limited to 'drivers/tty/serial/samsung.c')
| -rw-r--r-- | drivers/tty/serial/samsung.c | 63 | 
1 files changed, 54 insertions, 9 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 2769a38d15b..074b9194144 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -39,6 +39,7 @@  #include <linux/tty_flip.h>  #include <linux/serial_core.h>  #include <linux/serial.h> +#include <linux/serial_s3c.h>  #include <linux/delay.h>  #include <linux/clk.h>  #include <linux/cpufreq.h> @@ -46,10 +47,9 @@  #include <asm/irq.h> -#include <mach/hardware.h> - -#include <plat/regs-serial.h> +#ifdef CONFIG_SAMSUNG_CLOCK  #include <plat/clock.h> +#endif  #include "samsung.h" @@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)  	/* Clear pending interrupts and mask all interrupts */  	if (s3c24xx_serial_has_interrupt_mask(port)) { +		free_irq(port->irq, ourport); +  		wr_regl(port, S3C64XX_UINTP, 0xf);  		wr_regl(port, S3C64XX_UINTM, 0xf);  	} @@ -505,6 +507,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)  	dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",  	    port->mapbase, port->membase); +	wr_regl(port, S3C64XX_UINTM, 0xf); +  	ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,  			  s3c24xx_serial_portname(port), ourport);  	if (ret) { @@ -894,7 +898,7 @@ console_initcall(s3c24xx_serial_console_init);  #define S3C24XX_SERIAL_CONSOLE NULL  #endif -#ifdef CONFIG_CONSOLE_POLL +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)  static int s3c24xx_serial_get_poll_char(struct uart_port *port);  static void s3c24xx_serial_put_poll_char(struct uart_port *port,  			 unsigned char c); @@ -918,7 +922,7 @@ static struct uart_ops s3c24xx_serial_ops = {  	.request_port	= s3c24xx_serial_request_port,  	.config_port	= s3c24xx_serial_config_port,  	.verify_port	= s3c24xx_serial_verify_port, -#ifdef CONFIG_CONSOLE_POLL +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)  	.poll_get_char = s3c24xx_serial_get_poll_char,  	.poll_put_char = s3c24xx_serial_put_poll_char,  #endif @@ -1179,6 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,  	return 0;  } +#ifdef CONFIG_SAMSUNG_CLOCK  static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,  					  struct device_attribute *attr,  					  char *buf) @@ -1194,7 +1199,7 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,  }  static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); - +#endif  /* Device driver serial port probe */ @@ -1252,9 +1257,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)  	uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);  	platform_set_drvdata(pdev, &ourport->port); +#ifdef CONFIG_SAMSUNG_CLOCK  	ret = device_create_file(&pdev->dev, &dev_attr_clock_source);  	if (ret < 0)  		dev_err(&pdev->dev, "failed to add clock source attr.\n"); +#endif  	ret = s3c24xx_serial_cpufreq_register(ourport);  	if (ret < 0) @@ -1272,7 +1279,9 @@ static int s3c24xx_serial_remove(struct platform_device *dev)  	if (port) {  		s3c24xx_serial_cpufreq_deregister(to_ourport(port)); +#ifdef CONFIG_SAMSUNG_CLOCK  		device_remove_file(&dev->dev, &dev_attr_clock_source); +#endif  		uart_remove_one_port(&s3c24xx_uart_drv, port);  	} @@ -1307,9 +1316,29 @@ static int s3c24xx_serial_resume(struct device *dev)  	return 0;  } +static int s3c24xx_serial_resume_noirq(struct device *dev) +{ +	struct uart_port *port = s3c24xx_dev_to_port(dev); + +	if (port) { +		/* restore IRQ mask */ +		if (s3c24xx_serial_has_interrupt_mask(port)) { +			unsigned int uintm = 0xf; +			if (tx_enabled(port)) +				uintm &= ~S3C64XX_UINTM_TXD_MSK; +			if (rx_enabled(port)) +				uintm &= ~S3C64XX_UINTM_RXD_MSK; +			wr_regl(port, S3C64XX_UINTM, uintm); +		} +	} + +	return 0; +} +  static const struct dev_pm_ops s3c24xx_serial_pm_ops = {  	.suspend = s3c24xx_serial_suspend,  	.resume = s3c24xx_serial_resume, +	.resume_noirq = s3c24xx_serial_resume_noirq,  };  #define SERIAL_SAMSUNG_PM_OPS	(&s3c24xx_serial_pm_ops) @@ -1343,6 +1372,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)  	return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;  } +static bool +s3c24xx_port_configured(unsigned int ucon) +{ +	/* consider the serial port configured if the tx/rx mode set */ +	return (ucon & 0xf) != 0; +} +  #ifdef CONFIG_CONSOLE_POLL  /*   * Console polling routines for writing and reading from the uart while @@ -1365,6 +1401,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,  		unsigned char c)  {  	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); +	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + +	/* not possible to xmit on unconfigured port */ +	if (!s3c24xx_port_configured(ucon)) +		return;  	while (!s3c24xx_serial_console_txrdy(port, ufcon))  		cpu_relax(); @@ -1377,6 +1418,12 @@ static void  s3c24xx_serial_console_putchar(struct uart_port *port, int ch)  {  	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); +	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + +	/* not possible to xmit on unconfigured port */ +	if (!s3c24xx_port_configured(ucon)) +		return; +  	while (!s3c24xx_serial_console_txrdy(port, ufcon))  		barrier();  	wr_regb(cons_uart, S3C2410_UTXH, ch); @@ -1409,9 +1456,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,  	    "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",  	    port, ulcon, ucon, ubrdiv); -	if ((ucon & 0xf) != 0) { -		/* consider the serial port configured if the tx/rx mode set */ - +	if (s3c24xx_port_configured(ucon)) {  		switch (ulcon & S3C2410_LCON_CSMASK) {  		case S3C2410_LCON_CS5:  			*bits = 5;  |