1 #include <linux/slab.h>
7 static LIST_HEAD(clk_pd_notifier_list);
9 static int __clk_pd_notify(struct clk *clk, unsigned long msg)
11 struct clk_pd_notifier *cn;
12 int ret = NOTIFY_DONE;
14 list_for_each_entry(cn, &clk_pd_notifier_list, node) {
16 ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
25 int rk_clk_pd_notifier_register(struct clk *clk, struct notifier_block *nb)
27 struct clk_pd_notifier *cn;
35 /* search the list of notifiers for this clk */
36 list_for_each_entry(cn, &clk_pd_notifier_list, node)
40 /* if clk wasn't in the notifier list, allocate new clk_notifier */
42 cn = kzalloc(sizeof(struct clk_pd_notifier), GFP_KERNEL);
47 srcu_init_notifier_head(&cn->notifier_head);
49 list_add(&cn->node, &clk_pd_notifier_list);
52 ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
54 //clk->notifier_count++;
57 //clk_prepare_unlock();
61 EXPORT_SYMBOL_GPL(rk_clk_pd_notifier_register);
63 int rk_clk_pd_notifier_unregister(struct clk *clk, struct notifier_block *nb)
65 struct clk_pd_notifier *cn = NULL;
73 list_for_each_entry(cn, &clk_pd_notifier_list, node)
78 ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
80 //clk->notifier_count--;
82 /* XXX the notifier code should handle this better */
83 if (!cn->notifier_head.head) {
84 srcu_cleanup_notifier_head(&cn->notifier_head);
93 //clk_prepare_unlock();
97 EXPORT_SYMBOL_GPL(rk_clk_pd_notifier_unregister);
99 static int clk_pd_endisable(struct clk_hw *hw, bool enable)
101 struct clk_pd *pd = to_clk_pd(hw);
102 unsigned long flags = 0;
106 spin_lock_irqsave(pd->lock, flags);
108 /* ret = rockchip_pmu_ops.set_power_domain(pd->id, enable); */
111 spin_unlock_irqrestore(pd->lock, flags);
116 static int clk_pd_enable(struct clk_hw *hw)
120 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_ENABLE);
122 ret = clk_pd_endisable(hw, true);
124 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_ENABLE);
129 static void clk_pd_disable(struct clk_hw *hw)
131 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_DISABLE);
133 clk_pd_endisable(hw, false);
135 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_DISABLE);
139 static int clk_pd_is_enabled(struct clk_hw *hw)
141 struct clk_pd *pd = to_clk_pd(hw);
143 return rockchip_pmu_ops.power_domain_is_on(pd->id);
147 static int clk_pd_prepare(struct clk_hw *hw)
149 __clk_pd_notify(hw->clk, RK_CLK_PD_PREPARE);
154 static void clk_pd_unprepare(struct clk_hw *hw)
156 __clk_pd_notify(hw->clk, RK_CLK_PD_UNPREPARE);
159 const struct clk_ops clk_pd_ops = {
160 .prepare = clk_pd_prepare,
161 .unprepare = clk_pd_unprepare,
162 .enable = clk_pd_enable,
163 .disable = clk_pd_disable,
164 /*.is_enabled = clk_pd_is_enabled,*/
167 static int clk_pd_virt_enable(struct clk_hw *hw)
169 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_ENABLE);
171 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_ENABLE);
176 static void clk_pd_virt_disable(struct clk_hw *hw)
178 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_DISABLE);
180 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_DISABLE);
183 const struct clk_ops clk_pd_virt_ops = {
184 .prepare = clk_pd_prepare,
185 .unprepare = clk_pd_unprepare,
186 .enable = clk_pd_virt_enable,
187 .disable = clk_pd_virt_disable,
191 struct clk *rk_clk_register_pd(struct device *dev, const char *name,
192 const char *parent_name, unsigned long flags,
193 u32 pd_id, spinlock_t *lock)
197 struct clk_init_data init;
200 /* allocate the pd */
201 pd = kzalloc(sizeof(struct clk_pd), GFP_KERNEL);
203 clk_err("%s: could not allocate pd clk\n", __func__);
204 return ERR_PTR(-ENOMEM);
208 init.flags = flags | CLK_IS_BASIC;
209 init.parent_names = (parent_name ? &parent_name: NULL);
210 init.num_parents = (parent_name ? 1 : 0);
212 if(pd_id == CLK_PD_VIRT)
213 init.ops = &clk_pd_virt_ops;
215 init.ops = &clk_pd_ops;
217 /* struct clk_pd assignments */
222 /* register the clock */
223 clk = clk_register(dev, &pd->hw);