diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/uartlite.c | 99 |
1 files changed, 65 insertions, 34 deletions
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 10e0da97811e..c00a627ef89e 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -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 = { |