0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/io.h>
0009
0010 #include "ccu_gate.h"
0011
0012 void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
0013 {
0014 unsigned long flags;
0015 u32 reg;
0016
0017 if (!gate)
0018 return;
0019
0020 spin_lock_irqsave(common->lock, flags);
0021
0022 reg = readl(common->base + common->reg);
0023 writel(reg & ~gate, common->base + common->reg);
0024
0025 spin_unlock_irqrestore(common->lock, flags);
0026 }
0027 EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU);
0028
0029 static void ccu_gate_disable(struct clk_hw *hw)
0030 {
0031 struct ccu_gate *cg = hw_to_ccu_gate(hw);
0032
0033 return ccu_gate_helper_disable(&cg->common, cg->enable);
0034 }
0035
0036 int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
0037 {
0038 unsigned long flags;
0039 u32 reg;
0040
0041 if (!gate)
0042 return 0;
0043
0044 spin_lock_irqsave(common->lock, flags);
0045
0046 reg = readl(common->base + common->reg);
0047 writel(reg | gate, common->base + common->reg);
0048
0049 spin_unlock_irqrestore(common->lock, flags);
0050
0051 return 0;
0052 }
0053 EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU);
0054
0055 static int ccu_gate_enable(struct clk_hw *hw)
0056 {
0057 struct ccu_gate *cg = hw_to_ccu_gate(hw);
0058
0059 return ccu_gate_helper_enable(&cg->common, cg->enable);
0060 }
0061
0062 int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
0063 {
0064 if (!gate)
0065 return 1;
0066
0067 return readl(common->base + common->reg) & gate;
0068 }
0069 EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU);
0070
0071 static int ccu_gate_is_enabled(struct clk_hw *hw)
0072 {
0073 struct ccu_gate *cg = hw_to_ccu_gate(hw);
0074
0075 return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
0076 }
0077
0078 static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
0079 unsigned long parent_rate)
0080 {
0081 struct ccu_gate *cg = hw_to_ccu_gate(hw);
0082 unsigned long rate = parent_rate;
0083
0084 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
0085 rate /= cg->common.prediv;
0086
0087 return rate;
0088 }
0089
0090 static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
0091 unsigned long *prate)
0092 {
0093 struct ccu_gate *cg = hw_to_ccu_gate(hw);
0094 int div = 1;
0095
0096 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
0097 div = cg->common.prediv;
0098
0099 if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
0100 unsigned long best_parent = rate;
0101
0102 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
0103 best_parent *= div;
0104 *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
0105 }
0106
0107 return *prate / div;
0108 }
0109
0110 static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
0111 unsigned long parent_rate)
0112 {
0113
0114
0115
0116
0117
0118
0119 return 0;
0120 }
0121
0122 const struct clk_ops ccu_gate_ops = {
0123 .disable = ccu_gate_disable,
0124 .enable = ccu_gate_enable,
0125 .is_enabled = ccu_gate_is_enabled,
0126 .round_rate = ccu_gate_round_rate,
0127 .set_rate = ccu_gate_set_rate,
0128 .recalc_rate = ccu_gate_recalc_rate,
0129 };
0130 EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU);