^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "ccu_gate.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "ccu_div.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct clk_hw *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) unsigned long *parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct ccu_div *cd = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) rate *= cd->fixed_post_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) rate = divider_round_rate_parent(&cd->common.hw, parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) rate, parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) cd->div.table, cd->div.width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) cd->div.flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) rate /= cd->fixed_post_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static void ccu_div_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return ccu_gate_helper_disable(&cd->common, cd->enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static int ccu_div_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return ccu_gate_helper_enable(&cd->common, cd->enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int ccu_div_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return ccu_gate_helper_is_enabled(&cd->common, cd->enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) reg = readl(cd->common.base + cd->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) val = reg >> cd->div.shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) val &= (1 << cd->div.width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) val = divider_recalc_rate(hw, parent_rate, val, cd->div.table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) cd->div.flags, cd->div.width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) val /= cd->fixed_post_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int ccu_div_determine_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct clk_rate_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) req, ccu_div_round_rate, cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) rate *= cd->fixed_post_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) cd->div.flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) spin_lock_irqsave(cd->common.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) reg = readl(cd->common.base + cd->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) writel(reg | (val << cd->div.shift),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) cd->common.base + cd->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) spin_unlock_irqrestore(cd->common.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static u8 ccu_div_get_parent(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return ccu_mux_helper_get_parent(&cd->common, &cd->mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct ccu_div *cd = hw_to_ccu_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) const struct clk_ops ccu_div_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .disable = ccu_div_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .enable = ccu_div_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .is_enabled = ccu_div_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .get_parent = ccu_div_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .set_parent = ccu_div_set_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .determine_rate = ccu_div_determine_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .recalc_rate = ccu_div_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .set_rate = ccu_div_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };