18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/bitops.h> 78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/export.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic inline u32 clk_mult_readl(struct clk_multiplier *mult) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN) 188c2ecf20Sopenharmony_ci return ioread32be(mult->reg); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci return readl(mult->reg); 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic inline void clk_mult_writel(struct clk_multiplier *mult, u32 val) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN) 268c2ecf20Sopenharmony_ci iowrite32be(val, mult->reg); 278c2ecf20Sopenharmony_ci else 288c2ecf20Sopenharmony_ci writel(val, mult->reg); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned long __get_mult(struct clk_multiplier *mult, 328c2ecf20Sopenharmony_ci unsigned long rate, 338c2ecf20Sopenharmony_ci unsigned long parent_rate) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST) 368c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(rate, parent_rate); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return rate / parent_rate; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw, 428c2ecf20Sopenharmony_ci unsigned long parent_rate) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct clk_multiplier *mult = to_clk_multiplier(hw); 458c2ecf20Sopenharmony_ci unsigned long val; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci val = clk_mult_readl(mult) >> mult->shift; 488c2ecf20Sopenharmony_ci val &= GENMASK(mult->width - 1, 0); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS) 518c2ecf20Sopenharmony_ci val = 1; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return parent_rate * val; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool __is_best_rate(unsigned long rate, unsigned long new, 578c2ecf20Sopenharmony_ci unsigned long best, unsigned long flags) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci if (flags & CLK_MULTIPLIER_ROUND_CLOSEST) 608c2ecf20Sopenharmony_ci return abs(rate - new) < abs(rate - best); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return new >= rate && new < best; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, 668c2ecf20Sopenharmony_ci unsigned long *best_parent_rate, 678c2ecf20Sopenharmony_ci u8 width, unsigned long flags) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct clk_multiplier *mult = to_clk_multiplier(hw); 708c2ecf20Sopenharmony_ci unsigned long orig_parent_rate = *best_parent_rate; 718c2ecf20Sopenharmony_ci unsigned long parent_rate, current_rate, best_rate = ~0; 728c2ecf20Sopenharmony_ci unsigned int i, bestmult = 0; 738c2ecf20Sopenharmony_ci unsigned int maxmult = (1 << width) - 1; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { 768c2ecf20Sopenharmony_ci bestmult = rate / orig_parent_rate; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Make sure we don't end up with a 0 multiplier */ 798c2ecf20Sopenharmony_ci if ((bestmult == 0) && 808c2ecf20Sopenharmony_ci !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)) 818c2ecf20Sopenharmony_ci bestmult = 1; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Make sure we don't overflow the multiplier */ 848c2ecf20Sopenharmony_ci if (bestmult > maxmult) 858c2ecf20Sopenharmony_ci bestmult = maxmult; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return bestmult; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (i = 1; i < maxmult; i++) { 918c2ecf20Sopenharmony_ci if (rate == orig_parent_rate * i) { 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * This is the best case for us if we have a 948c2ecf20Sopenharmony_ci * perfect match without changing the parent 958c2ecf20Sopenharmony_ci * rate. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci *best_parent_rate = orig_parent_rate; 988c2ecf20Sopenharmony_ci return i; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1028c2ecf20Sopenharmony_ci rate / i); 1038c2ecf20Sopenharmony_ci current_rate = parent_rate * i; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (__is_best_rate(rate, current_rate, best_rate, flags)) { 1068c2ecf20Sopenharmony_ci bestmult = i; 1078c2ecf20Sopenharmony_ci best_rate = current_rate; 1088c2ecf20Sopenharmony_ci *best_parent_rate = parent_rate; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return bestmult; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate, 1168c2ecf20Sopenharmony_ci unsigned long *parent_rate) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct clk_multiplier *mult = to_clk_multiplier(hw); 1198c2ecf20Sopenharmony_ci unsigned long factor = __bestmult(hw, rate, parent_rate, 1208c2ecf20Sopenharmony_ci mult->width, mult->flags); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return *parent_rate * factor; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate, 1268c2ecf20Sopenharmony_ci unsigned long parent_rate) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct clk_multiplier *mult = to_clk_multiplier(hw); 1298c2ecf20Sopenharmony_ci unsigned long factor = __get_mult(mult, rate, parent_rate); 1308c2ecf20Sopenharmony_ci unsigned long flags = 0; 1318c2ecf20Sopenharmony_ci unsigned long val; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (mult->lock) 1348c2ecf20Sopenharmony_ci spin_lock_irqsave(mult->lock, flags); 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci __acquire(mult->lock); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci val = clk_mult_readl(mult); 1398c2ecf20Sopenharmony_ci val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift); 1408c2ecf20Sopenharmony_ci val |= factor << mult->shift; 1418c2ecf20Sopenharmony_ci clk_mult_writel(mult, val); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (mult->lock) 1448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(mult->lock, flags); 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci __release(mult->lock); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ciconst struct clk_ops clk_multiplier_ops = { 1528c2ecf20Sopenharmony_ci .recalc_rate = clk_multiplier_recalc_rate, 1538c2ecf20Sopenharmony_ci .round_rate = clk_multiplier_round_rate, 1548c2ecf20Sopenharmony_ci .set_rate = clk_multiplier_set_rate, 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_multiplier_ops); 157