sh: use the common ascii hex helpers
[safe/jmp/linux-2.6] / drivers / serial / sh-sci.c
index 266aa32..ce6ee92 100644 (file)
@@ -4,6 +4,7 @@
  * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
  *
  *  Copyright (C) 2002 - 2006  Paul Mundt
+ *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
  *
  * based off of the old drivers/char/sh-sci.c by:
  *
  *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
  *   Modified to support SecureEdge. David McCullough (2002)
  *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ *   Removed SH7300 support (Jul 2007).
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
 
 #undef DEBUG
 
 #include <linux/delay.h>
 #include <linux/console.h>
 #include <linux/platform_device.h>
-
-#ifdef CONFIG_CPU_FREQ
+#include <linux/serial_sci.h>
 #include <linux/notifier.h>
 #include <linux/cpufreq.h>
-#endif
+#include <linux/clk.h>
+#include <linux/ctype.h>
 
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#ifdef CONFIG_SUPERH
 #include <asm/clock.h>
 #include <asm/sh_bios.h>
 #include <asm/kgdb.h>
 #endif
 
-#include <asm/sci.h>
-
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
 #include "sh-sci.h"
 
 struct sci_port {
@@ -63,7 +62,7 @@ struct sci_port {
        unsigned int            type;
 
        /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
-       unsigned int            irqs[SCIx_NR_IRQS]; 
+       unsigned int            irqs[SCIx_NR_IRQS];
 
        /* Port pin configuration */
        void                    (*init_pins)(struct uart_port *port,
@@ -78,6 +77,11 @@ struct sci_port {
        /* Break timer */
        struct timer_list       break_timer;
        int                     break_flag;
+
+#ifdef CONFIG_SUPERH
+       /* Port clock */
+       struct clk              *clk;
+#endif
 };
 
 #ifdef CONFIG_SH_KGDB
@@ -165,7 +169,7 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
        usegdb |= sh_bios_in_gdb_mode();
 #endif
 #ifdef CONFIG_SH_KGDB
-       usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
+       usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
 #endif
 
        if (usegdb) {
@@ -180,15 +184,15 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
                        int h, l;
 
                        c = *p++;
-                       h = highhex(c);
-                       l = lowhex(c);
+                       h = hex_asc_hi(c);
+                       l = hex_asc_lo(c);
                        put_char(port, h);
                        put_char(port, l);
                        checksum += h + l;
                }
                put_char(port, '#');
-               put_char(port, highhex(checksum));
-               put_char(port, lowhex(checksum));
+               put_char(port, hex_asc_hi(checksum));
+               put_char(port, hex_asc_lo(checksum));
            } while  (get_char(port) != '+');
        } else
 #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
@@ -206,7 +210,7 @@ static int kgdb_sci_getchar(void)
         int c;
 
         /* Keep trying to read a character, this could be neater */
-        while ((c = get_char(kgdb_sci_port)) < 0)
+        while ((c = get_char(&kgdb_sci_port->port)) < 0)
                cpu_relax();
 
         return c;
@@ -214,7 +218,7 @@ static int kgdb_sci_getchar(void)
 
 static inline void kgdb_sci_putchar(int c)
 {
-        put_char(kgdb_sci_port, c);
+        put_char(&kgdb_sci_port->port, c);
 }
 #endif /* CONFIG_SH_KGDB */
 
@@ -285,11 +289,47 @@ static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
 #endif
 
 #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
-/* SH7300 doesn't use RTS/CTS */
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
+{
+       unsigned int fcr_val = 0;
+
+       set_sh771x_scif_pfc(port);
+       if (cflag & CRTSCTS) {
+               fcr_val |= SCFCR_MCE;
+       }
+       sci_out(port, SCFCR, fcr_val);
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 {
-       sci_out(port, SCFCR, 0);
+       unsigned int fcr_val = 0;
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = ctrl_inw(PORT_PTCR);
+                       ctrl_outw((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = ctrl_inw(PORT_PVCR);
+                       ctrl_outw((data & 0xfc03), PORT_PVCR);
+               }
+               fcr_val |= SCFCR_MCE;
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = ctrl_inw(PORT_PTCR);
+                       ctrl_outw((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = ctrl_inw(PORT_PVCR);
+                       ctrl_outw((data & 0xffc3), PORT_PVCR);
+               }
+       }
+       sci_out(port, SCFCR, fcr_val);
 }
 #elif defined(CONFIG_CPU_SH3)
 /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
@@ -319,6 +359,32 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 
        sci_out(port, SCFCR, fcr_val);
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+       unsigned int fcr_val = 0;
+       unsigned short data;
+
+       if (port->mapbase == 0xffe00000) {
+               data = ctrl_inw(PSCR);
+               data &= ~0x03cf;
+               if (cflag & CRTSCTS)
+                       fcr_val |= SCFCR_MCE;
+               else
+                       data |= 0x0340;
+
+               ctrl_outw(data, PSCR);
+       }
+       /* SCIF1 and SCIF2 should be setup by board code */
+
+       sci_out(port, SCFCR, fcr_val);
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+       /* Nothing to do here.. */
+       sci_out(port, SCFCR, 0);
+}
 #else
 /* For SH7750 */
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -328,9 +394,12 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
        if (cflag & CRTSCTS) {
                fcr_val |= SCFCR_MCE;
        } else {
-#ifdef CONFIG_CPU_SUBTYPE_SH7343
+#if defined(CONFIG_CPU_SUBTYPE_SH7343) || defined(CONFIG_CPU_SUBTYPE_SH7366)
                /* Nothing */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SHX3)
                ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
 #else
                ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
@@ -340,15 +409,18 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 }
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
 static inline int scif_txroom(struct uart_port *port)
 {
-       return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
+       return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
 }
 
 static inline int scif_rxroom(struct uart_port *port)
 {
-       return sci_in(port, SCRFDR) & 0x7f;
+       return sci_in(port, SCRFDR) & 0xff;
 }
 #else
 static inline int scif_txroom(struct uart_port *port)
@@ -623,6 +695,9 @@ static inline int sci_handle_breaks(struct uart_port *port)
        struct tty_struct *tty = port->info->tty;
        struct sci_port *s = &sci_ports[port->line];
 
+       if (uart_handle_break(port))
+               return 0;
+
        if (!s->break_flag && status & SCxSR_BRK(port)) {
 #if defined(CONFIG_CPU_SH3)
                /* Debounce break */
@@ -712,12 +787,6 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
 
        /* Handle BREAKs */
        sci_handle_breaks(port);
-
-#ifdef CONFIG_SH_KGDB
-       /* Break into the debugger if a break is detected */
-       BREAKPOINT();
-#endif
-
        sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
 
        return IRQ_HANDLED;
@@ -775,14 +844,14 @@ static int sci_notifier(struct notifier_block *self,
                         *
                         * Clean this up later..
                         */
-                       clk = clk_get("module_clk");
+                       clk = clk_get(NULL, "module_clk");
                        port->uartclk = clk_get_rate(clk) * 16;
                        clk_put(clk);
                }
 
                printk(KERN_INFO "%s: got a postchange notification "
                       "for cpu %d (old %d, new %d)\n",
-                      __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+                      __func__, freqs->cpu, freqs->old, freqs->new);
        }
 
        return NOTIFY_OK;
@@ -808,7 +877,7 @@ static int sci_request_irq(struct sci_port *port)
                }
 
                if (request_irq(port->irqs[0], sci_mpxed_interrupt,
-                               SA_INTERRUPT, "sci", port)) {
+                               IRQF_DISABLED, "sci", port)) {
                        printk(KERN_ERR "sci: Cannot allocate irq.\n");
                        return -ENODEV;
                }
