18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Maxime Ripard 48c2ecf20Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "ccu_phase.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic int ccu_phase_get_phase(struct clk_hw *hw) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct ccu_phase *phase = hw_to_ccu_phase(hw); 168c2ecf20Sopenharmony_ci struct clk_hw *parent, *grandparent; 178c2ecf20Sopenharmony_ci unsigned int parent_rate, grandparent_rate; 188c2ecf20Sopenharmony_ci u16 step, parent_div; 198c2ecf20Sopenharmony_ci u32 reg; 208c2ecf20Sopenharmony_ci u8 delay; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci reg = readl(phase->common.base + phase->common.reg); 238c2ecf20Sopenharmony_ci delay = (reg >> phase->shift); 248c2ecf20Sopenharmony_ci delay &= (1 << phase->width) - 1; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (!delay) 278c2ecf20Sopenharmony_ci return 180; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* Get our parent clock, it's the one that can adjust its rate */ 308c2ecf20Sopenharmony_ci parent = clk_hw_get_parent(hw); 318c2ecf20Sopenharmony_ci if (!parent) 328c2ecf20Sopenharmony_ci return -EINVAL; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* And its rate */ 358c2ecf20Sopenharmony_ci parent_rate = clk_hw_get_rate(parent); 368c2ecf20Sopenharmony_ci if (!parent_rate) 378c2ecf20Sopenharmony_ci return -EINVAL; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Now, get our parent's parent (most likely some PLL) */ 408c2ecf20Sopenharmony_ci grandparent = clk_hw_get_parent(parent); 418c2ecf20Sopenharmony_ci if (!grandparent) 428c2ecf20Sopenharmony_ci return -EINVAL; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* And its rate */ 458c2ecf20Sopenharmony_ci grandparent_rate = clk_hw_get_rate(grandparent); 468c2ecf20Sopenharmony_ci if (!grandparent_rate) 478c2ecf20Sopenharmony_ci return -EINVAL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Get our parent clock divider */ 508c2ecf20Sopenharmony_ci parent_div = grandparent_rate / parent_rate; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci step = DIV_ROUND_CLOSEST(360, parent_div); 538c2ecf20Sopenharmony_ci return delay * step; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int ccu_phase_set_phase(struct clk_hw *hw, int degrees) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct ccu_phase *phase = hw_to_ccu_phase(hw); 598c2ecf20Sopenharmony_ci struct clk_hw *parent, *grandparent; 608c2ecf20Sopenharmony_ci unsigned int parent_rate, grandparent_rate; 618c2ecf20Sopenharmony_ci unsigned long flags; 628c2ecf20Sopenharmony_ci u32 reg; 638c2ecf20Sopenharmony_ci u8 delay; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Get our parent clock, it's the one that can adjust its rate */ 668c2ecf20Sopenharmony_ci parent = clk_hw_get_parent(hw); 678c2ecf20Sopenharmony_ci if (!parent) 688c2ecf20Sopenharmony_ci return -EINVAL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* And its rate */ 718c2ecf20Sopenharmony_ci parent_rate = clk_hw_get_rate(parent); 728c2ecf20Sopenharmony_ci if (!parent_rate) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Now, get our parent's parent (most likely some PLL) */ 768c2ecf20Sopenharmony_ci grandparent = clk_hw_get_parent(parent); 778c2ecf20Sopenharmony_ci if (!grandparent) 788c2ecf20Sopenharmony_ci return -EINVAL; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* And its rate */ 818c2ecf20Sopenharmony_ci grandparent_rate = clk_hw_get_rate(grandparent); 828c2ecf20Sopenharmony_ci if (!grandparent_rate) 838c2ecf20Sopenharmony_ci return -EINVAL; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (degrees != 180) { 868c2ecf20Sopenharmony_ci u16 step, parent_div; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Get our parent divider */ 898c2ecf20Sopenharmony_ci parent_div = grandparent_rate / parent_rate; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * We can only outphase the clocks by multiple of the 938c2ecf20Sopenharmony_ci * PLL's period. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Since our parent clock is only a divider, and the 968c2ecf20Sopenharmony_ci * formula to get the outphasing in degrees is deg = 978c2ecf20Sopenharmony_ci * 360 * delta / period 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * If we simplify this formula, we can see that the 1008c2ecf20Sopenharmony_ci * only thing that we're concerned about is the number 1018c2ecf20Sopenharmony_ci * of period we want to outphase our clock from, and 1028c2ecf20Sopenharmony_ci * the divider set by our parent clock. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci step = DIV_ROUND_CLOSEST(360, parent_div); 1058c2ecf20Sopenharmony_ci delay = DIV_ROUND_CLOSEST(degrees, step); 1068c2ecf20Sopenharmony_ci } else { 1078c2ecf20Sopenharmony_ci delay = 0; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(phase->common.lock, flags); 1118c2ecf20Sopenharmony_ci reg = readl(phase->common.base + phase->common.reg); 1128c2ecf20Sopenharmony_ci reg &= ~GENMASK(phase->width + phase->shift - 1, phase->shift); 1138c2ecf20Sopenharmony_ci writel(reg | (delay << phase->shift), 1148c2ecf20Sopenharmony_ci phase->common.base + phase->common.reg); 1158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(phase->common.lock, flags); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciconst struct clk_ops ccu_phase_ops = { 1218c2ecf20Sopenharmony_ci .get_phase = ccu_phase_get_phase, 1228c2ecf20Sopenharmony_ci .set_phase = ccu_phase_set_phase, 1238c2ecf20Sopenharmony_ci}; 124