diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-08-05 12:50:09 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2013-08-05 12:50:09 +0200 |
commit | df6494123fddfa9540f2e0be7b91faed6bab6c00 (patch) | |
tree | f4f6657590a91374d720608315eee9354bedca81 /drivers | |
parent | a67ba6597dfb5e0127742064748227471e616e31 (diff) | |
parent | f9ae3fb01cd7b4e5cfd51152386f0aa1b796fe20 (diff) | |
download | barebox-df6494123fddfa9540f2e0be7b91faed6bab6c00.tar.gz barebox-df6494123fddfa9540f2e0be7b91faed6bab6c00.tar.xz |
Merge branch 'for-next/serial'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Kconfig | 3 | ||||
-rw-r--r-- | drivers/serial/serial_ns16550.c | 139 |
2 files changed, 103 insertions, 39 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a00e5395a2..daf778a441 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -1,8 +1,11 @@ +config HAVE_CLK + bool config CLKDEV_LOOKUP bool config COMMON_CLK + select HAVE_CLK bool config COMMON_CLK_OF_PROVIDER diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index b7913aa3ce..5899d57110 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -38,12 +38,22 @@ #include <errno.h> #include <malloc.h> #include <io.h> +#include <linux/clk.h> #include "serial_ns16550.h" #include <ns16550.h> -/*********** Private Functions **********************************/ -static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate); +struct ns16550_priv { + struct console_device cdev; + struct NS16550_plat plat; + int access_width; + struct clk *clk; +}; + +static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev) +{ + return container_of(cdev, struct ns16550_priv, cdev); +} /** * @brief read register @@ -55,9 +65,10 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate); */ static uint32_t ns16550_read(struct console_device *cdev, uint32_t off) { + struct ns16550_priv *priv = to_ns16550_priv(cdev); struct device_d *dev = cdev->dev; - struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data; - int width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; + struct NS16550_plat *plat = &priv->plat; + int width = priv->access_width; off <<= plat->shift; @@ -85,9 +96,10 @@ static uint32_t ns16550_read(struct console_device *cdev, uint32_t off) static void ns16550_write(struct console_device *cdev, uint32_t val, uint32_t off) { + struct ns16550_priv *priv = to_ns16550_priv(cdev); struct device_d *dev = cdev->dev; - struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data; - int width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; + struct NS16550_plat *plat = &priv->plat; + int width = priv->access_width; off <<= plat->shift; @@ -120,8 +132,8 @@ static void ns16550_write(struct console_device *cdev, uint32_t val, static inline unsigned int ns16550_calc_divisor(struct console_device *cdev, unsigned int baudrate) { - struct NS16550_plat *plat = (struct NS16550_plat *) - cdev->dev->platform_data; + struct ns16550_priv *priv = to_ns16550_priv(cdev); + struct NS16550_plat *plat = &priv->plat; unsigned int clk = plat->clock; return (clk / MODE_X_DIV / baudrate); @@ -129,6 +141,34 @@ static inline unsigned int ns16550_calc_divisor(struct console_device *cdev, } /** + * @brief Set the baudrate for the uart port + * + * @param[in] cdev console device + * @param[in] baud_rate baud rate to set + * + * @return 0-implied to support the baudrate + */ +static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate) +{ + unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate); + struct ns16550_priv *priv = to_ns16550_priv(cdev); + struct NS16550_plat *plat = &priv->plat; + + ns16550_write(cdev, LCR_BKSE, lcr); + ns16550_write(cdev, baud_divisor & 0xff, dll); + ns16550_write(cdev, (baud_divisor >> 8) & 0xff, dlm); + ns16550_write(cdev, LCRVAL, lcr); + ns16550_write(cdev, MCRVAL, mcr); + + if (plat->flags & NS16650_FLAG_DISABLE_FIFO) + ns16550_write(cdev, FCRVAL & ~FCR_FIFO_EN, fcr); + else + ns16550_write(cdev, FCRVAL, fcr); + + return 0; +} + +/** * @brief Initialize the device * * @param[in] cdev pointer to console device @@ -191,32 +231,14 @@ static int ns16550_tstc(struct console_device *cdev) return ((ns16550_read(cdev, lsr) & LSR_DR) != 0); } -/** - * @brief Set the baudrate for the uart port - * - * @param[in] cdev console device - * @param[in] baud_rate baud rate to set - * - * @return 0-implied to support the baudrate - */ -static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate) +static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) { - unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate); - struct NS16550_plat *plat = (struct NS16550_plat *) - cdev->dev->platform_data; + struct device_node *np = dev->device_node; - ns16550_write(cdev, LCR_BKSE, lcr); - ns16550_write(cdev, baud_divisor & 0xff, dll); - ns16550_write(cdev, (baud_divisor >> 8) & 0xff, dlm); - ns16550_write(cdev, LCRVAL, lcr); - ns16550_write(cdev, MCRVAL, mcr); - - if (plat->flags & NS16650_FLAG_DISABLE_FIFO) - ns16550_write(cdev, FCRVAL & ~FCR_FIFO_EN, fcr); - else - ns16550_write(cdev, FCRVAL, fcr); + if (!IS_ENABLED(CONFIG_OFDEVICE)) + return; - return 0; + of_property_read_u32(np, "reg-shift", &priv->plat.shift); } /** @@ -230,21 +252,46 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate) */ static int ns16550_probe(struct device_d *dev) { + struct ns16550_priv *priv; struct console_device *cdev; struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data; + int ret; - /* we do expect platform specific data */ - if (plat == NULL) - return -EINVAL; dev->priv = dev_request_mem_region(dev, 0); - cdev = xzalloc(sizeof(*cdev)); + priv = xzalloc(sizeof(*priv)); - cdev->dev = dev; - if (plat->f_caps) - cdev->f_caps = plat->f_caps; + if (plat) + priv->plat = *plat; else - cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; + ns16550_probe_dt(dev, priv); + + if (!plat || !plat->clock) { + priv->clk = clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto err; + } + priv->plat.clock = clk_get_rate(priv->clk); + } + + if (priv->plat.clock == 0 && IS_ENABLED(CONFIG_OFDEVICE)) { + struct device_node *np = dev->device_node; + + of_property_read_u32(np, "clock-frequency", &priv->plat.clock); + } + + if (priv->plat.clock == 0) { + dev_err(dev, "no valid clockrate\n"); + ret = -EINVAL; + goto err; + } + + priv->access_width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; + + cdev = &priv->cdev; + cdev->dev = dev; + cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; cdev->tstc = ns16550_tstc; cdev->putc = ns16550_putc; cdev->getc = ns16550_getc; @@ -253,13 +300,27 @@ static int ns16550_probe(struct device_d *dev) ns16550_serial_init_port(cdev); return console_register(cdev); + +err: + free(priv); + + return ret; } +static struct of_device_id ns16550_serial_dt_ids[] = { + { + .compatible = "ns16550a", + }, { + /* sentinel */ + }, +}; + /** * @brief Driver registration structure */ static struct driver_d ns16550_serial_driver = { .name = "ns16550_serial", .probe = ns16550_probe, + .of_compatible = DRV_OF_COMPAT(ns16550_serial_dt_ids), }; console_platform_driver(ns16550_serial_driver); |