123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /*
- * arch/arm/common/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 <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/device.h>
- #include <linux/list.h>
- #include <linux/errno.h>
- #include <linux/err.h>
- #include <linux/string.h>
- #include <linux/mutex.h>
- #include <asm/clkdev.h>
- #include <mach/clkdev.h>
- static LIST_HEAD(clocks);
- static DEFINE_MUTEX(clocks_mutex);
- /*
- * 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 precidence: 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 == 0)
- continue;
- if (match > best) {
- clk = p->clk;
- best = match;
- }
- }
- return clk;
- }
- struct clk *clk_get_sys(const char *dev_id, const char *con_id)
- {
- struct clk *clk;
- mutex_lock(&clocks_mutex);
- clk = clk_find(dev_id, con_id);
- if (clk && !__clk_get(clk))
- clk = NULL;
- mutex_unlock(&clocks_mutex);
- return clk ? clk : ERR_PTR(-ENOENT);
- }
- EXPORT_SYMBOL(clk_get_sys);
- struct clk *clk_get(struct device *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)
- {
- mutex_lock(&clocks_mutex);
- list_add_tail(&cl->node, &clocks);
- mutex_unlock(&clocks_mutex);
- }
- EXPORT_SYMBOL(clkdev_add);
- #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);
- /*
- * clkdev_drop - remove a clock dynamically allocated
- */
- void clkdev_drop(struct clk_lookup *cl)
- {
- mutex_lock(&clocks_mutex);
- list_del(&cl->node);
- mutex_unlock(&clocks_mutex);
- kfree(cl);
- }
- EXPORT_SYMBOL(clkdev_drop);
|