diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2014-02-03 09:52:34 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-02-03 09:52:34 +0100 |
commit | f4cece7db55f09069d729d4c915989980694d5c7 (patch) | |
tree | 87a80dff7de4f9ad0fc3a1ee8023a5bd2cdecb94 /drivers | |
parent | ca10989374ffb6f08fde864a95c623fc7557b8e8 (diff) | |
parent | 32d6d2ae769b5d3fa8815d28b442711dc4585cbe (diff) | |
download | barebox-f4cece7db55f09069d729d4c915989980694d5c7.tar.gz barebox-f4cece7db55f09069d729d4c915989980694d5c7.tar.xz |
Merge branch 'for-next/clps711x'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpio-clps711x.c | 39 | ||||
-rw-r--r-- | drivers/mfd/syscon.c | 23 | ||||
-rw-r--r-- | drivers/serial/serial_clps711x.c | 120 |
3 files changed, 128 insertions, 54 deletions
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index feead51527..2f12439e0f 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru> + * Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,15 +15,18 @@ static int clps711x_gpio_probe(struct device_d *dev) { - int err; + int err, id = dev->id; void __iomem *dat, *dir = NULL, *dir_inv = NULL; struct bgpio_chip *bgc; - if ((dev->id < 0) || (dev->id > 4)) + if (dev->device_node) + id = of_alias_get_id(dev->device_node, "gpio"); + + if (id < 0 || id > 4) return -ENODEV; dat = dev_request_mem_region(dev, 0); - switch (dev->id) { + switch (id) { case 3: dir_inv = dev_request_mem_region(dev, 1); break; @@ -40,27 +43,35 @@ static int clps711x_gpio_probe(struct device_d *dev) return -ENOMEM; err = bgpio_init(bgc, dev, 1, dat, NULL, NULL, dir, dir_inv, 0); - if (err) { - free(bgc); - return err; - } + if (err) + goto out_err; - bgc->gc.base = dev->id * 8; - switch (dev->id) { + bgc->gc.base = id * 8; + switch (id) { case 4: bgc->gc.ngpio = 3; break; default: - bgc->gc.ngpio = 8; break; } - return gpiochip_add(&bgc->gc); + err = gpiochip_add(&bgc->gc); + +out_err: + if (err) + free(bgc); + + return err; } +static struct of_device_id __maybe_unused clps711x_gpio_dt_ids[] = { + { .compatible = "cirrus,clps711x-gpio", }, +}; + static struct driver_d clps711x_gpio_driver = { - .name = "clps711x-gpio", - .probe = clps711x_gpio_probe, + .name = "clps711x-gpio", + .probe = clps711x_gpio_probe, + .of_compatible = DRV_OF_COMPAT(clps711x_gpio_dt_ids), }; static __init int clps711x_gpio_register(void) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 52cb433a39..8fc84c34d8 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -41,6 +41,26 @@ void __iomem *syscon_base_lookup_by_pdevname(const char *s) return ERR_PTR(-ENODEV); } +void __iomem *syscon_base_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *node; + struct syscon *syscon; + struct device_d *dev; + + node = of_parse_phandle(np, property, 0); + if (!node) + return ERR_PTR(-ENODEV); + + dev = of_find_device_by_node(node); + if (!dev) + return ERR_PTR(-ENODEV); + + syscon = dev->priv; + + return syscon->base; +} + static int syscon_probe(struct device_d *dev) { struct syscon *syscon; @@ -72,9 +92,6 @@ static int syscon_probe(struct device_d *dev) static struct platform_device_id syscon_ids[] = { { "syscon", }, -#ifdef CONFIG_ARCH_CLPS711X - { "clps711x-syscon", }, -#endif { } }; diff --git a/drivers/serial/serial_clps711x.c b/drivers/serial/serial_clps711x.c index e43d141703..a75547ce80 100644 --- a/drivers/serial/serial_clps711x.c +++ b/drivers/serial/serial_clps711x.c @@ -1,7 +1,7 @@ /* * Simple CLPS711X serial driver * - * (C) Copyright 2012 Alexander Shiyan <shc_work@mail.ru> + * (C) Copyright 2012-2014 Alexander Shiyan <shc_work@mail.ru> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,19 +17,37 @@ #include <linux/err.h> #include <mfd/syscon.h> -#include <mach/clps711x.h> +#define UARTDR 0x00 +# define UARTDR_FRMERR (1 << 8) +# define UARTDR_PARERR (1 << 9) +# define UARTDR_OVERR (1 << 10) +#define UBRLCR 0x40 +# define UBRLCR_BAUD_MASK ((1 << 12) - 1) +# define UBRLCR_BREAK (1 << 12) +# define UBRLCR_PRTEN (1 << 13) +# define UBRLCR_EVENPRT (1 << 14) +# define UBRLCR_XSTOP (1 << 15) +# define UBRLCR_FIFOEN (1 << 16) +# define UBRLCR_WRDLEN5 (0 << 17) +# define UBRLCR_WRDLEN6 (1 << 17) +# define UBRLCR_WRDLEN7 (2 << 17) +# define UBRLCR_WRDLEN8 (3 << 17) +# define UBRLCR_WRDLEN_MASK (3 << 17) + +#define SYSCON 0x00 +# define SYSCON_UARTEN (1 << 8) +#define SYSFLG 0x40 +# define SYSFLG_UBUSY (1 << 11) +# define SYSFLG_URXFE (1 << 22) +# define SYSFLG_UTXFF (1 << 23) struct clps711x_uart { - void __iomem *UBRLCR; - void __iomem *UARTDR; + void __iomem *base; void __iomem *syscon; struct clk *uart_clk; struct console_device cdev; }; -#define SYSCON(x) ((x)->syscon + 0x00) -#define SYSFLG(x) ((x)->syscon + 0x40) - static int clps711x_setbaudrate(struct console_device *cdev, int baudrate) { struct clps711x_uart *s = cdev->dev->priv; @@ -38,9 +56,9 @@ static int clps711x_setbaudrate(struct console_device *cdev, int baudrate) divisor = (clk_get_rate(s->uart_clk) / 16) / baudrate; - tmp = readl(s->UBRLCR) & ~UBRLCR_BAUD_MASK; + tmp = readl(s->base + UBRLCR) & ~UBRLCR_BAUD_MASK; tmp |= divisor - 1; - writel(tmp, s->UBRLCR); + writel(tmp, s->base + UBRLCR); return 0; } @@ -51,15 +69,17 @@ static void clps711x_init_port(struct console_device *cdev) u32 tmp; /* Disable the UART */ - writel(readl(SYSCON(s)) & ~SYSCON_UARTEN, SYSCON(s)); + tmp = readl(s->syscon + SYSCON); + writel(tmp & ~SYSCON_UARTEN, s->syscon + SYSCON); /* Setup Line Control Register */ - tmp = readl(s->UBRLCR) & UBRLCR_BAUD_MASK; + tmp = readl(s->base + UBRLCR) & UBRLCR_BAUD_MASK; tmp |= UBRLCR_FIFOEN | UBRLCR_WRDLEN8; /* FIFO on, 8N1 mode */ - writel(tmp, s->UBRLCR); + writel(tmp, s->base + UBRLCR); /* Enable the UART */ - writel(readl(SYSCON(s)) | SYSCON_UARTEN, SYSCON(s)); + tmp = readl(s->syscon + SYSCON); + writel(tmp | SYSCON_UARTEN, s->syscon + SYSCON); } static void clps711x_putc(struct console_device *cdev, char c) @@ -67,11 +87,11 @@ static void clps711x_putc(struct console_device *cdev, char c) struct clps711x_uart *s = cdev->dev->priv; /* Wait until there is space in the FIFO */ - while (readl(SYSFLG(s)) & SYSFLG_UTXFF) - barrier(); + do { + } while (readl(s->syscon + SYSFLG) & SYSFLG_UTXFF); /* Send the character */ - writew(c, s->UARTDR); + writew(c, s->base + UARTDR); } static int clps711x_getc(struct console_device *cdev) @@ -80,10 +100,10 @@ static int clps711x_getc(struct console_device *cdev) u16 data; /* Wait until there is data in the FIFO */ - while (readl(SYSFLG(s)) & SYSFLG_URXFE) - barrier(); + do { + } while (readl(s->syscon + SYSFLG) & SYSFLG_URXFE); - data = readw(s->UARTDR); + data = readw(s->base + UARTDR); /* Check for an error flag */ if (data & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) @@ -96,35 +116,50 @@ static int clps711x_tstc(struct console_device *cdev) { struct clps711x_uart *s = cdev->dev->priv; - return !(readl(SYSFLG(s)) & SYSFLG_URXFE); + return !(readl(s->syscon + SYSFLG) & SYSFLG_URXFE); } static void clps711x_flush(struct console_device *cdev) { struct clps711x_uart *s = cdev->dev->priv; - while (readl(SYSFLG(s)) & SYSFLG_UBUSY) - barrier(); + do { + } while (readl(s->syscon + SYSFLG) & SYSFLG_UBUSY); } static int clps711x_probe(struct device_d *dev) { struct clps711x_uart *s; - char syscon_dev[18]; + int err, id = dev->id; + char syscon_dev[8]; + + if (dev->device_node) + id = of_alias_get_id(dev->device_node, "serial"); - BUG_ON(dev->num_resources != 2); - BUG_ON((dev->id != 0) && (dev->id != 1)); + if (id != 0 && id != 1) + return -EINVAL; s = xzalloc(sizeof(struct clps711x_uart)); s->uart_clk = clk_get(dev, NULL); - BUG_ON(IS_ERR(s->uart_clk)); - - s->UBRLCR = dev_get_mem_region(dev, 0); - s->UARTDR = dev_get_mem_region(dev, 1); - - sprintf(syscon_dev, "clps711x-syscon%i", dev->id + 1); - s->syscon = syscon_base_lookup_by_pdevname(syscon_dev); - BUG_ON(IS_ERR(s->syscon)); + if (IS_ERR(s->uart_clk)) { + err = PTR_ERR(s->uart_clk); + goto out_err; + } + + s->base = dev_get_mem_region(dev, 0); + + if (!dev->device_node) { + sprintf(syscon_dev, "syscon%i", id + 1); + s->syscon = syscon_base_lookup_by_pdevname(syscon_dev); + } else { + s->syscon = syscon_base_lookup_by_phandle(dev->device_node, + "syscon"); + } + + if (IS_ERR(s->syscon)) { + err = PTR_ERR(s->syscon); + goto out_err; + } dev->priv = s; s->cdev.dev = dev; @@ -135,7 +170,13 @@ static int clps711x_probe(struct device_d *dev) s->cdev.setbrg = clps711x_setbaudrate; clps711x_init_port(&s->cdev); - return console_register(&s->cdev); + err = console_register(&s->cdev); + +out_err: + if (err) + free(s); + + return err; } static void clps711x_remove(struct device_d *dev) @@ -147,9 +188,14 @@ static void clps711x_remove(struct device_d *dev) free(s); } +static struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { + { .compatible = "cirrus,clps711x-uart", }, +}; + static struct driver_d clps711x_driver = { - .name = "clps711x_serial", - .probe = clps711x_probe, - .remove = clps711x_remove, + .name = "clps711x-uart", + .probe = clps711x_probe, + .remove = clps711x_remove, + .of_compatible = DRV_OF_COMPAT(clps711x_uart_dt_ids), }; console_platform_driver(clps711x_driver); |