18f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad/* 28f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 38f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 48f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * This program is free software; you can redistribute it and/or modify it 58f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * under the terms and conditions of the GNU General Public License, 68f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * version 2, as published by the Free Software Foundation. 78f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 88f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * This program is distributed in the hope it will be useful, but WITHOUT 98f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 108f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 118f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * more details. 128f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 138f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * You should have received a copy of the GNU General Public License 148f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * along with this program. If not, see <http://www.gnu.org/licenses/>. 158f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad */ 168f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 178f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/kernel.h> 188f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/io.h> 198f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/err.h> 208f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/slab.h> 218f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/clk-provider.h> 228f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/clk.h> 238f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 248f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include "clk.h" 258f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 268f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define pll_out_override(p) (BIT((p->shift - 6))) 278f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define div_mask(d) ((1 << (d->width)) - 1) 288f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define get_mul(d) (1 << d->frac_width) 298f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define get_max_div(d) div_mask(d) 308f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 318f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define PERIPH_CLK_UART_DIV_ENB BIT(24) 328f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 338f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, 348f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long parent_rate) 358f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 368f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad s64 divider_ux1 = parent_rate; 378f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u8 flags = divider->flags; 388f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad int mul; 398f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 408f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (!rate) 418f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return 0; 428f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 438f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad mul = get_mul(divider); 448f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 458f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (!(flags & TEGRA_DIVIDER_INT)) 468f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider_ux1 *= mul; 478f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 488f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (flags & TEGRA_DIVIDER_ROUND_UP) 498f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider_ux1 += rate - 1; 508f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 518f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad do_div(divider_ux1, rate); 528f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 538f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (flags & TEGRA_DIVIDER_INT) 548f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider_ux1 *= mul; 558f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 568f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider_ux1 -= mul; 578f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 588f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider_ux1 < 0) 598f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return 0; 608f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 618f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider_ux1 > get_max_div(divider)) 623de5bdfb4cb3bd99052a4ffaee358189779be042Andrew Bresticker return get_max_div(divider); 638f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 648f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return divider_ux1; 658f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 668f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 678f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, 688f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long parent_rate) 698f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 708f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); 718f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u32 reg; 728f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad int div, mul; 738f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u64 rate = parent_rate; 748f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 758f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad reg = readl_relaxed(divider->reg) >> divider->shift; 768f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad div = reg & div_mask(divider); 778f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 788f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad mul = get_mul(divider); 798f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad div += mul; 808f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 818f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad rate *= mul; 828f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad rate += div - 1; 838f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad do_div(rate, div); 848f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 858f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return rate; 868f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 878f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 888f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, 898f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long *prate) 908f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 918f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); 928f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad int div, mul; 938f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long output_rate = *prate; 948f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 958f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (!rate) 968f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return output_rate; 978f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 988f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad div = get_div(divider, rate, output_rate); 998f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (div < 0) 1008f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return *prate; 1018f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1028f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad mul = get_mul(divider); 1038f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1048f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return DIV_ROUND_UP(output_rate * mul, div + mul); 1058f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 1068f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1078f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, 1088f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long parent_rate) 1098f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 1108f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); 1118f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad int div; 1128f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long flags = 0; 1138f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u32 val; 1148f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1158f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad div = get_div(divider, rate, parent_rate); 1168f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (div < 0) 1178f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return div; 1188f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1198f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider->lock) 1208f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad spin_lock_irqsave(divider->lock, flags); 1218f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1228f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val = readl_relaxed(divider->reg); 1238f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val &= ~(div_mask(divider) << divider->shift); 1248f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val |= div << divider->shift; 1258f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1268f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider->flags & TEGRA_DIVIDER_UART) { 1278f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (div) 1288f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val |= PERIPH_CLK_UART_DIV_ENB; 1298f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad else 1308f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val &= ~PERIPH_CLK_UART_DIV_ENB; 1318f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad } 1328f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1338f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider->flags & TEGRA_DIVIDER_FIXED) 1348f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val |= pll_out_override(divider); 1358f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1368f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad writel_relaxed(val, divider->reg); 1378f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1388f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (divider->lock) 1398f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad spin_unlock_irqrestore(divider->lock, flags); 1408f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1418f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return 0; 1428f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 1438f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1448f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadconst struct clk_ops tegra_clk_frac_div_ops = { 1458f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad .recalc_rate = clk_frac_div_recalc_rate, 1468f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad .set_rate = clk_frac_div_set_rate, 1478f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad .round_rate = clk_frac_div_round_rate, 1488f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad}; 1498f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1508f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstruct clk *tegra_clk_register_divider(const char *name, 1518f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad const char *parent_name, void __iomem *reg, 1528f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, 1538f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u8 frac_width, spinlock_t *lock) 1548f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 1558f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_frac_div *divider; 1568f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct clk *clk; 1578f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct clk_init_data init; 1588f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1598f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider = kzalloc(sizeof(*divider), GFP_KERNEL); 1608f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (!divider) { 1618f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad pr_err("%s: could not allocate fractional divider clk\n", 1628f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad __func__); 1638f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return ERR_PTR(-ENOMEM); 1648f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad } 1658f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1668f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.name = name; 1678f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.ops = &tegra_clk_frac_div_ops; 1688f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.flags = flags; 1698f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.parent_names = parent_name ? &parent_name : NULL; 1708f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.num_parents = parent_name ? 1 : 0; 1718f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1728f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->reg = reg; 1738f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->shift = shift; 1748f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->width = width; 1758f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->frac_width = frac_width; 1768f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->lock = lock; 1778f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->flags = clk_divider_flags; 1788f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1798f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad /* Data in .init is copied by clk_register(), so stack variable OK */ 1808f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad divider->hw.init = &init; 1818f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1828f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad clk = clk_register(NULL, ÷r->hw); 1838f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (IS_ERR(clk)) 1848f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad kfree(divider); 1858f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1868f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return clk; 1878f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 188