]> Pileus Git - ~andy/linux/blobdiff - drivers/tty/serial/sh-sci.c
Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee139...
[~andy/linux] / drivers / tty / serial / sh-sci.c
index 7d8103cd3e2ec56eacbb5a5d3f3f332597e190ff..be33d2b0613bb95a51092b1173c9d1291082a211 100644 (file)
 
 #undef DEBUG
 
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
 #include <linux/errno.h>
-#include <linux/sh_dma.h>
-#include <linux/timer.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/sysrq.h>
 #include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/platform_device.h>
-#include <linux/serial_sci.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/cpufreq.h>
-#include <linux/clk.h>
-#include <linux/ctype.h>
-#include <linux/err.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
 
 #include "sh-sci.h"
 
+/* Offsets into the sci_port->irqs array */
+enum {
+       SCIx_ERI_IRQ,
+       SCIx_RXI_IRQ,
+       SCIx_TXI_IRQ,
+       SCIx_BRI_IRQ,
+       SCIx_NR_IRQS,
+
+       SCIx_MUX_IRQ = SCIx_NR_IRQS,    /* special case */
+};
+
+#define SCIx_IRQ_IS_MUXED(port)                        \
+       ((port)->irqs[SCIx_ERI_IRQ] ==  \
+        (port)->irqs[SCIx_RXI_IRQ]) || \
+       ((port)->irqs[SCIx_ERI_IRQ] &&  \
+        ((port)->irqs[SCIx_RXI_IRQ] < 0))
+
 struct sci_port {
        struct uart_port        port;
 
        /* Platform configuration */
        struct plat_sci_port    *cfg;
+       int                     overrun_bit;
+       unsigned int            error_mask;
+       unsigned int            sampling_rate;
+
 
        /* Break timer */
        struct timer_list       break_timer;
@@ -74,8 +95,8 @@ struct sci_port {
        /* Function clock */
        struct clk              *fclk;
 
+       int                     irqs[SCIx_NR_IRQS];
        char                    *irqstr[SCIx_NR_IRQS];
-       char                    *gpiostr[SCIx_NR_FNS];
 
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
@@ -421,9 +442,9 @@ static void sci_port_enable(struct sci_port *sci_port)
 
        pm_runtime_get_sync(sci_port->port.dev);
 
-       clk_enable(sci_port->iclk);
+       clk_prepare_enable(sci_port->iclk);
        sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_enable(sci_port->fclk);
+       clk_prepare_enable(sci_port->fclk);
 }
 
 static void sci_port_disable(struct sci_port *sci_port)
@@ -431,8 +452,16 @@ static void sci_port_disable(struct sci_port *sci_port)
        if (!sci_port->port.dev)
                return;
 
-       clk_disable(sci_port->fclk);
-       clk_disable(sci_port->iclk);
+       /* Cancel the break timer to ensure that the timer handler will not try
+        * to access the hardware with clocks and power disabled. Reset the
+        * break flag to make the break debouncing state machine ready for the
+        * next break.
+        */
+       del_timer_sync(&sci_port->break_timer);
+       sci_port->break_flag = 0;
+
+       clk_disable_unprepare(sci_port->fclk);
+       clk_disable_unprepare(sci_port->iclk);
 
        pm_runtime_put_sync(sci_port->port.dev);
 }
@@ -557,7 +586,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return 1;
 
        /* Cast for ARM damage */
-       return !!__raw_readb((void __iomem *)s->cfg->port_reg);
+       return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg);
 }
 
 /* ********************************************************************** *
@@ -733,8 +762,6 @@ static void sci_break_timer(unsigned long data)
 {
        struct sci_port *port = (struct sci_port *)data;
 
-       sci_port_enable(port);
-
        if (sci_rxd_in(&port->port) == 0) {
                port->break_flag = 1;
                sci_schedule_break_timer(port);
@@ -744,8 +771,6 @@ static void sci_break_timer(unsigned long data)
                sci_schedule_break_timer(port);
        } else
                port->break_flag = 0;
-
-       sci_port_disable(port);
 }
 
 static int sci_handle_errors(struct uart_port *port)
@@ -755,19 +780,15 @@ static int sci_handle_errors(struct uart_port *port)
        struct tty_port *tport = &port->state->port;
        struct sci_port *s = to_sci_port(port);
 
-       /*
-        * Handle overruns, if supported.
-        */
-       if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) {
-               if (status & (1 << s->cfg->overrun_bit)) {
-                       port->icount.overrun++;
+       /* Handle overruns */
+       if (status & (1 << s->overrun_bit)) {
+               port->icount.overrun++;
 
-                       /* overrun error */
-                       if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
-                               copied++;
+               /* overrun error */
+               if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
+                       copied++;
 
-                       dev_notice(port->dev, "overrun error");
-               }
+               dev_notice(port->dev, "overrun error");
        }
 
        if (status & SCxSR_FER(port)) {
@@ -829,7 +850,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
        if (!reg->size)
                return 0;
 
-       if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) {
+       if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) {
                serial_port_out(port, SCLSR, 0);
 
                port->icount.overrun++;
@@ -1075,19 +1096,19 @@ static int sci_request_irq(struct sci_port *port)
 
        for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
                struct sci_irq_desc *desc;
-               unsigned int irq;
+               int irq;
 
                if (SCIx_IRQ_IS_MUXED(port)) {
                        i = SCIx_MUX_IRQ;
                        irq = up->irq;
                } else {
-                       irq = port->cfg->irqs[i];
+                       irq = port->irqs[i];
 
                        /*
                         * Certain port types won't support all of the
                         * available interrupt sources.
                         */
-                       if (unlikely(!irq))
+                       if (unlikely(irq < 0))
                                continue;
                }
 
@@ -1112,7 +1133,7 @@ static int sci_request_irq(struct sci_port *port)
 
 out_noirq:
        while (--i >= 0)
-               free_irq(port->cfg->irqs[i], port);
+               free_irq(port->irqs[i], port);
 
 out_nomem:
        while (--j >= 0)
@@ -1130,16 +1151,16 @@ static void sci_free_irq(struct sci_port *port)
         * IRQ first.
         */
        for (i = 0; i < SCIx_NR_IRQS; i++) {
-               unsigned int irq = port->cfg->irqs[i];
+               int irq = port->irqs[i];
 
                /*
                 * Certain port types won't support all of the available
                 * interrupt sources.
                 */
-               if (unlikely(!irq))
+               if (unlikely(irq < 0))
                        continue;
 
-               free_irq(port->cfg->irqs[i], port);
+               free_irq(port->irqs[i], port);
                kfree(port->irqstr[i]);
 
                if (SCIx_IRQ_IS_MUXED(port)) {
@@ -1149,67 +1170,6 @@ static void sci_free_irq(struct sci_port *port)
        }
 }
 
-static const char *sci_gpio_names[SCIx_NR_FNS] = {
-       "sck", "rxd", "txd", "cts", "rts",
-};
-
-static const char *sci_gpio_str(unsigned int index)
-{
-       return sci_gpio_names[index];
-}
-
-static void sci_init_gpios(struct sci_port *port)
-{
-       struct uart_port *up = &port->port;
-       int i;
-
-       if (!port->cfg)
-               return;
-
-       for (i = 0; i < SCIx_NR_FNS; i++) {
-               const char *desc;
-               int ret;
-
-               if (!port->cfg->gpios[i])
-                       continue;
-
-               desc = sci_gpio_str(i);
-
-               port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s",
-                                            dev_name(up->dev), desc);
-
-               /*
-                * If we've failed the allocation, we can still continue
-                * on with a NULL string.
-                */
-               if (!port->gpiostr[i])
-                       dev_notice(up->dev, "%s string allocation failure\n",
-                                  desc);
-
-               ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]);
-               if (unlikely(ret != 0)) {
-                       dev_notice(up->dev, "failed %s gpio request\n", desc);
-
-                       /*
-                        * If we can't get the GPIO for whatever reason,
-                        * no point in keeping the verbose string around.
-                        */
-                       kfree(port->gpiostr[i]);
-               }
-       }
-}
-
-static void sci_free_gpios(struct sci_port *port)
-{
-       int i;
-
-       for (i = 0; i < SCIx_NR_FNS; i++)
-               if (port->cfg->gpios[i]) {
-                       gpio_free(port->cfg->gpios[i]);
-                       kfree(port->gpiostr[i]);
-               }
-}
-
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
        unsigned short status = serial_port_in(port, SCxSR);
@@ -1309,7 +1269,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count)
        }
 
        if (room < count)
-               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+               dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
                         count - room);
        if (!room)
                return room;
@@ -1442,7 +1402,7 @@ static void work_fn_rx(struct work_struct *work)
                int count;
 
                chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
-               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
+               dev_dbg(port->dev, "Read %zu bytes with cookie %d\n",
                        sh_desc->partial, sh_desc->cookie);
 
                spin_lock_irqsave(&port->lock, flags);
@@ -1655,7 +1615,7 @@ static void rx_timer_fn(unsigned long arg)
 
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
                scr &= ~0x4000;
-               enable_irq(s->cfg->irqs[1]);
+               enable_irq(s->irqs[SCIx_RXI_IRQ]);
        }
        serial_port_out(port, SCSCR, scr | SCSCR_RIE);
        dev_dbg(port->dev, "DMA Rx timed out\n");
@@ -1691,16 +1651,17 @@ static void sci_request_dma(struct uart_port *port)
                s->chan_tx = chan;
                sg_init_table(&s->sg_tx, 1);
                /* UART circular tx buffer is an aligned page. */
-               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+               BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
                sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
-                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
+                           UART_XMIT_SIZE,
+                           (uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
                nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
                if (!nent)
                        sci_tx_dma_release(s, false);
                else
-                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
-                               sg_dma_len(&s->sg_tx),
-                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
+                       dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
+                               sg_dma_len(&s->sg_tx), port->state->xmit.buf,
+                               &sg_dma_address(&s->sg_tx));
 
                s->sg_len_tx = nent;
 
@@ -1740,7 +1701,7 @@ static void sci_request_dma(struct uart_port *port)
 
                        sg_init_table(sg, 1);
                        sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
-                                   (int)buf[i] & ~PAGE_MASK);
+                                   (uintptr_t)buf[i] & ~PAGE_MASK);
                        sg_dma_address(sg) = dma[i];
                }
 
@@ -1808,21 +1769,11 @@ static void sci_shutdown(struct uart_port *port)
        sci_free_irq(s);
 }
 
-static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
+static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
                                   unsigned long freq)
 {
-       switch (algo_id) {
-       case SCBRR_ALGO_1:
-               return ((freq + 16 * bps) / (16 * bps) - 1);
-       case SCBRR_ALGO_2:
-               return ((freq + 16 * bps) / (32 * bps) - 1);
-       case SCBRR_ALGO_3:
-               return (((freq * 2) + 16 * bps) / (16 * bps) - 1);
-       case SCBRR_ALGO_4:
-               return (((freq * 2) + 16 * bps) / (32 * bps) - 1);
-       case SCBRR_ALGO_5:
-               return (((freq * 1000 / 32) / bps) - 1);
-       }
+       if (s->sampling_rate)
+               return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
 
        /* Warn, but use a safe default */
        WARN_ON(1);
@@ -1903,12 +1854,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 
        baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
        if (likely(baud && port->uartclk)) {
-               if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) {
+               if (s->cfg->type == PORT_HSCIF) {
                        sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
                                            &cks);
                } else {
-                       t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud,
-                                          port->uartclk);
+                       t = sci_scbrr_calc(s, baud, port->uartclk);
                        for (cks = 0; t >= 256 && cks <= 3; cks++)
                                t >>= 2;
                }
@@ -2115,10 +2065,6 @@ static void sci_config_port(struct uart_port *port, int flags)
 
 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->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
-               return -EINVAL;
        if (ser->baud_base < 2400)
                /* No paper tape reader for Mitch.. */
                return -EINVAL;
