162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Maxime Ripard 462306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk-provider.h> 862306a36Sopenharmony_ci#include <linux/io.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "ccu_gate.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_civoid ccu_gate_helper_disable(struct ccu_common *common, u32 gate) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci unsigned long flags; 1562306a36Sopenharmony_ci u32 reg; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci if (!gate) 1862306a36Sopenharmony_ci return; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci spin_lock_irqsave(common->lock, flags); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci reg = readl(common->base + common->reg); 2362306a36Sopenharmony_ci writel(reg & ~gate, common->base + common->reg); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci spin_unlock_irqrestore(common->lock, flags); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void ccu_gate_disable(struct clk_hw *hw) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct ccu_gate *cg = hw_to_ccu_gate(hw); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return ccu_gate_helper_disable(&cg->common, cg->enable); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint ccu_gate_helper_enable(struct ccu_common *common, u32 gate) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci unsigned long flags; 3962306a36Sopenharmony_ci u32 reg; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!gate) 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci spin_lock_irqsave(common->lock, flags); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci reg = readl(common->base + common->reg); 4762306a36Sopenharmony_ci writel(reg | gate, common->base + common->reg); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci spin_unlock_irqrestore(common->lock, flags); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int ccu_gate_enable(struct clk_hw *hw) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct ccu_gate *cg = hw_to_ccu_gate(hw); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return ccu_gate_helper_enable(&cg->common, cg->enable); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciint ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci if (!gate) 6562306a36Sopenharmony_ci return 1; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return readl(common->base + common->reg) & gate; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int ccu_gate_is_enabled(struct clk_hw *hw) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct ccu_gate *cg = hw_to_ccu_gate(hw); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return ccu_gate_helper_is_enabled(&cg->common, cg->enable); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic unsigned long ccu_gate_recalc_rate(struct clk_hw *hw, 7962306a36Sopenharmony_ci unsigned long parent_rate) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct ccu_gate *cg = hw_to_ccu_gate(hw); 8262306a36Sopenharmony_ci unsigned long rate = parent_rate; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (cg->common.features & CCU_FEATURE_ALL_PREDIV) 8562306a36Sopenharmony_ci rate /= cg->common.prediv; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return rate; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate, 9162306a36Sopenharmony_ci unsigned long *prate) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct ccu_gate *cg = hw_to_ccu_gate(hw); 9462306a36Sopenharmony_ci int div = 1; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (cg->common.features & CCU_FEATURE_ALL_PREDIV) 9762306a36Sopenharmony_ci div = cg->common.prediv; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { 10062306a36Sopenharmony_ci unsigned long best_parent = rate; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (cg->common.features & CCU_FEATURE_ALL_PREDIV) 10362306a36Sopenharmony_ci best_parent *= div; 10462306a36Sopenharmony_ci *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return *prate / div; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate, 11162306a36Sopenharmony_ci unsigned long parent_rate) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * We must report success but we can do so unconditionally because 11562306a36Sopenharmony_ci * clk_factor_round_rate returns values that ensure this call is a 11662306a36Sopenharmony_ci * nop. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciconst struct clk_ops ccu_gate_ops = { 12362306a36Sopenharmony_ci .disable = ccu_gate_disable, 12462306a36Sopenharmony_ci .enable = ccu_gate_enable, 12562306a36Sopenharmony_ci .is_enabled = ccu_gate_is_enabled, 12662306a36Sopenharmony_ci .round_rate = ccu_gate_round_rate, 12762306a36Sopenharmony_ci .set_rate = ccu_gate_set_rate, 12862306a36Sopenharmony_ci .recalc_rate = ccu_gate_recalc_rate, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU); 131