162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/clk/clkdev.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2008 Russell King.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Helper for the clk API to assist looking up a struct clk.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/list.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/err.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/mutex.h>
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include <linux/clkdev.h>
1962306a36Sopenharmony_ci#include <linux/clk-provider.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "clk.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic LIST_HEAD(clocks);
2562306a36Sopenharmony_cistatic DEFINE_MUTEX(clocks_mutex);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * Find the correct struct clk for the device and connection ID.
2962306a36Sopenharmony_ci * We do slightly fuzzy matching here:
3062306a36Sopenharmony_ci *  An entry with a NULL ID is assumed to be a wildcard.
3162306a36Sopenharmony_ci *  If an entry has a device ID, it must match
3262306a36Sopenharmony_ci *  If an entry has a connection ID, it must match
3362306a36Sopenharmony_ci * Then we take the most specific entry - with the following
3462306a36Sopenharmony_ci * order of precedence: dev+con > dev only > con only.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistatic struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct clk_lookup *p, *cl = NULL;
3962306a36Sopenharmony_ci	int match, best_found = 0, best_possible = 0;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (dev_id)
4262306a36Sopenharmony_ci		best_possible += 2;
4362306a36Sopenharmony_ci	if (con_id)
4462306a36Sopenharmony_ci		best_possible += 1;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	lockdep_assert_held(&clocks_mutex);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	list_for_each_entry(p, &clocks, node) {
4962306a36Sopenharmony_ci		match = 0;
5062306a36Sopenharmony_ci		if (p->dev_id) {
5162306a36Sopenharmony_ci			if (!dev_id || strcmp(p->dev_id, dev_id))
5262306a36Sopenharmony_ci				continue;
5362306a36Sopenharmony_ci			match += 2;
5462306a36Sopenharmony_ci		}
5562306a36Sopenharmony_ci		if (p->con_id) {
5662306a36Sopenharmony_ci			if (!con_id || strcmp(p->con_id, con_id))
5762306a36Sopenharmony_ci				continue;
5862306a36Sopenharmony_ci			match += 1;
5962306a36Sopenharmony_ci		}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (match > best_found) {
6262306a36Sopenharmony_ci			cl = p;
6362306a36Sopenharmony_ci			if (match != best_possible)
6462306a36Sopenharmony_ci				best_found = match;
6562306a36Sopenharmony_ci			else
6662306a36Sopenharmony_ci				break;
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	return cl;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct clk_hw *clk_find_hw(const char *dev_id, const char *con_id)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct clk_lookup *cl;
7562306a36Sopenharmony_ci	struct clk_hw *hw = ERR_PTR(-ENOENT);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	mutex_lock(&clocks_mutex);
7862306a36Sopenharmony_ci	cl = clk_find(dev_id, con_id);
7962306a36Sopenharmony_ci	if (cl)
8062306a36Sopenharmony_ci		hw = cl->clk_hw;
8162306a36Sopenharmony_ci	mutex_unlock(&clocks_mutex);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return hw;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
8762306a36Sopenharmony_ci				 const char *con_id)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct clk_hw *hw = clk_find_hw(dev_id, con_id);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return clk_hw_create_clk(dev, hw, dev_id, con_id);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct clk *clk_get_sys(const char *dev_id, const char *con_id)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	return __clk_get_sys(NULL, dev_id, con_id);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ciEXPORT_SYMBOL(clk_get_sys);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct clk *clk_get(struct device *dev, const char *con_id)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	const char *dev_id = dev ? dev_name(dev) : NULL;
10362306a36Sopenharmony_ci	struct clk_hw *hw;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (dev && dev->of_node) {
10662306a36Sopenharmony_ci		hw = of_clk_get_hw(dev->of_node, 0, con_id);
10762306a36Sopenharmony_ci		if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
10862306a36Sopenharmony_ci			return clk_hw_create_clk(dev, hw, dev_id, con_id);
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return __clk_get_sys(dev, dev_id, con_id);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ciEXPORT_SYMBOL(clk_get);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civoid clk_put(struct clk *clk)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	__clk_put(clk);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ciEXPORT_SYMBOL(clk_put);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void __clkdev_add(struct clk_lookup *cl)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	mutex_lock(&clocks_mutex);
12462306a36Sopenharmony_ci	list_add_tail(&cl->node, &clocks);
12562306a36Sopenharmony_ci	mutex_unlock(&clocks_mutex);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_civoid clkdev_add(struct clk_lookup *cl)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if (!cl->clk_hw)
13162306a36Sopenharmony_ci		cl->clk_hw = __clk_get_hw(cl->clk);
13262306a36Sopenharmony_ci	__clkdev_add(cl);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ciEXPORT_SYMBOL(clkdev_add);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_civoid clkdev_add_table(struct clk_lookup *cl, size_t num)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	mutex_lock(&clocks_mutex);
13962306a36Sopenharmony_ci	while (num--) {
14062306a36Sopenharmony_ci		cl->clk_hw = __clk_get_hw(cl->clk);
14162306a36Sopenharmony_ci		list_add_tail(&cl->node, &clocks);
14262306a36Sopenharmony_ci		cl++;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	mutex_unlock(&clocks_mutex);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define MAX_DEV_ID	20
14862306a36Sopenharmony_ci#define MAX_CON_ID	16
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistruct clk_lookup_alloc {
15162306a36Sopenharmony_ci	struct clk_lookup cl;
15262306a36Sopenharmony_ci	char	dev_id[MAX_DEV_ID];
15362306a36Sopenharmony_ci	char	con_id[MAX_CON_ID];
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic struct clk_lookup * __ref
15762306a36Sopenharmony_civclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
15862306a36Sopenharmony_ci	va_list ap)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct clk_lookup_alloc *cla;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	cla = kzalloc(sizeof(*cla), GFP_KERNEL);
16362306a36Sopenharmony_ci	if (!cla)
16462306a36Sopenharmony_ci		return NULL;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	cla->cl.clk_hw = hw;
16762306a36Sopenharmony_ci	if (con_id) {
16862306a36Sopenharmony_ci		strscpy(cla->con_id, con_id, sizeof(cla->con_id));
16962306a36Sopenharmony_ci		cla->cl.con_id = cla->con_id;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (dev_fmt) {
17362306a36Sopenharmony_ci		vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
17462306a36Sopenharmony_ci		cla->cl.dev_id = cla->dev_id;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return &cla->cl;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic struct clk_lookup *
18162306a36Sopenharmony_civclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
18262306a36Sopenharmony_ci	va_list ap)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct clk_lookup *cl;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
18762306a36Sopenharmony_ci	if (cl)
18862306a36Sopenharmony_ci		__clkdev_add(cl);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return cl;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/**
19462306a36Sopenharmony_ci * clkdev_create - allocate and add a clkdev lookup structure
19562306a36Sopenharmony_ci * @clk: struct clk to associate with all clk_lookups
19662306a36Sopenharmony_ci * @con_id: connection ID string on device
19762306a36Sopenharmony_ci * @dev_fmt: format string describing device name
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci * Returns a clk_lookup structure, which can be later unregistered and
20062306a36Sopenharmony_ci * freed.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistruct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
20362306a36Sopenharmony_ci	const char *dev_fmt, ...)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct clk_lookup *cl;
20662306a36Sopenharmony_ci	va_list ap;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	va_start(ap, dev_fmt);
20962306a36Sopenharmony_ci	cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
21062306a36Sopenharmony_ci	va_end(ap);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return cl;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clkdev_create);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/**
21762306a36Sopenharmony_ci * clkdev_hw_create - allocate and add a clkdev lookup structure
21862306a36Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups
21962306a36Sopenharmony_ci * @con_id: connection ID string on device
22062306a36Sopenharmony_ci * @dev_fmt: format string describing device name
22162306a36Sopenharmony_ci *
22262306a36Sopenharmony_ci * Returns a clk_lookup structure, which can be later unregistered and
22362306a36Sopenharmony_ci * freed.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_cistruct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id,
22662306a36Sopenharmony_ci	const char *dev_fmt, ...)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct clk_lookup *cl;
22962306a36Sopenharmony_ci	va_list ap;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	va_start(ap, dev_fmt);
23262306a36Sopenharmony_ci	cl = vclkdev_create(hw, con_id, dev_fmt, ap);
23362306a36Sopenharmony_ci	va_end(ap);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return cl;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clkdev_hw_create);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint clk_add_alias(const char *alias, const char *alias_dev_name,
24062306a36Sopenharmony_ci	const char *con_id, struct device *dev)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct clk *r = clk_get(dev, con_id);
24362306a36Sopenharmony_ci	struct clk_lookup *l;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (IS_ERR(r))
24662306a36Sopenharmony_ci		return PTR_ERR(r);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	l = clkdev_create(r, alias, alias_dev_name ? "%s" : NULL,
24962306a36Sopenharmony_ci			  alias_dev_name);
25062306a36Sopenharmony_ci	clk_put(r);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return l ? 0 : -ENODEV;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ciEXPORT_SYMBOL(clk_add_alias);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/*
25762306a36Sopenharmony_ci * clkdev_drop - remove a clock dynamically allocated
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_civoid clkdev_drop(struct clk_lookup *cl)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	mutex_lock(&clocks_mutex);
26262306a36Sopenharmony_ci	list_del(&cl->node);
26362306a36Sopenharmony_ci	mutex_unlock(&clocks_mutex);
26462306a36Sopenharmony_ci	kfree(cl);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ciEXPORT_SYMBOL(clkdev_drop);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
26962306a36Sopenharmony_ci						const char *con_id,
27062306a36Sopenharmony_ci						const char *dev_id, ...)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct clk_lookup *cl;
27362306a36Sopenharmony_ci	va_list ap;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	va_start(ap, dev_id);
27662306a36Sopenharmony_ci	cl = vclkdev_create(hw, con_id, dev_id, ap);
27762306a36Sopenharmony_ci	va_end(ap);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return cl;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int do_clk_register_clkdev(struct clk_hw *hw,
28362306a36Sopenharmony_ci	struct clk_lookup **cl, const char *con_id, const char *dev_id)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	if (IS_ERR(hw))
28662306a36Sopenharmony_ci		return PTR_ERR(hw);
28762306a36Sopenharmony_ci	/*
28862306a36Sopenharmony_ci	 * Since dev_id can be NULL, and NULL is handled specially, we must
28962306a36Sopenharmony_ci	 * pass it as either a NULL format string, or with "%s".
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	if (dev_id)
29262306a36Sopenharmony_ci		*cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
29362306a36Sopenharmony_ci	else
29462306a36Sopenharmony_ci		*cl = __clk_register_clkdev(hw, con_id, NULL);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return *cl ? 0 : -ENOMEM;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * clk_register_clkdev - register one clock lookup for a struct clk
30162306a36Sopenharmony_ci * @clk: struct clk to associate with all clk_lookups
30262306a36Sopenharmony_ci * @con_id: connection ID string on device
30362306a36Sopenharmony_ci * @dev_id: string describing device name
30462306a36Sopenharmony_ci *
30562306a36Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of
30662306a36Sopenharmony_ci * clkdev.
30762306a36Sopenharmony_ci *
30862306a36Sopenharmony_ci * To make things easier for mass registration, we detect error clks
30962306a36Sopenharmony_ci * from a previous clk_register() call, and return the error code for
31062306a36Sopenharmony_ci * those.  This is to permit this function to be called immediately
31162306a36Sopenharmony_ci * after clk_register().
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_ciint clk_register_clkdev(struct clk *clk, const char *con_id,
31462306a36Sopenharmony_ci	const char *dev_id)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct clk_lookup *cl;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (IS_ERR(clk))
31962306a36Sopenharmony_ci		return PTR_ERR(clk);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
32262306a36Sopenharmony_ci					      dev_id);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ciEXPORT_SYMBOL(clk_register_clkdev);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw
32862306a36Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups
32962306a36Sopenharmony_ci * @con_id: connection ID string on device
33062306a36Sopenharmony_ci * @dev_id: format string describing device name
33162306a36Sopenharmony_ci *
33262306a36Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of
33362306a36Sopenharmony_ci * clkdev.
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * To make things easier for mass registration, we detect error clk_hws
33662306a36Sopenharmony_ci * from a previous clk_hw_register_*() call, and return the error code for
33762306a36Sopenharmony_ci * those.  This is to permit this function to be called immediately
33862306a36Sopenharmony_ci * after clk_hw_register_*().
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_ciint clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
34162306a36Sopenharmony_ci	const char *dev_id)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct clk_lookup *cl;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ciEXPORT_SYMBOL(clk_hw_register_clkdev);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic void devm_clkdev_release(void *res)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	clkdev_drop(res);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/**
35562306a36Sopenharmony_ci * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
35662306a36Sopenharmony_ci * @dev: device this lookup is bound
35762306a36Sopenharmony_ci * @hw: struct clk_hw to associate with all clk_lookups
35862306a36Sopenharmony_ci * @con_id: connection ID string on device
35962306a36Sopenharmony_ci * @dev_id: format string describing device name
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci * con_id or dev_id may be NULL as a wildcard, just as in the rest of
36262306a36Sopenharmony_ci * clkdev.
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * To make things easier for mass registration, we detect error clk_hws
36562306a36Sopenharmony_ci * from a previous clk_hw_register_*() call, and return the error code for
36662306a36Sopenharmony_ci * those.  This is to permit this function to be called immediately
36762306a36Sopenharmony_ci * after clk_hw_register_*().
36862306a36Sopenharmony_ci */
36962306a36Sopenharmony_ciint devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
37062306a36Sopenharmony_ci				const char *con_id, const char *dev_id)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct clk_lookup *cl;
37362306a36Sopenharmony_ci	int rval;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	rval = do_clk_register_clkdev(hw, &cl, con_id, dev_id);
37662306a36Sopenharmony_ci	if (rval)
37762306a36Sopenharmony_ci		return rval;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return devm_add_action_or_reset(dev, devm_clkdev_release, cl);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ciEXPORT_SYMBOL(devm_clk_hw_register_clkdev);
382