From cdd1de46ff81bdcfc323953156c1b4573a36cb1f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 23 Jul 2013 07:14:52 +0200 Subject: [PATCH 1/8] clk: provide static inline wrappers So that drivers can use clk_* functions without having to ifdef them away. Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 3 +++ drivers/clk/Kconfig | 3 +++ include/linux/clk.h | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e7d8cdd31..3a7483783 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,6 +34,7 @@ config ARCH_AT91 select CLKDEV_LOOKUP select HAS_DEBUG_LL select HAVE_MACH_ARM_HEAD + select HAVE_CLK config ARCH_BCM2835 bool "Broadcom BCM2835 boards" @@ -99,6 +100,7 @@ config ARCH_NOMADIK bool "STMicroelectronics Nomadik" select CPU_ARM926T select CLOCKSOURCE_NOMADIK + select HAVE_CLK help Support for the Nomadik platform by ST-Ericsson @@ -133,6 +135,7 @@ config ARCH_VERSATILE bool "ARM Versatile boards (ARM926EJ-S)" select CPU_ARM926T select GPIOLIB + select HAVE_CLK config ARCH_VEXPRESS bool "ARM Vexpres boards" diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a00e5395a..daf778a44 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/include/linux/clk.h b/include/linux/clk.h index 0a565efb0..6aed1dee7 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -19,12 +19,13 @@ struct device_d; * The base API. */ - /* * struct clk - an machine class defined object / cookie. */ struct clk; +#ifdef CONFIG_HAVE_CLK + /** * clk_get - lookup and obtain a reference to a clock producer. * @dev: device for clock "consumer" @@ -157,6 +158,42 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id); int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, struct device_d *dev); +#else + +static inline struct clk *clk_get(struct device_d *dev, const char *id) +{ + return NULL; +} + +static inline int clk_enable(struct clk *clk) +{ + return 0; +} + +static inline void clk_disable(struct clk *clk) +{ +} + +static inline unsigned long clk_get_rate(struct clk *clk) +{ + return 0; +} + +static inline void clk_put(struct clk *clk) +{ +} + +static inline long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} + +static inline int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} +#endif + #ifdef CONFIG_COMMON_CLK struct clk_ops { int (*enable)(struct clk *clk); From ffd44fc14c26048fecb8bc4ae616770d6b3eb8ec Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 22 Jul 2013 21:23:54 +0200 Subject: [PATCH 2/8] serial: ns16550: reorder functions to avoid forward declaration Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 59 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index b7913aa3c..b792ba546 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -42,9 +42,6 @@ #include "serial_ns16550.h" #include -/*********** Private Functions **********************************/ -static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate); - /** * @brief read register * @@ -128,6 +125,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_plat *plat = (struct NS16550_plat *) + cdev->dev->platform_data; + + 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 * @@ -191,34 +216,6 @@ 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) -{ - unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate); - struct NS16550_plat *plat = (struct NS16550_plat *) - cdev->dev->platform_data; - - 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 Probe entry point -called on the first match for device * From 25c9ecfa828e117427136478a9bae7deb233d790 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 22 Jul 2013 21:33:46 +0200 Subject: [PATCH 3/8] serial: ns16550: introduce private struct Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 37 +++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index b792ba546..f9a17f4a2 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -42,6 +42,17 @@ #include "serial_ns16550.h" #include +struct ns16550_priv { + struct console_device cdev; + struct NS16550_plat plat; + int access_width; +}; + +static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev) +{ + return container_of(cdev, struct ns16550_priv, cdev); +} + /** * @brief read register * @@ -52,9 +63,10 @@ */ 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; @@ -82,9 +94,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; @@ -117,8 +130,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); @@ -136,8 +149,8 @@ static inline unsigned int ns16550_calc_divisor(struct console_device *cdev, static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate) { unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate); - 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; ns16550_write(cdev, LCR_BKSE, lcr); ns16550_write(cdev, baud_divisor & 0xff, dll); @@ -227,6 +240,7 @@ static int ns16550_tstc(struct console_device *cdev) */ 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; @@ -235,7 +249,12 @@ static int ns16550_probe(struct device_d *dev) return -EINVAL; dev->priv = dev_request_mem_region(dev, 0); - cdev = xzalloc(sizeof(*cdev)); + priv = xzalloc(sizeof(*priv)); + + cdev = &priv->cdev; + priv->plat = *plat; + + priv->access_width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; cdev->dev = dev; if (plat->f_caps) From 38438d4a0f27e6fc8637819bc47ec00a87cefab6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 22 Jul 2013 21:35:20 +0200 Subject: [PATCH 4/8] serial: ns16550: remove f_caps from platform_data So far no user had the need to set the flags, so just remove them from platform data. Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 5 +---- include/ns16550.h | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index f9a17f4a2..dd50fc558 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -257,10 +257,7 @@ static int ns16550_probe(struct device_d *dev) priv->access_width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; cdev->dev = dev; - if (plat->f_caps) - cdev->f_caps = plat->f_caps; - else - cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; + cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; cdev->tstc = ns16550_tstc; cdev->putc = ns16550_putc; cdev->getc = ns16550_getc; diff --git a/include/ns16550.h b/include/ns16550.h index 27cb4cf10..36aa5ffae 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -33,10 +33,6 @@ struct NS16550_plat { /** Clock speed */ unsigned int clock; - /** Console capabilities: - * CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR @see console.h - */ - unsigned char f_caps; /** * register read access capability */ From 4b557daac9ca11b9ee4af54657caeb5674dd26fc Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 22 Jul 2013 21:42:56 +0200 Subject: [PATCH 5/8] serial: ns16550: Add clk support and make platform_data optional The clockrate was the only really needed field from platform data. Add clk support to retrieve the clockrate and make platform data optional. Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index dd50fc558..b01078575 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "serial_ns16550.h" #include @@ -46,6 +47,7 @@ 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) @@ -243,10 +245,8 @@ 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); priv = xzalloc(sizeof(*priv)); @@ -254,6 +254,21 @@ static int ns16550_probe(struct device_d *dev) cdev = &priv->cdev; priv->plat = *plat; + 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) { + dev_err(dev, "no valid clockrate\n"); + ret = -EINVAL; + goto err; + } + priv->access_width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; cdev->dev = dev; @@ -266,6 +281,11 @@ static int ns16550_probe(struct device_d *dev) ns16550_serial_init_port(cdev); return console_register(cdev); + +err: + free(priv); + + return ret; } /** From c841e7a26211459718552353d3aecdf2db686682 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 22 Jul 2013 21:55:36 +0200 Subject: [PATCH 6/8] serial: ns16550: Add devicetree probe support Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index b01078575..ad3125ac0 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -231,6 +231,16 @@ static int ns16550_tstc(struct console_device *cdev) return ((ns16550_read(cdev, lsr) & LSR_DR) != 0); } +static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) +{ + struct device_node *np = dev->device_node; + + if (!IS_ENABLED(CONFIG_OFDEVICE)) + return; + + of_property_read_u32(np, "reg-shift", &priv->plat.shift); +} + /** * @brief Probe entry point -called on the first match for device * @@ -251,8 +261,12 @@ static int ns16550_probe(struct device_d *dev) priv = xzalloc(sizeof(*priv)); + if (plat) + priv->plat = *plat; + else + ns16550_probe_dt(dev, priv); + cdev = &priv->cdev; - priv->plat = *plat; if (!plat || !plat->clock) { priv->clk = clk_get(dev, NULL); @@ -288,11 +302,20 @@ err: 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); From fe290ec08fb2195bb1d10035c7f07a8017c36f9d Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Tue, 23 Jul 2013 19:28:01 +0400 Subject: [PATCH 7/8] serial: ns16550: get clock-frequency from dt This patch helps clk-less boards to use device tree for clock frequency probing (taken from linux.git/drivers/tty/serial/of_serial.c). Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index ad3125ac0..6a3c865b3 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -277,6 +277,12 @@ static int ns16550_probe(struct device_d *dev) 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; From f9ae3fb01cd7b4e5cfd51152386f0aa1b796fe20 Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Tue, 23 Jul 2013 19:28:02 +0400 Subject: [PATCH 8/8] serial: ns16550: fill cdev just-in-time Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 6a3c865b3..5899d5711 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -266,8 +266,6 @@ static int ns16550_probe(struct device_d *dev) else ns16550_probe_dt(dev, priv); - cdev = &priv->cdev; - if (!plat || !plat->clock) { priv->clk = clk_get(dev, NULL); if (IS_ERR(priv->clk)) { @@ -291,6 +289,7 @@ static int ns16550_probe(struct device_d *dev) 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;