131 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2016 Maxime Ripard4 * Maxime Ripard <maxime.ripard@free-electrons.com>5 */6 7#include <linux/clk-provider.h>8#include <linux/io.h>9 10#include "ccu_gate.h"11 12void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)13{14 unsigned long flags;15 u32 reg;16 17 if (!gate)18 return;19 20 spin_lock_irqsave(common->lock, flags);21 22 reg = readl(common->base + common->reg);23 writel(reg & ~gate, common->base + common->reg);24 25 spin_unlock_irqrestore(common->lock, flags);26}27EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU);28 29static void ccu_gate_disable(struct clk_hw *hw)30{31 struct ccu_gate *cg = hw_to_ccu_gate(hw);32 33 return ccu_gate_helper_disable(&cg->common, cg->enable);34}35 36int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)37{38 unsigned long flags;39 u32 reg;40 41 if (!gate)42 return 0;43 44 spin_lock_irqsave(common->lock, flags);45 46 reg = readl(common->base + common->reg);47 writel(reg | gate, common->base + common->reg);48 49 spin_unlock_irqrestore(common->lock, flags);50 51 return 0;52}53EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU);54 55static int ccu_gate_enable(struct clk_hw *hw)56{57 struct ccu_gate *cg = hw_to_ccu_gate(hw);58 59 return ccu_gate_helper_enable(&cg->common, cg->enable);60}61 62int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)63{64 if (!gate)65 return 1;66 67 return readl(common->base + common->reg) & gate;68}69EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU);70 71static int ccu_gate_is_enabled(struct clk_hw *hw)72{73 struct ccu_gate *cg = hw_to_ccu_gate(hw);74 75 return ccu_gate_helper_is_enabled(&cg->common, cg->enable);76}77 78static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,79 unsigned long parent_rate)80{81 struct ccu_gate *cg = hw_to_ccu_gate(hw);82 unsigned long rate = parent_rate;83 84 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)85 rate /= cg->common.prediv;86 87 return rate;88}89 90static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,91 unsigned long *prate)92{93 struct ccu_gate *cg = hw_to_ccu_gate(hw);94 int div = 1;95 96 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)97 div = cg->common.prediv;98 99 if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {100 unsigned long best_parent = rate;101 102 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)103 best_parent *= div;104 *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);105 }106 107 return *prate / div;108}109 110static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,111 unsigned long parent_rate)112{113 /*114 * We must report success but we can do so unconditionally because115 * clk_factor_round_rate returns values that ensure this call is a116 * nop.117 */118 119 return 0;120}121 122const struct clk_ops ccu_gate_ops = {123 .disable = ccu_gate_disable,124 .enable = ccu_gate_enable,125 .is_enabled = ccu_gate_is_enabled,126 .round_rate = ccu_gate_round_rate,127 .set_rate = ccu_gate_set_rate,128 .recalc_rate = ccu_gate_recalc_rate,129};130EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU);131