|
@@ -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 = {
|