@@ -817,7 +886,7 @@ static int sci_request_irq(struct sci_port *port)
                        if (!port->irqs[i])
                                continue;
                        if (request_irq(port->irqs[i], handlers[i],
-                                       SA_INTERRUPT, desc[i], port)) {
+                                       IRQF_DISABLED, desc[i], port)) {
                                printk(KERN_ERR "sci: Cannot allocate irq.\n");
                                return -ENODEV;
                        }
@@ -924,6 +993,10 @@ static int sci_startup(struct uart_port *port)
        if (s->enable)
                s->enable(port);
 
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+       s->clk = clk_get(NULL, "module_clk");
+#endif
+
        sci_request_irq(s);
        sci_start_tx(port);
        sci_start_rx(port, 1);
@@ -941,14 +1014,18 @@ static void sci_shutdown(struct uart_port *port)
 
        if (s->disable)
                s->disable(port);
+
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+       clk_put(s->clk);
+       s->clk = NULL;
+#endif
 }
 
-static void sci_set_termios(struct uart_port *port, struct termios *termios,
-                           struct termios *old)
+static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
 {
        struct sci_port *s = &sci_ports[port->line];
        unsigned int status, baud, smr_val;
-       unsigned long flags;
        int t;
 
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
@@ -960,18 +1037,14 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
                default:
                {
 #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
-                       struct clk *clk = clk_get("module_clk");
-                       t = SCBRR_VALUE(baud, clk_get_rate(clk));
-                       clk_put(clk);
+                       t = SCBRR_VALUE(baud, clk_get_rate(s->clk));
 #else
                        t = SCBRR_VALUE(baud);
 #endif
-               }
                        break;
+               }
        }
 
-       spin_lock_irqsave(&port->lock, flags);
-
        do {
                status = sci_in(port, SCxSR);
        } while (!(status & SCxSR_TEND(port)));
@@ -1015,8 +1088,6 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
 
        if ((termios->c_cflag & CREAD) != 0)
               sci_start_rx(port,0);
-
-       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static const char *sci_type(struct uart_port *port)
@@ -1128,7 +1199,7 @@ static void __init sci_init_ports(void)
                 * XXX: We should use a proper SCI/SCIF clock
                 */
                {
-                       struct clk *clk = clk_get("module_clk");
+                       struct clk *clk = clk_get(NULL, "module_clk");
                        sci_ports[i].port.uartclk = clk_get_rate(clk) * 16;
                        clk_put(clk);
                }
@@ -1197,10 +1268,13 @@ static int __init serial_console_setup(struct console *co, char *options)
        if (!port->membase || !port->mapbase)
                return -ENODEV;
 
-       spin_lock_init(&port->lock);
-
        port->type = serial_console_port->type;
 
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+       if (!serial_console_port->clk)
+               serial_console_port->clk = clk_get(NULL, "module_clk");
+#endif
+
        if (port->flags & UPF_IOREMAP)
                sci_config_port(port, 0);
 
@@ -1224,7 +1298,7 @@ static struct console serial_console = {
        .device         = uart_console_device,
        .write          = serial_console_write,
        .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER, 
+       .flags          = CON_PRINTBUFFER,
        .index          = -1,
        .data           = &sci_uart_driver,
 };
@@ -1238,7 +1312,7 @@ static int __init sci_console_init(void)
 console_initcall(sci_console_init);
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
-#ifdef CONFIG_SH_KGDB
+#ifdef CONFIG_SH_KGDB_CONSOLE
 /*
  * FIXME: Most of this can go away.. at the moment, we rely on
  * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
@@ -1269,11 +1343,23 @@ int __init kgdb_console_setup(struct console *co, char *options)
        int parity = 'n';
        int flow = 'n';
 
-       spin_lock_init(&port->lock);
-
        if (co->index != kgdb_portnum)
                co->index = kgdb_portnum;
 
+       kgdb_sci_port = &sci_ports[co->index];
+       port = &kgdb_sci_port->port;
+
+       /*
+        * Also need to check port->type, we don't actually have any
+        * UPIO_PORT ports, but uart_report_port() handily misreports
+        * it anyways if we don't have a port available by the time this is
+        * called.
+        */
+       if (!port->type)
+               return -ENODEV;
+       if (!port->membase || !port->mapbase)
+               return -ENODEV;
+
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
@@ -1284,15 +1370,14 @@ int __init kgdb_console_setup(struct console *co, char *options)
 
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
-#endif /* CONFIG_SH_KGDB */
 
-#ifdef CONFIG_SH_KGDB_CONSOLE
 static struct console kgdb_console = {
-        .name          = "ttySC",
-        .write         = kgdb_console_write,
-        .setup         = kgdb_console_setup,
-        .flags         = CON_PRINTBUFFER | CON_ENABLED,
-        .index         = -1,
+       .name           = "ttySC",
+       .device         = uart_console_device,
+       .write          = kgdb_console_write,
+       .setup          = kgdb_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
        .data           = &sci_uart_driver,
 };
 
@@ -1338,9 +1423,19 @@ static int __devinit sci_probe(struct platform_device *dev)
        struct plat_sci_port *p = dev->dev.platform_data;
        int i;
 
-       for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
+       for (i = 0; p && p->flags != 0; p++, i++) {
                struct sci_port *sciport = &sci_ports[i];
 
+               /* Sanity check */
+               if (unlikely(i == SCI_NPORTS)) {
+                       dev_notice(&dev->dev, "Attempting to register port "
+                                  "%d when only %d are available.\n",
+                                  i+1, SCI_NPORTS);
+                       dev_notice(&dev->dev, "Consider bumping "
+                                  "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+                       break;
+               }
+
                sciport->port.mapbase   = p->mapbase;
 
                /*
@@ -1363,9 +1458,15 @@ static int __devinit sci_probe(struct platform_device *dev)
                uart_add_one_port(&sci_uart_driver, &sciport->port);
        }
 
+#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
+       kgdb_sci_port   = &sci_ports[kgdb_portnum];
+       kgdb_getchar    = kgdb_sci_getchar;
+       kgdb_putchar    = kgdb_sci_putchar;
+#endif
+
 #ifdef CONFIG_CPU_FREQ
        cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
-       dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
+       dev_info(&dev->dev, "CPU frequency notifier registered\n");
 #endif
 
 #ifdef CONFIG_SH_STANDARD_BIOS
@@ -1452,3 +1553,4 @@ module_init(sci_init);
 module_exit(sci_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-sci");