0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013
0014 #include "clk.h"
0015
0016 struct clk_hisi_phase {
0017 struct clk_hw hw;
0018 void __iomem *reg;
0019 u32 *phase_degrees;
0020 u32 *phase_regvals;
0021 u8 phase_num;
0022 u32 mask;
0023 u8 shift;
0024 u8 flags;
0025 spinlock_t *lock;
0026 };
0027
0028 #define to_clk_hisi_phase(_hw) container_of(_hw, struct clk_hisi_phase, hw)
0029
0030 static int hisi_phase_regval_to_degrees(struct clk_hisi_phase *phase,
0031 u32 regval)
0032 {
0033 int i;
0034
0035 for (i = 0; i < phase->phase_num; i++)
0036 if (phase->phase_regvals[i] == regval)
0037 return phase->phase_degrees[i];
0038
0039 return -EINVAL;
0040 }
0041
0042 static int hisi_clk_get_phase(struct clk_hw *hw)
0043 {
0044 struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
0045 u32 regval;
0046
0047 regval = readl(phase->reg);
0048 regval = (regval & phase->mask) >> phase->shift;
0049
0050 return hisi_phase_regval_to_degrees(phase, regval);
0051 }
0052
0053 static int hisi_phase_degrees_to_regval(struct clk_hisi_phase *phase,
0054 int degrees)
0055 {
0056 int i;
0057
0058 for (i = 0; i < phase->phase_num; i++)
0059 if (phase->phase_degrees[i] == degrees)
0060 return phase->phase_regvals[i];
0061
0062 return -EINVAL;
0063 }
0064
0065 static int hisi_clk_set_phase(struct clk_hw *hw, int degrees)
0066 {
0067 struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
0068 unsigned long flags = 0;
0069 int regval;
0070 u32 val;
0071
0072 regval = hisi_phase_degrees_to_regval(phase, degrees);
0073 if (regval < 0)
0074 return regval;
0075
0076 spin_lock_irqsave(phase->lock, flags);
0077
0078 val = readl(phase->reg);
0079 val &= ~phase->mask;
0080 val |= regval << phase->shift;
0081 writel(val, phase->reg);
0082
0083 spin_unlock_irqrestore(phase->lock, flags);
0084
0085 return 0;
0086 }
0087
0088 static const struct clk_ops clk_phase_ops = {
0089 .get_phase = hisi_clk_get_phase,
0090 .set_phase = hisi_clk_set_phase,
0091 };
0092
0093 struct clk *clk_register_hisi_phase(struct device *dev,
0094 const struct hisi_phase_clock *clks,
0095 void __iomem *base, spinlock_t *lock)
0096 {
0097 struct clk_hisi_phase *phase;
0098 struct clk_init_data init;
0099
0100 phase = devm_kzalloc(dev, sizeof(struct clk_hisi_phase), GFP_KERNEL);
0101 if (!phase)
0102 return ERR_PTR(-ENOMEM);
0103
0104 init.name = clks->name;
0105 init.ops = &clk_phase_ops;
0106 init.flags = clks->flags;
0107 init.parent_names = clks->parent_names ? &clks->parent_names : NULL;
0108 init.num_parents = clks->parent_names ? 1 : 0;
0109
0110 phase->reg = base + clks->offset;
0111 phase->shift = clks->shift;
0112 phase->mask = (BIT(clks->width) - 1) << clks->shift;
0113 phase->lock = lock;
0114 phase->phase_degrees = clks->phase_degrees;
0115 phase->phase_regvals = clks->phase_regvals;
0116 phase->phase_num = clks->phase_num;
0117 phase->hw.init = &init;
0118
0119 return devm_clk_register(dev, &phase->hw);
0120 }
0121 EXPORT_SYMBOL_GPL(clk_register_hisi_phase);