^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 (C) 2016 Maxime Ripard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Maxime Ripard <maxime.ripard@free-electrons.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/clk-provider.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/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "ccu_frac.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) bool ccu_frac_helper_is_enabled(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct ccu_frac_internal *cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) return !(readl(common->base + common->reg) & cf->enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) void ccu_frac_helper_enable(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct ccu_frac_internal *cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) spin_lock_irqsave(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) reg = readl(common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) writel(reg & ~cf->enable, common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) spin_unlock_irqrestore(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) void ccu_frac_helper_disable(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct ccu_frac_internal *cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) spin_lock_irqsave(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) reg = readl(common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) writel(reg | cf->enable, common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) spin_unlock_irqrestore(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) bool ccu_frac_helper_has_rate(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct ccu_frac_internal *cf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned long rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return (cf->rates[0] == rate) || (cf->rates[1] == rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct ccu_frac_internal *cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) pr_debug("%s: clock is fractional (rates %lu and %lu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) reg = readl(common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) clk_hw_get_name(&common->hw), reg, cf->select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
^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) int ccu_frac_helper_set_rate(struct ccu_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct ccu_frac_internal *cf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long rate, u32 lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 reg, sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!(common->features & CCU_FEATURE_FRACTIONAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (cf->rates[0] == rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) sel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) else if (cf->rates[1] == rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) sel = cf->select;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) spin_lock_irqsave(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) reg = readl(common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) reg &= ~cf->select;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) writel(reg | sel, common->base + common->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) spin_unlock_irqrestore(common->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ccu_helper_wait_for_lock(common, lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }