Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / tty / serial / samsung.c
index 2769a38..074b919 100644 (file)
@@ -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>
 
 #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;