On 2014-08-08 at 13:32:03 +0200, Matthias Brugger <matthias.bgg@xxxxxxxxx> wrote: > This patch adds support for the UART block found on Mediatek SoCs. > The device has a highspeed register which influences the calcualtion of the > divisor. The chip lacks support for some baudrates. When requested, we set the > divisor to the next smaller baudrate and adjust the c_cflag accordingly. > > Signed-off-by: Matthias Brugger <matthias.bgg@xxxxxxxxx> > --- > drivers/tty/serial/8250/8250_mtk.c | 296 ++++++++++++++++++++++++++++++++++++ > drivers/tty/serial/8250/Kconfig | 7 + > drivers/tty/serial/8250/Makefile | 1 + > 3 files changed, 304 insertions(+) > create mode 100644 drivers/tty/serial/8250/8250_mtk.c > > diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c > new file mode 100644 > index 0000000..d63080b > --- /dev/null > +++ b/drivers/tty/serial/8250/8250_mtk.c > @@ -0,0 +1,296 @@ [...] > +static int mtk8250_probe(struct platform_device *pdev) > +{ > + struct uart_8250_port uart = {}; > + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + struct mtk8250_data *data; > + int err; > + > + if (!regs || !irq) { > + dev_err(&pdev->dev, "no registers/irq defined\n"); > + return -EINVAL; > + } > + > + spin_lock_init(&uart.port.lock); > + uart.port.mapbase = regs->start; > + uart.port.irq = irq->start; > + uart.port.pm = mtk8250_do_pm; > + uart.port.type = PORT_16550; > + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; > + uart.port.dev = &pdev->dev; > + > + uart.port.membase = devm_ioremap(&pdev->dev, regs->start, > + resource_size(regs)); > + if (!uart.port.membase) > + return -ENOMEM; You can use devm_ioremap_resource here and get rid of the check for !regs above, since devm_ioremap_resource already does that. regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ... uart.port.membase = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(uart.port.membase)) return PTR_ERR(uart.port.membase); > + > + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; I'd suggest to move this kzalloc and the ioremap before the uart.port initialization part above, so you can error out early in case of any failure. > + > + uart.port.iotype = UPIO_MEM32; > + uart.port.regshift = 2; > + uart.port.private_data = data; > + uart.port.set_termios = mtk8250_set_termios; > + > + if (pdev->dev.of_node) { > + err = mtk8250_probe_of(&uart.port, data); > + if (err) > + return err; > + } else > + return -ENODEV; This could also be moved up, directly below devm_kzalloc. > + > + /* Disable Rate Fix function */ > + writel(0x0, uart.port.membase + > + (MTK_UART_RATE_FIX << uart.port.regshift)); > + > + data->line = serial8250_register_8250_port(&uart); > + if (data->line < 0) > + return data->line; > + > + platform_set_drvdata(pdev, data); > + > + pm_runtime_set_active(&pdev->dev); > + pm_runtime_enable(&pdev->dev); > + > + return 0; > +} > + > +static int mtk8250_remove(struct platform_device *pdev) > +{ > + struct mtk8250_data *data = platform_get_drvdata(pdev); > + > + pm_runtime_get_sync(&pdev->dev); > + > + serial8250_unregister_port(data->line); > + if (!IS_ERR(data->clk)) { > + clk_disable_unprepare(data->clk); > + clk_put(data->clk); > + } > + > + pm_runtime_disable(&pdev->dev); > + pm_runtime_put_noidle(&pdev->dev); > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int mtk8250_suspend(struct device *dev) > +{ > + struct mtk8250_data *data = dev_get_drvdata(dev); > + > + serial8250_suspend_port(data->line); > + > + return 0; > +} > + > +static int mtk8250_resume(struct device *dev) > +{ > + struct mtk8250_data *data = dev_get_drvdata(dev); > + > + serial8250_resume_port(data->line); > + > + return 0; > +} > +#endif /* CONFIG_PM_SLEEP */ > + > +#ifdef CONFIG_PM_RUNTIME > +static int mtk8250_runtime_suspend(struct device *dev) > +{ > + struct mtk8250_data *data = dev_get_drvdata(dev); > + > + if (!IS_ERR(data->clk)) > + clk_disable_unprepare(data->clk); > + > + return 0; > +} > + > +static int mtk8250_runtime_resume(struct device *dev) > +{ > + struct mtk8250_data *data = dev_get_drvdata(dev); > + > + if (!IS_ERR(data->clk)) > + clk_prepare_enable(data->clk); > + > + return 0; > +} > +#endif > + > +static const struct dev_pm_ops mtk8250_pm_ops = { > + SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) > + SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, > + NULL) > +}; > + > +static const struct of_device_id mtk8250_of_match[] = { > + { .compatible = "mediatek,mt6577-uart" }, > + { /* Sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, mtk8250_of_match); > + > +static struct platform_driver mtk8250_platform_driver = { > + .driver = { > + .name = "mt6577-uart", > + .owner = THIS_MODULE, This doesn't need to be set here, module_platform_driver/platform_driver_register take care of setting it. > + .pm = &mtk8250_pm_ops, > + .of_match_table = mtk8250_of_match, > + }, > + .probe = mtk8250_probe, > + .remove = mtk8250_remove, > +}; > +module_platform_driver(mtk8250_platform_driver); > + > +MODULE_AUTHOR("Matthias Brugger"); > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html