18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics 38c2ecf20Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 68c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 78c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Fractional Synthesizer clock implementation 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "clk-frac-synth: " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include "clk.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define DIV_FACTOR_MASK 0x1FFFF 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * DOC: Fractional Synthesizer clock 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Fout from synthesizer can be given from below equation: 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Fout= Fin/2*div (division factor) 288c2ecf20Sopenharmony_ci * div is 17 bits:- 298c2ecf20Sopenharmony_ci * 0-13 (fractional part) 308c2ecf20Sopenharmony_ci * 14-16 (integer part) 318c2ecf20Sopenharmony_ci * div is (16-14 bits).(13-0 bits) (in binary) 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Fout = Fin/(2 * div) 348c2ecf20Sopenharmony_ci * Fout = ((Fin / 10000)/(2 * div)) * 10000 358c2ecf20Sopenharmony_ci * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000 368c2ecf20Sopenharmony_ci * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * div << 14 simply 17 bit value written at register. 398c2ecf20Sopenharmony_ci * Max error due to scaling down by 10000 is 10 KHz 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, 458c2ecf20Sopenharmony_ci int index) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 488c2ecf20Sopenharmony_ci struct frac_rate_tbl *rtbl = frac->rtbl; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci prate /= 10000; 518c2ecf20Sopenharmony_ci prate <<= 14; 528c2ecf20Sopenharmony_ci prate /= (2 * rtbl[index].div); 538c2ecf20Sopenharmony_ci prate *= 10000; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return prate; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, 598c2ecf20Sopenharmony_ci unsigned long *prate) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 628c2ecf20Sopenharmony_ci int unused; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, 658c2ecf20Sopenharmony_ci frac->rtbl_cnt, &unused); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic unsigned long clk_frac_recalc_rate(struct clk_hw *hw, 698c2ecf20Sopenharmony_ci unsigned long parent_rate) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 728c2ecf20Sopenharmony_ci unsigned long flags = 0; 738c2ecf20Sopenharmony_ci unsigned int div = 1, val; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (frac->lock) 768c2ecf20Sopenharmony_ci spin_lock_irqsave(frac->lock, flags); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci val = readl_relaxed(frac->reg); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (frac->lock) 818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(frac->lock, flags); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci div = val & DIV_FACTOR_MASK; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (!div) 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci parent_rate = parent_rate / 10000; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci parent_rate = (parent_rate << 14) / (2 * div); 918c2ecf20Sopenharmony_ci return parent_rate * 10000; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Configures new clock rate of frac */ 958c2ecf20Sopenharmony_cistatic int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, 968c2ecf20Sopenharmony_ci unsigned long prate) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct clk_frac *frac = to_clk_frac(hw); 998c2ecf20Sopenharmony_ci struct frac_rate_tbl *rtbl = frac->rtbl; 1008c2ecf20Sopenharmony_ci unsigned long flags = 0, val; 1018c2ecf20Sopenharmony_ci int i; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt, 1048c2ecf20Sopenharmony_ci &i); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (frac->lock) 1078c2ecf20Sopenharmony_ci spin_lock_irqsave(frac->lock, flags); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK; 1108c2ecf20Sopenharmony_ci val |= rtbl[i].div & DIV_FACTOR_MASK; 1118c2ecf20Sopenharmony_ci writel_relaxed(val, frac->reg); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (frac->lock) 1148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(frac->lock, flags); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct clk_ops clk_frac_ops = { 1208c2ecf20Sopenharmony_ci .recalc_rate = clk_frac_recalc_rate, 1218c2ecf20Sopenharmony_ci .round_rate = clk_frac_round_rate, 1228c2ecf20Sopenharmony_ci .set_rate = clk_frac_set_rate, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistruct clk *clk_register_frac(const char *name, const char *parent_name, 1268c2ecf20Sopenharmony_ci unsigned long flags, void __iomem *reg, 1278c2ecf20Sopenharmony_ci struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct clk_init_data init; 1308c2ecf20Sopenharmony_ci struct clk_frac *frac; 1318c2ecf20Sopenharmony_ci struct clk *clk; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { 1348c2ecf20Sopenharmony_ci pr_err("Invalid arguments passed\n"); 1358c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci frac = kzalloc(sizeof(*frac), GFP_KERNEL); 1398c2ecf20Sopenharmony_ci if (!frac) 1408c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* struct clk_frac assignments */ 1438c2ecf20Sopenharmony_ci frac->reg = reg; 1448c2ecf20Sopenharmony_ci frac->rtbl = rtbl; 1458c2ecf20Sopenharmony_ci frac->rtbl_cnt = rtbl_cnt; 1468c2ecf20Sopenharmony_ci frac->lock = lock; 1478c2ecf20Sopenharmony_ci frac->hw.init = &init; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci init.name = name; 1508c2ecf20Sopenharmony_ci init.ops = &clk_frac_ops; 1518c2ecf20Sopenharmony_ci init.flags = flags; 1528c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 1538c2ecf20Sopenharmony_ci init.num_parents = 1; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci clk = clk_register(NULL, &frac->hw); 1568c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(clk)) 1578c2ecf20Sopenharmony_ci return clk; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci pr_err("clk register failed\n"); 1608c2ecf20Sopenharmony_ci kfree(frac); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return NULL; 1638c2ecf20Sopenharmony_ci} 164