Thomas Gleixner | 2874c5f | 2019-05-27 08:55:01 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 2 | /* |
| 3 | * arch/arm/mach-ep93xx/clock.c |
| 4 | * Clock control for Cirrus EP93xx chips. |
| 5 | * |
| 6 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 7 | */ |
| 8 | |
Hartley Sweeten | 99acbb9 | 2010-01-11 18:30:41 +0100 | [diff] [blame] | 9 | #define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt |
| 10 | |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/clk.h> |
| 13 | #include <linux/err.h> |
Lennert Buytenhek | 51dd249 | 2007-02-04 22:45:33 +0100 | [diff] [blame] | 14 | #include <linux/module.h> |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 15 | #include <linux/string.h> |
Russell King | fced80c | 2008-09-06 12:10:45 +0100 | [diff] [blame] | 16 | #include <linux/io.h> |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 17 | #include <linux/spinlock.h> |
Jean-Christop PLAGNIOL-VILLARD | 6d803ba | 2010-11-17 10:04:33 +0100 | [diff] [blame] | 18 | #include <linux/clkdev.h> |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 19 | #include <linux/clk-provider.h> |
Arnd Bergmann | 67e38f5 | 2019-04-15 22:17:11 +0200 | [diff] [blame] | 20 | #include <linux/soc/cirrus/ep93xx.h> |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 21 | |
Arnd Bergmann | 5b7cc90 | 2019-04-15 22:17:12 +0200 | [diff] [blame] | 22 | #include "hardware.h" |
Russell King | ae696fd | 2008-11-30 17:11:49 +0000 | [diff] [blame] | 23 | |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 24 | #include <asm/div64.h> |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 25 | |
Ryan Mallon | 999c53f | 2012-01-11 13:43:02 +1100 | [diff] [blame] | 26 | #include "soc.h" |
Hartley Sweeten | ff05c03 | 2009-05-07 18:41:47 +0100 | [diff] [blame] | 27 | |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 28 | static DEFINE_SPINLOCK(clk_lock); |
| 29 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 30 | static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; |
| 31 | static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; |
| 32 | static char pclk_divisors[] = { 1, 2, 4, 8 }; |
| 33 | |
| 34 | static char adc_divisors[] = { 16, 4 }; |
| 35 | static char sclk_divisors[] = { 2, 4 }; |
| 36 | static char lrclk_divisors[] = { 32, 64, 128 }; |
| 37 | |
| 38 | static const char * const mux_parents[] = { |
| 39 | "xtali", |
| 40 | "pll1", |
| 41 | "pll2" |
| 42 | }; |
| 43 | |
| 44 | /* |
| 45 | * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS |
| 46 | */ |
| 47 | static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word) |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 48 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 49 | int i; |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 50 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 51 | rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ |
| 52 | rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ |
| 53 | do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ |
| 54 | for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ |
| 55 | rate >>= 1; |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 56 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 57 | return (unsigned long)rate; |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 58 | } |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 59 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 60 | struct clk_psc { |
| 61 | struct clk_hw hw; |
| 62 | void __iomem *reg; |
| 63 | u8 bit_idx; |
| 64 | u32 mask; |
| 65 | u8 shift; |
| 66 | u8 width; |
| 67 | char *div; |
| 68 | u8 num_div; |
| 69 | spinlock_t *lock; |
| 70 | }; |
| 71 | |
| 72 | #define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw) |
| 73 | |
| 74 | static int ep93xx_clk_is_enabled(struct clk_hw *hw) |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 75 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 76 | struct clk_psc *psc = to_clk_psc(hw); |
| 77 | u32 val = readl(psc->reg); |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 78 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 79 | return (val & BIT(psc->bit_idx)) ? 1 : 0; |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 80 | } |
| 81 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 82 | static int ep93xx_clk_enable(struct clk_hw *hw) |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 83 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 84 | struct clk_psc *psc = to_clk_psc(hw); |
| 85 | unsigned long flags = 0; |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 86 | u32 val; |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 87 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 88 | if (psc->lock) |
| 89 | spin_lock_irqsave(psc->lock, flags); |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 90 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 91 | val = __raw_readl(psc->reg); |
| 92 | val |= BIT(psc->bit_idx); |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 93 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 94 | ep93xx_syscon_swlocked_write(val, psc->reg); |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 95 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 96 | if (psc->lock) |
| 97 | spin_unlock_irqrestore(psc->lock, flags); |
| 98 | |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 99 | return 0; |
| 100 | } |
| 101 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 102 | static void ep93xx_clk_disable(struct clk_hw *hw) |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 103 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 104 | struct clk_psc *psc = to_clk_psc(hw); |
| 105 | unsigned long flags = 0; |
| 106 | u32 val; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 107 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 108 | if (psc->lock) |
| 109 | spin_lock_irqsave(psc->lock, flags); |
| 110 | |
| 111 | val = __raw_readl(psc->reg); |
| 112 | val &= ~BIT(psc->bit_idx); |
| 113 | |
| 114 | ep93xx_syscon_swlocked_write(val, psc->reg); |
| 115 | |
| 116 | if (psc->lock) |
| 117 | spin_unlock_irqrestore(psc->lock, flags); |
| 118 | } |
| 119 | |
| 120 | static const struct clk_ops clk_ep93xx_gate_ops = { |
| 121 | .enable = ep93xx_clk_enable, |
| 122 | .disable = ep93xx_clk_disable, |
| 123 | .is_enabled = ep93xx_clk_is_enabled, |
| 124 | }; |
| 125 | |
| 126 | static struct clk_hw *ep93xx_clk_register_gate(const char *name, |
| 127 | const char *parent_name, |
| 128 | void __iomem *reg, |
| 129 | u8 bit_idx) |
| 130 | { |
| 131 | struct clk_init_data init; |
| 132 | struct clk_psc *psc; |
| 133 | struct clk *clk; |
| 134 | |
| 135 | psc = kzalloc(sizeof(*psc), GFP_KERNEL); |
| 136 | if (!psc) |
| 137 | return ERR_PTR(-ENOMEM); |
| 138 | |
| 139 | init.name = name; |
| 140 | init.ops = &clk_ep93xx_gate_ops; |
| 141 | init.flags = CLK_SET_RATE_PARENT; |
| 142 | init.parent_names = (parent_name ? &parent_name : NULL); |
| 143 | init.num_parents = (parent_name ? 1 : 0); |
| 144 | |
| 145 | psc->reg = reg; |
| 146 | psc->bit_idx = bit_idx; |
| 147 | psc->hw.init = &init; |
| 148 | psc->lock = &clk_lock; |
| 149 | |
| 150 | clk = clk_register(NULL, &psc->hw); |
Alexander Sverdlin | 3b68b08 | 2022-01-30 16:25:02 +0100 | [diff] [blame] | 151 | if (IS_ERR(clk)) { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 152 | kfree(psc); |
Alexander Sverdlin | 3b68b08 | 2022-01-30 16:25:02 +0100 | [diff] [blame] | 153 | return ERR_CAST(clk); |
| 154 | } |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 155 | |
| 156 | return &psc->hw; |
| 157 | } |
| 158 | |
| 159 | static u8 ep93xx_mux_get_parent(struct clk_hw *hw) |
| 160 | { |
| 161 | struct clk_psc *psc = to_clk_psc(hw); |
| 162 | u32 val = __raw_readl(psc->reg); |
| 163 | |
| 164 | if (!(val & EP93XX_SYSCON_CLKDIV_ESEL)) |
| 165 | return 0; |
| 166 | |
| 167 | if (!(val & EP93XX_SYSCON_CLKDIV_PSEL)) |
| 168 | return 1; |
| 169 | |
| 170 | return 2; |
| 171 | } |
| 172 | |
| 173 | static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index) |
| 174 | { |
| 175 | struct clk_psc *psc = to_clk_psc(hw); |
| 176 | unsigned long flags = 0; |
| 177 | u32 val; |
| 178 | |
| 179 | if (index >= ARRAY_SIZE(mux_parents)) |
| 180 | return -EINVAL; |
| 181 | |
| 182 | if (psc->lock) |
| 183 | spin_lock_irqsave(psc->lock, flags); |
| 184 | |
| 185 | val = __raw_readl(psc->reg); |
| 186 | val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL); |
| 187 | |
| 188 | |
| 189 | if (index != 0) { |
| 190 | val |= EP93XX_SYSCON_CLKDIV_ESEL; |
| 191 | val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0; |
| 192 | } |
| 193 | |
| 194 | ep93xx_syscon_swlocked_write(val, psc->reg); |
| 195 | |
| 196 | if (psc->lock) |
| 197 | spin_unlock_irqrestore(psc->lock, flags); |
| 198 | |
| 199 | return 0; |
| 200 | } |
| 201 | |
| 202 | static bool is_best(unsigned long rate, unsigned long now, |
| 203 | unsigned long best) |
| 204 | { |
| 205 | return abs(rate - now) < abs(rate - best); |
| 206 | } |
| 207 | |
| 208 | static int ep93xx_mux_determine_rate(struct clk_hw *hw, |
| 209 | struct clk_rate_request *req) |
| 210 | { |
| 211 | unsigned long rate = req->rate; |
Alexander Sverdlin | caee010 | 2022-01-20 14:37:39 +0100 | [diff] [blame] | 212 | struct clk *best_parent = NULL; |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 213 | unsigned long __parent_rate; |
| 214 | unsigned long best_rate = 0, actual_rate, mclk_rate; |
| 215 | unsigned long best_parent_rate; |
| 216 | int __div = 0, __pdiv = 0; |
| 217 | int i; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 218 | |
| 219 | /* |
| 220 | * Try the two pll's and the external clock |
| 221 | * Because the valid predividers are 2, 2.5 and 3, we multiply |
| 222 | * all the clocks by 2 to avoid floating point math. |
| 223 | * |
| 224 | * This is based on the algorithm in the ep93xx raster guide: |
| 225 | * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf |
| 226 | * |
| 227 | */ |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 228 | for (i = 0; i < ARRAY_SIZE(mux_parents); i++) { |
| 229 | struct clk *parent = clk_get_sys(mux_parents[i], NULL); |
| 230 | |
| 231 | __parent_rate = clk_get_rate(parent); |
| 232 | mclk_rate = __parent_rate * 2; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 233 | |
| 234 | /* Try each predivider value */ |
| 235 | for (__pdiv = 4; __pdiv <= 6; __pdiv++) { |
| 236 | __div = mclk_rate / (rate * __pdiv); |
| 237 | if (__div < 2 || __div > 127) |
| 238 | continue; |
| 239 | |
| 240 | actual_rate = mclk_rate / (__pdiv * __div); |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 241 | if (is_best(rate, actual_rate, best_rate)) { |
| 242 | best_rate = actual_rate; |
| 243 | best_parent_rate = __parent_rate; |
| 244 | best_parent = parent; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 249 | if (!best_parent) |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 250 | return -EINVAL; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 251 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 252 | req->best_parent_rate = best_parent_rate; |
| 253 | req->best_parent_hw = __clk_get_hw(best_parent); |
| 254 | req->rate = best_rate; |
| 255 | |
Hartley Sweeten | ebd00c0 | 2009-10-08 23:44:41 +0100 | [diff] [blame] | 256 | return 0; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 257 | } |
| 258 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 259 | static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw, |
| 260 | unsigned long parent_rate) |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 261 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 262 | struct clk_psc *psc = to_clk_psc(hw); |
| 263 | unsigned long rate = 0; |
| 264 | u32 val = __raw_readl(psc->reg); |
| 265 | int __pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03); |
| 266 | int __div = val & 0x7f; |
| 267 | |
| 268 | if (__div > 0) |
| 269 | rate = (parent_rate * 2) / ((__pdiv + 3) * __div); |
| 270 | |
| 271 | return rate; |
| 272 | } |
| 273 | |
| 274 | static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, |
| 275 | unsigned long parent_rate) |
| 276 | { |
| 277 | struct clk_psc *psc = to_clk_psc(hw); |
| 278 | int pdiv = 0, div = 0; |
| 279 | unsigned long best_rate = 0, actual_rate, mclk_rate; |
| 280 | int __div = 0, __pdiv = 0; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 281 | u32 val; |
| 282 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 283 | mclk_rate = parent_rate * 2; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 284 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 285 | for (__pdiv = 4; __pdiv <= 6; __pdiv++) { |
| 286 | __div = mclk_rate / (rate * __pdiv); |
| 287 | if (__div < 2 || __div > 127) |
| 288 | continue; |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 289 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 290 | actual_rate = mclk_rate / (__pdiv * __div); |
| 291 | if (is_best(rate, actual_rate, best_rate)) { |
| 292 | pdiv = __pdiv - 3; |
| 293 | div = __div; |
| 294 | best_rate = actual_rate; |
| 295 | } |
| 296 | } |
Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 297 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 298 | if (!best_rate) |
Ryan Mallon | ed67ea8 | 2010-06-08 22:01:10 +1200 | [diff] [blame] | 299 | return -EINVAL; |
| 300 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 301 | val = __raw_readl(psc->reg); |
| 302 | |
| 303 | /* Clear old dividers */ |
| 304 | val &= ~0x37f; |
| 305 | |
| 306 | /* Set the new pdiv and div bits for the new clock rate */ |
| 307 | val |= (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div; |
| 308 | ep93xx_syscon_swlocked_write(val, psc->reg); |
| 309 | |
Ryan Mallon | ed67ea8 | 2010-06-08 22:01:10 +1200 | [diff] [blame] | 310 | return 0; |
| 311 | } |
| 312 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 313 | static const struct clk_ops clk_ddiv_ops = { |
| 314 | .enable = ep93xx_clk_enable, |
| 315 | .disable = ep93xx_clk_disable, |
| 316 | .is_enabled = ep93xx_clk_is_enabled, |
| 317 | .get_parent = ep93xx_mux_get_parent, |
| 318 | .set_parent = ep93xx_mux_set_parent_lock, |
| 319 | .determine_rate = ep93xx_mux_determine_rate, |
| 320 | .recalc_rate = ep93xx_ddiv_recalc_rate, |
| 321 | .set_rate = ep93xx_ddiv_set_rate, |
| 322 | }; |
Ryan Mallon | ed67ea8 | 2010-06-08 22:01:10 +1200 | [diff] [blame] | 323 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 324 | static struct clk_hw *clk_hw_register_ddiv(const char *name, |
| 325 | void __iomem *reg, |
| 326 | u8 bit_idx) |
| 327 | { |
| 328 | struct clk_init_data init; |
| 329 | struct clk_psc *psc; |
| 330 | struct clk *clk; |
| 331 | |
| 332 | psc = kzalloc(sizeof(*psc), GFP_KERNEL); |
| 333 | if (!psc) |
| 334 | return ERR_PTR(-ENOMEM); |
| 335 | |
| 336 | init.name = name; |
| 337 | init.ops = &clk_ddiv_ops; |
| 338 | init.flags = 0; |
| 339 | init.parent_names = mux_parents; |
| 340 | init.num_parents = ARRAY_SIZE(mux_parents); |
| 341 | |
| 342 | psc->reg = reg; |
| 343 | psc->bit_idx = bit_idx; |
| 344 | psc->lock = &clk_lock; |
| 345 | psc->hw.init = &init; |
| 346 | |
| 347 | clk = clk_register(NULL, &psc->hw); |
Genjian Zhang | 8a7322a | 2022-05-17 15:39:46 +0800 | [diff] [blame] | 348 | if (IS_ERR(clk)) { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 349 | kfree(psc); |
Genjian Zhang | 8a7322a | 2022-05-17 15:39:46 +0800 | [diff] [blame] | 350 | return ERR_CAST(clk); |
| 351 | } |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 352 | return &psc->hw; |
Ryan Mallon | ed67ea8 | 2010-06-08 22:01:10 +1200 | [diff] [blame] | 353 | } |
| 354 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 355 | static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, |
| 356 | unsigned long parent_rate) |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 357 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 358 | struct clk_psc *psc = to_clk_psc(hw); |
| 359 | u32 val = __raw_readl(psc->reg); |
| 360 | u8 index = (val & psc->mask) >> psc->shift; |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 361 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 362 | if (index > psc->num_div) |
| 363 | return 0; |
| 364 | |
| 365 | return DIV_ROUND_UP_ULL(parent_rate, psc->div[index]); |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 366 | } |
Hartley Sweeten | 701fac8 | 2009-06-30 23:06:43 +0100 | [diff] [blame] | 367 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 368 | static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate, |
| 369 | unsigned long *parent_rate) |
Alexander Sverdlin | ef8aa4e | 2015-11-22 15:24:28 +0100 | [diff] [blame] | 370 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 371 | struct clk_psc *psc = to_clk_psc(hw); |
| 372 | unsigned long best = 0, now, maxdiv; |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 373 | int i; |
| 374 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 375 | maxdiv = psc->div[psc->num_div - 1]; |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 376 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 377 | for (i = 0; i < psc->num_div; i++) { |
| 378 | if ((rate * psc->div[i]) == *parent_rate) |
| 379 | return DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]); |
| 380 | |
| 381 | now = DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]); |
| 382 | |
| 383 | if (is_best(rate, now, best)) |
| 384 | best = now; |
| 385 | } |
| 386 | |
| 387 | if (!best) |
| 388 | best = DIV_ROUND_UP_ULL(*parent_rate, maxdiv); |
| 389 | |
| 390 | return best; |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 391 | } |
| 392 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 393 | static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate, |
| 394 | unsigned long parent_rate) |
| 395 | { |
| 396 | struct clk_psc *psc = to_clk_psc(hw); |
| 397 | u32 val = __raw_readl(psc->reg) & ~psc->mask; |
| 398 | int i; |
| 399 | |
| 400 | for (i = 0; i < psc->num_div; i++) |
| 401 | if (rate == parent_rate / psc->div[i]) { |
| 402 | val |= i << psc->shift; |
| 403 | break; |
| 404 | } |
| 405 | |
| 406 | if (i == psc->num_div) |
| 407 | return -EINVAL; |
| 408 | |
| 409 | ep93xx_syscon_swlocked_write(val, psc->reg); |
| 410 | |
| 411 | return 0; |
| 412 | } |
| 413 | |
| 414 | static const struct clk_ops ep93xx_div_ops = { |
| 415 | .enable = ep93xx_clk_enable, |
| 416 | .disable = ep93xx_clk_disable, |
| 417 | .is_enabled = ep93xx_clk_is_enabled, |
| 418 | .recalc_rate = ep93xx_div_recalc_rate, |
| 419 | .round_rate = ep93xx_div_round_rate, |
| 420 | .set_rate = ep93xx_div_set_rate, |
| 421 | }; |
| 422 | |
| 423 | static struct clk_hw *clk_hw_register_div(const char *name, |
| 424 | const char *parent_name, |
| 425 | void __iomem *reg, |
| 426 | u8 enable_bit, |
| 427 | u8 shift, |
| 428 | u8 width, |
| 429 | char *clk_divisors, |
| 430 | u8 num_div) |
| 431 | { |
| 432 | struct clk_init_data init; |
| 433 | struct clk_psc *psc; |
| 434 | struct clk *clk; |
| 435 | |
| 436 | psc = kzalloc(sizeof(*psc), GFP_KERNEL); |
| 437 | if (!psc) |
| 438 | return ERR_PTR(-ENOMEM); |
| 439 | |
| 440 | init.name = name; |
| 441 | init.ops = &ep93xx_div_ops; |
| 442 | init.flags = 0; |
| 443 | init.parent_names = (parent_name ? &parent_name : NULL); |
| 444 | init.num_parents = 1; |
| 445 | |
| 446 | psc->reg = reg; |
| 447 | psc->bit_idx = enable_bit; |
| 448 | psc->mask = GENMASK(shift + width - 1, shift); |
| 449 | psc->shift = shift; |
| 450 | psc->div = clk_divisors; |
| 451 | psc->num_div = num_div; |
| 452 | psc->lock = &clk_lock; |
| 453 | psc->hw.init = &init; |
| 454 | |
| 455 | clk = clk_register(NULL, &psc->hw); |
Genjian Zhang | 8a7322a | 2022-05-17 15:39:46 +0800 | [diff] [blame] | 456 | if (IS_ERR(clk)) { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 457 | kfree(psc); |
Genjian Zhang | 8a7322a | 2022-05-17 15:39:46 +0800 | [diff] [blame] | 458 | return ERR_CAST(clk); |
| 459 | } |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 460 | return &psc->hw; |
| 461 | } |
| 462 | |
| 463 | struct ep93xx_gate { |
| 464 | unsigned int bit; |
| 465 | const char *dev_id; |
| 466 | const char *con_id; |
| 467 | }; |
| 468 | |
| 469 | static struct ep93xx_gate ep93xx_uarts[] = { |
| 470 | {EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL}, |
| 471 | {EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL}, |
| 472 | {EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL}, |
| 473 | }; |
| 474 | |
| 475 | static void __init ep93xx_uart_clock_init(void) |
| 476 | { |
| 477 | unsigned int i; |
| 478 | struct clk_hw *hw; |
| 479 | u32 value; |
| 480 | unsigned int clk_uart_div; |
| 481 | |
| 482 | value = __raw_readl(EP93XX_SYSCON_PWRCNT); |
| 483 | if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) |
| 484 | clk_uart_div = 1; |
| 485 | else |
| 486 | clk_uart_div = 2; |
| 487 | |
| 488 | hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div); |
| 489 | |
| 490 | /* parenting uart gate clocks to uart clock */ |
| 491 | for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) { |
| 492 | hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id, |
| 493 | "uart", |
| 494 | EP93XX_SYSCON_DEVCFG, |
| 495 | ep93xx_uarts[i].bit); |
| 496 | |
| 497 | clk_hw_register_clkdev(hw, NULL, ep93xx_uarts[i].dev_id); |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | static struct ep93xx_gate ep93xx_dmas[] = { |
| 502 | {EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"}, |
| 503 | {EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"}, |
| 504 | {EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"}, |
| 505 | {EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"}, |
| 506 | {EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"}, |
| 507 | {EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"}, |
| 508 | {EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"}, |
| 509 | {EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"}, |
| 510 | {EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"}, |
| 511 | {EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"}, |
| 512 | {EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"}, |
| 513 | {EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"}, |
| 514 | }; |
| 515 | |
Ryan Mallon | 1c8daab | 2009-02-25 22:22:38 +0100 | [diff] [blame] | 516 | static void __init ep93xx_dma_clock_init(void) |
| 517 | { |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 518 | unsigned int i; |
| 519 | struct clk_hw *hw; |
| 520 | int ret; |
| 521 | |
| 522 | for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) { |
| 523 | hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id, |
| 524 | "hclk", 0, |
| 525 | EP93XX_SYSCON_PWRCNT, |
| 526 | ep93xx_dmas[i].bit, |
| 527 | 0, |
| 528 | &clk_lock); |
| 529 | |
| 530 | ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL); |
| 531 | if (ret) |
| 532 | pr_err("%s: failed to register lookup %s\n", |
| 533 | __func__, ep93xx_dmas[i].con_id); |
| 534 | } |
Ryan Mallon | 1c8daab | 2009-02-25 22:22:38 +0100 | [diff] [blame] | 535 | } |
| 536 | |
Lennert Buytenhek | 51dd249 | 2007-02-04 22:45:33 +0100 | [diff] [blame] | 537 | static int __init ep93xx_clock_init(void) |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 538 | { |
| 539 | u32 value; |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 540 | struct clk_hw *hw; |
| 541 | unsigned long clk_pll1_rate; |
| 542 | unsigned long clk_f_rate; |
| 543 | unsigned long clk_h_rate; |
| 544 | unsigned long clk_p_rate; |
| 545 | unsigned long clk_pll2_rate; |
| 546 | unsigned int clk_f_div; |
| 547 | unsigned int clk_h_div; |
| 548 | unsigned int clk_p_div; |
| 549 | unsigned int clk_usb_div; |
| 550 | unsigned long clk_spi_div; |
| 551 | |
| 552 | hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE); |
| 553 | clk_hw_register_clkdev(hw, NULL, "xtali"); |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 554 | |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 555 | /* Determine the bootloader configured pll1 rate */ |
| 556 | value = __raw_readl(EP93XX_SYSCON_CLKSET1); |
| 557 | if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1)) |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 558 | clk_pll1_rate = EP93XX_EXT_CLK_RATE; |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 559 | else |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 560 | clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); |
| 561 | |
| 562 | hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate); |
| 563 | clk_hw_register_clkdev(hw, NULL, "pll1"); |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 564 | |
| 565 | /* Initialize the pll1 derived clocks */ |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 566 | clk_f_div = fclk_divisors[(value >> 25) & 0x7]; |
| 567 | clk_h_div = hclk_divisors[(value >> 20) & 0x7]; |
| 568 | clk_p_div = pclk_divisors[(value >> 18) & 0x3]; |
| 569 | |
| 570 | hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div); |
| 571 | clk_f_rate = clk_get_rate(hw->clk); |
| 572 | hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div); |
| 573 | clk_h_rate = clk_get_rate(hw->clk); |
| 574 | hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div); |
| 575 | clk_p_rate = clk_get_rate(hw->clk); |
| 576 | |
| 577 | clk_hw_register_clkdev(hw, "apb_pclk", NULL); |
| 578 | |
Ryan Mallon | 1c8daab | 2009-02-25 22:22:38 +0100 | [diff] [blame] | 579 | ep93xx_dma_clock_init(); |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 580 | |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 581 | /* Determine the bootloader configured pll2 rate */ |
Hartley Sweeten | ba7c6a3 | 2010-02-23 21:20:31 +0100 | [diff] [blame] | 582 | value = __raw_readl(EP93XX_SYSCON_CLKSET2); |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 583 | if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2)) |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 584 | clk_pll2_rate = EP93XX_EXT_CLK_RATE; |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 585 | else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN) |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 586 | clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 587 | else |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 588 | clk_pll2_rate = 0; |
| 589 | |
| 590 | hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate); |
| 591 | clk_hw_register_clkdev(hw, NULL, "pll2"); |
Hartley Sweeten | 346e34ab | 2010-01-11 21:41:29 +0100 | [diff] [blame] | 592 | |
| 593 | /* Initialize the pll2 derived clocks */ |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 594 | /* |
| 595 | * These four bits set the divide ratio between the PLL2 |
| 596 | * output and the USB clock. |
| 597 | * 0000 - Divide by 1 |
| 598 | * 0001 - Divide by 2 |
| 599 | * 0010 - Divide by 3 |
| 600 | * 0011 - Divide by 4 |
| 601 | * 0100 - Divide by 5 |
| 602 | * 0101 - Divide by 6 |
| 603 | * 0110 - Divide by 7 |
| 604 | * 0111 - Divide by 8 |
| 605 | * 1000 - Divide by 9 |
| 606 | * 1001 - Divide by 10 |
| 607 | * 1010 - Divide by 11 |
| 608 | * 1011 - Divide by 12 |
| 609 | * 1100 - Divide by 13 |
| 610 | * 1101 - Divide by 14 |
| 611 | * 1110 - Divide by 15 |
| 612 | * 1111 - Divide by 1 |
| 613 | * On power-on-reset these bits are reset to 0000b. |
| 614 | */ |
| 615 | clk_usb_div = (((value >> 28) & 0xf) + 1); |
| 616 | hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div); |
| 617 | hw = clk_hw_register_gate(NULL, "ohci-platform", |
| 618 | "usb_clk", 0, |
| 619 | EP93XX_SYSCON_PWRCNT, |
| 620 | EP93XX_SYSCON_PWRCNT_USH_EN, |
| 621 | 0, |
| 622 | &clk_lock); |
| 623 | clk_hw_register_clkdev(hw, NULL, "ohci-platform"); |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 624 | |
Mika Westerberg | 4fec997 | 2010-05-11 15:34:54 +0100 | [diff] [blame] | 625 | /* |
| 626 | * EP93xx SSP clock rate was doubled in version E2. For more information |
| 627 | * see: |
| 628 | * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf |
| 629 | */ |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 630 | clk_spi_div = 1; |
Mika Westerberg | 4fec997 | 2010-05-11 15:34:54 +0100 | [diff] [blame] | 631 | if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2) |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 632 | clk_spi_div = 2; |
| 633 | hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div); |
| 634 | clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0"); |
| 635 | |
| 636 | /* pwm clock */ |
| 637 | hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1); |
| 638 | clk_hw_register_clkdev(hw, "pwm_clk", NULL); |
Mika Westerberg | 4fec997 | 2010-05-11 15:34:54 +0100 | [diff] [blame] | 639 | |
Hartley Sweeten | 99acbb9 | 2010-01-11 18:30:41 +0100 | [diff] [blame] | 640 | pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n", |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 641 | clk_pll1_rate / 1000000, clk_pll2_rate / 1000000); |
Hartley Sweeten | 99acbb9 | 2010-01-11 18:30:41 +0100 | [diff] [blame] | 642 | pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 643 | clk_f_rate / 1000000, clk_h_rate / 1000000, |
| 644 | clk_p_rate / 1000000); |
Lennert Buytenhek | 51dd249 | 2007-02-04 22:45:33 +0100 | [diff] [blame] | 645 | |
Nikita Shubin | 9645ccc | 2021-10-18 12:31:05 +0200 | [diff] [blame] | 646 | ep93xx_uart_clock_init(); |
| 647 | |
| 648 | /* touchscreen/adc clock */ |
| 649 | hw = clk_hw_register_div("ep93xx-adc", |
| 650 | "xtali", |
| 651 | EP93XX_SYSCON_KEYTCHCLKDIV, |
| 652 | EP93XX_SYSCON_KEYTCHCLKDIV_TSEN, |
| 653 | EP93XX_SYSCON_KEYTCHCLKDIV_ADIV, |
| 654 | 1, |
| 655 | adc_divisors, |
| 656 | ARRAY_SIZE(adc_divisors)); |
| 657 | |
| 658 | clk_hw_register_clkdev(hw, NULL, "ep93xx-adc"); |
| 659 | |
| 660 | /* keypad clock */ |
| 661 | hw = clk_hw_register_div("ep93xx-keypad", |
| 662 | "xtali", |
| 663 | EP93XX_SYSCON_KEYTCHCLKDIV, |
| 664 | EP93XX_SYSCON_KEYTCHCLKDIV_KEN, |
| 665 | EP93XX_SYSCON_KEYTCHCLKDIV_KDIV, |
| 666 | 1, |
| 667 | adc_divisors, |
| 668 | ARRAY_SIZE(adc_divisors)); |
| 669 | |
| 670 | clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad"); |
| 671 | |
| 672 | /* On reset PDIV and VDIV is set to zero, while PDIV zero |
| 673 | * means clock disable, VDIV shouldn't be zero. |
| 674 | * So i set both dividers to minimum. |
| 675 | */ |
| 676 | /* ENA - Enable CLK divider. */ |
| 677 | /* PDIV - 00 - Disable clock */ |
| 678 | /* VDIV - at least 2 */ |
| 679 | /* Check and enable video clk registers */ |
| 680 | value = __raw_readl(EP93XX_SYSCON_VIDCLKDIV); |
| 681 | value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; |
| 682 | ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV); |
| 683 | |
| 684 | /* check and enable i2s clk registers */ |
| 685 | value = __raw_readl(EP93XX_SYSCON_I2SCLKDIV); |
| 686 | value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; |
| 687 | ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV); |
| 688 | |
| 689 | /* video clk */ |
| 690 | hw = clk_hw_register_ddiv("ep93xx-fb", |
| 691 | EP93XX_SYSCON_VIDCLKDIV, |
| 692 | EP93XX_SYSCON_CLKDIV_ENABLE); |
| 693 | |
| 694 | clk_hw_register_clkdev(hw, NULL, "ep93xx-fb"); |
| 695 | |
| 696 | /* i2s clk */ |
| 697 | hw = clk_hw_register_ddiv("mclk", |
| 698 | EP93XX_SYSCON_I2SCLKDIV, |
| 699 | EP93XX_SYSCON_CLKDIV_ENABLE); |
| 700 | |
| 701 | clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s"); |
| 702 | |
| 703 | /* i2s sclk */ |
| 704 | #define EP93XX_I2SCLKDIV_SDIV_SHIFT 16 |
| 705 | #define EP93XX_I2SCLKDIV_SDIV_WIDTH 1 |
| 706 | hw = clk_hw_register_div("sclk", |
| 707 | "mclk", |
| 708 | EP93XX_SYSCON_I2SCLKDIV, |
| 709 | EP93XX_SYSCON_I2SCLKDIV_SENA, |
| 710 | EP93XX_I2SCLKDIV_SDIV_SHIFT, |
| 711 | EP93XX_I2SCLKDIV_SDIV_WIDTH, |
| 712 | sclk_divisors, |
| 713 | ARRAY_SIZE(sclk_divisors)); |
| 714 | |
| 715 | clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s"); |
| 716 | |
| 717 | /* i2s lrclk */ |
| 718 | #define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17 |
| 719 | #define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 3 |
| 720 | hw = clk_hw_register_div("lrclk", |
| 721 | "sclk", |
| 722 | EP93XX_SYSCON_I2SCLKDIV, |
| 723 | EP93XX_SYSCON_I2SCLKDIV_SENA, |
| 724 | EP93XX_I2SCLKDIV_LRDIV32_SHIFT, |
| 725 | EP93XX_I2SCLKDIV_LRDIV32_WIDTH, |
| 726 | lrclk_divisors, |
| 727 | ARRAY_SIZE(lrclk_divisors)); |
| 728 | |
| 729 | clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s"); |
| 730 | |
Lennert Buytenhek | 51dd249 | 2007-02-04 22:45:33 +0100 | [diff] [blame] | 731 | return 0; |
Lennert Buytenhek | 1d81eed | 2006-06-24 10:33:02 +0100 | [diff] [blame] | 732 | } |
Mika Westerberg | a387f0f5 | 2010-09-03 17:14:54 +0100 | [diff] [blame] | 733 | postcore_initcall(ep93xx_clock_init); |