^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_frac - mxs fractional divider clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * @hw: clk_hw for the fractional divider clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * @reg: register address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @shift: the divider bit shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * @width: the divider bit width
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * @busy: busy bit shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * The clock is an adjustable fractional divider with a busy bit to wait
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * when the divider is adjusted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct clk_frac {
^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 shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) u8 width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) u8 busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct clk_frac *frac = to_clk_frac(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u32 div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u64 tmp_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) div = readl_relaxed(frac->reg) >> frac->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) div &= (1 << frac->width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) tmp_rate = (u64)parent_rate * div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return tmp_rate >> frac->width;
^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 long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct clk_frac *frac = to_clk_frac(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long parent_rate = *prate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u32 div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u64 tmp, tmp_rate, result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (rate > parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) tmp = rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) tmp <<= frac->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) do_div(tmp, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) div = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (!div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) tmp_rate = (u64)parent_rate * div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) result = tmp_rate >> frac->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if ((result << frac->width) < tmp_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) result += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct clk_frac *frac = to_clk_frac(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u32 div, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (rate > parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) tmp = rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) tmp <<= frac->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) do_div(tmp, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) div = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (!div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) spin_lock_irqsave(&mxs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) val = readl_relaxed(frac->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) val &= ~(((1 << frac->width) - 1) << frac->shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) val |= div << frac->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) writel_relaxed(val, frac->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) spin_unlock_irqrestore(&mxs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return mxs_clk_wait(frac->reg, frac->busy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static const struct clk_ops clk_frac_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .recalc_rate = clk_frac_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .round_rate = clk_frac_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .set_rate = clk_frac_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct clk *mxs_clk_frac(const char *name, const char *parent_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) void __iomem *reg, u8 shift, u8 width, u8 busy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct clk_frac *frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) frac = kzalloc(sizeof(*frac), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!frac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) init.ops = &clk_frac_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) init.flags = CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) init.parent_names = (parent_name ? &parent_name: NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) init.num_parents = (parent_name ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) frac->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) frac->shift = shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) frac->width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) frac->busy = busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) frac->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) clk = clk_register(NULL, &frac->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) kfree(frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }