sh: use the common ascii hex helpers
[safe/jmp/linux-2.6] / drivers / serial / sh-sci.c
index 4b17f84..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:
  *
@@ -12,6 +13,7 @@
  *   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
 #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
-
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#include <linux/clk.h>
 #include <linux/ctype.h>
+
+#ifdef CONFIG_SUPERH
 #include <asm/clock.h>
 #include <asm/sh_bios.h>
 #include <asm/kgdb.h>
 #endif
 
-#include <asm/sci.h>
 #include "sh-sci.h"
 
 struct sci_port {
@@ -62,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,
@@ -77,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
@@ -179,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 */
@@ -284,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 */
@@ -322,24 +363,28 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 {
        unsigned int fcr_val = 0;
+       unsigned short data;
 
-       if (cflag & CRTSCTS) {
-               fcr_val |= SCFCR_MCE;
-
-               ctrl_outw(0x0000, PORT_PSCR);
-       } else {
-               unsigned short data;
-
-               data = ctrl_inw(PORT_PSCR);
-               data &= 0x033f;
-               data |= 0x0400;
-               ctrl_outw(data, PORT_PSCR);
+       if (port->mapbase == 0xffe00000) {
+               data = ctrl_inw(PSCR);
+               data &= ~0x03cf;
+               if (cflag & CRTSCTS)
+                       fcr_val |= SCFCR_MCE;
+               else
+                       data |= 0x0340;
 
-               ctrl_outw(ctrl_inw(SCSPTR0) & 0x17, SCSPTR0);
+               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)
@@ -349,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 */
@@ -361,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)
@@ -736,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;
@@ -806,7 +851,7 @@ static int sci_notifier(struct notifier_block *self,
 
                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;
@@ -948,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);
@@ -965,6 +1014,11 @@ 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 ktermios *termios,
@@ -983,9 +1037,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                default:
                {
 #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
-                       struct clk *clk = clk_get(NULL, "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
@@ -1218,6 +1270,11 @@ static int __init serial_console_setup(struct console *co, char *options)
 
        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);
 
@@ -1255,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
@@ -1313,9 +1370,7 @@ 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",
        .device         = uart_console_device,
@@ -1368,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;
 
                /*
@@ -1401,7 +1466,7 @@ static int __devinit sci_probe(struct platform_device *dev)
 
 #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
@@ -1488,3 +1553,4 @@ module_init(sci_init);
 module_exit(sci_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-sci");