0001
0002
0003
0004
0005
0006 #include <linux/slab.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/io.h>
0009 #include <linux/spinlock.h>
0010 #include <linux/kernel.h>
0011 #include "clk.h"
0012
0013 struct rockchip_inv_clock {
0014 struct clk_hw hw;
0015 void __iomem *reg;
0016 int shift;
0017 int flags;
0018 spinlock_t *lock;
0019 };
0020
0021 #define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw)
0022
0023 #define INVERTER_MASK 0x1
0024
0025 static int rockchip_inv_get_phase(struct clk_hw *hw)
0026 {
0027 struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
0028 u32 val;
0029
0030 val = readl(inv_clock->reg) >> inv_clock->shift;
0031 val &= INVERTER_MASK;
0032 return val ? 180 : 0;
0033 }
0034
0035 static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees)
0036 {
0037 struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
0038 u32 val;
0039
0040 if (degrees % 180 == 0) {
0041 val = !!degrees;
0042 } else {
0043 pr_err("%s: unsupported phase %d for %s\n",
0044 __func__, degrees, clk_hw_get_name(hw));
0045 return -EINVAL;
0046 }
0047
0048 if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) {
0049 writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift),
0050 inv_clock->reg);
0051 } else {
0052 unsigned long flags;
0053 u32 reg;
0054
0055 spin_lock_irqsave(inv_clock->lock, flags);
0056
0057 reg = readl(inv_clock->reg);
0058 reg &= ~BIT(inv_clock->shift);
0059 reg |= val;
0060 writel(reg, inv_clock->reg);
0061
0062 spin_unlock_irqrestore(inv_clock->lock, flags);
0063 }
0064
0065 return 0;
0066 }
0067
0068 static const struct clk_ops rockchip_inv_clk_ops = {
0069 .get_phase = rockchip_inv_get_phase,
0070 .set_phase = rockchip_inv_set_phase,
0071 };
0072
0073 struct clk *rockchip_clk_register_inverter(const char *name,
0074 const char *const *parent_names, u8 num_parents,
0075 void __iomem *reg, int shift, int flags,
0076 spinlock_t *lock)
0077 {
0078 struct clk_init_data init;
0079 struct rockchip_inv_clock *inv_clock;
0080 struct clk *clk;
0081
0082 inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL);
0083 if (!inv_clock)
0084 return ERR_PTR(-ENOMEM);
0085
0086 init.name = name;
0087 init.num_parents = num_parents;
0088 init.flags = CLK_SET_RATE_PARENT;
0089 init.parent_names = parent_names;
0090 init.ops = &rockchip_inv_clk_ops;
0091
0092 inv_clock->hw.init = &init;
0093 inv_clock->reg = reg;
0094 inv_clock->shift = shift;
0095 inv_clock->flags = flags;
0096 inv_clock->lock = lock;
0097
0098 clk = clk_register(NULL, &inv_clock->hw);
0099 if (IS_ERR(clk))
0100 kfree(inv_clock);
0101
0102 return clk;
0103 }