[POWERPC] Uartlite: Separate the bus binding from the driver proper
[linux-2.6.git] / drivers / serial / uartlite.c
index 10e0da9..c00a627 100644 (file)
@@ -413,59 +413,90 @@ static struct uart_driver ulite_uart_driver = {
 #endif
 };
 
-static int __devinit ulite_probe(struct platform_device *pdev)
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
 {
-       struct resource *res, *res2;
        struct uart_port *port;
+       int rc;
 
-       if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+       /* if id = -1; then scan for a free id and use that */
+       if (id < 0) {
+               for (id = 0; id < ULITE_NR_UARTS; id++)
+                       if (ulite_ports[id].mapbase == 0)
+                               break;
+       }
+       if (id < 0 || id >= ULITE_NR_UARTS) {
+               dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
                return -EINVAL;
+       }
 
-       if (ulite_ports[pdev->id].membase)
+       if (ulite_ports[id].mapbase) {
+               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+                       ULITE_NAME, id);
                return -EBUSY;
+       }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
+       port = &ulite_ports[id];
 
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
+       spin_lock_init(&port->lock);
+       port->fifosize = 16;
+       port->regshift = 2;
+       port->iotype = UPIO_MEM;
+       port->iobase = 1; /* mark port in use */
+       port->mapbase = base;
+       port->membase = NULL;
+       port->ops = &ulite_ops;
+       port->irq = irq;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = dev;
+       port->type = PORT_UNKNOWN;
+       port->line = id;
+
+       dev_set_drvdata(dev, port);
+
+       /* Register the port */
+       rc = uart_add_one_port(&ulite_uart_driver, port);
+       if (rc) {
+               dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+               port->mapbase = 0;
+               dev_set_drvdata(dev, NULL);
+               return rc;
+       }
 
-       port = &ulite_ports[pdev->id];
+       return 0;
+}
 
-       port->fifosize  = 16;
-       port->regshift  = 2;
-       port->iotype    = UPIO_MEM;
-       port->iobase    = 1; /* mark port in use */
-       port->mapbase   = res->start;
-       port->membase   = NULL;
-       port->ops       = &ulite_ops;
-       port->irq       = res2->start;
-       port->flags     = UPF_BOOT_AUTOCONF;
-       port->dev       = &pdev->dev;
-       port->type      = PORT_UNKNOWN;
-       port->line      = pdev->id;
+static int __devinit ulite_release(struct device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(dev);
+       int rc = 0;
 
-       uart_add_one_port(&ulite_uart_driver, port);
-       platform_set_drvdata(pdev, port);
+       if (port) {
+               rc = uart_remove_one_port(&ulite_uart_driver, port);
+               dev_set_drvdata(dev, NULL);
+               port->mapbase = 0;
+       }
 
-       return 0;
+       return rc;
 }
 
-static int ulite_remove(struct platform_device *pdev)
+static int __devinit ulite_probe(struct platform_device *pdev)
 {
-       struct uart_port *port = platform_get_drvdata(pdev);
+       struct resource *res, *res2;
 
-       platform_set_drvdata(pdev, NULL);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
 
-       if (port)
-               uart_remove_one_port(&ulite_uart_driver, port);
+       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res2)
+               return -ENODEV;
 
-       /* mark port as free */
-       port->membase = NULL;
+       return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
+}
 
-       return 0;
+static int ulite_remove(struct platform_device *pdev)
+{
+       return ulite_release(&pdev->dev);
 }
 
 static struct platform_driver ulite_platform_driver = {