clkdev.c revision 6d803ba736abb5e122dede70a4720e4843dd6df4
10318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King/* 26d803ba736abb5e122dede70a4720e4843dd6df4Jean-Christop PLAGNIOL-VILLARD * drivers/clk/clkdev.c 30318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * 40318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * Copyright (C) 2008 Russell King. 50318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * 60318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * This program is free software; you can redistribute it and/or modify 70318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * it under the terms of the GNU General Public License version 2 as 80318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * published by the Free Software Foundation. 90318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * 100318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * Helper for the clk API to assist looking up a struct clk. 110318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King */ 120318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/module.h> 130318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/kernel.h> 140318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/device.h> 150318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/list.h> 160318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/errno.h> 170318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/err.h> 180318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/string.h> 190318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#include <linux/mutex.h> 20c0c60c4b9ab45bb02b20796401dd6a90770fd0eeHartley Sweeten#include <linux/clk.h> 216d803ba736abb5e122dede70a4720e4843dd6df4Jean-Christop PLAGNIOL-VILLARD#include <linux/clkdev.h> 220318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 230318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingstatic LIST_HEAD(clocks); 240318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingstatic DEFINE_MUTEX(clocks_mutex); 250318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 26409dc360b49480b57869ffd457e4b95901b76b75Russell King/* 27409dc360b49480b57869ffd457e4b95901b76b75Russell King * Find the correct struct clk for the device and connection ID. 28409dc360b49480b57869ffd457e4b95901b76b75Russell King * We do slightly fuzzy matching here: 29409dc360b49480b57869ffd457e4b95901b76b75Russell King * An entry with a NULL ID is assumed to be a wildcard. 30409dc360b49480b57869ffd457e4b95901b76b75Russell King * If an entry has a device ID, it must match 31409dc360b49480b57869ffd457e4b95901b76b75Russell King * If an entry has a connection ID, it must match 32409dc360b49480b57869ffd457e4b95901b76b75Russell King * Then we take the most specific entry - with the following 33659431fcafd820cc426afedadcc4548933224985Uwe Kleine-König * order of precedence: dev+con > dev only > con only. 34409dc360b49480b57869ffd457e4b95901b76b75Russell King */ 350318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingstatic struct clk *clk_find(const char *dev_id, const char *con_id) 360318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 370318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King struct clk_lookup *p; 380318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King struct clk *clk = NULL; 390318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King int match, best = 0; 400318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 410318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King list_for_each_entry(p, &clocks, node) { 420318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King match = 0; 43409dc360b49480b57869ffd457e4b95901b76b75Russell King if (p->dev_id) { 44409dc360b49480b57869ffd457e4b95901b76b75Russell King if (!dev_id || strcmp(p->dev_id, dev_id)) 45409dc360b49480b57869ffd457e4b95901b76b75Russell King continue; 46409dc360b49480b57869ffd457e4b95901b76b75Russell King match += 2; 47409dc360b49480b57869ffd457e4b95901b76b75Russell King } 48409dc360b49480b57869ffd457e4b95901b76b75Russell King if (p->con_id) { 49409dc360b49480b57869ffd457e4b95901b76b75Russell King if (!con_id || strcmp(p->con_id, con_id)) 50409dc360b49480b57869ffd457e4b95901b76b75Russell King continue; 51409dc360b49480b57869ffd457e4b95901b76b75Russell King match += 1; 52409dc360b49480b57869ffd457e4b95901b76b75Russell King } 530318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 540318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King if (match > best) { 550318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King clk = p->clk; 56e4bf5becccf4685754c4d8e4485bb2ff7d28147fviresh kumar if (match != 3) 57e4bf5becccf4685754c4d8e4485bb2ff7d28147fviresh kumar best = match; 58e4bf5becccf4685754c4d8e4485bb2ff7d28147fviresh kumar else 59e4bf5becccf4685754c4d8e4485bb2ff7d28147fviresh kumar break; 600318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King } 610318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King } 620318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King return clk; 630318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 640318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 6505fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauerstruct clk *clk_get_sys(const char *dev_id, const char *con_id) 660318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 670318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King struct clk *clk; 680318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 690318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_lock(&clocks_mutex); 700318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King clk = clk_find(dev_id, con_id); 710318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King if (clk && !__clk_get(clk)) 720318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King clk = NULL; 730318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_unlock(&clocks_mutex); 740318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 750318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King return clk ? clk : ERR_PTR(-ENOENT); 760318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 7705fd8e73e1357feaea9c48938d937eae76b4aef4Sascha HauerEXPORT_SYMBOL(clk_get_sys); 7805fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer 7905fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauerstruct clk *clk_get(struct device *dev, const char *con_id) 8005fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer{ 8105fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer const char *dev_id = dev ? dev_name(dev) : NULL; 8205fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer 8305fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer return clk_get_sys(dev_id, con_id); 8405fd8e73e1357feaea9c48938d937eae76b4aef4Sascha Hauer} 850318e693d3a56836632bf1a2cfdafb7f34bcc703Russell KingEXPORT_SYMBOL(clk_get); 860318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 870318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingvoid clk_put(struct clk *clk) 880318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 890318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King __clk_put(clk); 900318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 910318e693d3a56836632bf1a2cfdafb7f34bcc703Russell KingEXPORT_SYMBOL(clk_put); 920318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 930318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingvoid clkdev_add(struct clk_lookup *cl) 940318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 950318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_lock(&clocks_mutex); 960318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King list_add_tail(&cl->node, &clocks); 970318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_unlock(&clocks_mutex); 980318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 990318e693d3a56836632bf1a2cfdafb7f34bcc703Russell KingEXPORT_SYMBOL(clkdev_add); 1000318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1010a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell Kingvoid __init clkdev_add_table(struct clk_lookup *cl, size_t num) 1020a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King{ 1030a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King mutex_lock(&clocks_mutex); 1040a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King while (num--) { 1050a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King list_add_tail(&cl->node, &clocks); 1060a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King cl++; 1070a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King } 1080a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King mutex_unlock(&clocks_mutex); 1090a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King} 1100a0300dc8c4b3f3ce5c9ef5a0a4be5442590398fRussell King 1110318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#define MAX_DEV_ID 20 1120318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King#define MAX_CON_ID 16 1130318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1140318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingstruct clk_lookup_alloc { 1150318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King struct clk_lookup cl; 1160318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King char dev_id[MAX_DEV_ID]; 1170318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King char con_id[MAX_CON_ID]; 1180318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King}; 1190318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1206d803ba736abb5e122dede70a4720e4843dd6df4Jean-Christop PLAGNIOL-VILLARDstruct clk_lookup * __init_refok 1216d803ba736abb5e122dede70a4720e4843dd6df4Jean-Christop PLAGNIOL-VILLARDclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 1220318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 1230318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King struct clk_lookup_alloc *cla; 1240318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1256d803ba736abb5e122dede70a4720e4843dd6df4Jean-Christop PLAGNIOL-VILLARD cla = __clkdev_alloc(sizeof(*cla)); 1260318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King if (!cla) 1270318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King return NULL; 1280318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1290318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King cla->cl.clk = clk; 1300318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King if (con_id) { 1310318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); 1320318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King cla->cl.con_id = cla->con_id; 1330318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King } 1340318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1350318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King if (dev_fmt) { 1360318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King va_list ap; 1370318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1380318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King va_start(ap, dev_fmt); 1390318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); 1400318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King cla->cl.dev_id = cla->dev_id; 1410318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King va_end(ap); 1420318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King } 1430318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 1440318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King return &cla->cl; 1450318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 1460318e693d3a56836632bf1a2cfdafb7f34bcc703Russell KingEXPORT_SYMBOL(clkdev_alloc); 1470318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King 148c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgrenint clk_add_alias(const char *alias, const char *alias_dev_name, char *id, 149c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren struct device *dev) 150c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren{ 151c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren struct clk *r = clk_get(dev, id); 152c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren struct clk_lookup *l; 153c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren 154c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren if (IS_ERR(r)) 155c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren return PTR_ERR(r); 156c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren 157c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren l = clkdev_alloc(r, alias, alias_dev_name); 158c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren clk_put(r); 159c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren if (!l) 160c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren return -ENODEV; 161c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren clkdev_add(l); 162c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren return 0; 163c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren} 164c0683039207226afcffbe0fbf6a1caaee77a37b0Tony LindgrenEXPORT_SYMBOL(clk_add_alias); 165c0683039207226afcffbe0fbf6a1caaee77a37b0Tony Lindgren 1660318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King/* 1670318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King * clkdev_drop - remove a clock dynamically allocated 1680318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King */ 1690318e693d3a56836632bf1a2cfdafb7f34bcc703Russell Kingvoid clkdev_drop(struct clk_lookup *cl) 1700318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King{ 1710318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_lock(&clocks_mutex); 1720318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King list_del(&cl->node); 1730318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King mutex_unlock(&clocks_mutex); 1740318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King kfree(cl); 1750318e693d3a56836632bf1a2cfdafb7f34bcc703Russell King} 1760318e693d3a56836632bf1a2cfdafb7f34bcc703Russell KingEXPORT_SYMBOL(clkdev_drop); 177