serial: sh-sci: Handle port memory region reservations.
authorPaul Mundt <lethal@linux-sh.org>
Thu, 20 Jan 2011 12:24:03 +0000 (21:24 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Thu, 20 Jan 2011 12:24:03 +0000 (21:24 +0900)
At the moment the request/release_port ops are no-ops with the port
remapping case tied in to the config_port op. This moves the remap logic
in to the request_port, balances it with unmapping in the port release,
and finally takes care of the mem region reservations.

All existing users are of the port autoconf variety, so we follow the
example of other drivers that wrap in to the port request by way of the
config op in the UART_CONFIG_TYPE case.

This is the first step towards fixing up conflicts with multiple users
of the same ports, as currently happens between sh-sci and spi_sh_sci.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
drivers/serial/sh-sci.c

index 44d5bd1..cf2c780 100644 (file)
@@ -1595,27 +1595,43 @@ static const char *sci_type(struct uart_port *port)
        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 .. */
+       /*
+        * 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 int sci_request_port(struct uart_port *port)
+static void sci_release_port(struct uart_port *port)
 {
-       /* Nothing here yet .. */
-       return 0;
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, sci_port_size(port));
 }
 
-static void sci_config_port(struct uart_port *port, int flags)
+static int sci_request_port(struct uart_port *port)
 {
-       struct sci_port *s = to_sci_port(port);
+       unsigned long size = sci_port_size(port);
+       struct resource *res;
 
-       port->type = s->cfg->type;
+       res = request_mem_region(port->mapbase, size, sci_type(port));
+       if (unlikely(res == NULL))
+               return -EBUSY;
 
        if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap_nocache(port->mapbase, 0x40);
-               if (unlikely(!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);
+                       release_resource(res);
+                       return -ENXIO;
+               }
        } else {
                /*
                 * For the simple (and majority of) cases where we don't
@@ -1624,6 +1640,18 @@ static void sci_config_port(struct uart_port *port, int flags)
                 */
                port->membase = (void __iomem *)port->mapbase;
        }
+
+       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)