1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/init.h>
8 #include <linux/delay.h>
10 #include <linux/clk-provider.h>
11 #include <linux/spinlock.h>
13 #include <asm/krait-l2-accessors.h>
15 #include "clk-krait.h"
17 /* Secondary and primary muxes share the same cp15 register */
18 static DEFINE_SPINLOCK(krait_clock_reg_lock
);
21 static void __krait_mux_set_sel(struct krait_mux_clk
*mux
, int sel
)
26 spin_lock_irqsave(&krait_clock_reg_lock
, flags
);
27 regval
= krait_get_l2_indirect_reg(mux
->offset
);
28 regval
&= ~(mux
->mask
<< mux
->shift
);
29 regval
|= (sel
& mux
->mask
) << mux
->shift
;
31 regval
&= ~(mux
->mask
<< (mux
->shift
+ LPL_SHIFT
));
32 regval
|= (sel
& mux
->mask
) << (mux
->shift
+ LPL_SHIFT
);
34 krait_set_l2_indirect_reg(mux
->offset
, regval
);
35 spin_unlock_irqrestore(&krait_clock_reg_lock
, flags
);
37 /* Wait for switch to complete. */
42 static int krait_mux_set_parent(struct clk_hw
*hw
, u8 index
)
44 struct krait_mux_clk
*mux
= to_krait_mux_clk(hw
);
47 sel
= clk_mux_index_to_val(mux
->parent_map
, 0, index
);
49 /* Don't touch mux if CPU is off as it won't work */
50 if (__clk_is_enabled(hw
->clk
))
51 __krait_mux_set_sel(mux
, sel
);
58 static u8
krait_mux_get_parent(struct clk_hw
*hw
)
60 struct krait_mux_clk
*mux
= to_krait_mux_clk(hw
);
63 sel
= krait_get_l2_indirect_reg(mux
->offset
);
68 return clk_mux_val_to_index(hw
, mux
->parent_map
, 0, sel
);
71 const struct clk_ops krait_mux_clk_ops
= {
72 .set_parent
= krait_mux_set_parent
,
73 .get_parent
= krait_mux_get_parent
,
74 .determine_rate
= __clk_mux_determine_rate_closest
,
76 EXPORT_SYMBOL_GPL(krait_mux_clk_ops
);
78 /* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
79 static long krait_div2_round_rate(struct clk_hw
*hw
, unsigned long rate
,
80 unsigned long *parent_rate
)
82 *parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
), rate
* 2);
83 return DIV_ROUND_UP(*parent_rate
, 2);
86 static int krait_div2_set_rate(struct clk_hw
*hw
, unsigned long rate
,
87 unsigned long parent_rate
)
89 struct krait_div2_clk
*d
= to_krait_div2_clk(hw
);
92 u32 mask
= BIT(d
->width
) - 1;
95 mask
= mask
<< (d
->shift
+ LPL_SHIFT
) | mask
<< d
->shift
;
97 spin_lock_irqsave(&krait_clock_reg_lock
, flags
);
98 val
= krait_get_l2_indirect_reg(d
->offset
);
100 krait_set_l2_indirect_reg(d
->offset
, val
);
101 spin_unlock_irqrestore(&krait_clock_reg_lock
, flags
);
107 krait_div2_recalc_rate(struct clk_hw
*hw
, unsigned long parent_rate
)
109 struct krait_div2_clk
*d
= to_krait_div2_clk(hw
);
110 u32 mask
= BIT(d
->width
) - 1;
113 div
= krait_get_l2_indirect_reg(d
->offset
);
118 return DIV_ROUND_UP(parent_rate
, div
);
121 const struct clk_ops krait_div2_clk_ops
= {
122 .round_rate
= krait_div2_round_rate
,
123 .set_rate
= krait_div2_set_rate
,
124 .recalc_rate
= krait_div2_recalc_rate
,
126 EXPORT_SYMBOL_GPL(krait_div2_clk_ops
);