162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics 462306a36Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Fractional Synthesizer clock implementation 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) "clk-frac-synth: " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk-provider.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include "clk.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define DIV_FACTOR_MASK 0x1FFFF 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * DOC: Fractional Synthesizer clock 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Fout from synthesizer can be given from below equation: 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Fout= Fin/2*div (division factor) 2562306a36Sopenharmony_ci * div is 17 bits:- 2662306a36Sopenharmony_ci * 0-13 (fractional part) 2762306a36Sopenharmony_ci * 14-16 (integer part) 2862306a36Sopenharmony_ci * div is (16-14 bits).(13-0 bits) (in binary) 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Fout = Fin/(2 * div) 3162306a36Sopenharmony_ci * Fout = ((Fin / 10000)/(2 * div)) * 10000 3262306a36Sopenharmony_ci * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000 3362306a36Sopenharmony_ci * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * div << 14 simply 17 bit value written at register. 3662306a36Sopenharmony_ci * Max error due to scaling down by 10000 is 10 KHz 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, 4262306a36Sopenharmony_ci int index) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 4562306a36Sopenharmony_ci struct frac_rate_tbl *rtbl = frac->rtbl; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci prate /= 10000; 4862306a36Sopenharmony_ci prate <<= 14; 4962306a36Sopenharmony_ci prate /= (2 * rtbl[index].div); 5062306a36Sopenharmony_ci prate *= 10000; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return prate; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, 5662306a36Sopenharmony_ci unsigned long *prate) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 5962306a36Sopenharmony_ci int unused; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, 6262306a36Sopenharmony_ci frac->rtbl_cnt, &unused); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic unsigned long clk_frac_recalc_rate(struct clk_hw *hw, 6662306a36Sopenharmony_ci unsigned long parent_rate) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 6962306a36Sopenharmony_ci unsigned long flags = 0; 7062306a36Sopenharmony_ci unsigned int div = 1, val; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (frac->lock) 7362306a36Sopenharmony_ci spin_lock_irqsave(frac->lock, flags); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci val = readl_relaxed(frac->reg); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (frac->lock) 7862306a36Sopenharmony_ci spin_unlock_irqrestore(frac->lock, flags); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci div = val & DIV_FACTOR_MASK; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (!div) 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci parent_rate = parent_rate / 10000; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci parent_rate = (parent_rate << 14) / (2 * div); 8862306a36Sopenharmony_ci return parent_rate * 10000; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Configures new clock rate of frac */ 9262306a36Sopenharmony_cistatic int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, 9362306a36Sopenharmony_ci unsigned long prate) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 9662306a36Sopenharmony_ci struct frac_rate_tbl *rtbl = frac->rtbl; 9762306a36Sopenharmony_ci unsigned long flags = 0, val; 9862306a36Sopenharmony_ci int i; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt, 10162306a36Sopenharmony_ci &i); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (frac->lock) 10462306a36Sopenharmony_ci spin_lock_irqsave(frac->lock, flags); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK; 10762306a36Sopenharmony_ci val |= rtbl[i].div & DIV_FACTOR_MASK; 10862306a36Sopenharmony_ci writel_relaxed(val, frac->reg); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (frac->lock) 11162306a36Sopenharmony_ci spin_unlock_irqrestore(frac->lock, flags); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct clk_ops clk_frac_ops = { 11762306a36Sopenharmony_ci .recalc_rate = clk_frac_recalc_rate, 11862306a36Sopenharmony_ci .round_rate = clk_frac_round_rate, 11962306a36Sopenharmony_ci .set_rate = clk_frac_set_rate, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistruct clk *clk_register_frac(const char *name, const char *parent_name, 12362306a36Sopenharmony_ci unsigned long flags, void __iomem *reg, 12462306a36Sopenharmony_ci struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct clk_init_data init; 12762306a36Sopenharmony_ci struct clk_frac *frac; 12862306a36Sopenharmony_ci struct clk *clk; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { 13162306a36Sopenharmony_ci pr_err("Invalid arguments passed\n"); 13262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci frac = kzalloc(sizeof(*frac), GFP_KERNEL); 13662306a36Sopenharmony_ci if (!frac) 13762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* struct clk_frac assignments */ 14062306a36Sopenharmony_ci frac->reg = reg; 14162306a36Sopenharmony_ci frac->rtbl = rtbl; 14262306a36Sopenharmony_ci frac->rtbl_cnt = rtbl_cnt; 14362306a36Sopenharmony_ci frac->lock = lock; 14462306a36Sopenharmony_ci frac->hw.init = &init; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci init.name = name; 14762306a36Sopenharmony_ci init.ops = &clk_frac_ops; 14862306a36Sopenharmony_ci init.flags = flags; 14962306a36Sopenharmony_ci init.parent_names = &parent_name; 15062306a36Sopenharmony_ci init.num_parents = 1; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci clk = clk_register(NULL, &frac->hw); 15362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(clk)) 15462306a36Sopenharmony_ci return clk; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci pr_err("clk register failed\n"); 15762306a36Sopenharmony_ci kfree(frac); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return NULL; 16062306a36Sopenharmony_ci} 161