1 /* 2 * MVEBU Core divider clock 3 * 4 * Copyright (C) 2013 Marvell 5 * 6 * Ezequiel Garcia <ezequiel.garcia@free-electrons.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/clk-provider.h> 15 #include <linux/of_address.h> 16 #include <linux/slab.h> 17 #include <linux/delay.h> 18 #include "common.h" 19 20 #define CORE_CLK_DIV_RATIO_MASK 0xff 21 #define CORE_CLK_DIV_RATIO_RELOAD BIT(8) 22 #define CORE_CLK_DIV_ENABLE_OFFSET 24 23 #define CORE_CLK_DIV_RATIO_OFFSET 0x8 24 25 struct clk_corediv_desc { 26 unsigned int mask; 27 unsigned int offset; 28 unsigned int fieldbit; 29 }; 30 31 struct clk_corediv { 32 struct clk_hw hw; 33 void __iomem *reg; 34 struct clk_corediv_desc desc; 35 spinlock_t lock; 36 }; 37 38 static struct clk_onecell_data clk_data; 39 40 static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = { 41 { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ 42 }; 43 44 #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) 45 46 static int clk_corediv_is_enabled(struct clk_hw *hwclk) 47 { 48 struct clk_corediv *corediv = to_corediv_clk(hwclk); 49 struct clk_corediv_desc *desc = &corediv->desc; 50 u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET; 51 52 return !!(readl(corediv->reg) & enable_mask); 53 } 54 55 static int clk_corediv_enable(struct clk_hw *hwclk) 56 { 57 struct clk_corediv *corediv = to_corediv_clk(hwclk); 58 struct clk_corediv_desc *desc = &corediv->desc; 59 unsigned long flags = 0; 60 u32 reg; 61 62 spin_lock_irqsave(&corediv->lock, flags); 63 64 reg = readl(corediv->reg); 65 reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 66 writel(reg, corediv->reg); 67 68 spin_unlock_irqrestore(&corediv->lock, flags); 69 70 return 0; 71 } 72 73 static void clk_corediv_disable(struct clk_hw *hwclk) 74 { 75 struct clk_corediv *corediv = to_corediv_clk(hwclk); 76 struct clk_corediv_desc *desc = &corediv->desc; 77 unsigned long flags = 0; 78 u32 reg; 79 80 spin_lock_irqsave(&corediv->lock, flags); 81 82 reg = readl(corediv->reg); 83 reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 84 writel(reg, corediv->reg); 85 86 spin_unlock_irqrestore(&corediv->lock, flags); 87 } 88 89 static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, 90 unsigned long parent_rate) 91 { 92 struct clk_corediv *corediv = to_corediv_clk(hwclk); 93 struct clk_corediv_desc *desc = &corediv->desc; 94 u32 reg, div; 95 96 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 97 div = (reg >> desc->offset) & desc->mask; 98 return parent_rate / div; 99 } 100 101 static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate, 102 unsigned long *parent_rate) 103 { 104 /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ 105 u32 div; 106 107 div = *parent_rate / rate; 108 if (div < 4) 109 div = 4; 110 else if (div > 6) 111 div = 8; 112 113 return *parent_rate / div; 114 } 115 116 static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, 117 unsigned long parent_rate) 118 { 119 struct clk_corediv *corediv = to_corediv_clk(hwclk); 120 struct clk_corediv_desc *desc = &corediv->desc; 121 unsigned long flags = 0; 122 u32 reg, div; 123 124 div = parent_rate / rate; 125 126 spin_lock_irqsave(&corediv->lock, flags); 127 128 /* Write new divider to the divider ratio register */ 129 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 130 reg &= ~(desc->mask << desc->offset); 131 reg |= (div & desc->mask) << desc->offset; 132 writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 133 134 /* Set reload-force for this clock */ 135 reg = readl(corediv->reg) | BIT(desc->fieldbit); 136 writel(reg, corediv->reg); 137 138 /* Now trigger the clock update */ 139 reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD; 140 writel(reg, corediv->reg); 141 142 /* 143 * Wait for clocks to settle down, and then clear all the 144 * ratios request and the reload request. 145 */ 146 udelay(1000); 147 reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD); 148 writel(reg, corediv->reg); 149 udelay(1000); 150 151 spin_unlock_irqrestore(&corediv->lock, flags); 152 153 return 0; 154 } 155 156 static const struct clk_ops corediv_ops = { 157 .enable = clk_corediv_enable, 158 .disable = clk_corediv_disable, 159 .is_enabled = clk_corediv_is_enabled, 160 .recalc_rate = clk_corediv_recalc_rate, 161 .round_rate = clk_corediv_round_rate, 162 .set_rate = clk_corediv_set_rate, 163 }; 164 165 static void __init mvebu_corediv_clk_init(struct device_node *node) 166 { 167 struct clk_init_data init; 168 struct clk_corediv *corediv; 169 struct clk **clks; 170 void __iomem *base; 171 const char *parent_name; 172 const char *clk_name; 173 int i; 174 175 base = of_iomap(node, 0); 176 if (WARN_ON(!base)) 177 return; 178 179 parent_name = of_clk_get_parent_name(node, 0); 180 181 clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc); 182 183 /* clks holds the clock array */ 184 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), 185 GFP_KERNEL); 186 if (WARN_ON(!clks)) 187 goto err_unmap; 188 /* corediv holds the clock specific array */ 189 corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv), 190 GFP_KERNEL); 191 if (WARN_ON(!corediv)) 192 goto err_free_clks; 193 194 spin_lock_init(&corediv->lock); 195 196 for (i = 0; i < clk_data.clk_num; i++) { 197 of_property_read_string_index(node, "clock-output-names", 198 i, &clk_name); 199 init.num_parents = 1; 200 init.parent_names = &parent_name; 201 init.name = clk_name; 202 init.ops = &corediv_ops; 203 init.flags = 0; 204 205 corediv[i].desc = mvebu_corediv_desc[i]; 206 corediv[i].reg = base; 207 corediv[i].hw.init = &init; 208 209 clks[i] = clk_register(NULL, &corediv[i].hw); 210 WARN_ON(IS_ERR(clks[i])); 211 } 212 213 clk_data.clks = clks; 214 of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data); 215 return; 216 217 err_free_clks: 218 kfree(clks); 219 err_unmap: 220 iounmap(base); 221 } 222 CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock", 223 mvebu_corediv_clk_init); 224