11638Srgrimes// SPDX-License-Identifier: GPL-2.0-or-later 21638Srgrimes/* 31638Srgrimes * Copyright 2012 Freescale Semiconductor, Inc. 41638Srgrimes */ 51638Srgrimes 61638Srgrimes#include <linux/clk-provider.h> 71638Srgrimes#include <linux/err.h> 81638Srgrimes#include <linux/io.h> 91638Srgrimes#include <linux/slab.h> 101638Srgrimes#include "clk.h" 111638Srgrimes 121638Srgrimes/** 131638Srgrimes * struct clk_ref - mxs reference clock 141638Srgrimes * @hw: clk_hw for the reference clock 151638Srgrimes * @reg: register address 161638Srgrimes * @idx: the index of the reference clock within the same register 171638Srgrimes * 181638Srgrimes * The mxs reference clock sources from pll. Every 4 reference clocks share 191638Srgrimes * one register space, and @idx is used to identify them. Each reference 201638Srgrimes * clock has a gate control and a fractional * divider. The rate is calculated 211638Srgrimes * as pll rate * (18 / FRAC), where FRAC = 18 ~ 35. 221638Srgrimes */ 231638Srgrimesstruct clk_ref { 241638Srgrimes struct clk_hw hw; 251638Srgrimes void __iomem *reg; 261638Srgrimes u8 idx; 271638Srgrimes}; 281638Srgrimes 291638Srgrimes#define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw) 301638Srgrimes 311638Srgrimesstatic int clk_ref_enable(struct clk_hw *hw) 321638Srgrimes{ 331638Srgrimes struct clk_ref *ref = to_clk_ref(hw); 341638Srgrimes 351638Srgrimes writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + CLR); 361638Srgrimes 371638Srgrimes return 0; 381638Srgrimes} 391638Srgrimes 401638Srgrimesstatic void clk_ref_disable(struct clk_hw *hw) 411638Srgrimes{ 421638Srgrimes struct clk_ref *ref = to_clk_ref(hw); 431638Srgrimes 441638Srgrimes writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + SET); 451638Srgrimes} 461638Srgrimes 471638Srgrimesstatic unsigned long clk_ref_recalc_rate(struct clk_hw *hw, 481638Srgrimes unsigned long parent_rate) 491638Srgrimes{ 501638Srgrimes struct clk_ref *ref = to_clk_ref(hw); 511638Srgrimes u64 tmp = parent_rate; 521638Srgrimes u8 frac = (readl_relaxed(ref->reg) >> (ref->idx * 8)) & 0x3f; 531638Srgrimes 541638Srgrimes tmp *= 18; 551638Srgrimes do_div(tmp, frac); 561638Srgrimes 571638Srgrimes return tmp; 581638Srgrimes} 591638Srgrimes 601638Srgrimesstatic long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate, 611638Srgrimes unsigned long *prate) 621638Srgrimes{ 631638Srgrimes unsigned long parent_rate = *prate; 641638Srgrimes u64 tmp = parent_rate; 651638Srgrimes u8 frac; 661638Srgrimes 671638Srgrimes tmp = tmp * 18 + rate / 2; 681638Srgrimes do_div(tmp, rate); 691638Srgrimes frac = tmp; 701638Srgrimes 711638Srgrimes if (frac < 18) 721638Srgrimes frac = 18; 731638Srgrimes else if (frac > 35) 741638Srgrimes frac = 35; 751638Srgrimes 761638Srgrimes tmp = parent_rate; 771638Srgrimes tmp *= 18; 781638Srgrimes do_div(tmp, frac); 791638Srgrimes 801638Srgrimes return tmp; 811638Srgrimes} 821638Srgrimes 831638Srgrimesstatic int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate, 841638Srgrimes unsigned long parent_rate) 851638Srgrimes{ 861638Srgrimes struct clk_ref *ref = to_clk_ref(hw); 871638Srgrimes unsigned long flags; 881638Srgrimes u64 tmp = parent_rate; 891638Srgrimes u32 val; 901638Srgrimes u8 frac, shift = ref->idx * 8; 911638Srgrimes 921638Srgrimes tmp = tmp * 18 + rate / 2; 931638Srgrimes do_div(tmp, rate); 941638Srgrimes frac = tmp; 951638Srgrimes 961638Srgrimes if (frac < 18) 971638Srgrimes frac = 18; 981638Srgrimes else if (frac > 35) 991638Srgrimes frac = 35; 1001638Srgrimes 1011638Srgrimes spin_lock_irqsave(&mxs_lock, flags); 1021638Srgrimes 1031638Srgrimes val = readl_relaxed(ref->reg); 1041638Srgrimes val &= ~(0x3f << shift); 1051638Srgrimes val |= frac << shift; 1061638Srgrimes writel_relaxed(val, ref->reg); 1071638Srgrimes 1081638Srgrimes spin_unlock_irqrestore(&mxs_lock, flags); 1091638Srgrimes 1101638Srgrimes return 0; 1111638Srgrimes} 1121638Srgrimes 1131638Srgrimesstatic const struct clk_ops clk_ref_ops = { 1141638Srgrimes .enable = clk_ref_enable, 1151638Srgrimes .disable = clk_ref_disable, 1161638Srgrimes .recalc_rate = clk_ref_recalc_rate, 1171638Srgrimes .round_rate = clk_ref_round_rate, 1181638Srgrimes .set_rate = clk_ref_set_rate, 1191638Srgrimes}; 1201638Srgrimes 1211638Srgrimesstruct clk *mxs_clk_ref(const char *name, const char *parent_name, 1221638Srgrimes void __iomem *reg, u8 idx) 1231638Srgrimes{ 1241638Srgrimes struct clk_ref *ref; 1251638Srgrimes struct clk *clk; 1261638Srgrimes struct clk_init_data init; 1271638Srgrimes 1281638Srgrimes ref = kzalloc(sizeof(*ref), GFP_KERNEL); 1291638Srgrimes if (!ref) 1301638Srgrimes return ERR_PTR(-ENOMEM); 1311638Srgrimes 1321638Srgrimes init.name = name; 1331638Srgrimes init.ops = &clk_ref_ops; 1341638Srgrimes init.flags = 0; 1351638Srgrimes init.parent_names = (parent_name ? &parent_name: NULL); 1361638Srgrimes init.num_parents = (parent_name ? 1 : 0); 1371638Srgrimes 1381638Srgrimes ref->reg = reg; 1391638Srgrimes ref->idx = idx; 1401638Srgrimes ref->hw.init = &init; 1411638Srgrimes 1421638Srgrimes clk = clk_register(NULL, &ref->hw); 1431638Srgrimes if (IS_ERR(clk)) 1441638Srgrimes kfree(ref); 1451638Srgrimes 1461638Srgrimes return clk; 1471638Srgrimes} 1481638Srgrimes