19d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette/* 29d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 39d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> 49d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 59d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * 69d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * This program is free software; you can redistribute it and/or modify 79d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * it under the terms of the GNU General Public License version 2 as 89d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * published by the Free Software Foundation. 99d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * 109d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * Adjustable divider clock implementation 119d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette */ 129d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 139d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/clk-provider.h> 149d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/module.h> 159d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/slab.h> 169d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/io.h> 179d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/err.h> 189d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#include <linux/string.h> 199d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 209d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette/* 219d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * DOC: basic adjustable divider clock that cannot gate 229d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * 239d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * Traits of this clock: 249d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * prepare - clk_prepare only ensures that parents are prepared 259d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * enable - clk_enable only ensures that parents are enabled 269d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * rate - rate is adjustable. clk->rate = parent->rate / divisor 279d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * parent - fixed parent. No clk_set_parent support 289d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette */ 299d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 309d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) 319d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 329d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#define div_mask(d) ((1 << (d->width)) - 1) 339d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 349d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestatic unsigned long clk_divider_recalc_rate(struct clk_hw *hw, 359d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long parent_rate) 369d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette{ 379d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette struct clk_divider *divider = to_clk_divider(hw); 389d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned int div; 399d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 409d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div = readl(divider->reg) >> divider->shift; 419d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div &= div_mask(divider); 429d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 439d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) 449d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div++; 459d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 469d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return parent_rate / div; 479d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette} 489d9f78ed9af0e465d2fd15550471956e7f559b9fMike TurquetteEXPORT_SYMBOL_GPL(clk_divider_recalc_rate); 499d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 509d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette/* 519d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * The reverse of DIV_ROUND_UP: The maximum number which 529d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * divided by m is r 539d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette */ 549d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) 559d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 569d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestatic int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, 579d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long *best_parent_rate) 589d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette{ 599d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette struct clk_divider *divider = to_clk_divider(hw); 609d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette int i, bestdiv = 0; 619d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long parent_rate, best = 0, now, maxdiv; 629d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 639d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!rate) 649d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette rate = 1; 659d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 669d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette maxdiv = (1 << divider->width); 679d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 689d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (divider->flags & CLK_DIVIDER_ONE_BASED) 699d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette maxdiv--; 709d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 719d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!best_parent_rate) { 729d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); 739d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv = DIV_ROUND_UP(parent_rate, rate); 749d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv = bestdiv == 0 ? 1 : bestdiv; 759d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; 769d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return bestdiv; 779d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 789d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 799d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette /* 809d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * The maximum divider we can use without overflowing 819d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette * unsigned long in rate * i below 829d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette */ 839d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette maxdiv = min(ULONG_MAX / rate, maxdiv); 849d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 859d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette for (i = 1; i <= maxdiv; i++) { 869d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 879d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette MULT_ROUND_UP(rate, i)); 889d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette now = parent_rate / i; 899d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (now <= rate && now > best) { 909d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv = i; 919d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette best = now; 929d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette *best_parent_rate = parent_rate; 939d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 949d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 959d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 969d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!bestdiv) { 979d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv = (1 << divider->width); 989d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (divider->flags & CLK_DIVIDER_ONE_BASED) 999d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette bestdiv--; 1009d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); 1019d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 1029d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1039d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return bestdiv; 1049d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette} 1059d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1069d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestatic long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 1079d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long *prate) 1089d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette{ 1099d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette int div; 1109d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div = clk_divider_bestdiv(hw, rate, prate); 1119d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1129d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (prate) 1139d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return *prate / div; 1149d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette else { 1159d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long r; 1169d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette r = __clk_get_rate(__clk_get_parent(hw->clk)); 1179d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return r / div; 1189d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 1199d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette} 1209d9f78ed9af0e465d2fd15550471956e7f559b9fMike TurquetteEXPORT_SYMBOL_GPL(clk_divider_round_rate); 1219d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1229d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestatic int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) 1239d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette{ 1249d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette struct clk_divider *divider = to_clk_divider(hw); 1259d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned int div; 1269d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette unsigned long flags = 0; 1279d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette u32 val; 1289d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1299d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; 1309d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1319d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) 1329d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div--; 1339d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1349d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (div > div_mask(divider)) 1359d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div = div_mask(divider); 1369d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1379d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (divider->lock) 1389d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette spin_lock_irqsave(divider->lock, flags); 1399d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1409d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette val = readl(divider->reg); 1419d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette val &= ~(div_mask(divider) << divider->shift); 1429d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette val |= div << divider->shift; 1439d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette writel(val, divider->reg); 1449d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1459d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (divider->lock) 1469d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette spin_unlock_irqrestore(divider->lock, flags); 1479d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1489d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return 0; 1499d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette} 1509d9f78ed9af0e465d2fd15550471956e7f559b9fMike TurquetteEXPORT_SYMBOL_GPL(clk_divider_set_rate); 1519d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1529d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestruct clk_ops clk_divider_ops = { 1539d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette .recalc_rate = clk_divider_recalc_rate, 1549d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette .round_rate = clk_divider_round_rate, 1559d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette .set_rate = clk_divider_set_rate, 1569d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette}; 1579d9f78ed9af0e465d2fd15550471956e7f559b9fMike TurquetteEXPORT_SYMBOL_GPL(clk_divider_ops); 1589d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1599d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquettestruct clk *clk_register_divider(struct device *dev, const char *name, 1609d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette const char *parent_name, unsigned long flags, 1619d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette void __iomem *reg, u8 shift, u8 width, 1629d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette u8 clk_divider_flags, spinlock_t *lock) 1639d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette{ 1649d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette struct clk_divider *div; 1659d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette struct clk *clk; 1669d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1679d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); 1689d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1699d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!div) { 1709d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette pr_err("%s: could not allocate divider clk\n", __func__); 1719d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return NULL; 1729d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 1739d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1749d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette /* struct clk_divider assignments */ 1759d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->reg = reg; 1769d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->shift = shift; 1779d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->width = width; 1789d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->flags = clk_divider_flags; 1799d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->lock = lock; 1809d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1819d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (parent_name) { 1829d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->parent[0] = kstrdup(parent_name, GFP_KERNEL); 1839d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (!div->parent[0]) 1849d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette goto out; 1859d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette } 1869d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1879d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette clk = clk_register(dev, name, 1889d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette &clk_divider_ops, &div->hw, 1899d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette div->parent, 1909d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette (parent_name ? 1 : 0), 1919d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette flags); 1929d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette if (clk) 1939d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return clk; 1949d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1959d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquetteout: 1969d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette kfree(div->parent[0]); 1979d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette kfree(div); 1989d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette 1999d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette return NULL; 2009d9f78ed9af0e465d2fd15550471956e7f559b9fMike Turquette} 201