@@ -2151,11 +2097,13 @@ static struct uart_ops sci_uart_ops = {
 };
 
 static int sci_init_single(struct platform_device *dev,
-                                    struct sci_port *sci_port,
-                                    unsigned int index,
-                                    struct plat_sci_port *p)
+                          struct sci_port *sci_port, unsigned int index,
+                          struct plat_sci_port *p, bool early)
 {
        struct uart_port *port = &sci_port->port;
+       const struct resource *res;
+       unsigned int sampling_rate;
+       unsigned int i;
        int ret;
 
        sci_port->cfg   = p;
@@ -2164,31 +2112,76 @@ static int sci_init_single(struct platform_device *dev,
        port->iotype    = UPIO_MEM;
        port->line      = index;
 
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (res == NULL)
+               return -ENOMEM;
+
+       port->mapbase = res->start;
+
+       for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i)
+               sci_port->irqs[i] = platform_get_irq(dev, i);
+
+       /* The SCI generates several interrupts. They can be muxed together or
+        * connected to different interrupt lines. In the muxed case only one
+        * interrupt resource is specified. In the non-muxed case three or four
+        * interrupt resources are specified, as the BRI interrupt is optional.
+        */
+       if (sci_port->irqs[0] < 0)
+               return -ENXIO;
+
+       if (sci_port->irqs[1] < 0) {
+               sci_port->irqs[1] = sci_port->irqs[0];
+               sci_port->irqs[2] = sci_port->irqs[0];
+               sci_port->irqs[3] = sci_port->irqs[0];
+       }
+
+       if (p->regtype == SCIx_PROBE_REGTYPE) {
+               ret = sci_probe_regmap(p);
+               if (unlikely(ret))
+                       return ret;
+       }
+
        switch (p->type) {
        case PORT_SCIFB:
                port->fifosize = 256;
+               sci_port->overrun_bit = 9;
+               sampling_rate = 16;
                break;
        case PORT_HSCIF:
                port->fifosize = 128;
+               sampling_rate = 0;
+               sci_port->overrun_bit = 0;
                break;
        case PORT_SCIFA:
                port->fifosize = 64;
+               sci_port->overrun_bit = 9;
+               sampling_rate = 16;
                break;
        case PORT_SCIF:
                port->fifosize = 16;
+               if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
+                       sci_port->overrun_bit = 9;
+                       sampling_rate = 16;
+               } else {
+                       sci_port->overrun_bit = 0;
+                       sampling_rate = 32;
+               }
                break;
        default:
                port->fifosize = 1;
+               sci_port->overrun_bit = 5;
+               sampling_rate = 32;
                break;
        }
 
-       if (p->regtype == SCIx_PROBE_REGTYPE) {
-               ret = sci_probe_regmap(p);
-               if (unlikely(ret))
-                       return ret;
-       }
+       /* SCIFA on sh7723 and sh7724 need a custom sampling rate that doesn't
+        * match the SoC datasheet, this should be investigated. Let platform
+        * data override the sampling rate for now.
+        */
+       sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate
+                               : sampling_rate;
 
