18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/clk/clkdev.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Russell King. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Helper for the clk API to assist looking up a struct clk. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 198c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "clk.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic LIST_HEAD(clocks); 258c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(clocks_mutex); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Find the correct struct clk for the device and connection ID. 298c2ecf20Sopenharmony_ci * We do slightly fuzzy matching here: 308c2ecf20Sopenharmony_ci * An entry with a NULL ID is assumed to be a wildcard. 318c2ecf20Sopenharmony_ci * If an entry has a device ID, it must match 328c2ecf20Sopenharmony_ci * If an entry has a connection ID, it must match 338c2ecf20Sopenharmony_ci * Then we take the most specific entry - with the following 348c2ecf20Sopenharmony_ci * order of precedence: dev+con > dev only > con only. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic struct clk_lookup *clk_find(const char *dev_id, const char *con_id) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct clk_lookup *p, *cl = NULL; 398c2ecf20Sopenharmony_ci int match, best_found = 0, best_possible = 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (dev_id) 428c2ecf20Sopenharmony_ci best_possible += 2; 438c2ecf20Sopenharmony_ci if (con_id) 448c2ecf20Sopenharmony_ci best_possible += 1; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci lockdep_assert_held(&clocks_mutex); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci list_for_each_entry(p, &clocks, node) { 498c2ecf20Sopenharmony_ci match = 0; 508c2ecf20Sopenharmony_ci if (p->dev_id) { 518c2ecf20Sopenharmony_ci if (!dev_id || strcmp(p->dev_id, dev_id)) 528c2ecf20Sopenharmony_ci continue; 538c2ecf20Sopenharmony_ci match += 2; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci if (p->con_id) { 568c2ecf20Sopenharmony_ci if (!con_id || strcmp(p->con_id, con_id)) 578c2ecf20Sopenharmony_ci continue; 588c2ecf20Sopenharmony_ci match += 1; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (match > best_found) { 628c2ecf20Sopenharmony_ci cl = p; 638c2ecf20Sopenharmony_ci if (match != best_possible) 648c2ecf20Sopenharmony_ci best_found = match; 658c2ecf20Sopenharmony_ci else 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return cl; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct clk_hw *clk_find_hw(const char *dev_id, const char *con_id) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct clk_lookup *cl; 758c2ecf20Sopenharmony_ci struct clk_hw *hw = ERR_PTR(-ENOENT); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci mutex_lock(&clocks_mutex); 788c2ecf20Sopenharmony_ci cl = clk_find(dev_id, con_id); 798c2ecf20Sopenharmony_ci if (cl) 808c2ecf20Sopenharmony_ci hw = cl->clk_hw; 818c2ecf20Sopenharmony_ci mutex_unlock(&clocks_mutex); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return hw; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct clk *__clk_get_sys(struct device *dev, const char *dev_id, 878c2ecf20Sopenharmony_ci const char *con_id) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct clk_hw *hw = clk_find_hw(dev_id, con_id); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return clk_hw_create_clk(dev, hw, dev_id, con_id); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct clk *clk_get_sys(const char *dev_id, const char *con_id) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return __clk_get_sys(NULL, dev_id, con_id); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_sys); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct clk *clk_get(struct device *dev, const char *con_id) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci const char *dev_id = dev ? dev_name(dev) : NULL; 1038c2ecf20Sopenharmony_ci struct clk_hw *hw; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (dev && dev->of_node) { 1068c2ecf20Sopenharmony_ci hw = of_clk_get_hw(dev->of_node, 0, con_id); 1078c2ecf20Sopenharmony_ci if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) 1088c2ecf20Sopenharmony_ci return clk_hw_create_clk(dev, hw, dev_id, con_id); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return __clk_get_sys(dev, dev_id, con_id); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid clk_put(struct clk *clk) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci __clk_put(clk); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_put); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void __clkdev_add(struct clk_lookup *cl) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci mutex_lock(&clocks_mutex); 1248c2ecf20Sopenharmony_ci list_add_tail(&cl->node, &clocks); 1258c2ecf20Sopenharmony_ci mutex_unlock(&clocks_mutex); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_civoid clkdev_add(struct clk_lookup *cl) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci if (!cl->clk_hw) 1318c2ecf20Sopenharmony_ci cl->clk_hw = __clk_get_hw(cl->clk); 1328c2ecf20Sopenharmony_ci __clkdev_add(cl); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clkdev_add); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_civoid clkdev_add_table(struct clk_lookup *cl, size_t num) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci mutex_lock(&clocks_mutex); 1398c2ecf20Sopenharmony_ci while (num--) { 1408c2ecf20Sopenharmony_ci cl->clk_hw = __clk_get_hw(cl->clk); 1418c2ecf20Sopenharmony_ci list_add_tail(&cl->node, &clocks); 1428c2ecf20Sopenharmony_ci cl++; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci mutex_unlock(&clocks_mutex); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define MAX_DEV_ID 20 1488c2ecf20Sopenharmony_ci#define MAX_CON_ID 16 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct clk_lookup_alloc { 1518c2ecf20Sopenharmony_ci struct clk_lookup cl; 1528c2ecf20Sopenharmony_ci char dev_id[MAX_DEV_ID]; 1538c2ecf20Sopenharmony_ci char con_id[MAX_CON_ID]; 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct clk_lookup * __ref 1578c2ecf20Sopenharmony_civclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, 1588c2ecf20Sopenharmony_ci va_list ap) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct clk_lookup_alloc *cla; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci cla = kzalloc(sizeof(*cla), GFP_KERNEL); 1638c2ecf20Sopenharmony_ci if (!cla) 1648c2ecf20Sopenharmony_ci return NULL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci cla->cl.clk_hw = hw; 1678c2ecf20Sopenharmony_ci if (con_id) { 1688c2ecf20Sopenharmony_ci strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); 1698c2ecf20Sopenharmony_ci cla->cl.con_id = cla->con_id; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (dev_fmt) { 1738c2ecf20Sopenharmony_ci vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); 1748c2ecf20Sopenharmony_ci cla->cl.dev_id = cla->dev_id; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return &cla->cl; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic struct clk_lookup * 1818c2ecf20Sopenharmony_civclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt, 1828c2ecf20Sopenharmony_ci va_list ap) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct clk_lookup *cl; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci cl = vclkdev_alloc(hw, con_id, dev_fmt, ap); 1878c2ecf20Sopenharmony_ci if (cl) 1888c2ecf20Sopenharmony_ci __clkdev_add(cl); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return cl; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistruct clk_lookup * __ref 1948c2ecf20Sopenharmony_ciclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct clk_lookup *cl; 1978c2ecf20Sopenharmony_ci va_list ap; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci va_start(ap, dev_fmt); 2008c2ecf20Sopenharmony_ci cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap); 2018c2ecf20Sopenharmony_ci va_end(ap); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return cl; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clkdev_alloc); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct clk_lookup * 2088c2ecf20Sopenharmony_ciclkdev_hw_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, ...) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct clk_lookup *cl; 2118c2ecf20Sopenharmony_ci va_list ap; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci va_start(ap, dev_fmt); 2148c2ecf20Sopenharmony_ci cl = vclkdev_alloc(hw, con_id, dev_fmt, ap); 2158c2ecf20Sopenharmony_ci va_end(ap); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return cl; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clkdev_hw_alloc); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * clkdev_create - allocate and add a clkdev lookup structure 2238c2ecf20Sopenharmony_ci * @clk: struct clk to associate with all clk_lookups 2248c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 2258c2ecf20Sopenharmony_ci * @dev_fmt: format string describing device name 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * Returns a clk_lookup structure, which can be later unregistered and 2288c2ecf20Sopenharmony_ci * freed. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistruct clk_lookup *clkdev_create(struct clk *clk, const char *con_id, 2318c2ecf20Sopenharmony_ci const char *dev_fmt, ...) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct clk_lookup *cl; 2348c2ecf20Sopenharmony_ci va_list ap; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci va_start(ap, dev_fmt); 2378c2ecf20Sopenharmony_ci cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap); 2388c2ecf20Sopenharmony_ci va_end(ap); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return cl; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clkdev_create); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * clkdev_hw_create - allocate and add a clkdev lookup structure 2468c2ecf20Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups 2478c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 2488c2ecf20Sopenharmony_ci * @dev_fmt: format string describing device name 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci * Returns a clk_lookup structure, which can be later unregistered and 2518c2ecf20Sopenharmony_ci * freed. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_cistruct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id, 2548c2ecf20Sopenharmony_ci const char *dev_fmt, ...) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct clk_lookup *cl; 2578c2ecf20Sopenharmony_ci va_list ap; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci va_start(ap, dev_fmt); 2608c2ecf20Sopenharmony_ci cl = vclkdev_create(hw, con_id, dev_fmt, ap); 2618c2ecf20Sopenharmony_ci va_end(ap); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return cl; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clkdev_hw_create); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciint clk_add_alias(const char *alias, const char *alias_dev_name, 2688c2ecf20Sopenharmony_ci const char *con_id, struct device *dev) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct clk *r = clk_get(dev, con_id); 2718c2ecf20Sopenharmony_ci struct clk_lookup *l; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (IS_ERR(r)) 2748c2ecf20Sopenharmony_ci return PTR_ERR(r); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci l = clkdev_create(r, alias, alias_dev_name ? "%s" : NULL, 2778c2ecf20Sopenharmony_ci alias_dev_name); 2788c2ecf20Sopenharmony_ci clk_put(r); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return l ? 0 : -ENODEV; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_add_alias); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * clkdev_drop - remove a clock dynamically allocated 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_civoid clkdev_drop(struct clk_lookup *cl) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci mutex_lock(&clocks_mutex); 2908c2ecf20Sopenharmony_ci list_del(&cl->node); 2918c2ecf20Sopenharmony_ci mutex_unlock(&clocks_mutex); 2928c2ecf20Sopenharmony_ci kfree(cl); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clkdev_drop); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw, 2978c2ecf20Sopenharmony_ci const char *con_id, 2988c2ecf20Sopenharmony_ci const char *dev_id, ...) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct clk_lookup *cl; 3018c2ecf20Sopenharmony_ci va_list ap; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci va_start(ap, dev_id); 3048c2ecf20Sopenharmony_ci cl = vclkdev_create(hw, con_id, dev_id, ap); 3058c2ecf20Sopenharmony_ci va_end(ap); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return cl; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int do_clk_register_clkdev(struct clk_hw *hw, 3118c2ecf20Sopenharmony_ci struct clk_lookup **cl, const char *con_id, const char *dev_id) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci if (IS_ERR(hw)) 3148c2ecf20Sopenharmony_ci return PTR_ERR(hw); 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * Since dev_id can be NULL, and NULL is handled specially, we must 3178c2ecf20Sopenharmony_ci * pass it as either a NULL format string, or with "%s". 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_ci if (dev_id) 3208c2ecf20Sopenharmony_ci *cl = __clk_register_clkdev(hw, con_id, "%s", dev_id); 3218c2ecf20Sopenharmony_ci else 3228c2ecf20Sopenharmony_ci *cl = __clk_register_clkdev(hw, con_id, NULL); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return *cl ? 0 : -ENOMEM; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/** 3288c2ecf20Sopenharmony_ci * clk_register_clkdev - register one clock lookup for a struct clk 3298c2ecf20Sopenharmony_ci * @clk: struct clk to associate with all clk_lookups 3308c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 3318c2ecf20Sopenharmony_ci * @dev_id: string describing device name 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of 3348c2ecf20Sopenharmony_ci * clkdev. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * To make things easier for mass registration, we detect error clks 3378c2ecf20Sopenharmony_ci * from a previous clk_register() call, and return the error code for 3388c2ecf20Sopenharmony_ci * those. This is to permit this function to be called immediately 3398c2ecf20Sopenharmony_ci * after clk_register(). 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ciint clk_register_clkdev(struct clk *clk, const char *con_id, 3428c2ecf20Sopenharmony_ci const char *dev_id) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct clk_lookup *cl; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 3478c2ecf20Sopenharmony_ci return PTR_ERR(clk); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id, 3508c2ecf20Sopenharmony_ci dev_id); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_register_clkdev); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/** 3558c2ecf20Sopenharmony_ci * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw 3568c2ecf20Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups 3578c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 3588c2ecf20Sopenharmony_ci * @dev_id: format string describing device name 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of 3618c2ecf20Sopenharmony_ci * clkdev. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * To make things easier for mass registration, we detect error clk_hws 3648c2ecf20Sopenharmony_ci * from a previous clk_hw_register_*() call, and return the error code for 3658c2ecf20Sopenharmony_ci * those. This is to permit this function to be called immediately 3668c2ecf20Sopenharmony_ci * after clk_hw_register_*(). 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ciint clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id, 3698c2ecf20Sopenharmony_ci const char *dev_id) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct clk_lookup *cl; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return do_clk_register_clkdev(hw, &cl, con_id, dev_id); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_hw_register_clkdev); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void devm_clkdev_release(struct device *dev, void *res) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci clkdev_drop(*(struct clk_lookup **)res); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int devm_clk_match_clkdev(struct device *dev, void *res, void *data) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct clk_lookup **l = res; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return *l == data; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/** 3908c2ecf20Sopenharmony_ci * devm_clk_release_clkdev - Resource managed clkdev lookup release 3918c2ecf20Sopenharmony_ci * @dev: device this lookup is bound 3928c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 3938c2ecf20Sopenharmony_ci * @dev_id: format string describing device name 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * Drop the clkdev lookup created with devm_clk_hw_register_clkdev. 3968c2ecf20Sopenharmony_ci * Normally this function will not need to be called and the resource 3978c2ecf20Sopenharmony_ci * management code will ensure that the resource is freed. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_civoid devm_clk_release_clkdev(struct device *dev, const char *con_id, 4008c2ecf20Sopenharmony_ci const char *dev_id) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct clk_lookup *cl; 4038c2ecf20Sopenharmony_ci int rval; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci mutex_lock(&clocks_mutex); 4068c2ecf20Sopenharmony_ci cl = clk_find(dev_id, con_id); 4078c2ecf20Sopenharmony_ci mutex_unlock(&clocks_mutex); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci WARN_ON(!cl); 4108c2ecf20Sopenharmony_ci rval = devres_release(dev, devm_clkdev_release, 4118c2ecf20Sopenharmony_ci devm_clk_match_clkdev, cl); 4128c2ecf20Sopenharmony_ci WARN_ON(rval); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_clk_release_clkdev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/** 4178c2ecf20Sopenharmony_ci * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw 4188c2ecf20Sopenharmony_ci * @dev: device this lookup is bound 4198c2ecf20Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups 4208c2ecf20Sopenharmony_ci * @con_id: connection ID string on device 4218c2ecf20Sopenharmony_ci * @dev_id: format string describing device name 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of 4248c2ecf20Sopenharmony_ci * clkdev. 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * To make things easier for mass registration, we detect error clk_hws 4278c2ecf20Sopenharmony_ci * from a previous clk_hw_register_*() call, and return the error code for 4288c2ecf20Sopenharmony_ci * those. This is to permit this function to be called immediately 4298c2ecf20Sopenharmony_ci * after clk_hw_register_*(). 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ciint devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw, 4328c2ecf20Sopenharmony_ci const char *con_id, const char *dev_id) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci int rval = -ENOMEM; 4358c2ecf20Sopenharmony_ci struct clk_lookup **cl; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL); 4388c2ecf20Sopenharmony_ci if (cl) { 4398c2ecf20Sopenharmony_ci rval = do_clk_register_clkdev(hw, cl, con_id, dev_id); 4408c2ecf20Sopenharmony_ci if (!rval) 4418c2ecf20Sopenharmony_ci devres_add(dev, cl); 4428c2ecf20Sopenharmony_ci else 4438c2ecf20Sopenharmony_ci devres_free(cl); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci return rval; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_clk_hw_register_clkdev); 448