Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30 148 lines 3.1 kB view raw
1/* 2 * arch/arm/common/clkdev.c 3 * 4 * Copyright (C) 2008 Russell King. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Helper for the clk API to assist looking up a struct clk. 11 */ 12#include <linux/module.h> 13#include <linux/kernel.h> 14#include <linux/device.h> 15#include <linux/list.h> 16#include <linux/errno.h> 17#include <linux/err.h> 18#include <linux/string.h> 19#include <linux/mutex.h> 20 21#include <asm/clkdev.h> 22#include <mach/clkdev.h> 23 24static LIST_HEAD(clocks); 25static DEFINE_MUTEX(clocks_mutex); 26 27/* 28 * Find the correct struct clk for the device and connection ID. 29 * We do slightly fuzzy matching here: 30 * An entry with a NULL ID is assumed to be a wildcard. 31 * If an entry has a device ID, it must match 32 * If an entry has a connection ID, it must match 33 * Then we take the most specific entry - with the following 34 * order of precidence: dev+con > dev only > con only. 35 */ 36static struct clk *clk_find(const char *dev_id, const char *con_id) 37{ 38 struct clk_lookup *p; 39 struct clk *clk = NULL; 40 int match, best = 0; 41 42 list_for_each_entry(p, &clocks, node) { 43 match = 0; 44 if (p->dev_id) { 45 if (!dev_id || strcmp(p->dev_id, dev_id)) 46 continue; 47 match += 2; 48 } 49 if (p->con_id) { 50 if (!con_id || strcmp(p->con_id, con_id)) 51 continue; 52 match += 1; 53 } 54 if (match == 0) 55 continue; 56 57 if (match > best) { 58 clk = p->clk; 59 best = match; 60 } 61 } 62 return clk; 63} 64 65struct clk *clk_get_sys(const char *dev_id, const char *con_id) 66{ 67 struct clk *clk; 68 69 mutex_lock(&clocks_mutex); 70 clk = clk_find(dev_id, con_id); 71 if (clk && !__clk_get(clk)) 72 clk = NULL; 73 mutex_unlock(&clocks_mutex); 74 75 return clk ? clk : ERR_PTR(-ENOENT); 76} 77EXPORT_SYMBOL(clk_get_sys); 78 79struct clk *clk_get(struct device *dev, const char *con_id) 80{ 81 const char *dev_id = dev ? dev_name(dev) : NULL; 82 83 return clk_get_sys(dev_id, con_id); 84} 85EXPORT_SYMBOL(clk_get); 86 87void clk_put(struct clk *clk) 88{ 89 __clk_put(clk); 90} 91EXPORT_SYMBOL(clk_put); 92 93void clkdev_add(struct clk_lookup *cl) 94{ 95 mutex_lock(&clocks_mutex); 96 list_add_tail(&cl->node, &clocks); 97 mutex_unlock(&clocks_mutex); 98} 99EXPORT_SYMBOL(clkdev_add); 100 101#define MAX_DEV_ID 20 102#define MAX_CON_ID 16 103 104struct clk_lookup_alloc { 105 struct clk_lookup cl; 106 char dev_id[MAX_DEV_ID]; 107 char con_id[MAX_CON_ID]; 108}; 109 110struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, 111 const char *dev_fmt, ...) 112{ 113 struct clk_lookup_alloc *cla; 114 115 cla = kzalloc(sizeof(*cla), GFP_KERNEL); 116 if (!cla) 117 return NULL; 118 119 cla->cl.clk = clk; 120 if (con_id) { 121 strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); 122 cla->cl.con_id = cla->con_id; 123 } 124 125 if (dev_fmt) { 126 va_list ap; 127 128 va_start(ap, dev_fmt); 129 vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); 130 cla->cl.dev_id = cla->dev_id; 131 va_end(ap); 132 } 133 134 return &cla->cl; 135} 136EXPORT_SYMBOL(clkdev_alloc); 137 138/* 139 * clkdev_drop - remove a clock dynamically allocated 140 */ 141void clkdev_drop(struct clk_lookup *cl) 142{ 143 mutex_lock(&clocks_mutex); 144 list_del(&cl->node); 145 mutex_unlock(&clocks_mutex); 146 kfree(cl); 147} 148EXPORT_SYMBOL(clkdev_drop);