^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * OMAP APLL clock support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2013 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * J Keerthy <j-keerthy@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This program is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * it under the terms of the GNU General Public License version 2 as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This program is distributed "as is" WITHOUT ANY WARRANTY of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * kind, whether express or implied; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/clk/ti.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "clock.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define APLL_FORCE_LOCK 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define APLL_AUTO_IDLE 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MAX_APLL_WAIT_TRIES 1000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #undef pr_fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define pr_fmt(fmt) "%s: " fmt, __func__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int dra7_apll_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int r = 0, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct dpll_data *ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const char *clk_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u8 state = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (!ad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) clk_name = clk_hw_get_name(&clk->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) state <<= __ffs(ad->idlest_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Check is already locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if ((v & ad->idlest_mask) == state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) v &= ~ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) state <<= __ffs(ad->idlest_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if ((v & ad->idlest_mask) == state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (i > MAX_APLL_WAIT_TRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (i == MAX_APLL_WAIT_TRIES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) pr_warn("clock: %s failed transition to '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) clk_name, (state) ? "locked" : "bypassed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) r = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) pr_debug("clock: %s transition to '%s' in %d loops\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) clk_name, (state) ? "locked" : "bypassed", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static void dra7_apll_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct dpll_data *ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u8 state = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) state <<= __ffs(ad->idlest_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) v &= ~ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int dra7_apll_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct dpll_data *ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) v &= ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) v >>= __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return v == APLL_AUTO_IDLE ? 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static u8 dra7_init_apll_parent(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static const struct clk_ops apll_ck_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .enable = &dra7_apll_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .disable = &dra7_apll_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .is_enabled = &dra7_apll_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .get_parent = &dra7_init_apll_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static void __init omap_clk_register_apll(void *user,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct clk_hw *hw = user;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct dpll_data *ad = clk_hw->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) const struct clk_init_data *init = clk_hw->hw.init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) clk = of_clk_get(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) pr_debug("clk-ref for %pOFn not ready, retry\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ad->clk_ref = __clk_get_hw(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) clk = of_clk_get(node, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) pr_debug("clk-bypass for %pOFn not ready, retry\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ad->clk_bypass = __clk_get_hw(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, node->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (!IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) of_clk_add_provider(node, of_clk_src_simple_get, clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) kfree(init->parent_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) kfree(init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) kfree(clk_hw->dpll_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) kfree(init->parent_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) kfree(init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) kfree(clk_hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static void __init of_dra7_apll_setup(struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct dpll_data *ad = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct clk_hw_omap *clk_hw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct clk_init_data *init = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) const char **parent_names = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ad = kzalloc(sizeof(*ad), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) init = kzalloc(sizeof(*init), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!ad || !clk_hw || !init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) clk_hw->dpll_data = ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) clk_hw->hw.init = init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) init->name = node->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) init->ops = &apll_ck_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) init->num_parents = of_clk_get_parent_count(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (init->num_parents < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) pr_err("dra7 apll %pOFn must have parent(s)\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) parent_names = kcalloc(init->num_parents, sizeof(char *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (!parent_names)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) of_clk_parent_fill(node, parent_names, init->num_parents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) init->parent_names = parent_names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) ret = ti_clk_get_reg_addr(node, 0, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) ret |= ti_clk_get_reg_addr(node, 1, &ad->idlest_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ad->idlest_mask = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ad->enable_mask = 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) omap_clk_register_apll(&clk_hw->hw, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) kfree(parent_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) kfree(ad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) kfree(clk_hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) kfree(init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) #define OMAP2_EN_APLL_LOCKED 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) #define OMAP2_EN_APLL_STOPPED 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) static int omap2_apll_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct dpll_data *ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) v &= ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) v >>= __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return v == OMAP2_EN_APLL_LOCKED ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static unsigned long omap2_apll_recalc(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (omap2_apll_is_enabled(hw))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return clk->fixed_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static int omap2_apll_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct dpll_data *ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) v &= ~ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) v |= OMAP2_EN_APLL_LOCKED << __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (v & ad->idlest_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (i > MAX_APLL_WAIT_TRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (i == MAX_APLL_WAIT_TRIES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) pr_warn("%s failed to transition to locked\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) clk_hw_get_name(&clk->hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static void omap2_apll_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) struct clk_hw_omap *clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) struct dpll_data *ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) v &= ~ad->enable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) v |= OMAP2_EN_APLL_STOPPED << __ffs(ad->enable_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static const struct clk_ops omap2_apll_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .enable = &omap2_apll_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .disable = &omap2_apll_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .is_enabled = &omap2_apll_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .recalc_rate = &omap2_apll_recalc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static void omap2_apll_set_autoidle(struct clk_hw_omap *clk, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct dpll_data *ad = clk->dpll_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) v = ti_clk_ll_ops->clk_readl(&ad->autoidle_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) v &= ~ad->autoidle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) v |= val << __ffs(ad->autoidle_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) #define OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) #define OMAP2_APLL_AUTOIDLE_DISABLE 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static void omap2_apll_allow_idle(struct clk_hw_omap *clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static void omap2_apll_deny_idle(struct clk_hw_omap *clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static const struct clk_hw_omap_ops omap2_apll_hwops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .allow_idle = &omap2_apll_allow_idle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .deny_idle = &omap2_apll_deny_idle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static void __init of_omap2_apll_setup(struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct dpll_data *ad = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct clk_hw_omap *clk_hw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct clk_init_data *init = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) const char *parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) ad = kzalloc(sizeof(*ad), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) init = kzalloc(sizeof(*init), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (!ad || !clk_hw || !init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) clk_hw->dpll_data = ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) clk_hw->hw.init = init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) init->ops = &omap2_apll_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) init->name = node->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) clk_hw->ops = &omap2_apll_hwops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) init->num_parents = of_clk_get_parent_count(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (init->num_parents != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) pr_err("%pOFn must have one parent\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) parent_name = of_clk_get_parent_name(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) init->parent_names = &parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (of_property_read_u32(node, "ti,clock-frequency", &val)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) pr_err("%pOFn missing clock-frequency\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) clk_hw->fixed_rate = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (of_property_read_u32(node, "ti,bit-shift", &val)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) pr_err("%pOFn missing bit-shift\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) clk_hw->enable_bit = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) ad->enable_mask = 0x3 << val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) ad->autoidle_mask = 0x3 << val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) pr_err("%pOFn missing idlest-shift\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) ad->idlest_mask = 1 << val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) ret = ti_clk_get_reg_addr(node, 0, &ad->control_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret |= ti_clk_get_reg_addr(node, 1, &ad->autoidle_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) ret |= ti_clk_get_reg_addr(node, 2, &ad->idlest_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, node->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (!IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) of_clk_add_provider(node, of_clk_src_simple_get, clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) kfree(init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) kfree(ad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) kfree(clk_hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) kfree(init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) CLK_OF_DECLARE(omap2_apll_clock, "ti,omap2-apll-clock",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) of_omap2_apll_setup);