1 /* 2 * Copyright 2015 Maxime Ripard 3 * 4 * Maxime Ripard <maxime.ripard@free-electrons.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/clk-provider.h> 18 #include <linux/of.h> 19 #include <linux/of_address.h> 20 #include <linux/slab.h> 21 #include <linux/spinlock.h> 22 23 #define TCON_CH1_SCLK2_PARENTS 4 24 25 #define TCON_CH1_SCLK2_GATE_BIT BIT(31) 26 #define TCON_CH1_SCLK2_MUX_MASK 3 27 #define TCON_CH1_SCLK2_MUX_SHIFT 24 28 #define TCON_CH1_SCLK2_DIV_MASK 0xf 29 #define TCON_CH1_SCLK2_DIV_SHIFT 0 30 31 #define TCON_CH1_SCLK1_GATE_BIT BIT(15) 32 #define TCON_CH1_SCLK1_HALF_BIT BIT(11) 33 34 struct tcon_ch1_clk { 35 struct clk_hw hw; 36 spinlock_t lock; 37 void __iomem *reg; 38 }; 39 40 #define hw_to_tclk(hw) container_of(hw, struct tcon_ch1_clk, hw) 41 42 static void tcon_ch1_disable(struct clk_hw *hw) 43 { 44 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 45 unsigned long flags; 46 u32 reg; 47 48 spin_lock_irqsave(&tclk->lock, flags); 49 reg = readl(tclk->reg); 50 reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); 51 writel(reg, tclk->reg); 52 spin_unlock_irqrestore(&tclk->lock, flags); 53 } 54 55 static int tcon_ch1_enable(struct clk_hw *hw) 56 { 57 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 58 unsigned long flags; 59 u32 reg; 60 61 spin_lock_irqsave(&tclk->lock, flags); 62 reg = readl(tclk->reg); 63 reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT; 64 writel(reg, tclk->reg); 65 spin_unlock_irqrestore(&tclk->lock, flags); 66 67 return 0; 68 } 69 70 static int tcon_ch1_is_enabled(struct clk_hw *hw) 71 { 72 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 73 u32 reg; 74 75 reg = readl(tclk->reg); 76 return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); 77 } 78 79 static u8 tcon_ch1_get_parent(struct clk_hw *hw) 80 { 81 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 82 u32 reg; 83 84 reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT; 85 reg &= reg >> TCON_CH1_SCLK2_MUX_MASK; 86 87 return reg; 88 } 89 90 static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index) 91 { 92 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 93 unsigned long flags; 94 u32 reg; 95 96 spin_lock_irqsave(&tclk->lock, flags); 97 reg = readl(tclk->reg); 98 reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT); 99 reg |= index << TCON_CH1_SCLK2_MUX_SHIFT; 100 writel(reg, tclk->reg); 101 spin_unlock_irqrestore(&tclk->lock, flags); 102 103 return 0; 104 }; 105 106 static unsigned long tcon_ch1_calc_divider(unsigned long rate, 107 unsigned long parent_rate, 108 u8 *div, 109 bool *half) 110 { 111 unsigned long best_rate = 0; 112 u8 best_m = 0, m; 113 bool is_double; 114 115 for (m = 1; m < 16; m++) { 116 u8 d; 117 118 for (d = 1; d < 3; d++) { 119 unsigned long tmp_rate; 120 121 tmp_rate = parent_rate / m / d; 122 123 if (tmp_rate > rate) 124 continue; 125 126 if (!best_rate || 127 (rate - tmp_rate) < (rate - best_rate)) { 128 best_rate = tmp_rate; 129 best_m = m; 130 is_double = d; 131 } 132 } 133 } 134 135 if (div && half) { 136 *div = best_m; 137 *half = is_double; 138 } 139 140 return best_rate; 141 } 142 143 static int tcon_ch1_determine_rate(struct clk_hw *hw, 144 struct clk_rate_request *req) 145 { 146 long best_rate = -EINVAL; 147 int i; 148 149 for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 150 unsigned long parent_rate; 151 unsigned long tmp_rate; 152 struct clk_hw *parent; 153 154 parent = clk_hw_get_parent_by_index(hw, i); 155 if (!parent) 156 continue; 157 158 parent_rate = clk_hw_get_rate(parent); 159 160 tmp_rate = tcon_ch1_calc_divider(req->rate, parent_rate, 161 NULL, NULL); 162 163 if (best_rate < 0 || 164 (req->rate - tmp_rate) < (req->rate - best_rate)) { 165 best_rate = tmp_rate; 166 req->best_parent_rate = parent_rate; 167 req->best_parent_hw = parent; 168 } 169 } 170 171 if (best_rate < 0) 172 return best_rate; 173 174 req->rate = best_rate; 175 return 0; 176 } 177 178 static unsigned long tcon_ch1_recalc_rate(struct clk_hw *hw, 179 unsigned long parent_rate) 180 { 181 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 182 u32 reg; 183 184 reg = readl(tclk->reg); 185 186 parent_rate /= (reg & TCON_CH1_SCLK2_DIV_MASK) + 1; 187 188 if (reg & TCON_CH1_SCLK1_HALF_BIT) 189 parent_rate /= 2; 190 191 return parent_rate; 192 } 193 194 static int tcon_ch1_set_rate(struct clk_hw *hw, unsigned long rate, 195 unsigned long parent_rate) 196 { 197 struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 198 unsigned long flags; 199 bool half; 200 u8 div_m; 201 u32 reg; 202 203 tcon_ch1_calc_divider(rate, parent_rate, &div_m, &half); 204 205 spin_lock_irqsave(&tclk->lock, flags); 206 reg = readl(tclk->reg); 207 reg &= ~(TCON_CH1_SCLK2_DIV_MASK | TCON_CH1_SCLK1_HALF_BIT); 208 reg |= (div_m - 1) & TCON_CH1_SCLK2_DIV_MASK; 209 210 if (half) 211 reg |= TCON_CH1_SCLK1_HALF_BIT; 212 213 writel(reg, tclk->reg); 214 spin_unlock_irqrestore(&tclk->lock, flags); 215 216 return 0; 217 } 218 219 static const struct clk_ops tcon_ch1_ops = { 220 .disable = tcon_ch1_disable, 221 .enable = tcon_ch1_enable, 222 .is_enabled = tcon_ch1_is_enabled, 223 224 .get_parent = tcon_ch1_get_parent, 225 .set_parent = tcon_ch1_set_parent, 226 227 .determine_rate = tcon_ch1_determine_rate, 228 .recalc_rate = tcon_ch1_recalc_rate, 229 .set_rate = tcon_ch1_set_rate, 230 }; 231 232 static void __init tcon_ch1_setup(struct device_node *node) 233 { 234 const char *parents[TCON_CH1_SCLK2_PARENTS]; 235 const char *clk_name = node->name; 236 struct clk_init_data init; 237 struct tcon_ch1_clk *tclk; 238 struct resource res; 239 struct clk *clk; 240 void __iomem *reg; 241 int ret; 242 243 of_property_read_string(node, "clock-output-names", &clk_name); 244 245 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 246 if (IS_ERR(reg)) { 247 pr_err("%s: Could not map the clock registers\n", clk_name); 248 return; 249 } 250 251 ret = of_clk_parent_fill(node, parents, TCON_CH1_SCLK2_PARENTS); 252 if (ret != TCON_CH1_SCLK2_PARENTS) { 253 pr_err("%s Could not retrieve the parents\n", clk_name); 254 goto err_unmap; 255 } 256 257 tclk = kzalloc(sizeof(*tclk), GFP_KERNEL); 258 if (!tclk) 259 goto err_unmap; 260 261 init.name = clk_name; 262 init.ops = &tcon_ch1_ops; 263 init.parent_names = parents; 264 init.num_parents = TCON_CH1_SCLK2_PARENTS; 265 init.flags = CLK_SET_RATE_PARENT; 266 267 tclk->reg = reg; 268 tclk->hw.init = &init; 269 spin_lock_init(&tclk->lock); 270 271 clk = clk_register(NULL, &tclk->hw); 272 if (IS_ERR(clk)) { 273 pr_err("%s: Couldn't register the clock\n", clk_name); 274 goto err_free_data; 275 } 276 277 ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); 278 if (ret) { 279 pr_err("%s: Couldn't register our clock provider\n", clk_name); 280 goto err_unregister_clk; 281 } 282 283 return; 284 285 err_unregister_clk: 286 clk_unregister(clk); 287 err_free_data: 288 kfree(tclk); 289 err_unmap: 290 iounmap(reg); 291 of_address_to_resource(node, 0, &res); 292 release_mem_region(res.start, resource_size(&res)); 293 } 294 295 CLK_OF_DECLARE(tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk", 296 tcon_ch1_setup); 297