1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2012 Freescale Semiconductor, Inc.
4 * Copyright 2012 Linaro Ltd.
7 #include <linux/bits.h>
9 #include <linux/clk-provider.h>
11 #include <linux/slab.h>
12 #include <linux/jiffies.h>
13 #include <linux/err.h>
16 static int clk_busy_wait(void __iomem
*reg
, u8 shift
)
18 unsigned long timeout
= jiffies
+ msecs_to_jiffies(10);
20 while (readl_relaxed(reg
) & (1 << shift
))
21 if (time_after(jiffies
, timeout
))
27 struct clk_busy_divider
{
28 struct clk_divider div
;
29 const struct clk_ops
*div_ops
;
34 static inline struct clk_busy_divider
*to_clk_busy_divider(struct clk_hw
*hw
)
36 struct clk_divider
*div
= to_clk_divider(hw
);
38 return container_of(div
, struct clk_busy_divider
, div
);
41 static unsigned long clk_busy_divider_recalc_rate(struct clk_hw
*hw
,
42 unsigned long parent_rate
)
44 struct clk_busy_divider
*busy
= to_clk_busy_divider(hw
);
46 return busy
->div_ops
->recalc_rate(&busy
->div
.hw
, parent_rate
);
49 static long clk_busy_divider_round_rate(struct clk_hw
*hw
, unsigned long rate
,
52 struct clk_busy_divider
*busy
= to_clk_busy_divider(hw
);
54 return busy
->div_ops
->round_rate(&busy
->div
.hw
, rate
, prate
);
57 static int clk_busy_divider_set_rate(struct clk_hw
*hw
, unsigned long rate
,
58 unsigned long parent_rate
)
60 struct clk_busy_divider
*busy
= to_clk_busy_divider(hw
);
63 ret
= busy
->div_ops
->set_rate(&busy
->div
.hw
, rate
, parent_rate
);
65 ret
= clk_busy_wait(busy
->reg
, busy
->shift
);
70 static const struct clk_ops clk_busy_divider_ops
= {
71 .recalc_rate
= clk_busy_divider_recalc_rate
,
72 .round_rate
= clk_busy_divider_round_rate
,
73 .set_rate
= clk_busy_divider_set_rate
,
76 struct clk_hw
*imx_clk_hw_busy_divider(const char *name
, const char *parent_name
,
77 void __iomem
*reg
, u8 shift
, u8 width
,
78 void __iomem
*busy_reg
, u8 busy_shift
)
80 struct clk_busy_divider
*busy
;
82 struct clk_init_data init
;
85 busy
= kzalloc(sizeof(*busy
), GFP_KERNEL
);
87 return ERR_PTR(-ENOMEM
);
90 busy
->shift
= busy_shift
;
93 busy
->div
.shift
= shift
;
94 busy
->div
.width
= width
;
95 busy
->div
.lock
= &imx_ccm_lock
;
96 busy
->div_ops
= &clk_divider_ops
;
99 init
.ops
= &clk_busy_divider_ops
;
100 init
.flags
= CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
;
101 init
.parent_names
= &parent_name
;
102 init
.num_parents
= 1;
104 busy
->div
.hw
.init
= &init
;
108 ret
= clk_hw_register(NULL
, hw
);
117 struct clk_busy_mux
{
119 const struct clk_ops
*mux_ops
;
124 static inline struct clk_busy_mux
*to_clk_busy_mux(struct clk_hw
*hw
)
126 struct clk_mux
*mux
= to_clk_mux(hw
);
128 return container_of(mux
, struct clk_busy_mux
, mux
);
131 static u8
clk_busy_mux_get_parent(struct clk_hw
*hw
)
133 struct clk_busy_mux
*busy
= to_clk_busy_mux(hw
);
135 return busy
->mux_ops
->get_parent(&busy
->mux
.hw
);
138 static int clk_busy_mux_set_parent(struct clk_hw
*hw
, u8 index
)
140 struct clk_busy_mux
*busy
= to_clk_busy_mux(hw
);
143 ret
= busy
->mux_ops
->set_parent(&busy
->mux
.hw
, index
);
145 ret
= clk_busy_wait(busy
->reg
, busy
->shift
);
150 static const struct clk_ops clk_busy_mux_ops
= {
151 .get_parent
= clk_busy_mux_get_parent
,
152 .set_parent
= clk_busy_mux_set_parent
,
155 struct clk_hw
*imx_clk_hw_busy_mux(const char *name
, void __iomem
*reg
, u8 shift
,
156 u8 width
, void __iomem
*busy_reg
, u8 busy_shift
,
157 const char * const *parent_names
, int num_parents
)
159 struct clk_busy_mux
*busy
;
161 struct clk_init_data init
;
164 busy
= kzalloc(sizeof(*busy
), GFP_KERNEL
);
166 return ERR_PTR(-ENOMEM
);
168 busy
->reg
= busy_reg
;
169 busy
->shift
= busy_shift
;
172 busy
->mux
.shift
= shift
;
173 busy
->mux
.mask
= BIT(width
) - 1;
174 busy
->mux
.lock
= &imx_ccm_lock
;
175 busy
->mux_ops
= &clk_mux_ops
;
178 init
.ops
= &clk_busy_mux_ops
;
179 init
.flags
= CLK_IS_CRITICAL
;
180 init
.parent_names
= parent_names
;
181 init
.num_parents
= num_parents
;
183 busy
->mux
.hw
.init
= &init
;
187 ret
= clk_hw_register(NULL
, hw
);