From 6186a855158afcd8d97002da973d88adc8637cdd Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 31 Aug 2010 01:36:52 +0800 Subject: arm: move clkdev to drivers/clk as refer in this patch "arm & sh: factorised duplicated clkdev.c" factorise some generic infrastructure to assist looking up struct clks for the ARM & SH architecture. as the code is identical at 99% in linux move it also as preparing for the SH adding Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/clk/Kconfig | 4 ++ drivers/clk/Makefile | 2 + drivers/clk/clkdev.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 drivers/clk/Kconfig create mode 100644 drivers/clk/Makefile create mode 100644 drivers/clk/clkdev.c (limited to 'drivers/clk') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig new file mode 100644 index 0000000000..4168c8896e --- /dev/null +++ b/drivers/clk/Kconfig @@ -0,0 +1,4 @@ + +config CLKDEV_LOOKUP + bool + select HAVE_CLK diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile new file mode 100644 index 0000000000..07613fa172 --- /dev/null +++ b/drivers/clk/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c new file mode 100644 index 0000000000..717fea5689 --- /dev/null +++ b/drivers/clk/clkdev.c @@ -0,0 +1,168 @@ +/* + * drivers/clk/lookup_clkdev.c + * + * Copyright (C) 2008 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Helper for the clk API to assist looking up a struct clk. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static LIST_HEAD(clocks); + +/* + * Find the correct struct clk for the device and connection ID. + * We do slightly fuzzy matching here: + * An entry with a NULL ID is assumed to be a wildcard. + * If an entry has a device ID, it must match + * If an entry has a connection ID, it must match + * Then we take the most specific entry - with the following + * order of precedence: dev+con > dev only > con only. + */ +static struct clk *clk_find(const char *dev_id, const char *con_id) +{ + struct clk_lookup *p; + struct clk *clk = NULL; + int match, best = 0; + + list_for_each_entry(p, &clocks, node) { + match = 0; + if (p->dev_id) { + if (!dev_id || strcmp(p->dev_id, dev_id)) + continue; + match += 2; + } + if (p->con_id) { + if (!con_id || strcmp(p->con_id, con_id)) + continue; + match += 1; + } + + if (match > best) { + clk = p->clk; + if (match != 3) + best = match; + else + break; + } + } + return clk; +} + +struct clk *clk_get_sys(const char *dev_id, const char *con_id) +{ + struct clk *clk; + + clk = clk_find(dev_id, con_id); + if (clk && !__clk_get(clk)) + clk = NULL; + + return clk ? clk : ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get_sys); + +struct clk *clk_get(struct device_d *dev, const char *con_id) +{ + const char *dev_id = dev ? dev_name(dev) : NULL; + + return clk_get_sys(dev_id, con_id); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + __clk_put(clk); +} +EXPORT_SYMBOL(clk_put); + +void clkdev_add(struct clk_lookup *cl) +{ + list_add_tail(&cl->node, &clocks); +} +EXPORT_SYMBOL(clkdev_add); + +void __init clkdev_add_table(struct clk_lookup *cl, size_t num) +{ + while (num--) { + list_add_tail(&cl->node, &clocks); + cl++; + } +} + +#define MAX_DEV_ID 20 +#define MAX_CON_ID 16 + +struct clk_lookup_alloc { + struct clk_lookup cl; + char dev_id[MAX_DEV_ID]; + char con_id[MAX_CON_ID]; +}; + +struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, + const char *dev_fmt, ...) +{ + struct clk_lookup_alloc *cla; + + cla = kzalloc(sizeof(*cla), GFP_KERNEL); + if (!cla) + return NULL; + + cla->cl.clk = clk; + if (con_id) { + strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); + cla->cl.con_id = cla->con_id; + } + + if (dev_fmt) { + va_list ap; + + va_start(ap, dev_fmt); + vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); + cla->cl.dev_id = cla->dev_id; + va_end(ap); + } + + return &cla->cl; +} +EXPORT_SYMBOL(clkdev_alloc); + +int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, + struct device_d *dev) +{ + struct clk *r = clk_get(dev, id); + struct clk_lookup *l; + + if (IS_ERR(r)) + return PTR_ERR(r); + + l = clkdev_alloc(r, alias, alias_dev_name); + clk_put(r); + if (!l) + return -ENODEV; + clkdev_add(l); + return 0; +} +EXPORT_SYMBOL(clk_add_alias); + +/* + * clkdev_drop - remove a clock dynamically allocated + */ +void clkdev_drop(struct clk_lookup *cl) +{ + list_del(&cl->node); + kfree(cl); +} +EXPORT_SYMBOL(clkdev_drop); -- cgit v1.2.3