1 /* 2 * drivers/clk/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 #include <linux/clk.h> 21 #include <linux/clkdev.h> 22 23 static LIST_HEAD(clocks); 24 static DEFINE_MUTEX(clocks_mutex); 25 26 /* 27 * Find the correct struct clk for the device and connection ID. 28 * We do slightly fuzzy matching here: 29 * An entry with a NULL ID is assumed to be a wildcard. 30 * If an entry has a device ID, it must match 31 * If an entry has a connection ID, it must match 32 * Then we take the most specific entry - with the following 33 * order of precedence: dev+con > dev only > con only. 34 */ 35 static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) 36 { 37 struct clk_lookup *p, *cl = NULL; 38 int match, best = 0; 39 40 list_for_each_entry(p, &clocks, node) { 41 match = 0; 42 if (p->dev_id) { 43 if (!dev_id || strcmp(p->dev_id, dev_id)) 44 continue; 45 match += 2; 46 } 47 if (p->con_id) { 48 if (!con_id || strcmp(p->con_id, con_id)) 49 continue; 50 match += 1; 51 } 52 53 if (match > best) { 54 cl = p; 55 if (match != 3) 56 best = match; 57 else 58 break; 59 } 60 } 61 return cl; 62 } 63 64 struct clk *clk_get_sys(const char *dev_id, const char *con_id) 65 { 66 struct clk_lookup *cl; 67 68 mutex_lock(&clocks_mutex); 69 cl = clk_find(dev_id, con_id); 70 if (cl && !__clk_get(cl->clk)) 71 cl = NULL; 72 mutex_unlock(&clocks_mutex); 73 74 return cl ? cl->clk : ERR_PTR(-ENOENT); 75 } 76 EXPORT_SYMBOL(clk_get_sys); 77 78 struct clk *clk_get(struct device *dev, const char *con_id) 79 { 80 const char *dev_id = dev ? dev_name(dev) : NULL; 81 82 return clk_get_sys(dev_id, con_id); 83 } 84 EXPORT_SYMBOL(clk_get); 85 86 void clk_put(struct clk *clk) 87 { 88 __clk_put(clk); 89 } 90 EXPORT_SYMBOL(clk_put); 91 92 void clkdev_add(struct clk_lookup *cl) 93 { 94 mutex_lock(&clocks_mutex); 95 list_add_tail(&cl->node, &clocks); 96 mutex_unlock(&clocks_mutex); 97 } 98 EXPORT_SYMBOL(clkdev_add); 99 100 void __init clkdev_add_table(struct clk_lookup *cl, size_t num) 101 { 102 mutex_lock(&clocks_mutex); 103 while (num--) { 104 list_add_tail(&cl->node, &clocks); 105 cl++; 106 } 107 mutex_unlock(&clocks_mutex); 108 } 109 110 #define MAX_DEV_ID 20 111 #define MAX_CON_ID 16 112 113 struct clk_lookup_alloc { 114 struct clk_lookup cl; 115 char dev_id[MAX_DEV_ID]; 116 char con_id[MAX_CON_ID]; 117 }; 118 119 struct clk_lookup * __init_refok 120 clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 121 { 122 struct clk_lookup_alloc *cla; 123 124 cla = __clkdev_alloc(sizeof(*cla)); 125 if (!cla) 126 return NULL; 127 128 cla->cl.clk = clk; 129 if (con_id) { 130 strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); 131 cla->cl.con_id = cla->con_id; 132 } 133 134 if (dev_fmt) { 135 va_list ap; 136 137 va_start(ap, dev_fmt); 138 vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); 139 cla->cl.dev_id = cla->dev_id; 140 va_end(ap); 141 } 142 143 return &cla->cl; 144 } 145 EXPORT_SYMBOL(clkdev_alloc); 146 147 int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, 148 struct device *dev) 149 { 150 struct clk *r = clk_get(dev, id); 151 struct clk_lookup *l; 152 153 if (IS_ERR(r)) 154 return PTR_ERR(r); 155 156 l = clkdev_alloc(r, alias, alias_dev_name); 157 clk_put(r); 158 if (!l) 159 return -ENODEV; 160 clkdev_add(l); 161 return 0; 162 } 163 EXPORT_SYMBOL(clk_add_alias); 164 165 /* 166 * clkdev_drop - remove a clock dynamically allocated 167 */ 168 void clkdev_drop(struct clk_lookup *cl) 169 { 170 mutex_lock(&clocks_mutex); 171 list_del(&cl->node); 172 mutex_unlock(&clocks_mutex); 173 kfree(cl); 174 } 175 EXPORT_SYMBOL(clkdev_drop); 176