Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
authorPaul Mundt <lethal@linux-sh.org>
Wed, 26 Jan 2011 09:23:27 +0000 (18:23 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 26 Jan 2011 09:23:27 +0000 (18:23 +0900)
1  2 
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h

@@@ -47,6 -47,7 +47,6 @@@
  #include <linux/clk.h>
  #include <linux/ctype.h>
  #include <linux/err.h>
 -#include <linux/list.h>
  #include <linux/dmaengine.h>
  #include <linux/scatterlist.h>
  #include <linux/slab.h>
  struct sci_port {
        struct uart_port        port;
  
 -      /* Port type */
 -      unsigned int            type;
 -
 -      /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
 -      unsigned int            irqs[SCIx_NR_IRQS];
 +      /* Platform configuration */
 +      struct plat_sci_port    *cfg;
  
        /* Port enable callback */
        void                    (*enable)(struct uart_port *port);
        struct timer_list       break_timer;
        int                     break_flag;
  
 -      /* SCSCR initialization */
 -      unsigned int            scscr;
 -
 -      /* SCBRR calculation algo */
 -      unsigned int            scbrr_algo_id;
 -
        /* Interface clock */
        struct clk              *iclk;
        /* Function clock */
        struct clk              *fclk;
  
 -      struct list_head        node;
 -
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
  
  #ifdef CONFIG_SERIAL_SH_SCI_DMA
 -      struct device                   *dma_dev;
 -      unsigned int                    slave_tx;
 -      unsigned int                    slave_rx;
        struct dma_async_tx_descriptor  *desc_tx;
        struct dma_async_tx_descriptor  *desc_rx[2];
        dma_cookie_t                    cookie_tx;
        struct timer_list               rx_timer;
        unsigned int                    rx_timeout;
  #endif
 -};
  
 -struct sh_sci_priv {
 -      spinlock_t lock;
 -      struct list_head ports;
 -      struct notifier_block clk_nb;
 +      struct notifier_block           freq_transition;
  };
  
  /* Function prototypes */
 +static void sci_start_tx(struct uart_port *port);
  static void sci_stop_tx(struct uart_port *port);
 +static void sci_start_rx(struct uart_port *port);
  
  #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
  
@@@ -125,6 -142,12 +125,6 @@@ to_sci_port(struct uart_port *uart
  #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
  
  #ifdef CONFIG_CONSOLE_POLL
 -static inline void handle_error(struct uart_port *port)
 -{
 -      /* Clear error flags */
 -      sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
 -}
 -
  static int sci_poll_get_char(struct uart_port *port)
  {
        unsigned short status;
        do {
                status = sci_in(port, SCxSR);
                if (status & SCxSR_ERRORS(port)) {
 -                      handle_error(port);
 +                      sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
                        continue;
                }
                break;
@@@ -452,7 -475,7 +452,7 @@@ static void sci_transmit_chars(struct u
  /* On SH3, SCIF may read end-of-break as a space->mark char */
  #define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
  
 -static inline void sci_receive_chars(struct uart_port *port)
 +static void sci_receive_chars(struct uart_port *port)
  {
        struct sci_port *sci_port = to_sci_port(port);
        struct tty_struct *tty = port->state->port.tty;
  }
  
  #define SCI_BREAK_JIFFIES (HZ/20)
 -/* The sci generates interrupts during the break,
 +
 +/*
 + * The sci generates interrupts during the break,
   * 1 per millisecond or so during the break period, for 9600 baud.
   * So dont bother disabling interrupts.
   * But dont want more than 1 break event.
   * Use a kernel timer to periodically poll the rx line until
   * the break is finished.
   */
 -static void sci_schedule_break_timer(struct sci_port *port)
 +static inline void sci_schedule_break_timer(struct sci_port *port)
  {
 -      port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
 -      add_timer(&port->break_timer);
 +      mod_timer(&port->break_timer, jiffies + SCI_BREAK_JIFFIES);
  }
 +
  /* Ensure that two consecutive samples find the break over. */
  static void sci_break_timer(unsigned long data)
  {
                port->break_flag = 0;
  }
  
 -static inline int sci_handle_errors(struct uart_port *port)
 +static int sci_handle_errors(struct uart_port *port)
  {
        int copied = 0;
        unsigned short status = sci_in(port, SCxSR);
        return copied;
  }
  
 -static inline int sci_handle_fifo_overrun(struct uart_port *port)
 +static int sci_handle_fifo_overrun(struct uart_port *port)
  {
        struct tty_struct *tty = port->state->port.tty;
        int copied = 0;
        return copied;
  }
  
 -static inline int sci_handle_breaks(struct uart_port *port)
 +static int sci_handle_breaks(struct uart_port *port)
  {
        int copied = 0;
        unsigned short status = sci_in(port, SCxSR);
@@@ -773,7 -794,7 +773,7 @@@ static inline unsigned long port_rx_irq
         * it's unset, it's logically inferred that there's no point in
         * testing for it.
         */
 -      return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE);
 +      return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
  }
  
  static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
  static int sci_notifier(struct notifier_block *self,
                        unsigned long phase, void *p)
  {
 -      struct sh_sci_priv *priv = container_of(self,
 -                                              struct sh_sci_priv, clk_nb);
        struct sci_port *sci_port;
        unsigned long flags;
  
 +      sci_port = container_of(self, struct sci_port, freq_transition);
 +
        if ((phase == CPUFREQ_POSTCHANGE) ||
            (phase == CPUFREQ_RESUMECHANGE)) {
 -              spin_lock_irqsave(&priv->lock, flags);
 -              list_for_each_entry(sci_port, &priv->ports, node)
 -                      sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
 -              spin_unlock_irqrestore(&priv->lock, flags);
 +              struct uart_port *port = &sci_port->port;
 +
 +              spin_lock_irqsave(&port->lock, flags);
 +              port->uartclk = clk_get_rate(sci_port->iclk);
 +              spin_unlock_irqrestore(&port->lock, flags);
        }
  
        return NOTIFY_OK;
@@@ -862,21 -882,21 +862,21 @@@ static int sci_request_irq(struct sci_p
        const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
                               "SCI Transmit Data Empty", "SCI Break" };
  
 -      if (port->irqs[0] == port->irqs[1]) {
 -              if (unlikely(!port->irqs[0]))
 +      if (port->cfg->irqs[0] == port->cfg->irqs[1]) {
 +              if (unlikely(!port->cfg->irqs[0]))
                        return -ENODEV;
  
 -              if (request_irq(port->irqs[0], sci_mpxed_interrupt,
 +              if (request_irq(port->cfg->irqs[0], sci_mpxed_interrupt,
                                IRQF_DISABLED, "sci", port)) {
                        dev_err(port->port.dev, "Can't allocate IRQ\n");
                        return -ENODEV;
                }
        } else {
                for (i = 0; i < ARRAY_SIZE(handlers); i++) {
 -                      if (unlikely(!port->irqs[i]))
 +                      if (unlikely(!port->cfg->irqs[i]))
                                continue;
  
 -                      if (request_irq(port->irqs[i], handlers[i],
 +                      if (request_irq(port->cfg->irqs[i], handlers[i],
                                        IRQF_DISABLED, desc[i], port)) {
                                dev_err(port->port.dev, "Can't allocate IRQ\n");
                                return -ENODEV;
@@@ -891,14 -911,14 +891,14 @@@ static void sci_free_irq(struct sci_por
  {
        int i;
  
 -      if (port->irqs[0] == port->irqs[1])
 -              free_irq(port->irqs[0], port);
 +      if (port->cfg->irqs[0] == port->cfg->irqs[1])
 +              free_irq(port->cfg->irqs[0], port);
        else {
 -              for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
 -                      if (!port->irqs[i])
 +              for (i = 0; i < ARRAY_SIZE(port->cfg->irqs); i++) {
 +                      if (!port->cfg->irqs[i])
                                continue;
  
 -                      free_irq(port->irqs[i], port);
 +                      free_irq(port->cfg->irqs[i], port);
                }
        }
  }
@@@ -1017,6 -1037,9 +1017,6 @@@ static void sci_dma_rx_complete(void *a
        schedule_work(&s->work_rx);
  }
  
 -static void sci_start_rx(struct uart_port *port);
 -static void sci_start_tx(struct uart_port *port);
 -
  static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
  {
        struct dma_chan *chan = s->chan_rx;
@@@ -1302,7 -1325,7 +1302,7 @@@ static void rx_timer_fn(unsigned long a
  
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
                scr &= ~0x4000;
 -              enable_irq(s->irqs[1]);
 +              enable_irq(s->cfg->irqs[1]);
        }
        sci_out(port, SCSCR, scr | SCSCR_RIE);
        dev_dbg(port->dev, "DMA Rx timed out\n");
@@@ -1318,9 -1341,9 +1318,9 @@@ static void sci_request_dma(struct uart
        int nent;
  
        dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
 -              port->line, s->dma_dev);
 +              port->line, s->cfg->dma_dev);
  
 -      if (!s->dma_dev)
 +      if (!s->cfg->dma_dev)
                return;
  
        dma_cap_zero(mask);
        param = &s->param_tx;
  
        /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
 -      param->slave_id = s->slave_tx;
 -      param->dma_dev = s->dma_dev;
 +      param->slave_id = s->cfg->dma_slave_tx;
 +      param->dma_dev = s->cfg->dma_dev;
  
        s->cookie_tx = -EINVAL;
        chan = dma_request_channel(mask, filter, param);
        param = &s->param_rx;
  
        /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
 -      param->slave_id = s->slave_rx;
 -      param->dma_dev = s->dma_dev;
 +      param->slave_id = s->cfg->dma_slave_rx;
 +      param->dma_dev = s->cfg->dma_dev;
  
        chan = dma_request_channel(mask, filter, param);
        dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
@@@ -1404,7 -1427,7 +1404,7 @@@ static void sci_free_dma(struct uart_po
  {
        struct sci_port *s = to_sci_port(port);
  
 -      if (!s->dma_dev)
 +      if (!s->cfg->dma_dev)
                return;
  
        if (s->chan_tx)
        if (s->chan_rx)
                sci_rx_dma_release(s, false);
  }
 +#else
 +static inline void sci_request_dma(struct uart_port *port)
 +{
 +}
 +
 +static inline void sci_free_dma(struct uart_port *port)
 +{
 +}
  #endif
  
  static int sci_startup(struct uart_port *port)
  {
        struct sci_port *s = to_sci_port(port);
 +      int ret;
  
        dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
  
        if (s->enable)
                s->enable(port);
  
 -      sci_request_irq(s);
 -#ifdef CONFIG_SERIAL_SH_SCI_DMA
 +      ret = sci_request_irq(s);
 +      if (unlikely(ret < 0))
 +              return ret;
 +
        sci_request_dma(port);
 -#endif
 +
        sci_start_tx(port);
        sci_start_rx(port);
  
@@@ -1452,8 -1464,9 +1452,8 @@@ static void sci_shutdown(struct uart_po
  
        sci_stop_rx(port);
        sci_stop_tx(port);
 -#ifdef CONFIG_SERIAL_SH_SCI_DMA
 +
        sci_free_dma(port);
 -#endif
        sci_free_irq(s);
  
        if (s->disable)
@@@ -1478,7 -1491,6 +1478,7 @@@ static unsigned int sci_scbrr_calc(unsi
  
        /* Warn, but use a safe default */
        WARN_ON(1);
 +
        return ((freq + 16 * bps) / (32 * bps) - 1);
  }
  
@@@ -1502,7 -1514,7 +1502,7 @@@ static void sci_set_termios(struct uart
  
        baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
        if (likely(baud && port->uartclk))
 -              t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk);
 +              t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk);
  
        do {
                status = sci_in(port, SCxSR);
                sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
  
        smr_val = sci_in(port, SCSMR) & 3;
 +
        if ((termios->c_cflag & CSIZE) == CS7)
                smr_val |= 0x40;
        if (termios->c_cflag & PARENB)
        sci_out(port, SCSMR, smr_val);
  
        dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
 -              s->scscr);
 +              s->cfg->scscr);
  
        if (t > 0) {
                if (t >= 256) {
        sci_init_pins(port, termios->c_cflag);
        sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
  
 -      sci_out(port, SCSCR, s->scscr);
 +      sci_out(port, SCSCR, s->cfg->scscr);
  
  #ifdef CONFIG_SERIAL_SH_SCI_DMA
        /*
@@@ -1591,33 -1602,31 +1591,33 @@@ static const char *sci_type(struct uart
        return NULL;
  }
  
 -static void sci_release_port(struct uart_port *port)
 +static inline unsigned long sci_port_size(struct uart_port *port)
  {
 -      /* Nothing here yet .. */
 -}
 -
 -static int sci_request_port(struct uart_port *port)
 -{
 -      /* Nothing here yet .. */
 -      return 0;
 +      /*
 +       * Pick an arbitrary size that encapsulates all of the base
 +       * registers by default. This can be optimized later, or derived
 +       * from platform resource data at such a time that ports begin to
 +       * behave more erratically.
 +       */
 +      return 64;
  }
  
 -static void sci_config_port(struct uart_port *port, int flags)
 +static int sci_remap_port(struct uart_port *port)
  {
 -      struct sci_port *s = to_sci_port(port);
 -
 -      port->type = s->type;
 +      unsigned long size = sci_port_size(port);
  
 +      /*
 +       * Nothing to do if there's already an established membase.
 +       */
        if (port->membase)
 -              return;
 +              return 0;
  
        if (port->flags & UPF_IOREMAP) {
 -              port->membase = ioremap_nocache(port->mapbase, 0x40);
 -
 -              if (IS_ERR(port->membase))
 +              port->membase = ioremap_nocache(port->mapbase, size);
 +              if (unlikely(!port->membase)) {
                        dev_err(port->dev, "can't remap port#%d\n", port->line);
 +                      return -ENXIO;
 +              }
        } else {
                /*
                 * For the simple (and majority of) cases where we don't
                 */
                port->membase = (void __iomem *)port->mapbase;
        }
 +
 +      return 0;
 +}
 +
 +static void sci_release_port(struct uart_port *port)
 +{
 +      if (port->flags & UPF_IOREMAP) {
 +              iounmap(port->membase);
 +              port->membase = NULL;
 +      }
 +
 +      release_mem_region(port->mapbase, sci_port_size(port));
 +}
 +
 +static int sci_request_port(struct uart_port *port)
 +{
 +      unsigned long size = sci_port_size(port);
 +      struct resource *res;
 +      int ret;
 +
 +      res = request_mem_region(port->mapbase, size, dev_name(port->dev));
 +      if (unlikely(res == NULL))
 +              return -EBUSY;
 +
 +      ret = sci_remap_port(port);
 +      if (unlikely(ret != 0)) {
 +              release_resource(res);
 +              return ret;
 +      }
 +
 +      return 0;
 +}
 +
 +static void sci_config_port(struct uart_port *port, int flags)
 +{
 +      if (flags & UART_CONFIG_TYPE) {
 +              struct sci_port *sport = to_sci_port(port);
 +
 +              port->type = sport->cfg->type;
 +              sci_request_port(port);
 +      }
  }
  
  static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
  {
        struct sci_port *s = to_sci_port(port);
  
 -      if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
 +      if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
                return -EINVAL;
        if (ser->baud_base < 2400)
                /* No paper tape reader for Mitch.. */
@@@ -1758,29 -1726,36 +1758,29 @@@ static int __devinit sci_init_single(st
        sci_port->break_timer.function = sci_break_timer;
        init_timer(&sci_port->break_timer);
  
 -      port->mapbase   = p->mapbase;
 -      port->membase   = p->membase;
 +      sci_port->cfg           = p;
  
 -      port->irq               = p->irqs[SCIx_TXI_IRQ];
 +      port->mapbase           = p->mapbase;
 +      port->type              = p->type;
        port->flags             = p->flags;
 -      sci_port->type          = port->type = p->type;
 -      sci_port->scscr         = p->scscr;
 -      sci_port->scbrr_algo_id = p->scbrr_algo_id;
  
 -#ifdef CONFIG_SERIAL_SH_SCI_DMA
 -      sci_port->dma_dev       = p->dma_dev;
 -      sci_port->slave_tx      = p->dma_slave_tx;
 -      sci_port->slave_rx      = p->dma_slave_rx;
 +      /*
 +       * The UART port needs an IRQ value, so we peg this to the TX IRQ
 +       * for the multi-IRQ ports, which is where we are primarily
 +       * concerned with the shutdown path synchronization.
 +       *
 +       * For the muxed case there's nothing more to do.
 +       */
 +      port->irq               = p->irqs[SCIx_TXI_IRQ];
  
 -      dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
 -              p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
 -#endif
 +      if (p->dma_dev)
 +              dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n",
 +                      p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
  
 -      memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
        return 0;
  }
  
  #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 -static struct tty_driver *serial_console_device(struct console *co, int *index)
 -{
 -      struct uart_driver *p = &sci_uart_driver;
 -      *index = co->index;
 -      return p->tty_driver;
 -}
 -
  static void serial_console_putchar(struct uart_port *port, int ch)
  {
        sci_poll_put_char(port, ch);
  static void serial_console_write(struct console *co, const char *s,
                                 unsigned count)
  {
 -      struct uart_port *port = co->data;
 -      struct sci_port *sci_port = to_sci_port(port);
 +      struct sci_port *sci_port = &sci_ports[co->index];
 +      struct uart_port *port = &sci_port->port;
        unsigned short bits;
  
        if (sci_port->enable)
@@@ -1822,17 -1797,32 +1822,17 @@@ static int __devinit serial_console_set
        int ret;
  
        /*
 -       * Check whether an invalid uart number has been specified, and
 -       * if so, search for the first available port that does have
 -       * console support.
 -       */
 -      if (co->index >= SCI_NPORTS)
 -              co->index = 0;
 -
 -      if (co->data) {
 -              port = co->data;
 -              sci_port = to_sci_port(port);
 -      } else {
 -              sci_port = &sci_ports[co->index];
 -              port = &sci_port->port;
 -              co->data = 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.
 +       * Refuse to handle any bogus ports.
         */
 -      if (!port->type)
 +      if (co->index < 0 || co->index >= SCI_NPORTS)
                return -ENODEV;
  
 -      sci_config_port(port, 0);
 +      sci_port = &sci_ports[co->index];
 +      port = &sci_port->port;
 +
 +      ret = sci_remap_port(port);
 +      if (unlikely(ret != 0))
 +              return ret;
  
        if (sci_port->enable)
                sci_port->enable(port);
  
  static struct console serial_console = {
        .name           = "ttySC",
 -      .device         = serial_console_device,
 +      .device         = uart_console_device,
        .write          = serial_console_write,
        .setup          = serial_console_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
 +      .data           = &sci_uart_driver,
  };
  
  static int __init sci_console_init(void)
  }
  console_initcall(sci_console_init);
  
 -static struct sci_port early_serial_port;
  static struct console early_serial_console = {
        .name           = "early_ttySC",
        .write          = serial_console_write,
        .flags          = CON_PRINTBUFFER,
 +      .index          = -1,
  };
 +
  static char early_serial_buf[32];
  
 +static int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
 +{
 +      struct plat_sci_port *cfg = pdev->dev.platform_data;
 +
 +      if (early_serial_console.data)
 +              return -EEXIST;
 +
 +      early_serial_console.index = pdev->id;
 +
 +      sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg);
 +
 +      serial_console_setup(&early_serial_console, early_serial_buf);
 +
 +      if (!strstr(early_serial_buf, "keep"))
 +              early_serial_console.flags |= CON_BOOT;
 +
 +      register_console(&early_serial_console);
 +      return 0;
 +}
 +#else
 +static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
 +{
 +      return -EINVAL;
 +}
  #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
  
  #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
@@@ -1921,18 -1885,24 +1921,18 @@@ static struct uart_driver sci_uart_driv
        .cons           = SCI_CONSOLE,
  };
  
 -
  static int sci_remove(struct platform_device *dev)
  {
 -      struct sh_sci_priv *priv = platform_get_drvdata(dev);
 -      struct sci_port *p;
 -      unsigned long flags;
 +      struct sci_port *port = platform_get_drvdata(dev);
  
 -      cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
 +      cpufreq_unregister_notifier(&port->freq_transition,
 +                                  CPUFREQ_TRANSITION_NOTIFIER);
  
 -      spin_lock_irqsave(&priv->lock, flags);
 -      list_for_each_entry(p, &priv->ports, node) {
 -              uart_remove_one_port(&sci_uart_driver, &p->port);
 -              clk_put(p->iclk);
 -              clk_put(p->fclk);
 -      }
 -      spin_unlock_irqrestore(&priv->lock, flags);
 +      uart_remove_one_port(&sci_uart_driver, &port->port);
 +
 +      clk_put(port->iclk);
 +      clk_put(port->fclk);
  
 -      kfree(priv);
        return 0;
  }
  
@@@ -1941,6 -1911,8 +1941,6 @@@ static int __devinit sci_probe_single(s
                                      struct plat_sci_port *p,
                                      struct sci_port *sciport)
  {
 -      struct sh_sci_priv *priv = platform_get_drvdata(dev);
 -      unsigned long flags;
        int ret;
  
        /* Sanity check */
        if (ret)
                return ret;
  
 -      ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
 -      if (ret)
 -              return ret;
 -
 -      INIT_LIST_HEAD(&sciport->node);
 -
 -      spin_lock_irqsave(&priv->lock, flags);
 -      list_add(&sciport->node, &priv->ports);
 -      spin_unlock_irqrestore(&priv->lock, flags);
 -
 -      return 0;
 +      return uart_add_one_port(&sci_uart_driver, &sciport->port);
  }
  
 -/*
 - * Register a set of serial devices attached to a platform device.  The
 - * list is terminated with a zero flags entry, which means we expect
 - * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
 - * remapping (such as sh64) should also set UPF_IOREMAP.
 - */
  static int __devinit sci_probe(struct platform_device *dev)
  {
        struct plat_sci_port *p = dev->dev.platform_data;
 -      struct sh_sci_priv *priv;
 -      int i, ret = -EINVAL;
 +      struct sci_port *sp = &sci_ports[dev->id];
 +      int ret;
  
 -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 -      if (is_early_platform_device(dev)) {
 -              if (dev->id == -1)
 -                      return -ENOTSUPP;
 -              early_serial_console.index = dev->id;
 -              early_serial_console.data = &early_serial_port.port;
 -              sci_init_single(NULL, &early_serial_port, dev->id, p);
 -              serial_console_setup(&early_serial_console, early_serial_buf);
 -              if (!strstr(early_serial_buf, "keep"))
 -                      early_serial_console.flags |= CON_BOOT;
 -              register_console(&early_serial_console);
 -              return 0;
 -      }
 -#endif
 +      /*
 +       * If we've come here via earlyprintk initialization, head off to
 +       * the special early probe. We don't have sufficient device state
 +       * to make it beyond this yet.
 +       */
 +      if (is_early_platform_device(dev))
 +              return sci_probe_earlyprintk(dev);
  
 -      priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 -      if (!priv)
 -              return -ENOMEM;
 +      platform_set_drvdata(dev, sp);
  
 -      INIT_LIST_HEAD(&priv->ports);
 -      spin_lock_init(&priv->lock);
 -      platform_set_drvdata(dev, priv);
 +      ret = sci_probe_single(dev, dev->id, p, sp);
 +      if (ret)
 +              goto err_unreg;
  
 -      priv->clk_nb.notifier_call = sci_notifier;
 -      cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
 +      sp->freq_transition.notifier_call = sci_notifier;
  
 -      if (dev->id != -1) {
 -              ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
 -              if (ret)
 -                      goto err_unreg;
 -      } else {
 -              for (i = 0; p && p->flags != 0; p++, i++) {
 -                      ret = sci_probe_single(dev, i, p, &sci_ports[i]);
 -                      if (ret)
 -                              goto err_unreg;
 -              }
 -      }
 +      ret = cpufreq_register_notifier(&sp->freq_transition,
 +                                      CPUFREQ_TRANSITION_NOTIFIER);
 +      if (unlikely(ret < 0))
 +              goto err_unreg;
  
  #ifdef CONFIG_SH_STANDARD_BIOS
        sh_bios_gdb_detach();
@@@ -2000,20 -2005,28 +2000,20 @@@ err_unreg
  
  static int sci_suspend(struct device *dev)
  {
 -      struct sh_sci_priv *priv = dev_get_drvdata(dev);
 -      struct sci_port *p;
 -      unsigned long flags;
 +      struct sci_port *sport = dev_get_drvdata(dev);
  
 -      spin_lock_irqsave(&priv->lock, flags);
 -      list_for_each_entry(p, &priv->ports, node)
 -              uart_suspend_port(&sci_uart_driver, &p->port);
 -      spin_unlock_irqrestore(&priv->lock, flags);
 +      if (sport)
 +              uart_suspend_port(&sci_uart_driver, &sport->port);
  
        return 0;
  }
  
  static int sci_resume(struct device *dev)
  {
 -      struct sh_sci_priv *priv = dev_get_drvdata(dev);
 -      struct sci_port *p;
 -      unsigned long flags;
 +      struct sci_port *sport = dev_get_drvdata(dev);
  
 -      spin_lock_irqsave(&priv->lock, flags);
 -      list_for_each_entry(p, &priv->ports, node)
 -              uart_resume_port(&sci_uart_driver, &p->port);
 -      spin_unlock_irqrestore(&priv->lock, flags);
 +      if (sport)
 +              uart_resume_port(&sci_uart_driver, &sport->port);
  
        return 0;
  }
@@@ -54,6 -54,9 +54,6 @@@
  # define PBCR 0xa4050102
  #elif defined(CONFIG_CPU_SUBTYPE_SH7343)
  # define SCSPTR0 0xffe00010   /* 16 bit SCIF */
 -# define SCSPTR1 0xffe10010   /* 16 bit SCIF */
 -# define SCSPTR2 0xffe20010   /* 16 bit SCIF */
 -# define SCSPTR3 0xffe30010   /* 16 bit SCIF */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7722)
  # define PADR                 0xA4050120
  # define PSDR                 0xA405013e
  # define SCIF_ORER            0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7723)
  # define SCSPTR0                0xa4050160
 -# define SCSPTR1                0xa405013e
 -# define SCSPTR2                0xa4050160
 -# define SCSPTR3                0xa405013e
 -# define SCSPTR4                0xa4050128
 -# define SCSPTR5                0xa4050128
  # define SCIF_ORER              0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7724)
  # define SCIF_ORER              0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
  # define SCSPTR2 0xffe80020 /* 16 bit SCIF */
  # define SCIF_ORER 0x0001   /* overrun error bit */
 -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
 -# define SCIF_PTR2_OFFS    0x0000020
 -# define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
  #elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
  # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
  #elif defined(CONFIG_H8S2678)
  # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
  #elif defined(CONFIG_CPU_SUBTYPE_SH7757)
  # define SCSPTR0 0xfe4b0020
 -# define SCSPTR1 0xfe4b0020
 -# define SCSPTR2 0xfe4b0020
  # define SCIF_ORER 0x0001
 -# define SCIF_ONLY
  #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
  # define SCSPTR0 0xffe00024 /* 16 bit SCIF */
 -# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
 -# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
  # define SCIF_ORER 0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
  # define SCSPTR0 0xff923020 /* 16 bit SCIF */
 -# define SCSPTR1 0xff924020 /* 16 bit SCIF */
 -# define SCSPTR2 0xff925020 /* 16 bit SCIF */
  # define SCIF_ORER 0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
  # define SCSPTR0      0xffe00024      /* 16 bit SCIF */
 -# define SCSPTR1      0xffe10024      /* 16 bit SCIF */
  # define SCIF_ORER    0x0001          /* Overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
        defined(CONFIG_CPU_SUBTYPE_SH7786)
  # define SCSPTR0      0xffea0024      /* 16 bit SCIF */
 -# define SCSPTR1      0xffeb0024      /* 16 bit SCIF */
 -# define SCSPTR2      0xffec0024      /* 16 bit SCIF */
 -# define SCSPTR3      0xffed0024      /* 16 bit SCIF */
 -# define SCSPTR4      0xffee0024      /* 16 bit SCIF */
 -# define SCSPTR5      0xffef0024      /* 16 bit SCIF */
  # define SCIF_ORER    0x0001          /* Overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
        defined(CONFIG_CPU_SUBTYPE_SH7203) || \
        defined(CONFIG_CPU_SUBTYPE_SH7206) || \
        defined(CONFIG_CPU_SUBTYPE_SH7263)
  # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
 -# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
 -# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
 -# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
 -# if defined(CONFIG_CPU_SUBTYPE_SH7201)
 -#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
 -#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
 -#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
 -#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
 -# endif
  #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
  # define SCSPTR0 0xf8400020 /* 16 bit SCIF */
 -# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
 -# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
  # define SCIF_ORER 0x0001  /* overrun error bit */
  #elif defined(CONFIG_CPU_SUBTYPE_SHX3)
  # define SCSPTR0 0xffc30020           /* 16 bit SCIF */
 -# define SCSPTR1 0xffc40020           /* 16 bit SCIF */
 -# define SCSPTR2 0xffc50020           /* 16 bit SCIF */
 -# define SCSPTR3 0xffc60020           /* 16 bit SCIF */
  # define SCIF_ORER 0x0001             /* Overrun error bit */
  #else
  # error CPU subtype not defined
@@@ -373,6 -411,7 +373,6 @@@ SCIF_FNS(SCSPTR,                   0,  0, 0x24, 16
  SCIF_FNS(SCLSR,                               0,  0, 0x28, 16)
  #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
  SCIF_FNS(SCFDR,                               0,  0, 0x1C, 16)
 -SCIF_FNS(SCSPTR2,                     0,  0, 0x20, 16)
  SCIF_FNS(SCTFDR,                   0x0e, 16, 0x1C, 16)
  SCIF_FNS(SCRFDR,                   0x0e, 16, 0x20, 16)
  SCIF_FNS(SCSPTR,                      0,  0, 0x24, 16)