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