162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
462306a36Sopenharmony_ci * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
562306a36Sopenharmony_ci * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Adjustable divider clock implementation
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/string.h>
1762306a36Sopenharmony_ci#include <linux/log2.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * DOC: basic adjustable divider clock that cannot gate
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Traits of this clock:
2362306a36Sopenharmony_ci * prepare - clk_prepare only ensures that parents are prepared
2462306a36Sopenharmony_ci * enable - clk_enable only ensures that parents are enabled
2562306a36Sopenharmony_ci * rate - rate is adjustable.  clk->rate = ceiling(parent->rate / divisor)
2662306a36Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic inline u32 clk_div_readl(struct clk_divider *divider)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
3262306a36Sopenharmony_ci		return ioread32be(divider->reg);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return readl(divider->reg);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic inline void clk_div_writel(struct clk_divider *divider, u32 val)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
4062306a36Sopenharmony_ci		iowrite32be(val, divider->reg);
4162306a36Sopenharmony_ci	else
4262306a36Sopenharmony_ci		writel(val, divider->reg);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic unsigned int _get_table_maxdiv(const struct clk_div_table *table,
4662306a36Sopenharmony_ci				      u8 width)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	unsigned int maxdiv = 0, mask = clk_div_mask(width);
4962306a36Sopenharmony_ci	const struct clk_div_table *clkt;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
5262306a36Sopenharmony_ci		if (clkt->div > maxdiv && clkt->val <= mask)
5362306a36Sopenharmony_ci			maxdiv = clkt->div;
5462306a36Sopenharmony_ci	return maxdiv;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic unsigned int _get_table_mindiv(const struct clk_div_table *table)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	unsigned int mindiv = UINT_MAX;
6062306a36Sopenharmony_ci	const struct clk_div_table *clkt;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
6362306a36Sopenharmony_ci		if (clkt->div < mindiv)
6462306a36Sopenharmony_ci			mindiv = clkt->div;
6562306a36Sopenharmony_ci	return mindiv;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
6962306a36Sopenharmony_ci				unsigned long flags)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_ONE_BASED)
7262306a36Sopenharmony_ci		return clk_div_mask(width);
7362306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
7462306a36Sopenharmony_ci		return 1 << clk_div_mask(width);
7562306a36Sopenharmony_ci	if (table)
7662306a36Sopenharmony_ci		return _get_table_maxdiv(table, width);
7762306a36Sopenharmony_ci	return clk_div_mask(width) + 1;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic unsigned int _get_table_div(const struct clk_div_table *table,
8162306a36Sopenharmony_ci							unsigned int val)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	const struct clk_div_table *clkt;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
8662306a36Sopenharmony_ci		if (clkt->val == val)
8762306a36Sopenharmony_ci			return clkt->div;
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic unsigned int _get_div(const struct clk_div_table *table,
9262306a36Sopenharmony_ci			     unsigned int val, unsigned long flags, u8 width)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_ONE_BASED)
9562306a36Sopenharmony_ci		return val;
9662306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
9762306a36Sopenharmony_ci		return 1 << val;
9862306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
9962306a36Sopenharmony_ci		return val ? val : clk_div_mask(width) + 1;
10062306a36Sopenharmony_ci	if (table)
10162306a36Sopenharmony_ci		return _get_table_div(table, val);
10262306a36Sopenharmony_ci	return val + 1;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic unsigned int _get_table_val(const struct clk_div_table *table,
10662306a36Sopenharmony_ci							unsigned int div)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	const struct clk_div_table *clkt;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
11162306a36Sopenharmony_ci		if (clkt->div == div)
11262306a36Sopenharmony_ci			return clkt->val;
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic unsigned int _get_val(const struct clk_div_table *table,
11762306a36Sopenharmony_ci			     unsigned int div, unsigned long flags, u8 width)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_ONE_BASED)
12062306a36Sopenharmony_ci		return div;
12162306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
12262306a36Sopenharmony_ci		return __ffs(div);
12362306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
12462306a36Sopenharmony_ci		return (div == clk_div_mask(width) + 1) ? 0 : div;
12562306a36Sopenharmony_ci	if (table)
12662306a36Sopenharmony_ci		return  _get_table_val(table, div);
12762306a36Sopenharmony_ci	return div - 1;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciunsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
13162306a36Sopenharmony_ci				  unsigned int val,
13262306a36Sopenharmony_ci				  const struct clk_div_table *table,
13362306a36Sopenharmony_ci				  unsigned long flags, unsigned long width)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	unsigned int div;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	div = _get_div(table, val, flags, width);
13862306a36Sopenharmony_ci	if (!div) {
13962306a36Sopenharmony_ci		WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
14062306a36Sopenharmony_ci			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
14162306a36Sopenharmony_ci			clk_hw_get_name(hw));
14262306a36Sopenharmony_ci		return parent_rate;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return DIV_ROUND_UP_ULL((u64)parent_rate, div);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_recalc_rate);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
15062306a36Sopenharmony_ci		unsigned long parent_rate)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct clk_divider *divider = to_clk_divider(hw);
15362306a36Sopenharmony_ci	unsigned int val;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	val = clk_div_readl(divider) >> divider->shift;
15662306a36Sopenharmony_ci	val &= clk_div_mask(divider->width);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return divider_recalc_rate(hw, parent_rate, val, divider->table,
15962306a36Sopenharmony_ci				   divider->flags, divider->width);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic bool _is_valid_table_div(const struct clk_div_table *table,
16362306a36Sopenharmony_ci							 unsigned int div)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	const struct clk_div_table *clkt;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
16862306a36Sopenharmony_ci		if (clkt->div == div)
16962306a36Sopenharmony_ci			return true;
17062306a36Sopenharmony_ci	return false;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
17462306a36Sopenharmony_ci			  unsigned long flags)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
17762306a36Sopenharmony_ci		return is_power_of_2(div);
17862306a36Sopenharmony_ci	if (table)
17962306a36Sopenharmony_ci		return _is_valid_table_div(table, div);
18062306a36Sopenharmony_ci	return true;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int _round_up_table(const struct clk_div_table *table, int div)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	const struct clk_div_table *clkt;
18662306a36Sopenharmony_ci	int up = INT_MAX;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
18962306a36Sopenharmony_ci		if (clkt->div == div)
19062306a36Sopenharmony_ci			return clkt->div;
19162306a36Sopenharmony_ci		else if (clkt->div < div)
19262306a36Sopenharmony_ci			continue;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		if ((clkt->div - div) < (up - div))
19562306a36Sopenharmony_ci			up = clkt->div;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	return up;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic int _round_down_table(const struct clk_div_table *table, int div)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	const struct clk_div_table *clkt;
20462306a36Sopenharmony_ci	int down = _get_table_mindiv(table);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
20762306a36Sopenharmony_ci		if (clkt->div == div)
20862306a36Sopenharmony_ci			return clkt->div;
20962306a36Sopenharmony_ci		else if (clkt->div > div)
21062306a36Sopenharmony_ci			continue;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		if ((div - clkt->div) < (div - down))
21362306a36Sopenharmony_ci			down = clkt->div;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return down;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int _div_round_up(const struct clk_div_table *table,
22062306a36Sopenharmony_ci			 unsigned long parent_rate, unsigned long rate,
22162306a36Sopenharmony_ci			 unsigned long flags)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
22662306a36Sopenharmony_ci		div = __roundup_pow_of_two(div);
22762306a36Sopenharmony_ci	if (table)
22862306a36Sopenharmony_ci		div = _round_up_table(table, div);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return div;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int _div_round_closest(const struct clk_div_table *table,
23462306a36Sopenharmony_ci			      unsigned long parent_rate, unsigned long rate,
23562306a36Sopenharmony_ci			      unsigned long flags)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	int up, down;
23862306a36Sopenharmony_ci	unsigned long up_rate, down_rate;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	up = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
24162306a36Sopenharmony_ci	down = parent_rate / rate;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO) {
24462306a36Sopenharmony_ci		up = __roundup_pow_of_two(up);
24562306a36Sopenharmony_ci		down = __rounddown_pow_of_two(down);
24662306a36Sopenharmony_ci	} else if (table) {
24762306a36Sopenharmony_ci		up = _round_up_table(table, up);
24862306a36Sopenharmony_ci		down = _round_down_table(table, down);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up);
25262306a36Sopenharmony_ci	down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return (rate - up_rate) <= (down_rate - rate) ? up : down;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int _div_round(const struct clk_div_table *table,
25862306a36Sopenharmony_ci		      unsigned long parent_rate, unsigned long rate,
25962306a36Sopenharmony_ci		      unsigned long flags)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_ROUND_CLOSEST)
26262306a36Sopenharmony_ci		return _div_round_closest(table, parent_rate, rate, flags);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return _div_round_up(table, parent_rate, rate, flags);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic bool _is_best_div(unsigned long rate, unsigned long now,
26862306a36Sopenharmony_ci			 unsigned long best, unsigned long flags)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_ROUND_CLOSEST)
27162306a36Sopenharmony_ci		return abs(rate - now) < abs(rate - best);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return now <= rate && now > best;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int _next_div(const struct clk_div_table *table, int div,
27762306a36Sopenharmony_ci		     unsigned long flags)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	div++;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (flags & CLK_DIVIDER_POWER_OF_TWO)
28262306a36Sopenharmony_ci		return __roundup_pow_of_two(div);
28362306a36Sopenharmony_ci	if (table)
28462306a36Sopenharmony_ci		return _round_up_table(table, div);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return div;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
29062306a36Sopenharmony_ci			       unsigned long rate,
29162306a36Sopenharmony_ci			       unsigned long *best_parent_rate,
29262306a36Sopenharmony_ci			       const struct clk_div_table *table, u8 width,
29362306a36Sopenharmony_ci			       unsigned long flags)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	int i, bestdiv = 0;
29662306a36Sopenharmony_ci	unsigned long parent_rate, best = 0, now, maxdiv;
29762306a36Sopenharmony_ci	unsigned long parent_rate_saved = *best_parent_rate;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (!rate)
30062306a36Sopenharmony_ci		rate = 1;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	maxdiv = _get_maxdiv(table, width, flags);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
30562306a36Sopenharmony_ci		parent_rate = *best_parent_rate;
30662306a36Sopenharmony_ci		bestdiv = _div_round(table, parent_rate, rate, flags);
30762306a36Sopenharmony_ci		bestdiv = bestdiv == 0 ? 1 : bestdiv;
30862306a36Sopenharmony_ci		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
30962306a36Sopenharmony_ci		return bestdiv;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * The maximum divider we can use without overflowing
31462306a36Sopenharmony_ci	 * unsigned long in rate * i below
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	maxdiv = min(ULONG_MAX / rate, maxdiv);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	for (i = _next_div(table, 0, flags); i <= maxdiv;
31962306a36Sopenharmony_ci					     i = _next_div(table, i, flags)) {
32062306a36Sopenharmony_ci		if (rate * i == parent_rate_saved) {
32162306a36Sopenharmony_ci			/*
32262306a36Sopenharmony_ci			 * It's the most ideal case if the requested rate can be
32362306a36Sopenharmony_ci			 * divided from parent clock without needing to change
32462306a36Sopenharmony_ci			 * parent rate, so return the divider immediately.
32562306a36Sopenharmony_ci			 */
32662306a36Sopenharmony_ci			*best_parent_rate = parent_rate_saved;
32762306a36Sopenharmony_ci			return i;
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci		parent_rate = clk_hw_round_rate(parent, rate * i);
33062306a36Sopenharmony_ci		now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
33162306a36Sopenharmony_ci		if (_is_best_div(rate, now, best, flags)) {
33262306a36Sopenharmony_ci			bestdiv = i;
33362306a36Sopenharmony_ci			best = now;
33462306a36Sopenharmony_ci			*best_parent_rate = parent_rate;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (!bestdiv) {
33962306a36Sopenharmony_ci		bestdiv = _get_maxdiv(table, width, flags);
34062306a36Sopenharmony_ci		*best_parent_rate = clk_hw_round_rate(parent, 1);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return bestdiv;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ciint divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
34762306a36Sopenharmony_ci			   const struct clk_div_table *table, u8 width,
34862306a36Sopenharmony_ci			   unsigned long flags)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int div;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate,
35362306a36Sopenharmony_ci				  &req->best_parent_rate, table, width, flags);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_determine_rate);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ciint divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
36262306a36Sopenharmony_ci			      const struct clk_div_table *table, u8 width,
36362306a36Sopenharmony_ci			      unsigned long flags, unsigned int val)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	int div;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	div = _get_div(table, val, flags, width);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* Even a read-only clock can propagate a rate change */
37062306a36Sopenharmony_ci	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
37162306a36Sopenharmony_ci		if (!req->best_parent_hw)
37262306a36Sopenharmony_ci			return -EINVAL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw,
37562306a36Sopenharmony_ci							  req->rate * div);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_ro_determine_rate);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cilong divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
38562306a36Sopenharmony_ci			       unsigned long rate, unsigned long *prate,
38662306a36Sopenharmony_ci			       const struct clk_div_table *table,
38762306a36Sopenharmony_ci			       u8 width, unsigned long flags)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct clk_rate_request req;
39062306a36Sopenharmony_ci	int ret;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	clk_hw_init_rate_request(hw, &req, rate);
39362306a36Sopenharmony_ci	req.best_parent_rate = *prate;
39462306a36Sopenharmony_ci	req.best_parent_hw = parent;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = divider_determine_rate(hw, &req, table, width, flags);
39762306a36Sopenharmony_ci	if (ret)
39862306a36Sopenharmony_ci		return ret;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	*prate = req.best_parent_rate;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return req.rate;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_round_rate_parent);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cilong divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
40762306a36Sopenharmony_ci				  unsigned long rate, unsigned long *prate,
40862306a36Sopenharmony_ci				  const struct clk_div_table *table, u8 width,
40962306a36Sopenharmony_ci				  unsigned long flags, unsigned int val)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct clk_rate_request req;
41262306a36Sopenharmony_ci	int ret;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	clk_hw_init_rate_request(hw, &req, rate);
41562306a36Sopenharmony_ci	req.best_parent_rate = *prate;
41662306a36Sopenharmony_ci	req.best_parent_hw = parent;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	ret = divider_ro_determine_rate(hw, &req, table, width, flags, val);
41962306a36Sopenharmony_ci	if (ret)
42062306a36Sopenharmony_ci		return ret;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	*prate = req.best_parent_rate;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return req.rate;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
42962306a36Sopenharmony_ci				unsigned long *prate)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct clk_divider *divider = to_clk_divider(hw);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* if read only, just return current value */
43462306a36Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
43562306a36Sopenharmony_ci		u32 val;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		val = clk_div_readl(divider) >> divider->shift;
43862306a36Sopenharmony_ci		val &= clk_div_mask(divider->width);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		return divider_ro_round_rate(hw, rate, prate, divider->table,
44162306a36Sopenharmony_ci					     divider->width, divider->flags,
44262306a36Sopenharmony_ci					     val);
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return divider_round_rate(hw, rate, prate, divider->table,
44662306a36Sopenharmony_ci				  divider->width, divider->flags);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int clk_divider_determine_rate(struct clk_hw *hw,
45062306a36Sopenharmony_ci				      struct clk_rate_request *req)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct clk_divider *divider = to_clk_divider(hw);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* if read only, just return current value */
45562306a36Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
45662306a36Sopenharmony_ci		u32 val;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		val = clk_div_readl(divider) >> divider->shift;
45962306a36Sopenharmony_ci		val &= clk_div_mask(divider->width);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		return divider_ro_determine_rate(hw, req, divider->table,
46262306a36Sopenharmony_ci						 divider->width,
46362306a36Sopenharmony_ci						 divider->flags, val);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return divider_determine_rate(hw, req, divider->table, divider->width,
46762306a36Sopenharmony_ci				      divider->flags);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ciint divider_get_val(unsigned long rate, unsigned long parent_rate,
47162306a36Sopenharmony_ci		    const struct clk_div_table *table, u8 width,
47262306a36Sopenharmony_ci		    unsigned long flags)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	unsigned int div, value;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (!_is_valid_div(table, div, flags))
47962306a36Sopenharmony_ci		return -EINVAL;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	value = _get_val(table, div, flags, width);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return min_t(unsigned int, value, clk_div_mask(width));
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(divider_get_val);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
48862306a36Sopenharmony_ci				unsigned long parent_rate)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct clk_divider *divider = to_clk_divider(hw);
49162306a36Sopenharmony_ci	int value;
49262306a36Sopenharmony_ci	unsigned long flags = 0;
49362306a36Sopenharmony_ci	u32 val;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	value = divider_get_val(rate, parent_rate, divider->table,
49662306a36Sopenharmony_ci				divider->width, divider->flags);
49762306a36Sopenharmony_ci	if (value < 0)
49862306a36Sopenharmony_ci		return value;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (divider->lock)
50162306a36Sopenharmony_ci		spin_lock_irqsave(divider->lock, flags);
50262306a36Sopenharmony_ci	else
50362306a36Sopenharmony_ci		__acquire(divider->lock);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
50662306a36Sopenharmony_ci		val = clk_div_mask(divider->width) << (divider->shift + 16);
50762306a36Sopenharmony_ci	} else {
50862306a36Sopenharmony_ci		val = clk_div_readl(divider);
50962306a36Sopenharmony_ci		val &= ~(clk_div_mask(divider->width) << divider->shift);
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci	val |= (u32)value << divider->shift;
51262306a36Sopenharmony_ci	clk_div_writel(divider, val);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (divider->lock)
51562306a36Sopenharmony_ci		spin_unlock_irqrestore(divider->lock, flags);
51662306a36Sopenharmony_ci	else
51762306a36Sopenharmony_ci		__release(divider->lock);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ciconst struct clk_ops clk_divider_ops = {
52362306a36Sopenharmony_ci	.recalc_rate = clk_divider_recalc_rate,
52462306a36Sopenharmony_ci	.round_rate = clk_divider_round_rate,
52562306a36Sopenharmony_ci	.determine_rate = clk_divider_determine_rate,
52662306a36Sopenharmony_ci	.set_rate = clk_divider_set_rate,
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_divider_ops);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciconst struct clk_ops clk_divider_ro_ops = {
53162306a36Sopenharmony_ci	.recalc_rate = clk_divider_recalc_rate,
53262306a36Sopenharmony_ci	.round_rate = clk_divider_round_rate,
53362306a36Sopenharmony_ci	.determine_rate = clk_divider_determine_rate,
53462306a36Sopenharmony_ci};
53562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_divider_ro_ops);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistruct clk_hw *__clk_hw_register_divider(struct device *dev,
53862306a36Sopenharmony_ci		struct device_node *np, const char *name,
53962306a36Sopenharmony_ci		const char *parent_name, const struct clk_hw *parent_hw,
54062306a36Sopenharmony_ci		const struct clk_parent_data *parent_data, unsigned long flags,
54162306a36Sopenharmony_ci		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
54262306a36Sopenharmony_ci		const struct clk_div_table *table, spinlock_t *lock)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct clk_divider *div;
54562306a36Sopenharmony_ci	struct clk_hw *hw;
54662306a36Sopenharmony_ci	struct clk_init_data init = {};
54762306a36Sopenharmony_ci	int ret;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
55062306a36Sopenharmony_ci		if (width + shift > 16) {
55162306a36Sopenharmony_ci			pr_warn("divider value exceeds LOWORD field\n");
55262306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* allocate the divider */
55762306a36Sopenharmony_ci	div = kzalloc(sizeof(*div), GFP_KERNEL);
55862306a36Sopenharmony_ci	if (!div)
55962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	init.name = name;
56262306a36Sopenharmony_ci	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
56362306a36Sopenharmony_ci		init.ops = &clk_divider_ro_ops;
56462306a36Sopenharmony_ci	else
56562306a36Sopenharmony_ci		init.ops = &clk_divider_ops;
56662306a36Sopenharmony_ci	init.flags = flags;
56762306a36Sopenharmony_ci	init.parent_names = parent_name ? &parent_name : NULL;
56862306a36Sopenharmony_ci	init.parent_hws = parent_hw ? &parent_hw : NULL;
56962306a36Sopenharmony_ci	init.parent_data = parent_data;
57062306a36Sopenharmony_ci	if (parent_name || parent_hw || parent_data)
57162306a36Sopenharmony_ci		init.num_parents = 1;
57262306a36Sopenharmony_ci	else
57362306a36Sopenharmony_ci		init.num_parents = 0;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* struct clk_divider assignments */
57662306a36Sopenharmony_ci	div->reg = reg;
57762306a36Sopenharmony_ci	div->shift = shift;
57862306a36Sopenharmony_ci	div->width = width;
57962306a36Sopenharmony_ci	div->flags = clk_divider_flags;
58062306a36Sopenharmony_ci	div->lock = lock;
58162306a36Sopenharmony_ci	div->hw.init = &init;
58262306a36Sopenharmony_ci	div->table = table;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* register the clock */
58562306a36Sopenharmony_ci	hw = &div->hw;
58662306a36Sopenharmony_ci	ret = clk_hw_register(dev, hw);
58762306a36Sopenharmony_ci	if (ret) {
58862306a36Sopenharmony_ci		kfree(div);
58962306a36Sopenharmony_ci		hw = ERR_PTR(ret);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return hw;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__clk_hw_register_divider);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/**
59762306a36Sopenharmony_ci * clk_register_divider_table - register a table based divider clock with
59862306a36Sopenharmony_ci * the clock framework
59962306a36Sopenharmony_ci * @dev: device registering this clock
60062306a36Sopenharmony_ci * @name: name of this clock
60162306a36Sopenharmony_ci * @parent_name: name of clock's parent
60262306a36Sopenharmony_ci * @flags: framework-specific flags
60362306a36Sopenharmony_ci * @reg: register address to adjust divider
60462306a36Sopenharmony_ci * @shift: number of bits to shift the bitfield
60562306a36Sopenharmony_ci * @width: width of the bitfield
60662306a36Sopenharmony_ci * @clk_divider_flags: divider-specific flags for this clock
60762306a36Sopenharmony_ci * @table: array of divider/value pairs ending with a div set to 0
60862306a36Sopenharmony_ci * @lock: shared register lock for this clock
60962306a36Sopenharmony_ci */
61062306a36Sopenharmony_cistruct clk *clk_register_divider_table(struct device *dev, const char *name,
61162306a36Sopenharmony_ci		const char *parent_name, unsigned long flags,
61262306a36Sopenharmony_ci		void __iomem *reg, u8 shift, u8 width,
61362306a36Sopenharmony_ci		u8 clk_divider_flags, const struct clk_div_table *table,
61462306a36Sopenharmony_ci		spinlock_t *lock)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct clk_hw *hw;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	hw =  __clk_hw_register_divider(dev, NULL, name, parent_name, NULL,
61962306a36Sopenharmony_ci			NULL, flags, reg, shift, width, clk_divider_flags,
62062306a36Sopenharmony_ci			table, lock);
62162306a36Sopenharmony_ci	if (IS_ERR(hw))
62262306a36Sopenharmony_ci		return ERR_CAST(hw);
62362306a36Sopenharmony_ci	return hw->clk;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_register_divider_table);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_civoid clk_unregister_divider(struct clk *clk)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct clk_divider *div;
63062306a36Sopenharmony_ci	struct clk_hw *hw;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	hw = __clk_get_hw(clk);
63362306a36Sopenharmony_ci	if (!hw)
63462306a36Sopenharmony_ci		return;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	div = to_clk_divider(hw);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	clk_unregister(clk);
63962306a36Sopenharmony_ci	kfree(div);
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_unregister_divider);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/**
64462306a36Sopenharmony_ci * clk_hw_unregister_divider - unregister a clk divider
64562306a36Sopenharmony_ci * @hw: hardware-specific clock data to unregister
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_civoid clk_hw_unregister_divider(struct clk_hw *hw)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct clk_divider *div;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	div = to_clk_divider(hw);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	clk_hw_unregister(hw);
65462306a36Sopenharmony_ci	kfree(div);
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_hw_unregister_divider);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic void devm_clk_hw_release_divider(struct device *dev, void *res)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	clk_hw_unregister_divider(*(struct clk_hw **)res);
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistruct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
66462306a36Sopenharmony_ci		struct device_node *np, const char *name,
66562306a36Sopenharmony_ci		const char *parent_name, const struct clk_hw *parent_hw,
66662306a36Sopenharmony_ci		const struct clk_parent_data *parent_data, unsigned long flags,
66762306a36Sopenharmony_ci		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
66862306a36Sopenharmony_ci		const struct clk_div_table *table, spinlock_t *lock)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct clk_hw **ptr, *hw;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	ptr = devres_alloc(devm_clk_hw_release_divider, sizeof(*ptr), GFP_KERNEL);
67362306a36Sopenharmony_ci	if (!ptr)
67462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	hw = __clk_hw_register_divider(dev, np, name, parent_name, parent_hw,
67762306a36Sopenharmony_ci				       parent_data, flags, reg, shift, width,
67862306a36Sopenharmony_ci				       clk_divider_flags, table, lock);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (!IS_ERR(hw)) {
68162306a36Sopenharmony_ci		*ptr = hw;
68262306a36Sopenharmony_ci		devres_add(dev, ptr);
68362306a36Sopenharmony_ci	} else {
68462306a36Sopenharmony_ci		devres_free(ptr);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return hw;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__devm_clk_hw_register_divider);
690