-       if (dev) {
+       if (!early) {
                sci_port->iclk = clk_get(&dev->dev, "sci_ick");
                if (IS_ERR(sci_port->iclk)) {
                        sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
@@ -2208,8 +2201,6 @@ static int sci_init_single(struct platform_device *dev,
 
                port->dev = &dev->dev;
 
-               sci_init_gpios(sci_port);
-
                pm_runtime_enable(&dev->dev);
        }
 
@@ -2220,32 +2211,22 @@ static int sci_init_single(struct platform_device *dev,
        /*
         * Establish some sensible defaults for the error detection.
         */
-       if (!p->error_mask)
-               p->error_mask = (p->type == PORT_SCI) ?
+       sci_port->error_mask = (p->type == PORT_SCI) ?
                        SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
 
        /*
         * Establish sensible defaults for the overrun detection, unless
         * the part has explicitly disabled support for it.
         */
-       if (p->overrun_bit != SCIx_NOT_SUPPORTED) {
-               if (p->type == PORT_SCI)
-                       p->overrun_bit = 5;
-               else if (p->scbrr_algo_id == SCBRR_ALGO_4)
-                       p->overrun_bit = 9;
-               else
-                       p->overrun_bit = 0;
 
-               /*
-                * Make the error mask inclusive of overrun detection, if
-                * supported.
-                */
-               p->error_mask |= (1 << p->overrun_bit);
-       }
+       /*
+        * Make the error mask inclusive of overrun detection, if
+        * supported.
+        */
+       sci_port->error_mask |= 1 << sci_port->overrun_bit;
 
-       port->mapbase           = p->mapbase;
        port->type              = p->type;
-       port->flags             = p->flags;
+       port->flags             = UPF_FIXED_PORT | p->flags;
        port->regshift          = p->regshift;
 
        /*
@@ -2255,7 +2236,7 @@ static int sci_init_single(struct platform_device *dev,
         *
         * For the muxed case there's nothing more to do.
         */
-       port->irq               = p->irqs[SCIx_RXI_IRQ];
+       port->irq               = sci_port->irqs[SCIx_RXI_IRQ];
        port->irqflags          = 0;
 
        port->serial_in         = sci_serial_in;
@@ -2270,8 +2251,6 @@ static int sci_init_single(struct platform_device *dev,
 
 static void sci_cleanup_single(struct sci_port *port)
 {
-       sci_free_gpios(port);
-
        clk_put(port->iclk);
        clk_put(port->fclk);
 
@@ -2387,7 +2366,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
 
        early_serial_console.index = pdev->id;
 
-       sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg);
+       sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
 
        serial_console_setup(&early_serial_console, early_serial_buf);
 
@@ -2437,6 +2416,83 @@ static int sci_remove(struct platform_device *dev)
        return 0;
 }
 
+struct sci_port_info {
+       unsigned int type;
+       unsigned int regtype;
+};
+
+static const struct of_device_id of_sci_match[] = {
+       {
+               .compatible = "renesas,scif",
+               .data = (void *)&(const struct sci_port_info) {
+                       .type = PORT_SCIF,
+                       .regtype = SCIx_SH4_SCIF_REGTYPE,
+               },
+       }, {
+               .compatible = "renesas,scifa",
+               .data = (void *)&(const struct sci_port_info) {
+                       .type = PORT_SCIFA,
+                       .regtype = SCIx_SCIFA_REGTYPE,
+               },
+       }, {
+               .compatible = "renesas,scifb",
+               .data = (void *)&(const struct sci_port_info) {
+                       .type = PORT_SCIFB,
+                       .regtype = SCIx_SCIFB_REGTYPE,
+               },
+       }, {
+               .compatible = "renesas,hscif",
+               .data = (void *)&(const struct sci_port_info) {
+                       .type = PORT_HSCIF,
+                       .regtype = SCIx_HSCIF_REGTYPE,
+               },
+       }, {
+               /* Terminator */
+       },
+};
+MODULE_DEVICE_TABLE(of, of_sci_match);
+
+static struct plat_sci_port *
+sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *match;
+       const struct sci_port_info *info;
+       struct plat_sci_port *p;
+       int id;
+
+       if (!IS_ENABLED(CONFIG_OF) || !np)
+               return NULL;
+
+       match = of_match_node(of_sci_match, pdev->dev.of_node);
+       if (!match)
+               return NULL;
+
+       info = match->data;
+
+       p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
+       if (!p) {
+               dev_err(&pdev->dev, "failed to allocate DT config data\n");
+               return NULL;
+       }
+
+       /* Get the line number for the aliases node. */
+       id = of_alias_get_id(np, "serial");
+       if (id < 0) {
+               dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
+               return NULL;
+       }
+
+       *dev_id = id;
+
+       p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       p->type = info->type;
+       p->regtype = info->regtype;
+       p->scscr = SCSCR_RE | SCSCR_TE;
+
+       return p;
+}
+
 static int sci_probe_single(struct platform_device *dev,
                                      unsigned int index,
                                      struct plat_sci_port *p,
@@ -2454,7 +2510,7 @@ static int sci_probe_single(struct platform_device *dev,
                return -EINVAL;
        }
 
-       ret = sci_init_single(dev, sciport, index, p);
+       ret = sci_init_single(dev, sciport, index, p, false);
        if (ret)
                return ret;
 
@@ -2469,8 +2525,9 @@ static int sci_probe_single(struct platform_device *dev,
 
 static int sci_probe(struct platform_device *dev)
 {
-       struct plat_sci_port *p = dev_get_platdata(&dev->dev);
-       struct sci_port *sp = &sci_ports[dev->id];
+       struct plat_sci_port *p;
+       struct sci_port *sp;
+       unsigned int dev_id;
        int ret;
 
        /*
@@ -2481,9 +2538,24 @@ static int sci_probe(struct platform_device *dev)
        if (is_early_platform_device(dev))
                return sci_probe_earlyprintk(dev);
 
+       if (dev->dev.of_node) {
+               p = sci_parse_dt(dev, &dev_id);
+               if (p == NULL)
+                       return -EINVAL;
+       } else {
+               p = dev->dev.platform_data;
+               if (p == NULL) {
+                       dev_err(&dev->dev, "no platform data supplied\n");
+                       return -EINVAL;
+               }
+
+               dev_id = dev->id;
+       }
+
+       sp = &sci_ports[dev_id];
        platform_set_drvdata(dev, sp);
 
-       ret = sci_probe_single(dev, dev->id, p, sp);
+       ret = sci_probe_single(dev, dev_id, p, sp);
        if (ret)
                return ret;
 
@@ -2535,6 +2607,7 @@ static struct platform_driver sci_driver = {
                .name   = "sh-sci",
                .owner  = THIS_MODULE,
                .pm     = &sci_dev_pm_ops,
+               .of_match_table = of_match_ptr(of_sci_match),
        },
 };