drivers: PL011: refactor pl011_probe()
authorAndre Przywara <andre.przywara@arm.com>
Thu, 21 May 2015 16:26:18 +0000 (17:26 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 24 May 2015 20:08:51 +0000 (13:08 -0700)
Currently the pl011_probe() function is relying on some AMBA IDs
and a device tree node to initialize the driver and a port.
Both features are not necessarily required for the driver:
- we lack AMBA IDs in the ARM SBSA generic UART and
- we lack a DT node in ACPI systems.
So lets refactor the function to ease later reuse.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Tested-by: Mark Langsdorf <mlangsdo@redhat.com>
Tested-by: Naresh Bhat <nbhat@cavium.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/amba-pl011.c

index 686951a..38d2245 100644 (file)
@@ -2173,65 +2173,54 @@ static void pl011_unregister_port(struct uart_amba_port *uap)
                uart_unregister_driver(&amba_reg);
 }
 
-static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+static int pl011_find_free_port(void)
 {
-       struct uart_amba_port *uap;
-       struct vendor_data *vendor = id->data;
-       void __iomem *base;
-       int i, ret;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
                if (amba_ports[i] == NULL)
-                       break;
-
-       if (i == ARRAY_SIZE(amba_ports))
-               return -EBUSY;
+                       return i;
 
-       uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
-                          GFP_KERNEL);
-       if (uap == NULL)
-               return -ENOMEM;
+       return -EBUSY;
+}
 
-       i = pl011_probe_dt_alias(i, &dev->dev);
+static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
+                           struct resource *mmiobase, int index)
+{
+       void __iomem *base;
 
-       base = devm_ioremap(&dev->dev, dev->res.start,
-                           resource_size(&dev->res));
+       base = devm_ioremap_resource(dev, mmiobase);
        if (!base)
                return -ENOMEM;
 
-       uap->clk = devm_clk_get(&dev->dev, NULL);
-       if (IS_ERR(uap->clk))
-               return PTR_ERR(uap->clk);
+       index = pl011_probe_dt_alias(index, dev);
 
-       uap->vendor = vendor;
-       uap->lcrh_rx = vendor->lcrh_rx;
-       uap->lcrh_tx = vendor->lcrh_tx;
        uap->old_cr = 0;
-       uap->fifosize = vendor->get_fifosize(dev);
-       uap->port.dev = &dev->dev;
-       uap->port.mapbase = dev->res.start;
+       uap->port.dev = dev;
+       uap->port.mapbase = mmiobase->start;
        uap->port.membase = base;
        uap->port.iotype = UPIO_MEM;
-       uap->port.irq = dev->irq[0];
        uap->port.fifosize = uap->fifosize;
-       uap->port.ops = &amba_pl011_pops;
        uap->port.flags = UPF_BOOT_AUTOCONF;
-       uap->port.line = i;
+       uap->port.line = index;
 
-       /* Ensure interrupts from this UART are masked and cleared */
-       writew(0, uap->port.membase + UART011_IMSC);
-       writew(0xffff, uap->port.membase + UART011_ICR);
+       amba_ports[index] = uap;
 
-       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+       return 0;
+}
 
-       amba_ports[i] = uap;
+static int pl011_register_port(struct uart_amba_port *uap)
+{
+       int ret;
 
-       amba_set_drvdata(dev, uap);
+       /* Ensure interrupts from this UART are masked and cleared */
+       writew(0, uap->port.membase + UART011_IMSC);
+       writew(0xffff, uap->port.membase + UART011_ICR);
 
        if (!amba_reg.state) {
                ret = uart_register_driver(&amba_reg);
                if (ret < 0) {
-                       dev_err(&dev->dev,
+                       dev_err(uap->port.dev,
                                "Failed to register AMBA-PL011 driver\n");
                        return ret;
                }
@@ -2244,6 +2233,43 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
        return ret;
 }
 
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+{
+       struct uart_amba_port *uap;
+       struct vendor_data *vendor = id->data;
+       int portnr, ret;
+
+       portnr = pl011_find_free_port();
+       if (portnr < 0)
+               return portnr;
+
+       uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+                          GFP_KERNEL);
+       if (!uap)
+               return -ENOMEM;
+
+       uap->clk = devm_clk_get(&dev->dev, NULL);
+       if (IS_ERR(uap->clk))
+               return PTR_ERR(uap->clk);
+
+       uap->vendor = vendor;
+       uap->lcrh_rx = vendor->lcrh_rx;
+       uap->lcrh_tx = vendor->lcrh_tx;
+       uap->fifosize = vendor->get_fifosize(dev);
+       uap->port.irq = dev->irq[0];
+       uap->port.ops = &amba_pl011_pops;
+
+       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+
+       ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
+       if (ret)
+               return ret;
+
+       amba_set_drvdata(dev, uap);
+
+       return pl011_register_port(uap);
+}
+
 static int pl011_remove(struct amba_device *dev)
 {
        struct uart_amba_port *uap = amba_get_drvdata(dev);