162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bitops.h>
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic inline u32 clk_mult_readl(struct clk_multiplier *mult)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
1862306a36Sopenharmony_ci		return ioread32be(mult->reg);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	return readl(mult->reg);
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic inline void clk_mult_writel(struct clk_multiplier *mult, u32 val)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
2662306a36Sopenharmony_ci		iowrite32be(val, mult->reg);
2762306a36Sopenharmony_ci	else
2862306a36Sopenharmony_ci		writel(val, mult->reg);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic unsigned long __get_mult(struct clk_multiplier *mult,
3262306a36Sopenharmony_ci				unsigned long rate,
3362306a36Sopenharmony_ci				unsigned long parent_rate)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
3662306a36Sopenharmony_ci		return DIV_ROUND_CLOSEST(rate, parent_rate);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return rate / parent_rate;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
4262306a36Sopenharmony_ci						unsigned long parent_rate)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct clk_multiplier *mult = to_clk_multiplier(hw);
4562306a36Sopenharmony_ci	unsigned long val;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	val = clk_mult_readl(mult) >> mult->shift;
4862306a36Sopenharmony_ci	val &= GENMASK(mult->width - 1, 0);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
5162306a36Sopenharmony_ci		val = 1;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return parent_rate * val;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic bool __is_best_rate(unsigned long rate, unsigned long new,
5762306a36Sopenharmony_ci			   unsigned long best, unsigned long flags)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
6062306a36Sopenharmony_ci		return abs(rate - new) < abs(rate - best);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return new >= rate && new < best;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
6662306a36Sopenharmony_ci				unsigned long *best_parent_rate,
6762306a36Sopenharmony_ci				u8 width, unsigned long flags)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct clk_multiplier *mult = to_clk_multiplier(hw);
7062306a36Sopenharmony_ci	unsigned long orig_parent_rate = *best_parent_rate;
7162306a36Sopenharmony_ci	unsigned long parent_rate, current_rate, best_rate = ~0;
7262306a36Sopenharmony_ci	unsigned int i, bestmult = 0;
7362306a36Sopenharmony_ci	unsigned int maxmult = (1 << width) - 1;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
7662306a36Sopenharmony_ci		bestmult = rate / orig_parent_rate;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		/* Make sure we don't end up with a 0 multiplier */
7962306a36Sopenharmony_ci		if ((bestmult == 0) &&
8062306a36Sopenharmony_ci		    !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
8162306a36Sopenharmony_ci			bestmult = 1;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		/* Make sure we don't overflow the multiplier */
8462306a36Sopenharmony_ci		if (bestmult > maxmult)
8562306a36Sopenharmony_ci			bestmult = maxmult;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		return bestmult;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	for (i = 1; i < maxmult; i++) {
9162306a36Sopenharmony_ci		if (rate == orig_parent_rate * i) {
9262306a36Sopenharmony_ci			/*
9362306a36Sopenharmony_ci			 * This is the best case for us if we have a
9462306a36Sopenharmony_ci			 * perfect match without changing the parent
9562306a36Sopenharmony_ci			 * rate.
9662306a36Sopenharmony_ci			 */
9762306a36Sopenharmony_ci			*best_parent_rate = orig_parent_rate;
9862306a36Sopenharmony_ci			return i;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
10262306a36Sopenharmony_ci						rate / i);
10362306a36Sopenharmony_ci		current_rate = parent_rate * i;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		if (__is_best_rate(rate, current_rate, best_rate, flags)) {
10662306a36Sopenharmony_ci			bestmult = i;
10762306a36Sopenharmony_ci			best_rate = current_rate;
10862306a36Sopenharmony_ci			*best_parent_rate = parent_rate;
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return bestmult;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
11662306a36Sopenharmony_ci				  unsigned long *parent_rate)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct clk_multiplier *mult = to_clk_multiplier(hw);
11962306a36Sopenharmony_ci	unsigned long factor = __bestmult(hw, rate, parent_rate,
12062306a36Sopenharmony_ci					  mult->width, mult->flags);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return *parent_rate * factor;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
12662306a36Sopenharmony_ci			       unsigned long parent_rate)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct clk_multiplier *mult = to_clk_multiplier(hw);
12962306a36Sopenharmony_ci	unsigned long factor = __get_mult(mult, rate, parent_rate);
13062306a36Sopenharmony_ci	unsigned long flags = 0;
13162306a36Sopenharmony_ci	unsigned long val;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (mult->lock)
13462306a36Sopenharmony_ci		spin_lock_irqsave(mult->lock, flags);
13562306a36Sopenharmony_ci	else
13662306a36Sopenharmony_ci		__acquire(mult->lock);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	val = clk_mult_readl(mult);
13962306a36Sopenharmony_ci	val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
14062306a36Sopenharmony_ci	val |= factor << mult->shift;
14162306a36Sopenharmony_ci	clk_mult_writel(mult, val);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (mult->lock)
14462306a36Sopenharmony_ci		spin_unlock_irqrestore(mult->lock, flags);
14562306a36Sopenharmony_ci	else
14662306a36Sopenharmony_ci		__release(mult->lock);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciconst struct clk_ops clk_multiplier_ops = {
15262306a36Sopenharmony_ci	.recalc_rate	= clk_multiplier_recalc_rate,
15362306a36Sopenharmony_ci	.round_rate	= clk_multiplier_round_rate,
15462306a36Sopenharmony_ci	.set_rate	= clk_multiplier_set_rate,
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_multiplier_ops);
157