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