0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/io.h>
0009 #include <linux/spinlock.h>
0010
0011 #include "ccu_frac.h"
0012
0013 bool ccu_frac_helper_is_enabled(struct ccu_common *common,
0014 struct ccu_frac_internal *cf)
0015 {
0016 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0017 return false;
0018
0019 return !(readl(common->base + common->reg) & cf->enable);
0020 }
0021 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU);
0022
0023 void ccu_frac_helper_enable(struct ccu_common *common,
0024 struct ccu_frac_internal *cf)
0025 {
0026 unsigned long flags;
0027 u32 reg;
0028
0029 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0030 return;
0031
0032 spin_lock_irqsave(common->lock, flags);
0033 reg = readl(common->base + common->reg);
0034 writel(reg & ~cf->enable, common->base + common->reg);
0035 spin_unlock_irqrestore(common->lock, flags);
0036 }
0037 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU);
0038
0039 void ccu_frac_helper_disable(struct ccu_common *common,
0040 struct ccu_frac_internal *cf)
0041 {
0042 unsigned long flags;
0043 u32 reg;
0044
0045 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0046 return;
0047
0048 spin_lock_irqsave(common->lock, flags);
0049 reg = readl(common->base + common->reg);
0050 writel(reg | cf->enable, common->base + common->reg);
0051 spin_unlock_irqrestore(common->lock, flags);
0052 }
0053 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU);
0054
0055 bool ccu_frac_helper_has_rate(struct ccu_common *common,
0056 struct ccu_frac_internal *cf,
0057 unsigned long rate)
0058 {
0059 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0060 return false;
0061
0062 return (cf->rates[0] == rate) || (cf->rates[1] == rate);
0063 }
0064 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU);
0065
0066 unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
0067 struct ccu_frac_internal *cf)
0068 {
0069 u32 reg;
0070
0071 pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
0072
0073 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0074 return 0;
0075
0076 pr_debug("%s: clock is fractional (rates %lu and %lu)\n",
0077 clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
0078
0079 reg = readl(common->base + common->reg);
0080
0081 pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
0082 clk_hw_get_name(&common->hw), reg, cf->select);
0083
0084 return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
0085 }
0086 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU);
0087
0088 int ccu_frac_helper_set_rate(struct ccu_common *common,
0089 struct ccu_frac_internal *cf,
0090 unsigned long rate, u32 lock)
0091 {
0092 unsigned long flags;
0093 u32 reg, sel;
0094
0095 if (!(common->features & CCU_FEATURE_FRACTIONAL))
0096 return -EINVAL;
0097
0098 if (cf->rates[0] == rate)
0099 sel = 0;
0100 else if (cf->rates[1] == rate)
0101 sel = cf->select;
0102 else
0103 return -EINVAL;
0104
0105 spin_lock_irqsave(common->lock, flags);
0106 reg = readl(common->base + common->reg);
0107 reg &= ~cf->select;
0108 writel(reg | sel, common->base + common->reg);
0109 spin_unlock_irqrestore(common->lock, flags);
0110
0111 ccu_helper_wait_for_lock(common, lock);
0112
0113 return 0;
0114 }
0115 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU);