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);
138 static int clk_pd_is_enabled(struct clk_hw *hw)
140 struct clk_pd *pd = to_clk_pd(hw);
142 return rockchip_pmu_ops.power_domain_is_on(pd->id);
145 static int clk_pd_prepare(struct clk_hw *hw)
147 __clk_pd_notify(hw->clk, RK_CLK_PD_PREPARE);
152 static void clk_pd_unprepare(struct clk_hw *hw)
154 __clk_pd_notify(hw->clk, RK_CLK_PD_UNPREPARE);
157 const struct clk_ops clk_pd_ops = {
158 .prepare = clk_pd_prepare,
159 .unprepare = clk_pd_unprepare,
160 .enable = clk_pd_enable,
161 .disable = clk_pd_disable,
162 .is_enabled = clk_pd_is_enabled,
165 static int clk_pd_virt_enable(struct clk_hw *hw)
167 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_ENABLE);
169 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_ENABLE);
174 static void clk_pd_virt_disable(struct clk_hw *hw)
176 __clk_pd_notify(hw->clk, RK_CLK_PD_PRE_DISABLE);
178 __clk_pd_notify(hw->clk, RK_CLK_PD_POST_DISABLE);
181 const struct clk_ops clk_pd_virt_ops = {
182 .prepare = clk_pd_prepare,
183 .unprepare = clk_pd_unprepare,
184 .enable = clk_pd_virt_enable,
185 .disable = clk_pd_virt_disable,
189 struct clk *rk_clk_register_pd(struct device *dev, const char *name,
190 const char *parent_name, unsigned long flags,
191 u32 pd_id, spinlock_t *lock)
195 struct clk_init_data init;
198 /* allocate the pd */
199 pd = kzalloc(sizeof(struct clk_pd), GFP_KERNEL);
201 clk_err("%s: could not allocate pd clk\n", __func__);
202 return ERR_PTR(-ENOMEM);
206 init.flags = flags | CLK_IS_BASIC;
207 init.parent_names = (parent_name ? &parent_name: NULL);
208 init.num_parents = (parent_name ? 1 : 0);
210 if(pd_id == CLK_PD_VIRT)
211 init.ops = &clk_pd_virt_ops;
213 init.ops = &clk_pd_ops;
215 /* struct clk_pd assignments */
220 /* register the clock */
221 clk = clk_register(dev, &pd->hw);