^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2012 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * struct clk_ref - mxs reference clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * @hw: clk_hw for the reference clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * @reg: register address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @idx: the index of the reference clock within the same register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * The mxs reference clock sources from pll. Every 4 reference clocks share
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * one register space, and @idx is used to identify them. Each reference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * clock has a gate control and a fractional * divider. The rate is calculated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * as pll rate * (18 / FRAC), where FRAC = 18 ~ 35.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct clk_ref {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct clk_hw hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u8 idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int clk_ref_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct clk_ref *ref = to_clk_ref(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + CLR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static void clk_ref_disable(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_ref *ref = to_clk_ref(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + SET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static unsigned long clk_ref_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct clk_ref *ref = to_clk_ref(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u64 tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u8 frac = (readl_relaxed(ref->reg) >> (ref->idx * 8)) & 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) tmp *= 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) do_div(tmp, frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long parent_rate = *prate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u64 tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u8 frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) tmp = tmp * 18 + rate / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) do_div(tmp, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) frac = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (frac < 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) frac = 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) else if (frac > 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) frac = 35;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) tmp *= 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) do_div(tmp, frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct clk_ref *ref = to_clk_ref(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u64 tmp = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u8 frac, shift = ref->idx * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) tmp = tmp * 18 + rate / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) do_div(tmp, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) frac = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (frac < 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) frac = 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) else if (frac > 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) frac = 35;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) spin_lock_irqsave(&mxs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) val = readl_relaxed(ref->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) val &= ~(0x3f << shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) val |= frac << shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) writel_relaxed(val, ref->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) spin_unlock_irqrestore(&mxs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static const struct clk_ops clk_ref_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .enable = clk_ref_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .disable = clk_ref_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .recalc_rate = clk_ref_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .round_rate = clk_ref_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .set_rate = clk_ref_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct clk *mxs_clk_ref(const char *name, const char *parent_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) void __iomem *reg, u8 idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct clk_ref *ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ref = kzalloc(sizeof(*ref), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) init.ops = &clk_ref_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) init.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) init.parent_names = (parent_name ? &parent_name: NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) init.num_parents = (parent_name ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ref->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ref->idx = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ref->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) clk = clk_register(NULL, &ref->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) kfree(ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }